Skip to content

Commit 5dfce14

Browse files
authored
Merge pull request #183 from flashcatcloud/chore/retire-unused-monit-apis
refactor(monit): remove retired commands and update SDK dependency
2 parents cbb4654 + c97f7f1 commit 5dfce14

18 files changed

Lines changed: 34 additions & 883 deletions

‎go.mod‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/flashcatcloud/flashduty-cli
33
go 1.25.1
44

55
require (
6-
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908030757-f478f34797be
6+
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908113851-5bf8f2902391
77
github.com/mattn/go-runewidth v0.0.28
88
github.com/spf13/cobra v1.10.2
99
github.com/spf13/pflag v1.0.10

‎go.sum‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908025802-4fa9a76d8b57 h1:3
77
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908025802-4fa9a76d8b57/go.mod h1:YpHiTYXR5NXBI/rGRZfUy537XMkhdCkwA8NW1QoRHwk=
88
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908030757-f478f34797be h1:F3+A0vVRICnEeBshac70P+VBtuo64P5hBmxcfbFxiXk=
99
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908030757-f478f34797be/go.mod h1:YpHiTYXR5NXBI/rGRZfUy537XMkhdCkwA8NW1QoRHwk=
10+
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908113851-5bf8f2902391 h1:u4IM9wE2/isYCAUMszeBsp4b9Na7Qh5mHlvPLpDgvkw=
11+
github.com/flashcatcloud/go-flashduty v0.15.1-0.20260908113851-5bf8f2902391/go.mod h1:YpHiTYXR5NXBI/rGRZfUy537XMkhdCkwA8NW1QoRHwk=
1012
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
1113
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1214
github.com/mattn/go-runewidth v0.0.28 h1:rPyg2ybwEKPebvpzVWe1gKBkH8EQFkxO4Y0hjBeLaBU=

‎internal/cli/monit_query.go‎

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,76 +12,10 @@ import (
1212

1313
func newMonitQueryCmd() *cobra.Command {
1414
cmd := newGroupCmd("monit-query", "Query configured datasources; structured diagnostics use monit datasource-tools-invoke")
15-
cmd.AddCommand(newMonitQueryDiagnoseCmd())
1615
cmd.AddCommand(newMonitQueryDataCmd())
1716
return cmd
1817
}
1918

20-
func newMonitQueryDiagnoseCmd() *cobra.Command {
21-
var (
22-
dsType, dsName, timeStart, timeEnd, inputQuery, operation string
23-
maxLogs, maxPatterns, timeoutSeconds int
24-
)
25-
26-
cmd := &cobra.Command{
27-
Use: "diagnose",
28-
Short: "Legacy log-pattern and metric-trend evidence (prefer monit datasource-tools-invoke)",
29-
Long: curatedLong("Run pre-clustered RCA over a datasource window, returning log_patterns or metric_trends findings.", "Diagnostics", "QueryDiagnose"),
30-
RunE: func(cmd *cobra.Command, args []string) error {
31-
if dsType == "" || dsName == "" || inputQuery == "" {
32-
return fmt.Errorf("--ds-type, --ds-name, --input-query are required")
33-
}
34-
startTime, err := timeutil.Parse(timeStart)
35-
if err != nil {
36-
return fmt.Errorf("invalid --time-start: %w", err)
37-
}
38-
endTime, err := timeutil.Parse(timeEnd)
39-
if err != nil {
40-
return fmt.Errorf("invalid --time-end: %w", err)
41-
}
42-
43-
return runCommand(cmd, args, func(ctx *RunContext) error {
44-
input := &flashduty.DiagnoseRequest{
45-
DsType: dsType,
46-
DsName: dsName,
47-
Operation: operation,
48-
Input: flashduty.DiagnoseRequestInput{Query: inputQuery},
49-
TimeRange: flashduty.DiagnoseRequestTimeRange{Start: startTime, End: endTime},
50-
}
51-
if maxLogs > 0 {
52-
input.Options.MaxLogsScanned = int64(maxLogs)
53-
}
54-
if maxPatterns > 0 {
55-
input.Options.MaxPatterns = int64(maxPatterns)
56-
}
57-
if timeoutSeconds > 0 {
58-
input.Options.TimeoutSeconds = int64(timeoutSeconds)
59-
}
60-
61-
//nolint:staticcheck // Keep the legacy command working while callers migrate to datasource tools.
62-
result, _, err := ctx.Client.Diagnostics.QueryDiagnose(cmdContext(ctx.Cmd), input)
63-
if err != nil {
64-
return err
65-
}
66-
return ctx.Printer.Print(result, nil)
67-
})
68-
},
69-
}
70-
71-
cmd.Flags().StringVar(&dsType, "ds-type", "", "Datasource type: loki|victorialogs (log_patterns) or prometheus (metric_trends) (required)")
72-
cmd.Flags().StringVar(&dsName, "ds-name", "", "Datasource name as configured (required)")
73-
registerEnumFlag(cmd, "ds-type", "prometheus", "victorialogs", "loki")
74-
cmd.Flags().StringVar(&timeStart, "time-start", "15m", "Window start: relative duration ('15m'/'1h'), 'now', a date/RFC3339 timestamp, or a unix epoch in seconds or milliseconds")
75-
cmd.Flags().StringVar(&timeEnd, "time-end", "now", "Window end: same formats as --time-start; span capped at 6h")
76-
cmd.Flags().StringVar(&inputQuery, "input-query", "", "Filter-only log query OR matrix PromQL (required)")
77-
cmd.Flags().StringVar(&operation, "operation", "", "log_patterns or metric_trends (default inferred from ds-type)")
78-
cmd.Flags().IntVar(&maxLogs, "max-logs", 0, "Max log lines scanned (default 10000, cap 50000)")
79-
cmd.Flags().IntVar(&maxPatterns, "max-patterns", 0, "Max patterns returned (default 20, cap 50)")
80-
cmd.Flags().IntVar(&timeoutSeconds, "timeout-seconds", 0, "Per-call timeout in seconds (default 25, cap 30)")
81-
82-
return cmd
83-
}
84-
8519
func newMonitQueryDataCmd() *cobra.Command {
8620
var (
8721
dsType, dsName, expr string

‎internal/cli/monit_query_test.go‎

Lines changed: 12 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,6 @@ import (
99
"time"
1010
)
1111

12-
func TestMonitQueryDiagnoseFlags(t *testing.T) {
13-
cmd := newMonitQueryDiagnoseCmd()
14-
for _, name := range []string{
15-
"ds-type", "ds-name", "time-start", "time-end",
16-
"input-query", "operation",
17-
"max-logs", "max-patterns", "timeout-seconds",
18-
} {
19-
if cmd.Flags().Lookup(name) == nil {
20-
t.Errorf("flag --%s missing", name)
21-
}
22-
}
23-
}
24-
2512
func TestMonitQueryDataFlags(t *testing.T) {
2613
cmd := newMonitQueryDataCmd()
2714
for _, name := range []string{"ds-type", "ds-name", "expr", "args", "delay-seconds"} {
@@ -31,175 +18,27 @@ func TestMonitQueryDataFlags(t *testing.T) {
3118
}
3219
}
3320

34-
// --- monit-query diagnose -------------------------------------------------
35-
36-
func TestMonitQueryDiagnoseHappyPath(t *testing.T) {
37-
saveAndResetGlobals(t)
38-
stub := newGFStub(t)
39-
stub.data = map[string]any{"operation": "log_patterns"}
40-
41-
_, err := execCommand(
42-
"monit-query", "diagnose",
43-
"--ds-type", "victorialogs",
44-
"--ds-name", "vl-prod",
45-
"--input-query", `{app="api"}`,
46-
"--operation", "log_patterns",
47-
"--max-logs", "5000",
48-
"--max-patterns", "10",
49-
"--timeout-seconds", "20",
50-
)
51-
if err != nil {
52-
t.Fatalf("unexpected error: %v", err)
53-
}
54-
if stub.lastPath != "/monit/query/diagnose" {
55-
t.Fatalf("expected /monit/query/diagnose, got %q", stub.lastPath)
56-
}
57-
body := stub.lastBody
58-
if body["ds_type"] != "victorialogs" || body["ds_name"] != "vl-prod" {
59-
t.Errorf("unexpected ds fields: %#v", body)
60-
}
61-
input, _ := body["input"].(map[string]any)
62-
if input["query"] != `{app="api"}` {
63-
t.Errorf("expected input query %q, got %v", `{app="api"}`, input["query"])
64-
}
65-
if body["operation"] != "log_patterns" {
66-
t.Errorf("expected operation log_patterns, got %v", body["operation"])
67-
}
68-
options, _ := body["options"].(map[string]any)
69-
if fmt.Sprint(options["max_logs_scanned"]) != "5000" ||
70-
fmt.Sprint(options["max_patterns"]) != "10" ||
71-
fmt.Sprint(options["timeout_seconds"]) != "20" {
72-
t.Errorf("unexpected caps: %#v", options)
73-
}
74-
timeRange, _ := body["time_range"].(map[string]any)
75-
if fmt.Sprint(timeRange["start"]) == "0" || fmt.Sprint(timeRange["start"]) == "<nil>" ||
76-
fmt.Sprint(timeRange["end"]) == "0" || fmt.Sprint(timeRange["end"]) == "<nil>" {
77-
t.Errorf("expected non-zero default time range, got %#v", timeRange)
78-
}
79-
}
80-
81-
func TestMonitQueryDiagnoseRendersMetricEvidence(t *testing.T) {
82-
saveAndResetGlobals(t)
83-
stub := newGFStub(t)
84-
stub.data = map[string]any{
85-
"schema_version": "2",
86-
"operation": "metric_trends",
87-
"ds_type": "prometheus",
88-
"ds_name": "prod-prometheus",
89-
"query": "up",
90-
"window": map[string]any{"start": "2026-07-14T06:00:00Z", "end": "2026-07-14T07:00:00Z"},
91-
"results": []any{map[string]any{
92-
"method": "window_compare",
93-
"window": map[string]any{"start": "2026-07-14T06:00:00Z", "end": "2026-07-14T07:00:00Z"},
94-
"summary": map[string]any{
95-
"series_total": 1, "series_analyzed": 1, "selected_series_total": 1, "series_returned": 1,
96-
"analysis_truncated": false, "evidence_summary": "One series changed.",
97-
},
98-
"series_evidence": []any{map[string]any{
99-
"labels": map[string]any{"instance": "api-1"},
100-
"observations": []any{"The current average increased."},
101-
}},
102-
"warnings": []any{},
103-
}},
104-
}
105-
106-
out, err := execCommand(
107-
"monit-query", "diagnose",
108-
"--ds-type", "prometheus",
109-
"--ds-name", "prod-prometheus",
110-
"--input-query", "up",
111-
"--operation", "metric_trends",
112-
"--output-format", "json",
113-
)
114-
if err != nil {
115-
t.Fatalf("unexpected error: %v", err)
116-
}
117-
var rendered map[string]any
118-
if err := json.Unmarshal([]byte(out), &rendered); err != nil {
119-
t.Fatalf("decode CLI JSON: %v\n%s", err, out)
120-
}
121-
if _, found := rendered["data_handling"]; found {
122-
t.Fatalf("metric output fabricated data_handling: %s", out)
123-
}
124-
evidence := rendered["results"].([]any)[0].(map[string]any)["series_evidence"].([]any)[0].(map[string]any)
125-
for _, field := range []string{"comparison_status", "current_window_stats", "baseline_window_stats"} {
126-
if _, found := evidence[field]; found {
127-
t.Fatalf("metric evidence fabricated %s: %s", field, out)
128-
}
129-
}
130-
}
131-
132-
func TestMonitQueryDiagnoseRequiredFlags(t *testing.T) {
133-
cases := []struct {
134-
name string
135-
args []string
136-
}{
137-
{
138-
name: "missing ds-type",
139-
args: []string{
140-
"monit-query", "diagnose",
141-
"--ds-name", "vl-prod",
142-
"--input-query", `{app="api"}`,
143-
},
144-
},
145-
{
146-
name: "missing ds-name",
147-
args: []string{
148-
"monit-query", "diagnose",
149-
"--ds-type", "victorialogs",
150-
"--input-query", `{app="api"}`,
151-
},
152-
},
153-
{
154-
name: "missing input-query",
155-
args: []string{
156-
"monit-query", "diagnose",
157-
"--ds-type", "victorialogs",
158-
"--ds-name", "vl-prod",
159-
},
160-
},
161-
}
162-
for _, tc := range cases {
163-
t.Run(tc.name, func(t *testing.T) {
21+
func TestRetiredMonitCommandsRejectBeforeRequest(t *testing.T) {
22+
for _, args := range [][]string{
23+
{"monit-query", "diagnose"}, {"monit", "query-diagnose"},
24+
{"monit", "rule-counter-status"},
25+
{"monit", "store-ruleset-create"}, {"monit", "store-ruleset-update"},
26+
{"monit", "store-ruleset-list"}, {"monit", "store-ruleset-info"}, {"monit", "store-ruleset-delete"},
27+
} {
28+
t.Run(strings.Join(args, " "), func(t *testing.T) {
16429
saveAndResetGlobals(t)
16530
stub := newGFStub(t)
166-
167-
_, err := execCommand(tc.args...)
168-
if err == nil {
169-
t.Fatal("expected required-flag error, got nil")
170-
}
171-
if !strings.Contains(err.Error(), "required") {
172-
t.Errorf("expected error to mention 'required', got %q", err.Error())
31+
_, err := execCommand(args...)
32+
if err == nil || !strings.Contains(err.Error(), "unknown command") {
33+
t.Fatalf("retired command error=%v", err)
17334
}
17435
if stub.requests != 0 {
175-
t.Errorf("diagnose should not have been called: %d request(s)", stub.requests)
36+
t.Fatalf("retired command sent %d requests", stub.requests)
17637
}
17738
})
17839
}
17940
}
18041

181-
func TestMonitQueryDiagnoseInvalidTimeStart(t *testing.T) {
182-
saveAndResetGlobals(t)
183-
stub := newGFStub(t)
184-
185-
_, err := execCommand(
186-
"monit-query", "diagnose",
187-
"--ds-type", "victorialogs",
188-
"--ds-name", "vl-prod",
189-
"--input-query", `{app="api"}`,
190-
"--time-start", "not-a-time",
191-
)
192-
if err == nil {
193-
t.Fatal("expected error for invalid --time-start, got nil")
194-
}
195-
if !strings.Contains(err.Error(), "--time-start") {
196-
t.Errorf("expected error to mention --time-start, got %q", err.Error())
197-
}
198-
if stub.requests != 0 {
199-
t.Errorf("diagnose should not have been called: %d request(s)", stub.requests)
200-
}
201-
}
202-
20342
// --- monit-query data -----------------------------------------------------
20443

20544
func TestMonitQueryDataHappyPath(t *testing.T) {

‎internal/cli/zz_generated_alert_rules.go‎

Lines changed: 0 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎internal/cli/zz_generated_data_sources.go‎

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)