github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/provisioning/apply_kyma_step.go (about) 1 package provisioning 2 3 import ( 4 "bytes" 5 "context" 6 "reflect" 7 "time" 8 9 "github.com/kyma-project/kyma-environment-broker/internal/process/steps" 10 11 "github.com/kyma-project/kyma-environment-broker/internal" 12 "github.com/kyma-project/kyma-environment-broker/internal/process" 13 "github.com/kyma-project/kyma-environment-broker/internal/storage" 14 "github.com/sirupsen/logrus" 15 "k8s.io/apimachinery/pkg/api/errors" 16 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 17 "k8s.io/apimachinery/pkg/runtime" 18 "k8s.io/apimachinery/pkg/runtime/serializer/yaml" 19 yamlutil "k8s.io/apimachinery/pkg/util/yaml" 20 "sigs.k8s.io/controller-runtime/pkg/client" 21 ) 22 23 type ApplyKymaStep struct { 24 operationManager *process.OperationManager 25 k8sClient client.Client 26 } 27 28 var _ process.Step = &ApplyKymaStep{} 29 30 func NewApplyKymaStep(os storage.Operations, cli client.Client) *ApplyKymaStep { 31 return &ApplyKymaStep{operationManager: process.NewOperationManager(os), k8sClient: cli} 32 } 33 34 func (a *ApplyKymaStep) Name() string { 35 return "Apply_Kyma" 36 } 37 38 func (a *ApplyKymaStep) Run(operation internal.Operation, logger logrus.FieldLogger) (internal.Operation, time.Duration, error) { 39 template, err := steps.DecodeKymaTemplate(operation.KymaTemplate) 40 if err != nil { 41 return a.operationManager.OperationFailed(operation, "unable to create a kyma template", err, logger) 42 } 43 a.addLabelsAndName(operation, template) 44 operation, backoff, _ := a.operationManager.UpdateOperation(operation, func(op *internal.Operation) { 45 op.KymaResourceName = template.GetName() 46 }, logger) 47 if backoff != 0 { 48 logger.Errorf("cannot save the operation") 49 return operation, 5 * time.Second, nil 50 } 51 52 var existingKyma unstructured.Unstructured 53 existingKyma.SetGroupVersionKind(template.GroupVersionKind()) 54 err = a.k8sClient.Get(context.Background(), client.ObjectKey{ 55 Namespace: operation.KymaResourceNamespace, 56 Name: template.GetName(), 57 }, &existingKyma) 58 59 switch { 60 case err == nil: 61 logger.Infof("Kyma resource already exists, updating Kyma resource: %s in namespace %s", existingKyma.GetName(), existingKyma.GetNamespace()) 62 changed := a.addLabelsAndName(operation, &existingKyma) 63 if !changed { 64 logger.Infof("Kyma resource does not need any change") 65 } 66 err = a.k8sClient.Update(context.Background(), &existingKyma) 67 if err != nil { 68 logger.Errorf("unable to update a Kyma resource: %s", err.Error()) 69 return a.operationManager.RetryOperation(operation, "unable to update the Kyma resource", err, time.Second, 10*time.Second, logger) 70 } 71 case errors.IsNotFound(err): 72 logger.Infof("creating Kyma resource: %s in namespace: %s", template.GetName(), template.GetNamespace()) 73 err := a.k8sClient.Create(context.Background(), template) 74 if err != nil { 75 logger.Errorf("unable to create a Kyma resource: %s", err.Error()) 76 return a.operationManager.RetryOperation(operation, "unable to create the Kyma resource", err, time.Second, 10*time.Second, logger) 77 } 78 default: 79 logger.Errorf("Unable to get Kyma: %s", err.Error()) 80 return a.operationManager.RetryOperation(operation, "unable to get the Kyma resource", err, time.Second, 10*time.Second, logger) 81 } 82 83 return operation, 0, nil 84 } 85 86 func (a *ApplyKymaStep) addLabelsAndName(operation internal.Operation, obj *unstructured.Unstructured) bool { 87 oldLabels := obj.GetLabels() 88 steps.ApplyLabelsAndAnnotationsForLM(obj, operation) 89 90 // this if-block is a temporary solution, should be removed after the migration of compass registration is completed 91 if operation.IsRegisteredInCompassByProvisioner() { 92 annotations := obj.GetAnnotations() 93 if annotations == nil { 94 annotations = map[string]string{} 95 } 96 annotations["compass-runtime-id-for-migration"] = operation.GetCompassRuntimeId() 97 obj.SetAnnotations(annotations) 98 } 99 100 obj.SetName(steps.KymaName(operation)) 101 return !reflect.DeepEqual(obj.GetLabels(), oldLabels) 102 } 103 104 func (a *ApplyKymaStep) createUnstructuredKyma(operation internal.Operation) (*unstructured.Unstructured, error) { 105 tmpl := a.kymaTemplate(operation) 106 107 decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader(tmpl), 512) 108 var rawObj runtime.RawExtension 109 if err := decoder.Decode(&rawObj); err != nil { 110 return nil, err 111 } 112 obj, _, err := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil) 113 if err != nil { 114 return nil, err 115 } 116 117 unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) 118 unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap} 119 return unstructuredObj, nil 120 } 121 122 func (a *ApplyKymaStep) kymaTemplate(operation internal.Operation) []byte { 123 return []byte(operation.KymaTemplate) 124 }