package cli import ( "context" "flag" "fmt" "strings" "github.com/peterbourgon/ff/v3/ffcli" alertmgr "edge-infra.dev/pkg/lib/gcp/monitoring/alertmanager" ) type getArgsT struct { overwrite bool templateFormat bool templatePath string prefix string name string } var getArgs getArgsT var getFlagSet = newGetFlagSet(&getArgs) func newGetFlagSet(getArgs *getArgsT) *flag.FlagSet { getf := newFlagSet("get") getf.BoolVar(&getArgs.overwrite, "overwrite", false, "Forces the overwrite of existing alert template files in the destination folder. (optional)\nNOTE: If not specified, any new files to be created that are in conflict will be appended with a timestamp.") getf.BoolVar(&getArgs.templateFormat, "all-fields", false, "Get all the fields of the running AlertPolicy (*.json). (optional)\nNOTE: If not specified, additional fields not required for the template are omitted.") getf.StringVar(&getArgs.templatePath, "path", "", "Folder path to save the alert template files to.\nFiles will be written with the filename based on the display name filtered for unsupported characters and whitespace (e.g. .json) (required)\nNOTE: Duplicate display names will be appended with a (Duplicate_Name_n) filename to prevent file conflicts.") getf.StringVar(&getArgs.prefix, "prefix", "", "Custom prefix to append to the alert template file name (i.e. _.json) (optional)") getf.StringVar(&getArgs.name, "name", "", "Only get the alert with the specified name or display name. (optional)\nNOTE: All alerts with the same display name will be retrieved, and the template file name will be automatically incremented.") return getf } var getCmd = &ffcli.Command{ Name: "get", ShortUsage: "get [flags]", ShortHelp: "Get and save alert policies as templates", LongHelp: strings.TrimSpace(` Saves alert template files to a specified path from project alert configurations. `), FlagSet: withGlobalFlags(getFlagSet), Exec: runGet, } func runGet(_ context.Context, args []string) error { var err error if len(args) > 0 { Fatalf("too many non-flag arguments: %q", args) } if !checkGetFlags() { Println() return flag.ErrHelp } var filter string // retrieve alert by name. if len(getArgs.name) > 0 { // https://cloud.google.com/monitoring/api/v3/sorting-and-filtering#sorting_and_filtering_basics filter = fmt.Sprintf("display_name=\"%s\"", getArgs.name) } // retrieve all alerts. an empty filter means get everything. if len(getArgs.name) == 0 { filter = "" } templates, err := alertmgr.GetAlertPolicies(projectID, "", filter) if err != nil && templates == nil { return err } if len(templates) == 0 { logger.Info("No alert policies were found") return Errorf("No alert policies were found") } for _, temp := range templates { if temp.UserLabels == nil { temp.UserLabels = make(map[string]string) temp.UserLabels["managed"] = "true" } else { temp.UserLabels["managed"] = "true" } } // save alert configs to template file(s). if err = alertmgr.CreateAlertTemplates(templates, tPath, getArgs.prefix, getArgs.overwrite, getArgs.templateFormat); err != nil { return err } logger.WithValues("tPath", tPath, "projectID", projectID).Info("alert templates saved to project.\n") return nil } // checkGetFlags validates the required get subcommand flags have been provided. func checkGetFlags() bool { if len(projectID) == 0 { logger.Error(nil, "Error: no value specified for [project] - a valid project-id is required") return false } if len(getArgs.templatePath) == 0 { logger.Error(nil, "Error: no value specified for [path] - a valid destination folder path is required") return false } if !checkPath(getArgs.templatePath, true) { logger.Error(nil, fmt.Sprintf("Error: invalid AlertPolicy [path] specified - %s\n", getArgs.templatePath)) return false } return true }