Last active
May 26, 2025 22:23
-
-
Save vchrombie/722374781d687bbdf9e4f62584adc9db to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import re | |
from collections import defaultdict | |
def parse_line(line): | |
""" | |
Parse a single line of input. | |
Expected formats: | |
- Client<TAB>AppServer<TAB>Instance Mismatch (a/b) | |
- Client<TAB>AppServer<TAB>SAM unreachable on <hostname> | |
Returns tuple (client, target, (action, a, b)) or None if no action needed. | |
""" | |
parts = line.strip().split('\t') | |
if len(parts) != 3: | |
return None | |
client, target, msg = parts | |
# Instance mismatch case | |
m = re.match(r'Instance Mismatch \((\d+)/(\d+)\)', msg) | |
if m: | |
a, b = map(int, m.groups()) | |
if a < b: | |
action = 'start' | |
elif a > b: | |
action = 'stop extra' | |
else: | |
return None | |
return client, target, (action, a, b) | |
# SAM unreachable case | |
m2 = re.match(r'SAM is unreachable on (\S+)', msg) | |
if m2: | |
host = m2.group(1) | |
return client, host, ('agent-start', None, None) | |
return None | |
def group_records(records): | |
""" | |
Build grouping structures: | |
- by_client[(client, action)] = set of targets (appservers or hosts) | |
- by_server[(server, action)] = set of clients | |
Also collects reasons for mismatch actions. | |
""" | |
by_client = defaultdict(set) | |
by_server = defaultdict(set) | |
reasons = defaultdict(set) | |
for rec in records: | |
client, target, (action, a, b) = rec | |
key = (client, action) | |
if action == 'agent-start': | |
by_client[key].add(target) | |
else: | |
by_client[key].add(target) | |
by_server[(target, action)].add(client) | |
reason = ( | |
"Instances fewer than expected" | |
if action == 'start' | |
else "Instances exceed expected" | |
) | |
reasons[key].add(reason) | |
return by_client, by_server, reasons | |
def format_samsh_command(action, clients, servers, reason=None): | |
""" | |
Format a samsh.pl command. | |
- For agent-start: include client outside quotes, list of hosts inside, with simple reason. | |
- For mismatch actions: include -c flag and full quoted payload with reason. | |
""" | |
base = "/usr/local/bfm/etc/samsh.pl" | |
if action == 'agent-start': | |
client = clients[0] | |
hosts = " ".join(servers) | |
# simple reason for SAM start | |
return f"{base} {client} -c '{action} {hosts} -r Starting SAM'" | |
else: | |
payload = f"{action} client={','.join(clients)} name={','.join(servers)}" | |
if reason: | |
payload += f" -r {reason}" | |
return f"{base} -c '{payload}'" | |
def generate_commands(by_client, by_server, reasons): | |
""" | |
Create the final list of commands in this order: | |
1. agent-start groups (per client) | |
2. instance-mismatch groups by client (multi-target) | |
3. instance-mismatch groups by server (multi-client) | |
4. any remaining single commands | |
""" | |
used = set() | |
cmds = [] | |
# 1. agent-start (unreachable) by client | |
for (client, action), targets in sorted(by_client.items()): | |
if action == 'agent-start': | |
servers = sorted(targets) | |
cmds.append(format_samsh_command(action, [client], servers)) | |
for srv in servers: | |
used.add((client, srv, action)) | |
# 2. instance-mismatch group by client (multi-target) | |
for (client, action), servers in sorted(by_client.items()): | |
if action in ('start', 'stop extra') and len(servers) > 1: | |
reason_text = next(iter(reasons[(client, action)])) | |
cmds.append(format_samsh_command( | |
action, [client], sorted(servers), reason_text | |
)) | |
for srv in servers: | |
used.add((client, srv, action)) | |
# 3. instance-mismatch group by server (multi-client) | |
for (server, action), clients in sorted(by_server.items()): | |
remaining = [c for c in sorted(clients) | |
if (c, server, action) not in used] | |
if len(remaining) > 1: | |
reason_text = next(iter(reasons[(remaining[0], action)])) | |
cmds.append(format_samsh_command( | |
action, remaining, [server], reason_text | |
)) | |
for c in remaining: | |
used.add((c, server, action)) | |
# 4. remaining individual commands | |
for (client, action), servers in sorted(by_client.items()): | |
for server in sorted(servers): | |
if (client, server, action) not in used: | |
reason_text = next(iter(reasons[(client, action)]), None) | |
cmds.append(format_samsh_command( | |
action, [client], [server], reason_text | |
)) | |
used.add((client, server, action)) | |
return cmds | |
def write_script(commands, output_file='samsh.sh'): | |
""" | |
Write the commands to a bash script with header. | |
""" | |
with open(output_file, 'w') as f: | |
for cmd in commands: | |
f.write(cmd + '\n') | |
def main(): | |
input_file = 'samsh.txt' | |
records = [] | |
with open(input_file, 'r') as f: | |
for line in f: | |
parsed = parse_line(line) | |
if parsed: | |
records.append(parsed) | |
by_client, by_server, reasons = group_records(records) | |
commands = generate_commands(by_client, by_server, reasons) | |
write_script(commands, output_file='samsh.sh') | |
if __name__ == '__main__': | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/usr/local/bfm/etc/samsh.pl "stop extra client=BLK name=LogRaiderSenseBetaServer,RTCServer_BLUE -r Active instances exceed expected count" | |
/usr/local/bfm/etc/samsh.pl "start client=JPMA name=VARServer_DR_SITE,VARServer_plus_batch_DR_SITE -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "start client=MIC name=AccountingPortalReportExportServer,AlphaValuationService,SRSAssetLoadServer -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "stop extra client=GUGGENHEIM,MLC name=AlphaValuationService -r Active instances exceed expected count" | |
/usr/local/bfm/etc/samsh.pl "start client=AEG name=VARServer_plus_batch_DR_SITE -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "stop extra client=AEG name=ADCDatasetManagementServer -r Active instances exceed expected count" | |
/usr/local/bfm/etc/samsh.pl "start client=ALX name=CLOServer_BETA -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "start client=AVIVA name=GPLiveSQLServerRpt -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "start client=CAIXABANK name=TSSHealth_TMP -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "start client=GUGGENHEIM name=AlphaValuationService_BETA -r Active instances fewer than expected" | |
/usr/local/bfm/etc/samsh.pl "stop extra client=SPC name=GRServerPROD -r Active instances exceed expected count" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GUGGENHEIM AlphaValuationService_BETA Instance Mismatch (0/1) | |
GUGGENHEIM AlphaValuationService_BETA Instance Mismatch (0/1) | |
GUGGENHEIM AlphaValuationService Instance Mismatch (3/1) | |
MLC AlphaValuationService Instance Mismatch (2/1) | |
MIC AlphaValuationService Instance Mismatch (0/1) | |
MIC AccountingPortalReportExportServer Instance Mismatch (0/1) | |
MIC AccountingPortalReportExportServer Instance Mismatch (0/1) | |
SPC GRServerPROD Instance Mismatch (1/0) | |
BLK LogRaiderSenseBetaServer Instance Mismatch (3/1) | |
BLK RTCServer_BLUE Instance Mismatch (4/2) | |
MIC SRSAssetLoadServer Instance Mismatch (0/7) | |
MIC SRSAssetLoadServer Instance Mismatch (0/6) | |
MIC SRSAssetLoadServer Instance Mismatch (0/7) | |
AVIVA GPLiveSQLServerRpt Instance Mismatch (1/2) | |
JPMA VARServer_plus_batch_DR_SITE Instance Mismatch (0/19) | |
JPMA VARServer_DR_SITE Instance Mismatch (0/1) | |
ALX CLOServer_BETA Instance Mismatch (0/1) | |
AEG ADCDatasetManagementServer Instance Mismatch (2/1) | |
AEG VARServer_plus_batch_DR_SITE Instance Mismatch (3/4) | |
CAIXABANK TSSHealth_TMP Instance Mismatch (0/1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment