github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/orchestration/manager/upgrade_cluster.go (about)

     1  package manager
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	internalOrchestration "github.com/kyma-project/kyma-environment-broker/internal/orchestration"
     8  
     9  	"sigs.k8s.io/controller-runtime/pkg/client"
    10  
    11  	"github.com/google/uuid"
    12  	"github.com/kyma-project/kyma-environment-broker/common/orchestration"
    13  
    14  	"github.com/kyma-project/kyma-environment-broker/internal"
    15  	"github.com/kyma-project/kyma-environment-broker/internal/notification"
    16  	"github.com/kyma-project/kyma-environment-broker/internal/process"
    17  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    18  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dbmodel"
    19  	"github.com/pivotal-cf/brokerapi/v8/domain"
    20  	"github.com/sirupsen/logrus"
    21  )
    22  
    23  type upgradeClusterFactory struct {
    24  	operationStorage storage.Operations
    25  }
    26  
    27  func NewUpgradeClusterManager(orchestrationStorage storage.Orchestrations, operationStorage storage.Operations, instanceStorage storage.Instances,
    28  	kymaClusterExecutor orchestration.OperationExecutor, resolver orchestration.RuntimeResolver, pollingInterval time.Duration,
    29  	log logrus.FieldLogger, cli client.Client, cfg internalOrchestration.Config, bundleBuilder notification.BundleBuilder, speedFactor int) process.Executor {
    30  	return &orchestrationManager{
    31  		orchestrationStorage: orchestrationStorage,
    32  		operationStorage:     operationStorage,
    33  		instanceStorage:      instanceStorage,
    34  		resolver:             resolver,
    35  		factory: &upgradeClusterFactory{
    36  			operationStorage: operationStorage,
    37  		},
    38  		executor:          kymaClusterExecutor,
    39  		pollingInterval:   pollingInterval,
    40  		log:               log,
    41  		k8sClient:         cli,
    42  		configNamespace:   cfg.Namespace,
    43  		configName:        cfg.Name,
    44  		kymaVersion:       cfg.KymaVersion,
    45  		kubernetesVersion: cfg.KubernetesVersion,
    46  		bundleBuilder:     bundleBuilder,
    47  		speedFactor:       speedFactor,
    48  	}
    49  }
    50  
    51  func (u *upgradeClusterFactory) NewOperation(o internal.Orchestration, r orchestration.Runtime, i internal.Instance, state domain.LastOperationState) (orchestration.RuntimeOperation, error) {
    52  	id := uuid.New().String()
    53  	r.Region = i.ProviderRegion
    54  	op := internal.UpgradeClusterOperation{
    55  		Operation: internal.Operation{
    56  			ID:                     id,
    57  			Version:                0,
    58  			CreatedAt:              time.Now(),
    59  			UpdatedAt:              time.Now(),
    60  			Type:                   internal.OperationTypeUpgradeCluster,
    61  			InstanceID:             r.InstanceID,
    62  			State:                  state,
    63  			Description:            "Operation created",
    64  			OrchestrationID:        o.OrchestrationID,
    65  			ProvisioningParameters: i.Parameters,
    66  			InstanceDetails:        i.InstanceDetails,
    67  			RuntimeOperation: orchestration.RuntimeOperation{
    68  				ID:           id,
    69  				Runtime:      r,
    70  				DryRun:       o.Parameters.DryRun,
    71  				Notification: o.Parameters.Notification,
    72  			},
    73  		},
    74  	}
    75  
    76  	err := u.operationStorage.InsertUpgradeClusterOperation(op)
    77  	return op.RuntimeOperation, err
    78  }
    79  
    80  func (u *upgradeClusterFactory) ResumeOperations(orchestrationID string) ([]orchestration.RuntimeOperation, error) {
    81  	ops, _, _, err := u.operationStorage.ListUpgradeClusterOperationsByOrchestrationID(orchestrationID, dbmodel.OperationFilter{States: []string{orchestration.InProgress, orchestration.Retrying, orchestration.Pending}})
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	pending := make([]orchestration.RuntimeOperation, 0)
    87  	retrying := make([]orchestration.RuntimeOperation, 0)
    88  	inProgress := make([]orchestration.RuntimeOperation, 0)
    89  	for _, op := range ops {
    90  		if op.State == orchestration.Pending {
    91  			pending = append(pending, op.RuntimeOperation)
    92  		}
    93  		if op.State == orchestration.Retrying {
    94  			runtimeop, err := u.updateRetryingOperation(op)
    95  			if err != nil {
    96  				return nil, err
    97  			}
    98  			retrying = append(retrying, runtimeop)
    99  		}
   100  		if op.State == orchestration.InProgress {
   101  			inProgress = append(inProgress, op.RuntimeOperation)
   102  		}
   103  	}
   104  
   105  	return append(inProgress, append(retrying, pending...)...), nil
   106  }
   107  
   108  func (u *upgradeClusterFactory) CancelOperation(orchestrationID string, runtimeID string) error {
   109  	ops, _, _, err := u.operationStorage.ListUpgradeClusterOperationsByOrchestrationID(orchestrationID, dbmodel.OperationFilter{States: []string{orchestration.Pending}})
   110  	if err != nil {
   111  		return fmt.Errorf("while listing upgrade cluster operations: %w", err)
   112  	}
   113  	for _, op := range ops {
   114  		if op.InstanceDetails.RuntimeID == runtimeID {
   115  			op.State = orchestration.Canceled
   116  			op.Description = "Operation was canceled"
   117  			_, err := u.operationStorage.UpdateUpgradeClusterOperation(op)
   118  			if err != nil {
   119  				return fmt.Errorf("while updating upgrade cluster operation: %w", err)
   120  			}
   121  		}
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func (u *upgradeClusterFactory) CancelOperations(orchestrationID string) error {
   128  	ops, _, _, err := u.operationStorage.ListUpgradeClusterOperationsByOrchestrationID(orchestrationID, dbmodel.OperationFilter{States: []string{orchestration.Pending}})
   129  	if err != nil {
   130  		return fmt.Errorf("while listing upgrade cluster operations: %w", err)
   131  	}
   132  	for _, op := range ops {
   133  		op.State = orchestration.Canceled
   134  		op.Description = "Operation was canceled"
   135  		_, err := u.operationStorage.UpdateUpgradeClusterOperation(op)
   136  		if err != nil {
   137  			return fmt.Errorf("while updating upgrade cluster operation: %w", err)
   138  		}
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  // get current retrying operations
   145  func (u *upgradeClusterFactory) RetryOperations(retryOps []string) ([]orchestration.RuntimeOperation, error) {
   146  
   147  	result := []orchestration.RuntimeOperation{}
   148  	for _, opId := range retryOps {
   149  		runtimeop, err := u.operationStorage.GetUpgradeClusterOperationByID(opId)
   150  		if err != nil {
   151  			return nil, fmt.Errorf("while geting (retrying) upgrade cluster operation %s in storage: %w", opId, err)
   152  
   153  		}
   154  		result = append(result, runtimeop.RuntimeOperation)
   155  	}
   156  
   157  	return result, nil
   158  }
   159  
   160  // update storage in corresponding upgrade factory to avoid too many storage read and write
   161  func (u *upgradeClusterFactory) updateRetryingOperation(op internal.UpgradeClusterOperation) (orchestration.RuntimeOperation, error) {
   162  	op.UpdatedAt = time.Now()
   163  	op.State = orchestration.Pending
   164  	op.Description = "Operation retry triggered"
   165  	op.ProvisionerOperationID = ""
   166  
   167  	opUpdated, err := u.operationStorage.UpdateUpgradeClusterOperation(op)
   168  	if err != nil {
   169  		return orchestration.RuntimeOperation{}, fmt.Errorf("while updating (retrying) upgrade cluster operation %s in storage: %w", op.Operation.ID, err)
   170  	}
   171  
   172  	return opUpdated.RuntimeOperation, nil
   173  }
   174  
   175  func (u *upgradeClusterFactory) QueryOperation(orchestrationID string, r orchestration.Runtime) (bool, orchestration.RuntimeOperation, error) {
   176  	ops, _, _, err := u.operationStorage.ListUpgradeClusterOperationsByOrchestrationID(orchestrationID, dbmodel.OperationFilter{States: []string{orchestration.Pending}})
   177  	if err != nil {
   178  		return false, orchestration.RuntimeOperation{}, fmt.Errorf("while listing upgrade cluster operations: %w", err)
   179  	}
   180  	for _, op := range ops {
   181  		if op.InstanceDetails.RuntimeID == r.RuntimeID {
   182  			return true, op.RuntimeOperation, nil
   183  		}
   184  	}
   185  
   186  	return false, orchestration.RuntimeOperation{}, nil
   187  }
   188  
   189  func (u *upgradeClusterFactory) QueryOperations(orchestrationID string) ([]orchestration.RuntimeOperation, error) {
   190  	ops, _, _, err := u.operationStorage.ListUpgradeClusterOperationsByOrchestrationID(orchestrationID, dbmodel.OperationFilter{States: []string{orchestration.Pending}})
   191  	if err != nil {
   192  		return []orchestration.RuntimeOperation{}, fmt.Errorf("while listing upgrade cluster operations: %w", err)
   193  	}
   194  	result := []orchestration.RuntimeOperation{}
   195  	for _, op := range ops {
   196  		result = append(result, op.RuntimeOperation)
   197  	}
   198  
   199  	return result, nil
   200  }
   201  
   202  func (u *upgradeClusterFactory) NotifyOperation(orchestrationID string, runtimeID string, oState string, notifyState orchestration.NotificationStateType) error {
   203  	ops, _, _, err := u.operationStorage.ListUpgradeClusterOperationsByOrchestrationID(orchestrationID, dbmodel.OperationFilter{States: []string{oState}})
   204  	if err != nil {
   205  		return fmt.Errorf("while listing upgrade cluster operations: %w", err)
   206  	}
   207  	for _, op := range ops {
   208  		if op.InstanceDetails.RuntimeID == runtimeID {
   209  			op.RuntimeOperation.NotificationState = notifyState
   210  			_, err := u.operationStorage.UpdateUpgradeClusterOperation(op)
   211  			if err != nil {
   212  				return fmt.Errorf("while updating pending upgrade cluster operation %s in storage: %w", op.Operation.ID, err)
   213  			}
   214  		}
   215  	}
   216  	return nil
   217  }