...

Source file src/edge-infra.dev/cmd/edge/monitoring/alertman/cli/update.go

Documentation: edge-infra.dev/cmd/edge/monitoring/alertman/cli

     1  package cli
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/peterbourgon/ff/v3/ffcli"
    10  
    11  	alertmgr "edge-infra.dev/pkg/lib/gcp/monitoring/alertmanager"
    12  )
    13  
    14  type updateArgsT struct {
    15  	addUserLabels string
    16  	delUserLabels string
    17  	name          string
    18  	filter        string
    19  	rename        string
    20  	enable        bool
    21  	disable       bool
    22  	templatePath  string
    23  }
    24  
    25  var updateArgs updateArgsT
    26  var updateFlagSet = newUpdateFlagSet(&updateArgs)
    27  
    28  func newUpdateFlagSet(updateArgs *updateArgsT) *flag.FlagSet {
    29  	updatef := newFlagSet("update")
    30  	updatef.StringVar(&updateArgs.name, "name", "", "AlertPolicy Name or Display Name to update. (required)\nNOTE: If a Display Name is used and multiple AlertPolicies exist with the same name, only the first match will be used.")
    31  	updatef.StringVar(&updateArgs.addUserLabels, "add-userlabels", "", "UserLabel(s) to append to the specified AlertPolicy. (optional)\nNOTE: Use ':' to separate each userlabel Key/Value pair and ',' if specifying multiple Key/Value pairs.\n      No empty Key/Value allowed.")
    32  	updatef.StringVar(&updateArgs.delUserLabels, "del-userlabels", "", "UserLabel(s) to remove from the specified AlertPolicy. (optional)\nNOTE: Use ':' to separate each userlabel Key/Value pair and ',' if specifying multiple Key/Value pairs.\n      No empty Key/Value allowed.")
    33  	updatef.StringVar(&updateArgs.filter, "filter", "", "Updates AlertPolicy(ies) matching filter criteria. (optional)\nNOTE: The filter syntax consists of a simple expression language. Negation, conjunction, and disjunction are written using NOT, AND, and OR keywords.\n      Fields can be compared with literal values by use of : (containment), = (equality), > (greater), < (less than), >= (greater than or equal to), <= (less than or equal to), and != (inequality) operators.")
    34  	updatef.StringVar(&updateArgs.rename, "new-name", "", "Rename's the AlertPolicy with the new name provided. (optional)")
    35  	updatef.StringVar(&updateArgs.templatePath, "path", "", "File path to the AlertPolicy (*.json) file.\nNOTE: Only supports updating a single AlertPolicy at a time. Recommend using the AlertPolicy 'Name' instead of 'DisplayName' to identify a unique match")
    36  	updatef.BoolVar(&updateArgs.enable, "enable", false, "Enable the AlertPolicy if not enabled. (optional)")
    37  	updatef.BoolVar(&updateArgs.disable, "disable", false, "Disable the AlertPolicy if enabled. (optional)")
    38  	return updatef
    39  }
    40  
    41  var updateCmd = &ffcli.Command{
    42  	Name:       "update",
    43  	ShortUsage: "update [flags]",
    44  	ShortHelp:  "Update running alert policy",
    45  	LongHelp: strings.TrimSpace(`
    46  Updates the AlertPolicy instance configuration in the project.
    47  `),
    48  	FlagSet: withGlobalFlags(updateFlagSet),
    49  	Exec:    runUpdate,
    50  }
    51  
    52  func runUpdate(_ context.Context, args []string) error {
    53  	if len(args) > 0 {
    54  		Fatalf("too many non-flag arguments: %q", args)
    55  	}
    56  	if !checkUpdateFlags() {
    57  		Println()
    58  		return flag.ErrHelp
    59  	}
    60  
    61  	// Enable AlertPolicy.
    62  	if updateArgs.enable {
    63  		err := alertmgr.ActivateAlertPolicy(projectID, updateArgs.enable, updateArgs.disable, updateArgs.name, updateArgs.filter)
    64  		if strings.Contains(err.Error(), "error") {
    65  			return err
    66  		}
    67  	}
    68  	// Disable AlertPolicy.
    69  	if updateArgs.disable {
    70  		err := alertmgr.ActivateAlertPolicy(projectID, updateArgs.enable, updateArgs.disable, updateArgs.name, updateArgs.filter)
    71  		if strings.Contains(err.Error(), "error") {
    72  			return err
    73  		}
    74  	}
    75  
    76  	// add AlertPolicy UserLabels.
    77  	if len(updateArgs.addUserLabels) > 0 {
    78  		callFlag := true
    79  		userlabels, err := strArray(updateArgs.addUserLabels, callFlag)
    80  		if err != nil {
    81  			logger.Info("Please update the [add-userlabel] to the required format")
    82  			return err
    83  		}
    84  		err = alertmgr.UpdateAlertPolicyUserLabels(projectID, userlabels, updateArgs.name, updateArgs.filter, callFlag)
    85  		if strings.Contains(err.Error(), "error") {
    86  			return err
    87  		}
    88  	}
    89  
    90  	// remove AlertPolicy UserLabels.
    91  	if len(updateArgs.delUserLabels) > 0 {
    92  		callFlag := false
    93  		userlabels, err := strArray(updateArgs.delUserLabels, callFlag)
    94  		if err != nil {
    95  			logger.Info("Please update the [remove-userlabel] to the required format")
    96  			return err
    97  		}
    98  		err = alertmgr.UpdateAlertPolicyUserLabels(projectID, userlabels, updateArgs.name, updateArgs.filter, callFlag)
    99  		if strings.Contains(err.Error(), "error") {
   100  			return err
   101  		}
   102  	}
   103  
   104  	// rename AlertPolicy.
   105  	if len(updateArgs.rename) > 0 {
   106  		err := alertmgr.RenameAlertPolicy(projectID, updateArgs.rename, updateArgs.name)
   107  		if err != nil {
   108  			return err
   109  		}
   110  	}
   111  
   112  	// Update AlertPolicy from template.
   113  	if len(updateArgs.templatePath) > 0 {
   114  		var flag bool
   115  		// Get the AlertPolicy configuration template(s) from the path.
   116  		sourceAlertPolicy, merr := alertmgr.ReadAlertPolicyFromPath(updateArgs.templatePath)
   117  		if merr != nil {
   118  			return Errorf("failed to read AlertPolicy configuration from file: %w", merr)
   119  		}
   120  		// Get the running AlertPolicy configuration.
   121  		matchedAlertPolicy, serr := alertmgr.GetAlertPolicies(projectID, updateArgs.name, "")
   122  		if serr == nil && len(matchedAlertPolicy) == 0 {
   123  			return fmt.Errorf("%s AlertPolicy doesn't exists in project %s and should be created instead", updateArgs.name, projectID)
   124  		}
   125  		// Validate alertPolicy doesn't have any duplicates. If yes return an error and exit.
   126  		switch {
   127  		case len(sourceAlertPolicy) > 1:
   128  			return Errorf("please provide the filepath to the AlertPolicy (*.json) template not the directory path: %s", updateArgs.templatePath)
   129  		case len(matchedAlertPolicy) > 1:
   130  			return fmt.Errorf("'%s' AlertPolicy has multiple matches in project %s a unique match is required for this update method. Recommend using the AlertPolicy 'Name' instead of 'DisplayName' in the cli", updateArgs.name, projectID)
   131  		}
   132  
   133  		for i := 0; i < len(sourceAlertPolicy); i++ {
   134  			err := alertmgr.UpdateAlertPolicyFromTemplate(projectID, flag, sourceAlertPolicy[i].AlertPolicy, matchedAlertPolicy)
   135  			if err != nil {
   136  				return err
   137  			}
   138  		}
   139  	}
   140  	return nil
   141  }
   142  
   143  // validates the required update subcommand flags have been provided.
   144  func checkUpdateFlags() bool {
   145  	if len(projectID) == 0 {
   146  		logger.Error(nil, "Error: no value specified for [project] - a valid project-id is required")
   147  		return false
   148  	}
   149  
   150  	if len(updateArgs.name) == 0 && len(updateArgs.filter) == 0 {
   151  		logger.Error(nil, "Error: no value specified for [name] or [filter] - a AlertPolicy (name / display name) or a filter critieria is required")
   152  		return false
   153  	}
   154  
   155  	if len(updateArgs.name) > 0 && len(updateArgs.filter) > 0 {
   156  		logger.Error(nil, "Error: cannot use both [name] and [filter] for update - Please use only one option")
   157  		return false
   158  	}
   159  
   160  	if len(updateArgs.rename) > 0 && len(updateArgs.filter) > 0 {
   161  		logger.Error(nil, "Error: cannot rename multiple AlertPolicies - Please use [name] insted of [filter] flag")
   162  		return false
   163  	}
   164  
   165  	if len(updateArgs.templatePath) > 0 && len(updateArgs.filter) > 0 {
   166  		logger.Error(nil, "Error: cannot update multiple AlertPolicies from Path - Please use [name] insted of [filter] flag")
   167  		return false
   168  	}
   169  
   170  	if len(updateArgs.addUserLabels) == 0 && len(updateArgs.delUserLabels) == 0 && len(updateArgs.rename) == 0 && !updateArgs.enable && !updateArgs.disable && len(updateArgs.templatePath) == 0 {
   171  		logger.Error(nil, "Error: no values specified for [add-userlabels], [remove-labels], [new-name], [path] or [enable]/[disable] - please provide at least one parameter to perform an update action on the AlertPolicy")
   172  		return false
   173  	}
   174  
   175  	if strings.ContainsAny(updateArgs.addUserLabels, "(){}[]_;.'") {
   176  		logger.Error(nil, "Error: no special characters '(' ')' '{' '}' '[' ']' '_' ';' '.' allowed in [add-userlabels] - please update the command")
   177  		return false
   178  	}
   179  
   180  	if strings.ContainsAny(updateArgs.delUserLabels, "(){}[]_;.'") {
   181  		logger.Error(nil, "Error: no special characters '(' ')' '{' '}' '[' ']' '_' ';' '.' allowed in [del-userlabels] - please update the command")
   182  		return false
   183  	}
   184  
   185  	if !checkPath(updateArgs.templatePath, false) {
   186  		logger.Error(nil, fmt.Sprintf("Error: invalid AlertPolicy [path] specified - %s\n", updateArgs.templatePath))
   187  		return false
   188  	}
   189  
   190  	return true
   191  }
   192  

View as plain text