github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/avs/delegator.go (about) 1 package avs 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/kyma-project/kyma-environment-broker/internal" 8 kebError "github.com/kyma-project/kyma-environment-broker/internal/error" 9 "github.com/kyma-project/kyma-environment-broker/internal/process" 10 "github.com/kyma-project/kyma-environment-broker/internal/storage" 11 "github.com/sirupsen/logrus" 12 ) 13 14 type Delegator struct { 15 operationManager *process.OperationManager 16 avsConfig Config 17 client *Client 18 operationsStorage storage.Operations 19 } 20 21 type avsApiErrorResp struct { 22 StatusCode int `json:"statusCode"` 23 Status string `json:"status"` 24 Message string `json:"message"` 25 } 26 27 func NewDelegator(client *Client, avsConfig Config, os storage.Operations) *Delegator { 28 return &Delegator{ 29 operationManager: process.NewOperationManager(os), 30 avsConfig: avsConfig, 31 client: client, 32 operationsStorage: os, 33 } 34 } 35 36 func (del *Delegator) CreateEvaluation(log logrus.FieldLogger, operation internal.Operation, evalAssistant EvalAssistant, url string) (internal.Operation, time.Duration, error) { 37 log.Infof("starting the step avs internal id [%d] and avs external id [%d]", operation.Avs.AvsEvaluationInternalId, operation.Avs.AVSEvaluationExternalId) 38 39 var updatedOperation internal.Operation 40 d := 0 * time.Second 41 42 if evalAssistant.IsValid(operation.Avs) { 43 log.Infof("step has already been finished previously") 44 updatedOperation = operation 45 } else { 46 log.Infof("making avs calls to create the Evaluation") 47 evaluationObject, err := evalAssistant.CreateBasicEvaluationRequest(operation, url) 48 if err != nil { 49 log.Errorf("step failed with error %v", err) 50 return operation, 5 * time.Second, nil 51 } 52 53 evalResp, err := del.client.CreateEvaluation(evaluationObject) 54 switch { 55 case err == nil: 56 case kebError.IsTemporaryError(err): 57 errMsg := "cannot create AVS evaluation (temporary)" 58 log.Errorf("%s: %s", errMsg, err) 59 retryConfig := evalAssistant.provideRetryConfig() 60 return del.operationManager.RetryOperation(operation, errMsg, err, retryConfig.retryInterval, retryConfig.maxTime, log) 61 default: 62 errMsg := "cannot create AVS evaluation" 63 log.Errorf("%s: %s", errMsg, err) 64 return del.operationManager.OperationFailed(operation, errMsg, err, log) 65 } 66 updatedOperation, d, _ = del.operationManager.UpdateOperation(operation, func(operation *internal.Operation) { 67 evalAssistant.SetEvalId(&operation.Avs, evalResp.Id) 68 evalAssistant.SetDeleted(&operation.Avs, false) 69 }, log) 70 } 71 72 return updatedOperation, d, nil 73 } 74 75 func (del *Delegator) AddTags(log logrus.FieldLogger, operation internal.Operation, evalAssistant EvalAssistant, tags []*Tag) (internal.Operation, time.Duration, error) { 76 log.Infof("starting the AddTag to avs internal id [%d]", operation.Avs.AvsEvaluationInternalId) 77 var updatedOperation internal.Operation 78 d := 0 * time.Second 79 80 log.Infof("making avs calls to add tags to the Evaluation") 81 evalID := evalAssistant.GetEvaluationId(operation.Avs) 82 83 for _, tag := range tags { 84 _, err := del.client.AddTag(evalID, tag) 85 switch { 86 case err == nil: 87 case kebError.IsTemporaryError(err): 88 errMsg := "cannot add tags to AVS evaluation (temporary)" 89 log.Errorf("%s: %s", errMsg, err) 90 retryConfig := evalAssistant.provideRetryConfig() 91 op, duration, err := del.operationManager.RetryOperation(operation, errMsg, err, retryConfig.retryInterval, retryConfig.maxTime, log) 92 return op, duration, err 93 default: 94 errMsg := "cannot add tags to AVS evaluation" 95 log.Errorf("%s: %s", errMsg, err) 96 op, duration, err := del.operationManager.OperationFailed(operation, errMsg, err, log) 97 return op, duration, err 98 } 99 } 100 return updatedOperation, d, nil 101 } 102 103 func (del *Delegator) ResetStatus(log logrus.FieldLogger, lifecycleData *internal.AvsLifecycleData, evalAssistant EvalAssistant) error { 104 status := evalAssistant.GetOriginalEvalStatus(*lifecycleData) 105 // For cases when operation is not loaded (properly) from DB, status fields will be rendered 106 // invalid. This will lead to a failing operation on reset in the following scenario: 107 // 108 // Upgrade operation when loaded (for the first time, on init) was InProgress and was later switched to complete. 109 // When launching post operation logic, SetStatus will be invoked with invalid value, failing the operation. 110 // One of possible hotfixes is to ensure that for invalid status there is a default value (such as Active). 111 if !ValidStatus(status) { 112 log.Errorf("invalid status for ResetStatus: %s", status) 113 status = StatusActive 114 } 115 116 return del.SetStatus(log, lifecycleData, evalAssistant, status) 117 } 118 119 // RefreshStatus ensures that operation AVS lifecycle data is fetched from Avs API 120 func (del *Delegator) RefreshStatus(log logrus.FieldLogger, lifecycleData *internal.AvsLifecycleData, evalAssistant EvalAssistant) string { 121 evalID := evalAssistant.GetEvaluationId(*lifecycleData) 122 currentStatus := evalAssistant.GetEvalStatus(*lifecycleData) 123 124 // obtain status from avs 125 log.Infof("making avs calls to get evaluation data") 126 eval, err := del.client.GetEvaluation(evalID) 127 if err != nil || eval == nil { 128 log.Errorf("cannot obtain evaluation data on RefreshStatus: %s", err) 129 } else { 130 currentStatus = eval.Status 131 } 132 133 evalAssistant.SetEvalStatus(lifecycleData, currentStatus) 134 135 return currentStatus 136 } 137 138 func (del *Delegator) SetStatus(log logrus.FieldLogger, lifecycleData *internal.AvsLifecycleData, evalAssistant EvalAssistant, status string) error { 139 // skip for non-existent or deleted evaluation 140 if !evalAssistant.IsValid(*lifecycleData) { 141 return nil 142 } 143 144 // fail for invalid status request 145 if !ValidStatus(status) { 146 errMsg := fmt.Sprintf("avs SetStatus tried invalid status: %s", status) 147 log.Error(errMsg) 148 return fmt.Errorf(errMsg) 149 } 150 151 evalID := evalAssistant.GetEvaluationId(*lifecycleData) 152 currentStatus := del.RefreshStatus(log, lifecycleData, evalAssistant) 153 154 log.Infof("SetStatus %s to avs id [%d]", status, evalID) 155 156 // do api call iff current and requested status are different 157 if currentStatus != status { 158 log.Infof("making avs calls to set status %s to the evaluation", status) 159 _, err := del.client.SetStatus(evalID, status) 160 161 switch { 162 case err == nil: 163 case kebError.IsTemporaryError(err): 164 errMsg := "cannot set status to AVS evaluation (temporary)" 165 log.Errorf("%s: %s", errMsg, err) 166 return err 167 default: 168 errMsg := "cannot set status to AVS evaluation" 169 log.Errorf("%s: %s", errMsg, err) 170 return err 171 } 172 } 173 // update operation with newly configured status 174 evalAssistant.SetEvalStatus(lifecycleData, status) 175 176 return nil 177 } 178 179 func (del *Delegator) DeleteAvsEvaluation(deProvisioningOperation internal.Operation, logger logrus.FieldLogger, assistant EvalAssistant) (internal.Operation, error) { 180 if assistant.IsAlreadyDeletedOrEmpty(deProvisioningOperation.Avs) { 181 logger.Infof("Evaluations have been deleted previously") 182 return deProvisioningOperation, nil 183 } 184 185 if err := del.tryDeleting(assistant, deProvisioningOperation, logger); err != nil { 186 return deProvisioningOperation, err 187 } 188 189 updatedDeProvisioningOp, _, err := del.operationManager.UpdateOperation(deProvisioningOperation, func(op *internal.Operation) { 190 assistant.SetDeleted(&op.Avs, true) 191 }, logger) 192 if err != nil { 193 return deProvisioningOperation, err 194 } 195 return updatedDeProvisioningOp, nil 196 } 197 198 func (del *Delegator) tryDeleting(assistant EvalAssistant, deProvisioningOperation internal.Operation, logger logrus.FieldLogger) error { 199 evaluationID := assistant.GetEvaluationId(deProvisioningOperation.Avs) 200 parentID := assistant.ProvideParentId(deProvisioningOperation.ProvisioningParameters) 201 err := del.client.RemoveReferenceFromParentEval(parentID, evaluationID) 202 if err != nil { 203 logger.Errorf("error while deleting reference for evaluation %v", err) 204 return err 205 } 206 207 err = del.client.DeleteEvaluation(evaluationID) 208 if err != nil { 209 logger.Errorf("error while deleting evaluation %v", err) 210 } 211 return err 212 }