github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/operation/k8s/k8s_scheduler.go (about)

     1  package k8s
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/kyma-incubator/compass/components/director/pkg/operation"
     8  	"github.com/kyma-incubator/compass/components/director/pkg/str"
     9  	"github.com/kyma-incubator/compass/components/operations-controller/api/v1alpha1"
    10  	v1 "k8s.io/api/core/v1"
    11  	"k8s.io/apimachinery/pkg/api/errors"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  )
    14  
    15  // K8SClient missing godoc
    16  //go:generate mockery --name=K8SClient --output=automock --outpkg=automock --case=underscore --disable-version-string
    17  type K8SClient interface {
    18  	Create(ctx context.Context, operation *v1alpha1.Operation) (*v1alpha1.Operation, error)
    19  	Get(ctx context.Context, name string, options metav1.GetOptions) (*v1alpha1.Operation, error)
    20  	Update(ctx context.Context, operation *v1alpha1.Operation) (*v1alpha1.Operation, error)
    21  }
    22  
    23  // Scheduler missing godoc
    24  type Scheduler struct {
    25  	kcli K8SClient
    26  }
    27  
    28  // NewScheduler missing godoc
    29  func NewScheduler(kcli K8SClient) *Scheduler {
    30  	return &Scheduler{
    31  		kcli: kcli,
    32  	}
    33  }
    34  
    35  // Schedule missing godoc
    36  func (s *Scheduler) Schedule(ctx context.Context, op *operation.Operation) (string, error) {
    37  	operationName := fmt.Sprintf("%s-%s", op.ResourceType, op.ResourceID)
    38  	getOp, err := s.kcli.Get(ctx, operationName, metav1.GetOptions{})
    39  	if err != nil {
    40  		if errors.IsNotFound(err) {
    41  			k8sOp := toK8SOperation(op)
    42  			createdOperation, err := s.kcli.Create(ctx, k8sOp)
    43  			if err != nil {
    44  				return "", err
    45  			}
    46  			return string(createdOperation.UID), nil
    47  		}
    48  		return "", err
    49  	}
    50  	if isOpInProgress(getOp) {
    51  		return "", fmt.Errorf("another operation is in progress for resource with ID %q", op.ResourceID)
    52  	}
    53  	getOp = updateOperationSpec(op, getOp)
    54  	updatedOperation, err := s.kcli.Update(ctx, getOp)
    55  	if err != nil {
    56  		if errors.IsConflict(err) {
    57  			return "", fmt.Errorf("another operation is in progress for resource with ID %q", op.ResourceID)
    58  		}
    59  		return "", err
    60  	}
    61  	return string(updatedOperation.UID), err
    62  }
    63  
    64  func isOpInProgress(op *v1alpha1.Operation) bool {
    65  	for _, cond := range op.Status.Conditions {
    66  		if cond.Status == v1.ConditionTrue {
    67  			return false
    68  		}
    69  	}
    70  	return true
    71  }
    72  
    73  func toK8SOperation(op *operation.Operation) *v1alpha1.Operation {
    74  	operationName := fmt.Sprintf("%s-%s", op.ResourceType, op.ResourceID)
    75  	result := &v1alpha1.Operation{
    76  		ObjectMeta: metav1.ObjectMeta{
    77  			Name: operationName,
    78  		},
    79  	}
    80  	return updateOperationSpec(op, result)
    81  }
    82  
    83  func updateOperationSpec(op *operation.Operation, k8sOp *v1alpha1.Operation) *v1alpha1.Operation {
    84  	k8sOp.Spec = v1alpha1.OperationSpec{
    85  		OperationCategory: op.OperationCategory,
    86  		OperationType:     v1alpha1.OperationType(str.Title(string(op.OperationType))),
    87  		ResourceType:      string(op.ResourceType),
    88  		ResourceID:        op.ResourceID,
    89  		CorrelationID:     op.CorrelationID,
    90  		WebhookIDs:        op.WebhookIDs,
    91  		RequestObject:     op.RequestObject,
    92  	}
    93  	return k8sOp
    94  }