github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/imaging/policy.go (about) 1 package imaging 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "net/http" 9 10 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/edgegriderr" 11 12 validation "github.com/go-ozzo/ozzo-validation/v4" 13 ) 14 15 // Code in this package is using autogenerated code located in the policy.gen.go file. 16 // Generator code is located in `dxe-tools` repo, and it is using OpenApi schema from 17 // https://git.source.akamai.com/users/eleclair/repos/terraform/browse/docs/schemas 18 19 type ( 20 // Policies is an Image and Video Manager API interface for Policy 21 // 22 // See: https://techdocs.akamai.com/ivm/reference/api 23 Policies interface { 24 // ListPolicies lists all Policies for the given network and an account 25 // 26 // See: https://techdocs.akamai.com/ivm/reference/get-policies 27 ListPolicies(context.Context, ListPoliciesRequest) (*ListPoliciesResponse, error) 28 29 // GetPolicy gets specific policy by PolicyID 30 GetPolicy(context.Context, GetPolicyRequest) (PolicyOutput, error) 31 32 // UpsertPolicy creates or updates the configuration for a policy 33 UpsertPolicy(context.Context, UpsertPolicyRequest) (*PolicyResponse, error) 34 35 // DeletePolicy deletes a policy 36 DeletePolicy(context.Context, DeletePolicyRequest) (*PolicyResponse, error) 37 38 // GetPolicyHistory retrieves history of changes for a policy 39 GetPolicyHistory(context.Context, GetPolicyHistoryRequest) (*GetPolicyHistoryResponse, error) 40 41 // RollbackPolicy reverts a policy to its previous version and deploys it to the network 42 RollbackPolicy(ctx context.Context, request RollbackPolicyRequest) (*PolicyResponse, error) 43 } 44 45 // ListPoliciesRequest describes the parameters of the ListPolicies request 46 ListPoliciesRequest struct { 47 Network PolicyNetwork 48 ContractID string 49 PolicySetID string 50 } 51 52 // ListPoliciesResponse is a response returned by ListPolicies operations 53 ListPoliciesResponse struct { 54 ItemKind string `json:"itemKind"` 55 Items PolicyOutputs `json:"items"` 56 TotalItems int `json:"totalItems"` 57 } 58 59 // GetPolicyRequest describes the parameters of the GetPolicy request 60 GetPolicyRequest policyRequest 61 // DeletePolicyRequest describes the parameters of the DeletePolicy request 62 DeletePolicyRequest policyRequest 63 // GetPolicyHistoryRequest describes the parameters of the GetHistoryPolicy request 64 GetPolicyHistoryRequest policyRequest 65 // RollbackPolicyRequest describes the parameters of the RollbackPolicy request 66 RollbackPolicyRequest policyRequest 67 68 // policyRequest describes the parameters of the various policy requests 69 policyRequest struct { 70 PolicyID string 71 Network PolicyNetwork 72 ContractID string 73 PolicySetID string 74 } 75 76 // UpsertPolicyRequest describes the parameters of the UpsertPolicy request 77 UpsertPolicyRequest struct { 78 PolicyID string 79 Network PolicyNetwork 80 ContractID string 81 PolicySetID string 82 PolicyInput 83 } 84 85 // PolicyResponse describes response of the UpsertPolicy, DeletePolicy and RollbackPolicy responses 86 PolicyResponse struct { 87 Description string `json:"description"` 88 ID string `json:"id"` 89 OperationPerformed string `json:"operationPerformed"` 90 } 91 92 // GetPolicyHistoryResponse describes the parameters of the GetPolicyHistory response 93 GetPolicyHistoryResponse struct { 94 ItemKind string `json:"itemKind"` 95 TotalItems int `json:"totalItems"` 96 Items []PolicyHistoryItem `json:"items"` 97 } 98 99 // PolicyHistoryItem describes items of the history for policy 100 PolicyHistoryItem struct { 101 ID string `json:"id"` 102 DateCreated string `json:"dateCreated"` 103 Policy string `json:"policy"` 104 Action string `json:"action"` 105 User string `json:"user"` 106 Version int `json:"version"` 107 } 108 109 // PolicyOutput is implemented by PolicyOutput types (image and video) 110 PolicyOutput interface { 111 policyOutputType() string 112 } 113 114 // PolicyInput is implemented by PolicyInput types (image and video) 115 PolicyInput interface { 116 policyInputType() string 117 } 118 119 // PolicyOutputs is an array of PolicyOutput types (image and video) 120 PolicyOutputs []PolicyOutput 121 122 // PolicyNetwork represents the network where policy set is stored 123 PolicyNetwork string 124 125 // PolicyInputImage Specifies details for each policy, such as transformations to apply and variations in image size and formats 126 PolicyInputImage struct { 127 // Breakpoints The breakpoint widths (in pixels) to use to create derivative images/videos 128 Breakpoints *Breakpoints `json:"breakpoints,omitempty"` 129 // Hosts Hosts that are allowed for image/video URLs within transformations or variables 130 Hosts []string `json:"hosts,omitempty"` 131 // Output Dictates the output quality (either `quality` or `perceptualQuality`) and formats that are created for each resized image If unspecified, image formats are created to support all browsers at the default quality level (`85`), which includes formats such as WEBP, JPEG2000 and JPEG-XR for specific browsers 132 Output *OutputImage `json:"output,omitempty"` 133 // PostBreakpointTransformations Post-processing Transformations are applied to the image after image and quality settings have been applied 134 PostBreakpointTransformations PostBreakpointTransformations `json:"postBreakpointTransformations,omitempty"` 135 // RolloutDuration The amount of time in seconds that the policy takes to rollout. During the rollout an increasing proportion of images/videos will begin to use the new policy instead of the cached images/videos from the previous version 136 RolloutDuration *int `json:"rolloutDuration,omitempty"` 137 // Transformations Set of image transformations to apply to the source image. If unspecified, no operations are performed 138 Transformations Transformations `json:"transformations,omitempty"` 139 // Variables Declares variables for use within the policy. Any variable declared here can be invoked throughout transformations as a [Variable](#variable) object, so that you don't have to specify values separately You can also pass in these variable names and values dynamically as query parameters in the image's request URL 140 Variables []Variable `json:"variables,omitempty"` 141 } 142 143 // PolicyInputVideo Specifies details for each policy such as video size 144 PolicyInputVideo struct { 145 // Breakpoints The breakpoint widths (in pixels) to use to create derivative images/videos 146 Breakpoints *Breakpoints `json:"breakpoints,omitempty"` 147 // Hosts Hosts that are allowed for image/video URLs within transformations or variables 148 Hosts []string `json:"hosts,omitempty"` 149 // Output Dictates the output quality that are created for each resized video 150 Output *OutputVideo `json:"output,omitempty"` 151 // RolloutDuration The amount of time in seconds that the policy takes to rollout. During the rollout an increasing proportion of images/videos will begin to use the new policy instead of the cached images/videos from the previous version 152 RolloutDuration *int `json:"rolloutDuration,omitempty"` 153 // Variables Declares variables for use within the policy. Any variable declared here can be invoked throughout transformations as a [Variable](#variable) object, so that you don't have to specify values separately You can also pass in these variable names and values dynamically as query parameters in the image's request URL 154 Variables []Variable `json:"variables,omitempty"` 155 } 156 ) 157 158 const ( 159 // PolicyNetworkStaging represents staging network 160 PolicyNetworkStaging PolicyNetwork = "staging" 161 // PolicyNetworkProduction represents production network 162 PolicyNetworkProduction PolicyNetwork = "production" 163 ) 164 165 var ( 166 // ErrUnmarshalPolicyOutputList represents an error while unmarshalling transformation list 167 ErrUnmarshalPolicyOutputList = errors.New("unmarshalling policy output list") 168 169 // ErrListPolicies is returned when ListPolicies fails 170 ErrListPolicies = errors.New("list policies") 171 172 // ErrGetPolicy is returned when GetPolicy fails 173 ErrGetPolicy = errors.New("get policy") 174 175 // ErrUpsertPolicy is returned when UpsertPolicy fails 176 ErrUpsertPolicy = errors.New("upsert policy") 177 178 // ErrDeletePolicy is returned when DeletePolicy fails 179 ErrDeletePolicy = errors.New("delete policy") 180 181 // ErrGetPolicyHistory is returned when GetPolicyHistory fails 182 ErrGetPolicyHistory = errors.New("get policy history") 183 184 // ErrRollbackPolicy is returned when RollbackPolicy fails 185 ErrRollbackPolicy = errors.New("rollback policy") 186 ) 187 188 func (*PolicyOutputImage) policyOutputType() string { 189 return "Image" 190 } 191 192 func (*PolicyOutputVideo) policyOutputType() string { 193 return "Video" 194 } 195 196 func (*PolicyInputImage) policyInputType() string { 197 return "Image" 198 } 199 200 func (*PolicyInputVideo) policyInputType() string { 201 return "Video" 202 } 203 204 // Validate validates PolicyInputImage 205 func (p *PolicyInputImage) Validate() error { 206 return validation.Errors{ 207 "Breakpoints": validation.Validate(p.Breakpoints), 208 "Hosts": validation.Validate(p.Hosts, validation.Each()), 209 "Output": validation.Validate(p.Output), 210 "PostBreakpointTransformations": validation.Validate(p.PostBreakpointTransformations), 211 "RolloutDuration": validation.Validate(p.RolloutDuration, 212 validation.Min(3600), 213 validation.Max(604800), 214 ), 215 "Transformations": validation.Validate(p.Transformations), 216 "Variables": validation.Validate(p.Variables, validation.Each()), 217 }.Filter() 218 } 219 220 // Validate validates PolicyInputVideo 221 func (p *PolicyInputVideo) Validate() error { 222 return validation.Errors{ 223 "Breakpoints": validation.Validate(p.Breakpoints), 224 "Hosts": validation.Validate(p.Hosts, validation.Each()), 225 "Output": validation.Validate(p.Output), 226 "RolloutDuration": validation.Validate(p.RolloutDuration, 227 validation.Min(3600), 228 validation.Max(604800), 229 ), 230 "Variables": validation.Validate(p.Variables, validation.Each()), 231 }.Filter() 232 } 233 234 var policyOutputHandlers = map[bool]func() PolicyOutput{ 235 false: func() PolicyOutput { return &PolicyOutputImage{} }, 236 true: func() PolicyOutput { return &PolicyOutputVideo{} }, 237 } 238 239 // UnmarshalJSON is a custom unmarshaler used to decode a slice of PolicyOutput interfaces 240 func (po *PolicyOutputs) UnmarshalJSON(in []byte) error { 241 data := make([]map[string]interface{}, 0) 242 if err := json.Unmarshal(in, &data); err != nil { 243 return fmt.Errorf("%w: %s", ErrUnmarshalPolicyOutputList, err) 244 } 245 for _, policyOutput := range data { 246 p, err := unmarshallPolicyOutput(policyOutput) 247 if err != nil { 248 return err 249 } 250 *po = append(*po, p) 251 } 252 return nil 253 } 254 255 func unmarshallPolicyOutput(policyOutput map[string]interface{}) (PolicyOutput, error) { 256 video, ok := policyOutput["video"] 257 if !ok { 258 return nil, fmt.Errorf("%w: policyOutput should contain 'video' field", ErrUnmarshalPolicyOutputList) 259 } 260 isVideo, ok := video.(bool) 261 if !ok { 262 return nil, fmt.Errorf("%w: 'video' field on policyOutput entry should be a boolean", ErrUnmarshalPolicyOutputList) 263 } 264 265 bytes, err := json.Marshal(policyOutput) 266 if err != nil { 267 return nil, fmt.Errorf("%w: %s", ErrUnmarshalPolicyOutputList, err) 268 } 269 270 indicatedPolicyOutputType, ok := policyOutputHandlers[isVideo] 271 if !ok { 272 return nil, fmt.Errorf("%w: unsupported policyOutput type: %v", ErrUnmarshalPolicyOutputList, isVideo) 273 } 274 ipt := indicatedPolicyOutputType() 275 err = json.Unmarshal(bytes, ipt) 276 if err != nil { 277 return nil, fmt.Errorf("%w: %s", ErrUnmarshalPolicyOutputList, err) 278 } 279 return ipt, nil 280 } 281 282 // Validate validates ListPoliciesRequest 283 func (v ListPoliciesRequest) Validate() error { 284 errs := validation.Errors{ 285 "ContractID": validation.Validate(v.ContractID, validation.Required), 286 "PolicySetID": validation.Validate(v.PolicySetID, validation.Required), 287 "Network": validation.Validate(v.Network, validation.Required, validation.In(PolicyNetworkStaging, PolicyNetworkProduction). 288 Error(fmt.Sprintf("network has to be '%s', '%s'", PolicyNetworkStaging, PolicyNetworkProduction))), 289 } 290 return edgegriderr.ParseValidationErrors(errs) 291 } 292 293 // Validate validates GetPolicyRequest 294 func (v GetPolicyRequest) Validate() error { 295 errs := validation.Errors{ 296 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 297 "ContractID": validation.Validate(v.ContractID, validation.Required), 298 "PolicySetID": validation.Validate(v.PolicySetID, validation.Required), 299 "Network": validation.Validate(v.Network, validation.Required, validation.In(PolicyNetworkStaging, PolicyNetworkProduction). 300 Error(fmt.Sprintf("network has to be '%s', '%s'", PolicyNetworkStaging, PolicyNetworkProduction))), 301 } 302 return edgegriderr.ParseValidationErrors(errs) 303 } 304 305 // Validate validates UpsertPolicyRequest 306 func (v UpsertPolicyRequest) Validate() error { 307 errs := validation.Errors{ 308 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 309 "ContractID": validation.Validate(v.ContractID, validation.Required), 310 "PolicySetID": validation.Validate(v.PolicySetID, validation.Required), 311 "Network": validation.Validate(v.Network, validation.Required, validation.In(PolicyNetworkStaging, PolicyNetworkProduction). 312 Error(fmt.Sprintf("network has to be '%s', '%s'", PolicyNetworkStaging, PolicyNetworkProduction))), 313 "Policy": validation.Validate(v.PolicyInput, validation.Required), 314 //Validate, Policy Input 315 } 316 return edgegriderr.ParseValidationErrors(errs) 317 } 318 319 // Validate validates DeletePolicyRequest 320 func (v DeletePolicyRequest) Validate() error { 321 errs := validation.Errors{ 322 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 323 "ContractID": validation.Validate(v.ContractID, validation.Required), 324 "PolicySetID": validation.Validate(v.PolicySetID, validation.Required), 325 "Network": validation.Validate(v.Network, validation.Required, validation.In(PolicyNetworkStaging, PolicyNetworkProduction). 326 Error(fmt.Sprintf("network has to be '%s', '%s'", PolicyNetworkStaging, PolicyNetworkProduction))), 327 } 328 return edgegriderr.ParseValidationErrors(errs) 329 } 330 331 // Validate validates GetPolicyHistoryRequest 332 func (v GetPolicyHistoryRequest) Validate() error { 333 errs := validation.Errors{ 334 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 335 "ContractID": validation.Validate(v.ContractID, validation.Required), 336 "PolicySetID": validation.Validate(v.PolicySetID, validation.Required), 337 "Network": validation.Validate(v.Network, validation.Required, validation.In(PolicyNetworkStaging, PolicyNetworkProduction). 338 Error(fmt.Sprintf("network has to be '%s', '%s'", PolicyNetworkStaging, PolicyNetworkProduction))), 339 } 340 return edgegriderr.ParseValidationErrors(errs) 341 } 342 343 // Validate validates RollbackPolicyRequest 344 func (v RollbackPolicyRequest) Validate() error { 345 errs := validation.Errors{ 346 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 347 "ContractID": validation.Validate(v.ContractID, validation.Required), 348 "PolicySetID": validation.Validate(v.PolicySetID, validation.Required), 349 "Network": validation.Validate(v.Network, validation.Required, validation.In(PolicyNetworkStaging, PolicyNetworkProduction). 350 Error(fmt.Sprintf("network has to be '%s', '%s'", PolicyNetworkStaging, PolicyNetworkProduction))), 351 } 352 return edgegriderr.ParseValidationErrors(errs) 353 } 354 355 func (i *imaging) ListPolicies(ctx context.Context, params ListPoliciesRequest) (*ListPoliciesResponse, error) { 356 logger := i.Log(ctx) 357 logger.Debug("ListPolicies") 358 359 if err := params.Validate(); err != nil { 360 return nil, fmt.Errorf("%s: %w:\n%s", ErrListPolicies, ErrStructValidation, err) 361 } 362 363 uri := fmt.Sprintf("/imaging/v2/network/%s/policies/", params.Network) 364 365 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 366 if err != nil { 367 return nil, fmt.Errorf("%w: failed to create request: %s", ErrListPolicies, err) 368 } 369 370 req.Header.Set("Contract", params.ContractID) 371 req.Header.Set("Policy-Set", params.PolicySetID) 372 373 var result ListPoliciesResponse 374 resp, err := i.Exec(req, &result) 375 if err != nil { 376 return nil, fmt.Errorf("%w: request failed: %s", ErrListPolicies, err) 377 } 378 379 if resp.StatusCode != http.StatusOK { 380 return nil, fmt.Errorf("%s: %w", ErrListPolicies, i.Error(resp)) 381 } 382 383 return &result, nil 384 } 385 386 func (i *imaging) GetPolicy(ctx context.Context, params GetPolicyRequest) (PolicyOutput, error) { 387 logger := i.Log(ctx) 388 logger.Debug("GetPolicy") 389 390 if err := params.Validate(); err != nil { 391 return nil, fmt.Errorf("%s: %w:\n%s", ErrGetPolicy, ErrStructValidation, err) 392 } 393 394 uri := fmt.Sprintf("/imaging/v2/network/%s/policies/%s", params.Network, params.PolicyID) 395 396 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 397 if err != nil { 398 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPolicy, err) 399 } 400 401 req.Header.Set("Contract", params.ContractID) 402 req.Header.Set("Policy-Set", params.PolicySetID) 403 404 var result map[string]interface{} 405 resp, err := i.Exec(req, &result) 406 if err != nil { 407 return nil, fmt.Errorf("%w: request failed: %s", ErrGetPolicy, err) 408 } 409 410 if resp.StatusCode != http.StatusOK { 411 return nil, fmt.Errorf("%s: %w", ErrGetPolicy, i.Error(resp)) 412 } 413 414 policyOutput, err := unmarshallPolicyOutput(result) 415 if err != nil { 416 return nil, err 417 } 418 419 return policyOutput, nil 420 } 421 422 func (i *imaging) UpsertPolicy(ctx context.Context, params UpsertPolicyRequest) (*PolicyResponse, error) { 423 logger := i.Log(ctx) 424 logger.Debug("UpsertPolicy") 425 426 if err := params.Validate(); err != nil { 427 return nil, fmt.Errorf("%s: %w:\n%s", ErrUpsertPolicy, ErrStructValidation, err) 428 } 429 430 uri := fmt.Sprintf("/imaging/v2/network/%s/policies/%s", params.Network, params.PolicyID) 431 432 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 433 if err != nil { 434 return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpsertPolicy, err) 435 } 436 437 req.Header.Set("Contract", params.ContractID) 438 req.Header.Set("Policy-Set", params.PolicySetID) 439 440 var result PolicyResponse 441 resp, err := i.Exec(req, &result, params.PolicyInput) 442 if err != nil { 443 return nil, fmt.Errorf("%w: request failed: %s", ErrUpsertPolicy, err) 444 } 445 446 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 447 return nil, fmt.Errorf("%s: %w", ErrUpsertPolicy, i.Error(resp)) 448 } 449 450 return &result, nil 451 } 452 453 func (i *imaging) DeletePolicy(ctx context.Context, params DeletePolicyRequest) (*PolicyResponse, error) { 454 logger := i.Log(ctx) 455 logger.Debug("DeletePolicy") 456 457 if err := params.Validate(); err != nil { 458 return nil, fmt.Errorf("%s: %w:\n%s", ErrDeletePolicy, ErrStructValidation, err) 459 } 460 461 uri := fmt.Sprintf("/imaging/v2/network/%s/policies/%s", params.Network, params.PolicyID) 462 463 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil) 464 if err != nil { 465 return nil, fmt.Errorf("%w: failed to create request: %s", ErrDeletePolicy, err) 466 } 467 468 req.Header.Set("Contract", params.ContractID) 469 req.Header.Set("Policy-Set", params.PolicySetID) 470 471 var result PolicyResponse 472 resp, err := i.Exec(req, &result) 473 if err != nil { 474 return nil, fmt.Errorf("%w: request failed: %s", ErrDeletePolicy, err) 475 } 476 477 if resp.StatusCode != http.StatusOK { 478 return nil, fmt.Errorf("%s: %w", ErrDeletePolicy, i.Error(resp)) 479 } 480 481 return &result, nil 482 } 483 484 func (i *imaging) GetPolicyHistory(ctx context.Context, params GetPolicyHistoryRequest) (*GetPolicyHistoryResponse, error) { 485 logger := i.Log(ctx) 486 logger.Debug("GetPolicyHistory") 487 488 if err := params.Validate(); err != nil { 489 return nil, fmt.Errorf("%s: %w:\n%s", ErrGetPolicyHistory, ErrStructValidation, err) 490 } 491 492 uri := fmt.Sprintf("/imaging/v2/network/%s/policies/history/%s", params.Network, params.PolicyID) 493 494 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 495 if err != nil { 496 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPolicyHistory, err) 497 } 498 499 req.Header.Set("Contract", params.ContractID) 500 req.Header.Set("Policy-Set", params.PolicySetID) 501 502 var result GetPolicyHistoryResponse 503 resp, err := i.Exec(req, &result) 504 if err != nil { 505 return nil, fmt.Errorf("%w: request failed: %s", ErrGetPolicyHistory, err) 506 } 507 508 if resp.StatusCode != http.StatusOK { 509 return nil, fmt.Errorf("%s: %w", ErrGetPolicyHistory, i.Error(resp)) 510 } 511 512 return &result, nil 513 } 514 515 func (i *imaging) RollbackPolicy(ctx context.Context, params RollbackPolicyRequest) (*PolicyResponse, error) { 516 logger := i.Log(ctx) 517 logger.Debug("RollbackPolicy") 518 519 if err := params.Validate(); err != nil { 520 return nil, fmt.Errorf("%s: %w:\n%s", ErrRollbackPolicy, ErrStructValidation, err) 521 } 522 523 uri := fmt.Sprintf("/imaging/v2/network/%s/policies/rollback/%s", params.Network, params.PolicyID) 524 525 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 526 if err != nil { 527 return nil, fmt.Errorf("%w: failed to create request: %s", ErrRollbackPolicy, err) 528 } 529 530 req.Header.Set("Contract", params.ContractID) 531 req.Header.Set("Policy-Set", params.PolicySetID) 532 533 var result PolicyResponse 534 resp, err := i.Exec(req, &result) 535 if err != nil { 536 return nil, fmt.Errorf("%w: request failed: %s", ErrRollbackPolicy, err) 537 } 538 539 if resp.StatusCode != http.StatusOK { 540 return nil, fmt.Errorf("%s: %w", ErrRollbackPolicy, i.Error(resp)) 541 } 542 543 return &result, nil 544 }