...

Source file src/edge-infra.dev/pkg/lib/gcp/monitoring/dsp/alert/cmd/create/create.go

Documentation: edge-infra.dev/pkg/lib/gcp/monitoring/dsp/alert/cmd/create

     1  package create
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"regexp"
     8  
     9  	"edge-infra.dev/pkg/lib/cli/rags"
    10  	"edge-infra.dev/pkg/lib/cli/sink"
    11  	"edge-infra.dev/pkg/lib/gcp/monitoring/dsp/alert"
    12  )
    13  
    14  var (
    15  	patternLabel   = regexp.MustCompile(`^([\w\-]+\|[\w\-]+)`)
    16  	patternProject = regexp.MustCompile(`^ret-edge-(\w+)(-\w+)*`)
    17  	patternTopic   = regexp.MustCompile(`^([\w]+)(-[\w]+)*`)
    18  )
    19  
    20  func New() *sink.Command {
    21  	var (
    22  		project    string
    23  		policyName string
    24  		labels     string
    25  		topic      string
    26  		encode     = true
    27  	)
    28  	cmd := &sink.Command{
    29  		Use:   "create [flags]",
    30  		Short: "create is used to simulate an incident message to dsp via pubsub",
    31  		Flags: []*rags.Rag{
    32  			{
    33  				Name:     "project",
    34  				Usage:    "GCP Project ID where alert policy is located (e.g. ret-edge-dev1-foreman)",
    35  				Value:    &rags.String{Var: &project},
    36  				Short:    "p",
    37  				Required: true,
    38  			},
    39  			{
    40  				Name:     "policyname",
    41  				Usage:    "name of an alert policy",
    42  				Value:    &rags.String{Var: &policyName},
    43  				Short:    "n",
    44  				Required: true,
    45  			},
    46  			{
    47  				Name:     "topic",
    48  				Usage:    "name of the Pub/Sub topic to be used",
    49  				Value:    &rags.String{Var: &topic},
    50  				Short:    "t",
    51  				Required: true,
    52  			},
    53  			{
    54  				Name:     "labels",
    55  				Usage:    "a comma separated list of key|value pairs (separated by |) for labels",
    56  				Value:    &rags.String{Var: &labels},
    57  				Short:    "l",
    58  				Required: false,
    59  			},
    60  			{
    61  				Name:     "encode",
    62  				Usage:    "should the message be base64 encoded (true by default)",
    63  				Value:    &rags.Bool{Var: &encode},
    64  				Short:    "e",
    65  				Required: false,
    66  			},
    67  		},
    68  		Exec: func(_ context.Context, r sink.Run) error {
    69  			// check if user labels were provided and that it is a comma separated list
    70  			var kvLabels []string
    71  
    72  			if len(labels) > 0 {
    73  				// split labels into string array
    74  				kvLabels = alert.SplitLabels(labels)
    75  			}
    76  
    77  			if len(topic) < 1 || !patternTopic.MatchString(topic) {
    78  				err := errors.New("Pub/Sub topic must be valid and cannot contain spaces")
    79  				return fmt.Errorf("invalid topic: %w", err)
    80  			}
    81  
    82  			if !ValidateLabels(kvLabels) {
    83  				err := errors.New("labels need to be a list of key|value pairs separated by commas")
    84  				return fmt.Errorf("invalid labels: %w", err)
    85  			}
    86  
    87  			if !patternProject.MatchString(project) {
    88  				err := errors.New("needs to be full name (e.g. ret-edge-dev1-foreman)")
    89  				return fmt.Errorf("invalid project name: %w", err)
    90  			}
    91  
    92  			// Get project number
    93  			projectNumber, err := alert.GetProjectNumber(project, r.Log)
    94  			if err != nil {
    95  				return fmt.Errorf("failed to get project number: %w", err)
    96  			}
    97  
    98  			// Use project number and policy name to get an alert policy
    99  			policy, err := alert.GetAlertPolicy(projectNumber, policyName, r.Log)
   100  			if err != nil || policy == nil {
   101  				return fmt.Errorf("failed to get alert policy: %w", err)
   102  			}
   103  
   104  			// Pass retrieved policy to create the incident
   105  			createdIncident, err := alert.CreateIncident(projectNumber, project, kvLabels, policy, r.Log)
   106  			if err != nil || createdIncident == nil {
   107  				return fmt.Errorf("failed to create incident: %w", err)
   108  			}
   109  
   110  			// Use new incident to create a JSON/string version that gets
   111  			// base64 encoded, pass back the encoded string
   112  			message, err := alert.CreateMessage(*createdIncident, r.Log)
   113  			if err != nil || message == nil {
   114  				return fmt.Errorf("failed to create message: %w", err)
   115  			}
   116  
   117  			// Take the encoded string and create the PubSub message format;
   118  			// use topic.publish to publish the message
   119  			responseID, err := alert.PublishMessage(project, message, topic, encode, r.Log)
   120  			if err != nil || responseID == "" {
   121  				return fmt.Errorf("failed to publish message: %w", err)
   122  			}
   123  			fmt.Printf("published message responseID: %s\n", responseID)
   124  			return nil
   125  		},
   126  	}
   127  	return cmd
   128  }
   129  
   130  func ValidateLabels(labels []string) bool {
   131  	goodLabel := true
   132  	for i := 0; i < len(labels); i++ {
   133  		if !patternLabel.MatchString(labels[i]) {
   134  			goodLabel = false
   135  			return goodLabel
   136  		}
   137  	}
   138  	return goodLabel
   139  }
   140  

View as plain text