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
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
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
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
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
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
113 if len(updateArgs.templatePath) > 0 {
114 var flag bool
115
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
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
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
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