github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/operation/operation.go (about) 1 /* 2 * Copyright 2020 The Compass Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package operation 18 19 import ( 20 "context" 21 "time" 22 23 "github.com/kyma-incubator/compass/components/director/internal/model" 24 25 validation "github.com/go-ozzo/ozzo-validation/v4" 26 "github.com/go-ozzo/ozzo-validation/v4/is" 27 "github.com/kyma-incubator/compass/components/director/pkg/resource" 28 29 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 30 ) 31 32 type contextKey string 33 34 const ( 35 // OpCtxKey missing godoc 36 OpCtxKey contextKey = "OperationCtx" 37 // OpModeKey missing godoc 38 OpModeKey contextKey = "OperationModeCtx" 39 ) 40 41 // OperationStatus denotes the different statuses that an Operation can be in 42 type OperationStatus string 43 44 const ( 45 // OperationStatusSucceeded missing godoc 46 OperationStatusSucceeded OperationStatus = "SUCCEEDED" 47 // OperationStatusFailed missing godoc 48 OperationStatusFailed OperationStatus = "FAILED" 49 // OperationStatusInProgress missing godoc 50 OperationStatusInProgress OperationStatus = "IN_PROGRESS" 51 ) 52 53 // OperationType missing godoc 54 type OperationType string 55 56 const ( 57 // OperationTypeCreate missing godoc 58 OperationTypeCreate OperationType = "Create" 59 // OperationTypeUpdate Operation type used for Update and Unpair flows 60 OperationTypeUpdate OperationType = "Update" 61 // OperationTypeDelete missing godoc 62 OperationTypeDelete OperationType = "Delete" 63 ) 64 65 // OperationResponse defines the expected response format for the Operations API 66 type OperationResponse struct { 67 *Operation 68 Status OperationStatus `json:"status,omitempty"` 69 Error *string `json:"error,omitempty"` 70 } 71 72 // Operation represents a GraphQL mutation which has associated HTTP requests (Webhooks) that need to be executed 73 // for the request to be completed fully. Objects of type Operation are meant to be constructed, enriched throughout 74 // the flow of the original mutation with information such as ResourceID and ResourceType and finally scheduled through 75 // a dedicated Scheduler implementation. 76 type Operation struct { 77 OperationID string `json:"operation_id,omitempty"` 78 OperationType OperationType `json:"operation_type,omitempty"` 79 OperationCategory string `json:"operation_category,omitempty"` 80 ResourceID string `json:"resource_id,omitempty"` 81 ResourceType resource.Type `json:"resource_type,omitempty"` 82 CreationTime time.Time `json:"creation_time,omitempty"` 83 CorrelationID string `json:"correlation_id,omitempty"` 84 WebhookIDs []string `json:"webhook_ids,omitempty"` 85 RequestObject string `json:"request_object,omitempty"` 86 } 87 88 // Validate ensures that the constructed Operation has valid properties 89 func (op *Operation) Validate() error { 90 return validation.ValidateStruct(op, 91 validation.Field(&op.ResourceID, is.UUID), 92 validation.Field(&op.ResourceType, validation.Required, validation.In(resource.Application))) 93 } 94 95 // SaveToContext saves Operation to the context 96 func SaveToContext(ctx context.Context, operations *[]*Operation) context.Context { 97 if operations == nil { 98 return ctx 99 } 100 101 operationsFromCtx, exists := FromCtx(ctx) 102 if exists { 103 *operationsFromCtx = append(*operationsFromCtx, *operations...) 104 return ctx 105 } 106 107 return context.WithValue(ctx, OpCtxKey, operations) 108 } 109 110 // FromCtx extracts Operation from context 111 func FromCtx(ctx context.Context) (*[]*Operation, bool) { 112 opCtx := ctx.Value(OpCtxKey) 113 114 if operations, ok := opCtx.(*[]*Operation); ok { 115 return operations, true 116 } 117 118 return nil, false 119 } 120 121 // SaveModeToContext saves operation mode to the context 122 func SaveModeToContext(ctx context.Context, opMode graphql.OperationMode) context.Context { 123 return context.WithValue(ctx, OpModeKey, opMode) 124 } 125 126 // ModeFromCtx extracts operation mode from context 127 func ModeFromCtx(ctx context.Context) graphql.OperationMode { 128 opCtx := ctx.Value(OpModeKey) 129 130 if opMode, ok := opCtx.(graphql.OperationMode); ok { 131 return opMode 132 } 133 134 return graphql.OperationModeSync 135 } 136 137 func (opResponse *OperationResponse) initializeOperationType(resource model.Entity) { 138 if !resource.GetDeletedAt().IsZero() { 139 opResponse.OperationType = OperationTypeDelete 140 } else if !resource.GetUpdatedAt().IsZero() { 141 opResponse.OperationType = OperationTypeUpdate 142 } else { 143 opResponse.OperationType = OperationTypeCreate 144 } 145 } 146 147 func (opResponse *OperationResponse) initializeOperationStatus(resource model.Entity) { 148 if !resource.GetReady() { 149 opResponse.Status = OperationStatusInProgress 150 } else if resource.GetError() == nil { 151 opResponse.Status = OperationStatusSucceeded 152 } else { 153 opResponse.Status = OperationStatusFailed 154 } 155 } 156 157 func (opResponse *OperationResponse) initializeCreationTime(resource model.Entity) { 158 createdAt, updatedAt, deletedAt := resource.GetCreatedAt(), resource.GetUpdatedAt(), resource.GetDeletedAt() 159 160 if deletedAt.After(createdAt) && deletedAt.After(updatedAt) { 161 opResponse.CreationTime = deletedAt 162 } else if updatedAt.After(createdAt) { 163 opResponse.CreationTime = updatedAt 164 } else { 165 opResponse.CreationTime = createdAt 166 } 167 }