package create import ( "context" "errors" "fmt" "regexp" "edge-infra.dev/pkg/lib/cli/rags" "edge-infra.dev/pkg/lib/cli/sink" "edge-infra.dev/pkg/lib/gcp/monitoring/dsp/alert" ) var ( patternLabel = regexp.MustCompile(`^([\w\-]+\|[\w\-]+)`) patternProject = regexp.MustCompile(`^ret-edge-(\w+)(-\w+)*`) patternTopic = regexp.MustCompile(`^([\w]+)(-[\w]+)*`) ) func New() *sink.Command { var ( project string policyName string labels string topic string encode = true ) cmd := &sink.Command{ Use: "create [flags]", Short: "create is used to simulate an incident message to dsp via pubsub", Flags: []*rags.Rag{ { Name: "project", Usage: "GCP Project ID where alert policy is located (e.g. ret-edge-dev1-foreman)", Value: &rags.String{Var: &project}, Short: "p", Required: true, }, { Name: "policyname", Usage: "name of an alert policy", Value: &rags.String{Var: &policyName}, Short: "n", Required: true, }, { Name: "topic", Usage: "name of the Pub/Sub topic to be used", Value: &rags.String{Var: &topic}, Short: "t", Required: true, }, { Name: "labels", Usage: "a comma separated list of key|value pairs (separated by |) for labels", Value: &rags.String{Var: &labels}, Short: "l", Required: false, }, { Name: "encode", Usage: "should the message be base64 encoded (true by default)", Value: &rags.Bool{Var: &encode}, Short: "e", Required: false, }, }, Exec: func(_ context.Context, r sink.Run) error { // check if user labels were provided and that it is a comma separated list var kvLabels []string if len(labels) > 0 { // split labels into string array kvLabels = alert.SplitLabels(labels) } if len(topic) < 1 || !patternTopic.MatchString(topic) { err := errors.New("Pub/Sub topic must be valid and cannot contain spaces") return fmt.Errorf("invalid topic: %w", err) } if !ValidateLabels(kvLabels) { err := errors.New("labels need to be a list of key|value pairs separated by commas") return fmt.Errorf("invalid labels: %w", err) } if !patternProject.MatchString(project) { err := errors.New("needs to be full name (e.g. ret-edge-dev1-foreman)") return fmt.Errorf("invalid project name: %w", err) } // Get project number projectNumber, err := alert.GetProjectNumber(project, r.Log) if err != nil { return fmt.Errorf("failed to get project number: %w", err) } // Use project number and policy name to get an alert policy policy, err := alert.GetAlertPolicy(projectNumber, policyName, r.Log) if err != nil || policy == nil { return fmt.Errorf("failed to get alert policy: %w", err) } // Pass retrieved policy to create the incident createdIncident, err := alert.CreateIncident(projectNumber, project, kvLabels, policy, r.Log) if err != nil || createdIncident == nil { return fmt.Errorf("failed to create incident: %w", err) } // Use new incident to create a JSON/string version that gets // base64 encoded, pass back the encoded string message, err := alert.CreateMessage(*createdIncident, r.Log) if err != nil || message == nil { return fmt.Errorf("failed to create message: %w", err) } // Take the encoded string and create the PubSub message format; // use topic.publish to publish the message responseID, err := alert.PublishMessage(project, message, topic, encode, r.Log) if err != nil || responseID == "" { return fmt.Errorf("failed to publish message: %w", err) } fmt.Printf("published message responseID: %s\n", responseID) return nil }, } return cmd } func ValidateLabels(labels []string) bool { goodLabel := true for i := 0; i < len(labels); i++ { if !patternLabel.MatchString(labels[i]) { goodLabel = false return goodLabel } } return goodLabel }