github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/deprovisioning/manager.go (about) 1 package deprovisioning 2 3 import ( 4 "context" 5 "sort" 6 "time" 7 8 "github.com/kyma-project/kyma-environment-broker/common/orchestration" 9 10 "github.com/kyma-project/kyma-environment-broker/internal" 11 kebError "github.com/kyma-project/kyma-environment-broker/internal/error" 12 "github.com/kyma-project/kyma-environment-broker/internal/event" 13 "github.com/kyma-project/kyma-environment-broker/internal/process" 14 "github.com/kyma-project/kyma-environment-broker/internal/storage" 15 "github.com/kyma-project/kyma-environment-broker/internal/storage/dberr" 16 "github.com/pivotal-cf/brokerapi/v8/domain" 17 "github.com/sirupsen/logrus" 18 ) 19 20 const ( 21 retryAfterTime = 1 * time.Minute 22 ) 23 24 type Step interface { 25 Name() string 26 Run(operation internal.DeprovisioningOperation, logger logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) 27 } 28 29 type Manager struct { 30 log logrus.FieldLogger 31 steps map[int][]Step 32 operationStorage storage.Operations 33 operationManager *process.DeprovisionOperationManager 34 35 publisher event.Publisher 36 } 37 38 func NewManager(storage storage.Operations, pub event.Publisher, logger logrus.FieldLogger) *Manager { 39 return &Manager{ 40 log: logger, 41 operationStorage: storage, 42 steps: make(map[int][]Step, 0), 43 publisher: pub, 44 operationManager: process.NewDeprovisionOperationManager(storage), 45 } 46 } 47 48 func (m *Manager) InitStep(step Step) { 49 m.AddStep(0, step) 50 } 51 52 func (m *Manager) AddStep(weight int, step Step) { 53 if weight <= 0 { 54 weight = 1 55 } 56 m.steps[weight] = append(m.steps[weight], step) 57 } 58 59 func (m *Manager) runStep(step Step, operation internal.DeprovisioningOperation, logger logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 60 start := time.Now() 61 processedOperation, when, err := step.Run(operation, logger) 62 if err != nil { 63 processedOperation.LastError = kebError.ReasonForError(err) 64 log := logger.WithFields(logrus.Fields{"error_component": processedOperation.LastError.Component(), "error_reason": processedOperation.LastError.Reason()}) 65 log.Errorf("Last error: %s", processedOperation.LastError.Error()) 66 // no saving to storage for deprovisioning 67 } 68 69 m.publisher.Publish(context.TODO(), process.DeprovisioningStepProcessed{ 70 StepProcessed: process.StepProcessed{ 71 StepName: step.Name(), 72 Duration: time.Since(start), 73 When: when, 74 Error: err, 75 }, 76 OldOperation: operation, 77 Operation: processedOperation, 78 }) 79 return processedOperation, when, err 80 } 81 82 func (m *Manager) Execute(operationID string) (time.Duration, error) { 83 op, err := m.operationStorage.GetDeprovisioningOperationByID(operationID) 84 if err != nil { 85 m.log.Errorf("Cannot fetch DeprovisioningOperation from storage: %s", err) 86 return retryAfterTime, nil 87 } 88 operation := *op 89 90 logOperation := m.log.WithFields(logrus.Fields{"operation": operationID, "instanceID": operation.InstanceID}) 91 92 provisioningOp, err := m.operationStorage.GetProvisioningOperationByInstanceID(op.InstanceID) 93 if err != nil { 94 m.log.Errorf("Cannot fetch ProvisioningOperation for instanceID %s from storage: %s", op.InstanceID, err) 95 96 operation.LastError = kebError.ReasonForError(err) 97 log := logOperation.WithFields(logrus.Fields{"error_component": operation.LastError.Component(), "error_reason": operation.LastError.Reason()}) 98 log.Errorf("Last error: %s", operation.LastError.Error()) 99 m.publisher.Publish(context.TODO(), process.DeprovisioningStepProcessed{ 100 StepProcessed: process.StepProcessed{ 101 Error: err, 102 }, 103 Operation: operation, 104 }) 105 106 if dberr.IsNotFound(err) { 107 _, duration, err := m.operationManager.OperationFailed(operation, "Error retrieving provisioning operation - operation not found", err, log) 108 return duration, err 109 } 110 111 return retryAfterTime, nil 112 } 113 114 logOperation = logOperation.WithField("planID", provisioningOp.ProvisioningParameters.PlanID) 115 116 var when time.Duration 117 logOperation.Info("Start process operation steps") 118 119 for _, weightStep := range m.sortWeight() { 120 steps := m.steps[weightStep] 121 for _, step := range steps { 122 logStep := logOperation.WithField("step", step.Name()) 123 logStep.Infof("Start step") 124 125 operation, when, err = m.runStep(step, operation, logStep) 126 if err != nil { 127 logStep.Errorf("Process operation failed: %s", err) 128 return 0, err 129 } 130 if operation.State != domain.InProgress && operation.State != orchestration.Pending { 131 if operation.RuntimeID == "" && operation.State == domain.Succeeded { 132 logStep.Infof("Operation %q has no runtime ID. Process finished.", operation.ID) 133 return when, nil 134 } 135 logStep.Infof("Operation %q got status %s. Process finished.", operation.ID, operation.State) 136 return 0, nil 137 } 138 if when == 0 { 139 logStep.Info("Process operation successful") 140 continue 141 } 142 143 logStep.Infof("Process operation will be repeated in %s ...", when) 144 return when, nil 145 } 146 } 147 148 logOperation.Infof("Operation %q got status %s. All steps finished.", operation.ID, operation.State) 149 return 0, nil 150 } 151 152 func (m *Manager) sortWeight() []int { 153 var weight []int 154 for w := range m.steps { 155 weight = append(weight, w) 156 } 157 sort.Ints(weight) 158 159 return weight 160 }