diff --git a/cmd/investigations.go b/cmd/investigations.go index ae9bc60e..96875d97 100644 --- a/cmd/investigations.go +++ b/cmd/investigations.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "net/http" - "strings" "github.com/DataDog/pup/pkg/formatter" "github.com/spf13/cobra" @@ -23,10 +22,10 @@ var investigationsCmd = &cobra.Command{ Long: `Manage Bits AI investigations. Bits AI investigations allow you to trigger automated root cause analysis -for monitor alerts or general infrastructure issues. +for monitor alerts. CAPABILITIES: - • Trigger a new investigation (monitor alert or general) + • Trigger a new investigation (monitor alert) • Get investigation details by ID • List investigations with optional filters @@ -34,9 +33,6 @@ EXAMPLES: # Trigger investigation from a monitor alert pup investigations trigger --type=monitor_alert --monitor-id=123456 --event-id="evt-abc" --event-ts=1706918956000 - # Trigger a general investigation - pup investigations trigger --type=general --tags="service:web-store" --description="High error rate" - # Get investigation details pup investigations get @@ -67,29 +63,21 @@ var investigationsListCmd = &cobra.Command{ } var ( - invTriggerType string - invMonitorID int64 - invEventID string - invEventTS int64 - invTags string - invDescription string - invStartTime int64 - invEndTime int64 - invPageOffset int64 - invPageLimit int64 - invFilterMonID int64 + invTriggerType string + invMonitorID int64 + invEventID string + invEventTS int64 + invPageOffset int64 + invPageLimit int64 + invFilterMonID int64 ) func init() { // trigger flags - investigationsTriggerCmd.Flags().StringVar(&invTriggerType, "type", "", "Investigation type: monitor_alert or general (required)") + investigationsTriggerCmd.Flags().StringVar(&invTriggerType, "type", "", "Investigation type: monitor_alert (required)") investigationsTriggerCmd.Flags().Int64Var(&invMonitorID, "monitor-id", 0, "Monitor ID (required for monitor_alert)") investigationsTriggerCmd.Flags().StringVar(&invEventID, "event-id", "", "Event ID (required for monitor_alert)") investigationsTriggerCmd.Flags().Int64Var(&invEventTS, "event-ts", 0, "Event timestamp in milliseconds (required for monitor_alert)") - investigationsTriggerCmd.Flags().StringVar(&invTags, "tags", "", "Comma-separated tags (required for general)") - investigationsTriggerCmd.Flags().StringVar(&invDescription, "description", "", "Problem description (required for general)") - investigationsTriggerCmd.Flags().Int64Var(&invStartTime, "start-time", 0, "Start time in milliseconds (optional for general)") - investigationsTriggerCmd.Flags().Int64Var(&invEndTime, "end-time", 0, "End time in milliseconds (optional for general)") if err := investigationsTriggerCmd.MarkFlagRequired("type"); err != nil { panic(fmt.Errorf("failed to mark flag as required: %w", err)) } @@ -196,50 +184,25 @@ func runInvestigationsList(cmd *cobra.Command, args []string) error { func buildTriggerRequestBody() (map[string]any, error) { var trigger map[string]any - switch invTriggerType { - case "monitor_alert": - if invMonitorID == 0 { - return nil, fmt.Errorf("--monitor-id is required for monitor_alert investigations") - } - if invEventID == "" { - return nil, fmt.Errorf("--event-id is required for monitor_alert investigations") - } - if invEventTS == 0 { - return nil, fmt.Errorf("--event-ts is required for monitor_alert investigations") - } - trigger = map[string]any{ - "type": "monitor_alert_trigger", - "monitor_alert_trigger": map[string]any{ - "monitor_id": invMonitorID, - "event_id": invEventID, - "event_ts": invEventTS, - }, - } - - case "general": - if invTags == "" { - return nil, fmt.Errorf("--tags is required for general investigations") - } - if invDescription == "" { - return nil, fmt.Errorf("--description is required for general investigations") - } - general := map[string]any{ - "tags": strings.Split(invTags, ","), - "description": invDescription, - } - if invStartTime != 0 { - general["start_time"] = invStartTime - } - if invEndTime != 0 { - general["end_time"] = invEndTime - } - trigger = map[string]any{ - "type": "general_investigation", - "general_investigation": general, - } - - default: - return nil, fmt.Errorf("invalid investigation type %q: must be monitor_alert or general", invTriggerType) + if invTriggerType != "monitor_alert" { + return nil, fmt.Errorf("invalid investigation type %q: must be monitor_alert", invTriggerType) + } + if invMonitorID == 0 { + return nil, fmt.Errorf("--monitor-id is required for monitor_alert investigations") + } + if invEventID == "" { + return nil, fmt.Errorf("--event-id is required for monitor_alert investigations") + } + if invEventTS == 0 { + return nil, fmt.Errorf("--event-ts is required for monitor_alert investigations") + } + trigger = map[string]any{ + "type": "monitor_alert_trigger", + "monitor_alert_trigger": map[string]any{ + "monitor_id": invMonitorID, + "event_id": invEventID, + "event_ts": invEventTS, + }, } return map[string]any{ diff --git a/cmd/investigations_test.go b/cmd/investigations_test.go index d49f11c8..4be95595 100644 --- a/cmd/investigations_test.go +++ b/cmd/investigations_test.go @@ -69,7 +69,7 @@ func TestInvestigationsTriggerCmd(t *testing.T) { // Check flags flags := investigationsTriggerCmd.Flags() - requiredFlags := []string{"type", "monitor-id", "event-id", "event-ts", "tags", "description", "start-time", "end-time"} + requiredFlags := []string{"type", "monitor-id", "event-id", "event-ts"} for _, name := range requiredFlags { if flags.Lookup(name) == nil { t.Errorf("Missing --%s flag", name) @@ -200,100 +200,6 @@ func TestBuildTriggerRequestBody_MonitorAlert(t *testing.T) { } } -func TestBuildTriggerRequestBody_General(t *testing.T) { - origType := invTriggerType - origTags := invTags - origDesc := invDescription - origStart := invStartTime - origEnd := invEndTime - defer func() { - invTriggerType = origType - invTags = origTags - invDescription = origDesc - invStartTime = origStart - invEndTime = origEnd - }() - - invTriggerType = "general" - invTags = "service:web-store,env:prod" - invDescription = "High error rate" - invStartTime = 1706918956000 - invEndTime = 1706919956000 - - body, err := buildTriggerRequestBody() - if err != nil { - t.Fatalf("buildTriggerRequestBody() error = %v", err) - } - - data := body["data"].(map[string]any) - attrs := data["attributes"].(map[string]any) - trigger := attrs["trigger"].(map[string]any) - - if trigger["type"] != "general_investigation" { - t.Errorf("trigger.type = %v, want general_investigation", trigger["type"]) - } - - gi := trigger["general_investigation"].(map[string]any) - - tags, ok := gi["tags"].([]string) - if !ok { - t.Fatal("tags is not []string") - } - if len(tags) != 2 || tags[0] != "service:web-store" || tags[1] != "env:prod" { - t.Errorf("tags = %v, want [service:web-store env:prod]", tags) - } - - if gi["description"] != "High error rate" { - t.Errorf("description = %v, want 'High error rate'", gi["description"]) - } - - if gi["start_time"] != int64(1706918956000) { - t.Errorf("start_time = %v, want 1706918956000", gi["start_time"]) - } - - if gi["end_time"] != int64(1706919956000) { - t.Errorf("end_time = %v, want 1706919956000", gi["end_time"]) - } -} - -func TestBuildTriggerRequestBody_GeneralNoOptionalTimes(t *testing.T) { - origType := invTriggerType - origTags := invTags - origDesc := invDescription - origStart := invStartTime - origEnd := invEndTime - defer func() { - invTriggerType = origType - invTags = origTags - invDescription = origDesc - invStartTime = origStart - invEndTime = origEnd - }() - - invTriggerType = "general" - invTags = "service:web-store" - invDescription = "Something is wrong" - invStartTime = 0 - invEndTime = 0 - - body, err := buildTriggerRequestBody() - if err != nil { - t.Fatalf("buildTriggerRequestBody() error = %v", err) - } - - data := body["data"].(map[string]any) - attrs := data["attributes"].(map[string]any) - trigger := attrs["trigger"].(map[string]any) - gi := trigger["general_investigation"].(map[string]any) - - if _, exists := gi["start_time"]; exists { - t.Error("start_time should not be present when zero") - } - if _, exists := gi["end_time"]; exists { - t.Error("end_time should not be present when zero") - } -} - func TestBuildTriggerRequestBody_Validation(t *testing.T) { tests := []struct { name string @@ -301,8 +207,6 @@ func TestBuildTriggerRequestBody_Validation(t *testing.T) { monitorID int64 eventID string eventTS int64 - tags string - description string wantErr string }{ { @@ -329,24 +233,10 @@ func TestBuildTriggerRequestBody_Validation(t *testing.T) { eventTS: 0, wantErr: "--event-ts is required", }, - { - name: "general missing tags", - triggerType: "general", - tags: "", - description: "Some issue", - wantErr: "--tags is required", - }, - { - name: "general missing description", - triggerType: "general", - tags: "service:web", - description: "", - wantErr: "--description is required", - }, { name: "invalid type", triggerType: "invalid", - wantErr: "invalid investigation type", + wantErr: "must be monitor_alert", }, } @@ -356,23 +246,17 @@ func TestBuildTriggerRequestBody_Validation(t *testing.T) { origMonitorID := invMonitorID origEventID := invEventID origEventTS := invEventTS - origTags := invTags - origDesc := invDescription defer func() { invTriggerType = origType invMonitorID = origMonitorID invEventID = origEventID invEventTS = origEventTS - invTags = origTags - invDescription = origDesc }() invTriggerType = tt.triggerType invMonitorID = tt.monitorID invEventID = tt.eventID invEventTS = tt.eventTS - invTags = tt.tags - invDescription = tt.description _, err := buildTriggerRequestBody() if err == nil {