Skip to content

Commit 387b89f

Browse files
RCA fixtures (#16)
1 parent 3dd796e commit 387b89f

7 files changed

Lines changed: 56 additions & 27 deletions

File tree

experiments/combine_rca_context/v1/scripts/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
"""CLI for splunk-log-analysis skill."""
2+
"""CLI for Root-Cause-Analysis skill."""
33

44
import argparse
55
import json

experiments/combine_rca_context/v2/scripts/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
"""CLI for splunk-log-analysis skill."""
2+
"""CLI for Root-Cause-Analysis skill."""
33

44
import argparse
55
import json

experiments/combine_rca_context/v3/scripts/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
"""CLI for splunk-log-analysis skill."""
2+
"""CLI for Root-Cause-Analysis skill."""
33

44
import argparse
55
import json

skills/feedback-capture/scripts/utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def upload_feedback_to_jumpbox(
8484
ssh_cmd = ["ssh"]
8585
if ssh_port:
8686
ssh_cmd.extend(["-p", ssh_port])
87-
ssh_cmd.extend([ssh_target, "mkdir -p /tmp/feedback/chat_history"])
87+
ssh_cmd.extend([ssh_target, "mkdir -p /tmp"])
8888

8989
try:
9090
subprocess.run(
@@ -105,15 +105,15 @@ def upload_feedback_to_jumpbox(
105105
scp_cmd.extend(["-P", ssh_port])
106106

107107
dest_filename = f"feedback_{session_id}.json" if session_id else feedback_file.name
108-
scp_cmd.extend([str(feedback_file), f"{ssh_target}:/tmp/feedback/{dest_filename}"])
108+
scp_cmd.extend([str(feedback_file), f"{ssh_target}:/tmp/{dest_filename}"])
109109

110110
subprocess.run(
111111
scp_cmd,
112112
check=True,
113113
capture_output=True,
114114
timeout=30,
115115
)
116-
print(f" Uploaded feedback to Jumpbox ({ssh_target}): /tmp/feedback/{dest_filename}")
116+
print(f" Uploaded feedback to Jumpbox ({ssh_target}): /tmp/{dest_filename}")
117117
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
118118
print(f" Error uploading feedback: {e}")
119119
return False
@@ -124,7 +124,7 @@ def upload_feedback_to_jumpbox(
124124
scp_cmd = ["scp"]
125125
if ssh_port:
126126
scp_cmd.extend(["-P", ssh_port])
127-
scp_cmd.extend([str(chat_history_file), f"{ssh_target}:/tmp/feedback/chat_history/"])
127+
scp_cmd.extend([str(chat_history_file), f"{ssh_target}:/tmp/"])
128128

129129
subprocess.run(
130130
scp_cmd,
@@ -133,7 +133,7 @@ def upload_feedback_to_jumpbox(
133133
timeout=30,
134134
)
135135
print(
136-
f" Uploaded chat history to Jumpbox ({ssh_target}): /tmp/feedback/chat_history/{chat_history_file.name}"
136+
f" Uploaded chat history to Jumpbox ({ssh_target}): /tmp/{chat_history_file.name}"
137137
)
138138
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
139139
print(f" Warning: Could not upload chat history: {e}")

skills/root-cause-analysis/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ All steps are executed automatically by the `cli.py analyze` command:
237237

238238
**Output**: `step5_analysis_summary.json` (or present directly to user)
239239

240+
**Post-Step 5 Action**: After saving the summary, run the upload command to send the analysis to the Jumpbox:
241+
```bash
242+
python scripts/cli.py upload --job-id <job-id>
243+
```
244+
240245
## Output
241246

242247
Analysis results are saved to `.analysis/<job-id>/`:

skills/root-cause-analysis/SKILL.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ python3 -m venv .venv
132132

133133
**Output**: `.analysis/<job-id>/step5_analysis_summary.json`
134134

135+
**Post-Step 5 Action**: After saving the summary, you MUST run the upload command to send the analysis to the Jumpbox:
136+
```bash
137+
python scripts/cli.py upload --job-id <job-id>
138+
```
139+
135140
### Analysis Guidelines
136141

137142
**Configuration Analysis**:

skills/root-cause-analysis/scripts/cli.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
"""CLI for splunk-log-analysis skill."""
2+
"""CLI for Root-Cause-Analysis skill."""
33

44
import argparse
55
import json
@@ -46,17 +46,29 @@ def save_step(analysis_dir: Path, step: int, data: dict) -> Path:
4646
return output_path
4747

4848

49-
def upload_analysis_to_jumpbox(analysis_dir: Path, config: Config) -> bool:
50-
"""Upload analysis directory to Jumpbox in analysis/{job_id}/ with session.json."""
49+
@trace(name="Upload analysis", span_type=SpanType.CHAIN if SpanType else None)
50+
def upload_analysis_to_jumpbox(args: argparse.Namespace, config: Config, span=None) -> int:
51+
"""Upload analysis directory to Jumpbox in /tmp/{job_id}/ with session.json."""
52+
analysis_dir = config.analysis_dir / args.job_id
53+
54+
if not analysis_dir.exists():
55+
error_message = f"No analysis found for job {args.job_id}"
56+
print(error_message)
57+
if span:
58+
span.set_outputs({"error": error_message})
59+
return 1
60+
61+
print(f"Uploading analysis for job {args.job_id}...")
62+
5163
if not config.jumpbox_uri:
5264
print(" Skipping upload: JUMPBOX_URI not configured")
53-
return False
65+
return 1
5466

5567
# Parse JUMPBOX_URI format: "user@host -p port"
5668
parts = config.jumpbox_uri.split()
5769
if len(parts) < 1:
5870
print(" Error: Invalid JUMPBOX_URI format")
59-
return False
71+
return 1
6072

6173
ssh_target = parts[0] # user@host
6274
ssh_port = None
@@ -71,14 +83,14 @@ def upload_analysis_to_jumpbox(analysis_dir: Path, config: Config) -> bool:
7183
pass
7284

7385
session_id = os.environ.get("CLAUDE_SESSION_ID", "unknown")
74-
job_id = analysis_dir.name
75-
remote_base_dir = "/tmp/analysis"
86+
job_id = args.job_id
87+
remote_base_dir = f"/tmp/{job_id}"
7688

7789
# Create session.json file locally (will be overwritten if exists)
7890
session_file = analysis_dir / "session.json"
7991
try:
8092
with open(session_file, "w") as f:
81-
json.dump({"session_id": session_id}, f, indent=2)
93+
json.dump({"session_id": session_id, "job_id": job_id}, f, indent=2)
8294
except Exception as e:
8395
print(f" Warning: Could not create session.json: {e}")
8496

@@ -98,25 +110,32 @@ def upload_analysis_to_jumpbox(analysis_dir: Path, config: Config) -> bool:
98110
)
99111
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
100112
print(f" Error creating remote directory: {e}")
101-
return False
113+
return 1
102114

103-
# Upload analysis directory using rsync
115+
# Upload analysis directory contents using rsync
104116
try:
105117
rsync_cmd = ["rsync"]
106118
if ssh_port:
107119
rsync_cmd.extend(["-e", f"ssh -p {ssh_port}"])
108-
rsync_cmd.extend(["-az", "--quiet", str(analysis_dir), f"{ssh_target}:{remote_base_dir}/"])
120+
# Add trailing slash to source to copy contents, not the directory itself
121+
rsync_cmd.extend(
122+
["-az", "--quiet", f"{str(analysis_dir)}/", f"{ssh_target}:{remote_base_dir}/"]
123+
)
109124

110125
subprocess.run(
111126
rsync_cmd,
112127
check=True,
113128
timeout=60,
114129
)
115-
print(f" Uploaded to Jumpbox ({ssh_target}): {remote_base_dir}/{job_id}/")
116-
return True
130+
print(f" Uploaded to Jumpbox ({ssh_target}): {remote_base_dir}/")
131+
if span:
132+
span.set_outputs({"job_id": job_id, "success": True})
133+
return 0
117134
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
118135
print(f" Error uploading to Jumpbox: {e}")
119-
return False
136+
if span:
137+
span.set_outputs({"job_id": job_id, "success": False, "error": str(e)})
138+
return 1
120139

121140

122141
def get_step_name(step: int) -> str:
@@ -344,18 +363,13 @@ def cmd_analyze(args: argparse.Namespace, config: Config, span=None) -> int:
344363
print("-" * 60)
345364
_print_quick_summary(job_context, splunk_logs, correlation)
346365

347-
# Upload analysis to Jumpbox
348-
print("\n[Upload] Uploading analysis to Jumpbox...")
349-
upload_success = upload_analysis_to_jumpbox(analysis_dir, config)
350-
351366
outputs = {
352367
"job_id": job_id,
353368
"status": job_context.get("status"),
354369
"correlation_confidence": corr.get("confidence"),
355370
"failed_tasks": len(job_context.get("failed_tasks", [])),
356371
"pods_found": len(splunk_logs.get("pods_found", [])),
357372
"analysis_dir": str(analysis_dir),
358-
"uploaded_to_jumpbox": upload_success,
359373
}
360374
if span:
361375
span.set_outputs(outputs)
@@ -565,6 +579,10 @@ def main() -> int:
565579
status_parser = subparsers.add_parser("status", help="Show analysis status")
566580
status_parser.add_argument("job_id", help="Job ID to check")
567581

582+
# upload command
583+
upload_parser = subparsers.add_parser("upload", help="Upload analysis to Jumpbox")
584+
upload_parser.add_argument("--job-id", required=True, help="Job ID to upload")
585+
568586
args = parser.parse_args()
569587

570588
# Load config
@@ -596,6 +614,7 @@ def main() -> int:
596614
"query": cmd_query,
597615
"setup": cmd_setup,
598616
"status": cmd_status,
617+
"upload": upload_analysis_to_jumpbox,
599618
}
600619

601620
exit_code = commands[args.command](args, config, span)

0 commit comments

Comments
 (0)