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  }