github.com/newrelic/newrelic-client-go@v1.1.0/pkg/alerts/policies.go (about) 1 package alerts 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/newrelic/newrelic-client-go/pkg/errors" 8 9 "github.com/newrelic/newrelic-client-go/internal/http" 10 "github.com/newrelic/newrelic-client-go/internal/serialization" 11 ) 12 13 // IncidentPreferenceType specifies rollup settings for alert policies. 14 type IncidentPreferenceType string 15 16 var ( 17 // IncidentPreferenceTypes specifies the possible incident preferenece types for an alert policy. 18 IncidentPreferenceTypes = struct { 19 PerPolicy IncidentPreferenceType 20 PerCondition IncidentPreferenceType 21 PerConditionAndTarget IncidentPreferenceType 22 }{ 23 PerPolicy: "PER_POLICY", 24 PerCondition: "PER_CONDITION", 25 PerConditionAndTarget: "PER_CONDITION_AND_TARGET", 26 } 27 ) 28 29 // Policy represents a New Relic alert policy. 30 type Policy struct { 31 ID int `json:"id,omitempty"` 32 IncidentPreference IncidentPreferenceType `json:"incident_preference,omitempty"` 33 Name string `json:"name,omitempty"` 34 CreatedAt *serialization.EpochTime `json:"created_at,omitempty"` 35 UpdatedAt *serialization.EpochTime `json:"updated_at,omitempty"` 36 } 37 38 // ListPoliciesParams represents a set of filters to be used when querying New 39 // Relic alert policies. 40 type ListPoliciesParams struct { 41 Name string `url:"filter[name],omitempty"` 42 } 43 44 // ListPolicies returns a list of Alert Policies for a given account. 45 func (a *Alerts) ListPolicies(params *ListPoliciesParams) ([]Policy, error) { 46 return a.ListPoliciesWithContext(context.Background(), params) 47 } 48 49 // ListPoliciesWithContext returns a list of Alert Policies for a given account. 50 func (a *Alerts) ListPoliciesWithContext(ctx context.Context, params *ListPoliciesParams) ([]Policy, error) { 51 alertPolicies := []Policy{} 52 53 nextURL := a.config.Region().RestURL("/alerts_policies.json") 54 55 for nextURL != "" { 56 response := alertPoliciesResponse{} 57 resp, err := a.client.GetWithContext(ctx, nextURL, ¶ms, &response) 58 59 if err != nil { 60 return nil, err 61 } 62 63 alertPolicies = append(alertPolicies, response.Policies...) 64 65 paging := a.pager.Parse(resp) 66 nextURL = paging.Next 67 } 68 69 return alertPolicies, nil 70 } 71 72 // GetPolicy returns a specific alert policy by ID for a given account. 73 func (a *Alerts) GetPolicy(id int) (*Policy, error) { 74 return a.GetPolicyWithContext(context.Background(), id) 75 } 76 77 // GetPolicyWithContext returns a specific alert policy by ID for a given account. 78 func (a *Alerts) GetPolicyWithContext(ctx context.Context, id int) (*Policy, error) { 79 policies, err := a.ListPoliciesWithContext(ctx, nil) 80 if err != nil { 81 return nil, err 82 } 83 84 for _, policy := range policies { 85 if policy.ID == id { 86 return &policy, nil 87 } 88 } 89 90 return nil, errors.NewNotFoundf("no alert policy found for id %d", id) 91 } 92 93 // CreatePolicy creates a new alert policy for a given account. 94 func (a *Alerts) CreatePolicy(policy Policy) (*Policy, error) { 95 return a.CreatePolicyWithContext(context.Background(), policy) 96 } 97 98 // CreatePolicyWithContext creates a new alert policy for a given account. 99 func (a *Alerts) CreatePolicyWithContext(ctx context.Context, policy Policy) (*Policy, error) { 100 reqBody := alertPolicyRequestBody{ 101 Policy: policy, 102 } 103 resp := alertPolicyResponse{} 104 105 _, err := a.client.PostWithContext(ctx, a.config.Region().RestURL("/alerts_policies.json"), nil, &reqBody, &resp) 106 107 if err != nil { 108 return nil, err 109 } 110 111 return &resp.Policy, nil 112 } 113 114 // UpdatePolicy update an alert policy for a given account. 115 func (a *Alerts) UpdatePolicy(policy Policy) (*Policy, error) { 116 return a.UpdatePolicyWithContext(context.Background(), policy) 117 } 118 119 // UpdatePolicyWithContext update an alert policy for a given account. 120 func (a *Alerts) UpdatePolicyWithContext(ctx context.Context, policy Policy) (*Policy, error) { 121 reqBody := alertPolicyRequestBody{ 122 Policy: policy, 123 } 124 resp := alertPolicyResponse{} 125 url := fmt.Sprintf("/alerts_policies/%d.json", policy.ID) 126 127 _, err := a.client.PutWithContext(ctx, a.config.Region().RestURL(url), nil, &reqBody, &resp) 128 if err != nil { 129 return nil, err 130 } 131 132 return &resp.Policy, nil 133 } 134 135 // DeletePolicy deletes an existing alert policy for a given account. 136 func (a *Alerts) DeletePolicy(id int) (*Policy, error) { 137 return a.DeletePolicyWithContext(context.Background(), id) 138 } 139 140 // DeletePolicyWithContext deletes an existing alert policy for a given account. 141 func (a *Alerts) DeletePolicyWithContext(ctx context.Context, id int) (*Policy, error) { 142 resp := alertPolicyResponse{} 143 url := fmt.Sprintf("/alerts_policies/%d.json", id) 144 145 _, err := a.client.DeleteWithContext(ctx, a.config.Region().RestURL(url), nil, &resp) 146 if err != nil { 147 return nil, err 148 } 149 150 return &resp.Policy, nil 151 } 152 153 func (a *Alerts) CreatePolicyMutation(accountID int, policy AlertsPolicyInput) (*AlertsPolicy, error) { 154 return a.CreatePolicyMutationWithContext(context.Background(), accountID, policy) 155 } 156 157 func (a *Alerts) CreatePolicyMutationWithContext(ctx context.Context, accountID int, policy AlertsPolicyInput) (*AlertsPolicy, error) { 158 vars := map[string]interface{}{ 159 "accountID": accountID, 160 "policy": policy, 161 } 162 163 resp := alertQueryPolicyCreateResponse{} 164 165 if err := a.client.NerdGraphQueryWithContext(ctx, alertsPolicyCreatePolicy, vars, &resp); err != nil { 166 return nil, err 167 } 168 169 return &resp.AlertsPolicy, nil 170 } 171 172 func (a *Alerts) UpdatePolicyMutation(accountID int, policyID string, policy AlertsPolicyUpdateInput) (*AlertsPolicy, error) { 173 return a.UpdatePolicyMutationWithContext(context.Background(), accountID, policyID, policy) 174 } 175 176 func (a *Alerts) UpdatePolicyMutationWithContext(ctx context.Context, accountID int, policyID string, policy AlertsPolicyUpdateInput) (*AlertsPolicy, error) { 177 vars := map[string]interface{}{ 178 "accountID": accountID, 179 "policyID": policyID, 180 "policy": policy, 181 } 182 183 resp := alertQueryPolicyUpdateResponse{} 184 185 if err := a.client.NerdGraphQueryWithContext(ctx, alertsPolicyUpdatePolicy, vars, &resp); err != nil { 186 return nil, err 187 } 188 189 return &resp.AlertsPolicy, nil 190 } 191 192 // QueryPolicy queries NerdGraph for a policy matching the given account ID and 193 // policy ID. 194 func (a *Alerts) QueryPolicy(accountID int, id string) (*AlertsPolicy, error) { 195 return a.QueryPolicyWithContext(context.Background(), accountID, id) 196 } 197 198 // QueryPolicyWithContext queries NerdGraph for a policy matching the given account ID and 199 // policy ID. 200 func (a *Alerts) QueryPolicyWithContext(ctx context.Context, accountID int, id string) (*AlertsPolicy, error) { 201 resp := alertQueryPolicyResponse{} 202 vars := map[string]interface{}{ 203 "accountID": accountID, 204 "policyID": id, 205 } 206 207 req, err := a.client.NewNerdGraphRequest(alertPolicyQueryPolicy, vars, &resp) 208 if err != nil { 209 return nil, err 210 } 211 212 req.WithContext(ctx) 213 214 var errorResponse alertPoliciesErrorResponse 215 req.SetErrorValue(&errorResponse) 216 217 if _, err := a.client.Do(req); err != nil { 218 return nil, err 219 } 220 221 return &resp.Actor.Account.Alerts.Policy, nil 222 } 223 224 // QueryPolicySearch searches NerdGraph for policies. 225 func (a *Alerts) QueryPolicySearch(accountID int, params AlertsPoliciesSearchCriteriaInput) ([]*AlertsPolicy, error) { 226 return a.QueryPolicySearchWithContext(context.Background(), accountID, params) 227 } 228 229 // QueryPolicySearchWithContext searches NerdGraph for policies. 230 func (a *Alerts) QueryPolicySearchWithContext(ctx context.Context, accountID int, params AlertsPoliciesSearchCriteriaInput) ([]*AlertsPolicy, error) { 231 policies := []*AlertsPolicy{} 232 var nextCursor *string 233 234 for ok := true; ok; ok = nextCursor != nil { 235 resp := alertQueryPolicySearchResponse{} 236 vars := map[string]interface{}{ 237 "accountID": accountID, 238 "cursor": nextCursor, 239 "searchCriteria": params, 240 } 241 242 if err := a.client.NerdGraphQueryWithContext(ctx, alertsPolicyQuerySearch, vars, &resp); err != nil { 243 return nil, err 244 } 245 246 policies = append(policies, resp.Actor.Account.Alerts.PoliciesSearch.Policies...) 247 248 nextCursor = resp.Actor.Account.Alerts.PoliciesSearch.NextCursor 249 } 250 251 return policies, nil 252 } 253 254 // DeletePolicyMutation is the NerdGraph mutation to delete a policy given the 255 // account ID and the policy ID. 256 func (a *Alerts) DeletePolicyMutation(accountID int, id string) (*AlertsPolicy, error) { 257 return a.DeletePolicyMutationWithContext(context.Background(), accountID, id) 258 } 259 260 // DeletePolicyMutationWithContext is the NerdGraph mutation to delete a policy given the 261 // account ID and the policy ID. 262 func (a *Alerts) DeletePolicyMutationWithContext(ctx context.Context, accountID int, id string) (*AlertsPolicy, error) { 263 policy := &AlertsPolicy{} 264 265 resp := alertQueryPolicyDeleteRespose{} 266 vars := map[string]interface{}{ 267 "accountID": accountID, 268 "policyID": id, 269 } 270 271 if err := a.client.NerdGraphQueryWithContext(ctx, alertPolicyDeletePolicy, vars, &resp); err != nil { 272 return nil, err 273 } 274 275 return policy, nil 276 } 277 278 type alertPoliciesErrorResponse struct { 279 http.GraphQLErrorResponse 280 } 281 282 func (r *alertPoliciesErrorResponse) IsNotFound() bool { 283 if len(r.Errors) == 0 { 284 return false 285 } 286 287 for _, err := range r.Errors { 288 if err.Message == "Not Found" && 289 // TODO: When the alerts API begins using `errorClass` 290 // instead of `code` to specify error type, the conditional 291 // checking the `code` field can be removed. 292 // 293 // https://newrelic.atlassian.net/browse/AINTER-7746 294 (err.Extensions.Code == "BAD_USER_INPUT" || err.Extensions.ErrorClass == "BAD_USER_INPUT") { 295 return true 296 } 297 } 298 299 return false 300 } 301 302 func (r *alertPoliciesErrorResponse) Error() string { 303 return r.GraphQLErrorResponse.Error() 304 } 305 306 func (r *alertPoliciesErrorResponse) New() http.ErrorResponse { 307 return &alertPoliciesErrorResponse{} 308 } 309 310 type alertPoliciesResponse struct { 311 Policies []Policy `json:"policies,omitempty"` 312 } 313 314 type alertPolicyResponse struct { 315 Policy Policy `json:"policy,omitempty"` 316 } 317 318 type alertPolicyRequestBody struct { 319 Policy Policy `json:"policy"` 320 } 321 322 type alertQueryPolicySearchResponse struct { 323 Actor struct { 324 Account struct { 325 Alerts struct { 326 PoliciesSearch struct { 327 NextCursor *string `json:"nextCursor"` 328 Policies []*AlertsPolicy `json:"policies"` 329 TotalCount int `json:"totalCount"` 330 } `json:"policiesSearch"` 331 } `json:"alerts"` 332 } `json:"account"` 333 } `json:"actor"` 334 } 335 336 type alertQueryPolicyCreateResponse struct { 337 AlertsPolicy AlertsPolicy `json:"alertsPolicyCreate"` 338 } 339 340 type alertQueryPolicyUpdateResponse struct { 341 AlertsPolicy AlertsPolicy `json:"alertsPolicyUpdate"` 342 } 343 344 type alertQueryPolicyResponse struct { 345 Actor struct { 346 Account struct { 347 Alerts struct { 348 Policy AlertsPolicy `json:"policy"` 349 } `json:"alerts"` 350 } `json:"account"` 351 } `json:"actor"` 352 } 353 354 type alertQueryPolicyDeleteRespose struct { 355 AlertsPolicyDelete struct { 356 ID int `json:"id,string"` 357 } `json:"alertsPolicyDelete"` 358 } 359 360 const ( 361 graphqlAlertPolicyFields = ` 362 id 363 name 364 incidentPreference 365 accountId 366 ` 367 alertPolicyQueryPolicy = `query($accountID: Int!, $policyID: ID!) { 368 actor { 369 account(id: $accountID) { 370 alerts { 371 policy(id: $policyID) {` + graphqlAlertPolicyFields + ` 372 } 373 } 374 } 375 } 376 }` 377 378 alertsPolicyQuerySearch = `query($accountID: Int!, $cursor: String, $criteria: AlertsPoliciesSearchCriteriaInput) { 379 actor { 380 account(id: $accountID) { 381 alerts { 382 policiesSearch(cursor: $cursor, searchCriteria: $criteria) { 383 nextCursor 384 totalCount 385 policies { 386 accountId 387 id 388 incidentPreference 389 name 390 } 391 } 392 } 393 } 394 } 395 }` 396 397 alertsPolicyCreatePolicy = `mutation CreatePolicy($accountID: Int!, $policy: AlertsPolicyInput!){ 398 alertsPolicyCreate(accountId: $accountID, policy: $policy) {` + graphqlAlertPolicyFields + ` 399 } }` 400 401 alertsPolicyUpdatePolicy = `mutation UpdatePolicy($accountID: Int!, $policyID: ID!, $policy: AlertsPolicyUpdateInput!){ 402 alertsPolicyUpdate(accountId: $accountID, id: $policyID, policy: $policy) {` + graphqlAlertPolicyFields + ` 403 } 404 }` 405 406 alertPolicyDeletePolicy = `mutation DeletePolicy($accountID: Int!, $policyID: ID!){ 407 alertsPolicyDelete(accountId: $accountID, id: $policyID) { 408 id 409 } }` 410 )