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

     1  package internal
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/kyma-project/kyma-environment-broker/internal/euaccess"
    11  
    12  	"sigs.k8s.io/controller-runtime/pkg/client"
    13  
    14  	"github.com/google/uuid"
    15  	reconcilerApi "github.com/kyma-incubator/reconciler/pkg/keb"
    16  	"github.com/kyma-project/control-plane/components/provisioner/pkg/gqlschema"
    17  	"github.com/kyma-project/kyma-environment-broker/common/gardener"
    18  	"github.com/kyma-project/kyma-environment-broker/common/orchestration"
    19  	kebError "github.com/kyma-project/kyma-environment-broker/internal/error"
    20  	"github.com/kyma-project/kyma-environment-broker/internal/events"
    21  	"github.com/kyma-project/kyma-environment-broker/internal/ptr"
    22  	"github.com/pivotal-cf/brokerapi/v8/domain"
    23  	log "github.com/sirupsen/logrus"
    24  )
    25  
    26  type ProvisionerInputCreator interface {
    27  	SetProvisioningParameters(params ProvisioningParameters) ProvisionerInputCreator
    28  	SetShootName(string) ProvisionerInputCreator
    29  	SetLabel(key, value string) ProvisionerInputCreator
    30  	// Deprecated, use: AppendOverrides
    31  	SetOverrides(component string, overrides []*gqlschema.ConfigEntryInput) ProvisionerInputCreator
    32  	AppendOverrides(component string, overrides []*gqlschema.ConfigEntryInput) ProvisionerInputCreator
    33  	AppendGlobalOverrides(overrides []*gqlschema.ConfigEntryInput) ProvisionerInputCreator
    34  	CreateProvisionRuntimeInput() (gqlschema.ProvisionRuntimeInput, error)
    35  	CreateUpgradeRuntimeInput() (gqlschema.UpgradeRuntimeInput, error)
    36  	CreateUpgradeShootInput() (gqlschema.UpgradeShootInput, error)
    37  	EnableOptionalComponent(componentName string) ProvisionerInputCreator
    38  	DisableOptionalComponent(componentName string) ProvisionerInputCreator
    39  	Provider() CloudProvider
    40  	Configuration() *ConfigForPlan
    41  
    42  	CreateClusterConfiguration() (reconcilerApi.Cluster, error)
    43  	CreateProvisionClusterInput() (gqlschema.ProvisionRuntimeInput, error)
    44  	SetKubeconfig(kcfg string) ProvisionerInputCreator
    45  	SetRuntimeID(runtimeID string) ProvisionerInputCreator
    46  	SetInstanceID(instanceID string) ProvisionerInputCreator
    47  	SetShootDomain(shootDomain string) ProvisionerInputCreator
    48  	SetShootDNSProviders(dnsProviders gardener.DNSProvidersData) ProvisionerInputCreator
    49  	SetClusterName(name string) ProvisionerInputCreator
    50  	SetOIDCLastValues(oidcConfig gqlschema.OIDCConfigInput) ProvisionerInputCreator
    51  }
    52  
    53  // GitKymaProject and GitKymaRepo define public Kyma GitHub parameters used for
    54  // external evaluation.
    55  const (
    56  	GitKymaProject = "kyma-project"
    57  	GitKymaRepo    = "kyma"
    58  )
    59  
    60  type AvsEvaluationStatus struct {
    61  	Current  string `json:"current_value"`
    62  	Original string `json:"original_value"`
    63  }
    64  
    65  type AvsLifecycleData struct {
    66  	AvsEvaluationInternalId int64 `json:"avs_evaluation_internal_id"`
    67  	AVSEvaluationExternalId int64 `json:"avs_evaluation_external_id"`
    68  
    69  	AvsInternalEvaluationStatus AvsEvaluationStatus `json:"avs_internal_evaluation_status"`
    70  	AvsExternalEvaluationStatus AvsEvaluationStatus `json:"avs_external_evaluation_status"`
    71  
    72  	AVSInternalEvaluationDeleted bool `json:"avs_internal_evaluation_deleted"`
    73  	AVSExternalEvaluationDeleted bool `json:"avs_external_evaluation_deleted"`
    74  }
    75  
    76  // RuntimeVersionOrigin defines the possible sources of the Kyma Version parameter
    77  type RuntimeVersionOrigin string
    78  
    79  const (
    80  	Parameters     RuntimeVersionOrigin = "parameters"
    81  	Defaults       RuntimeVersionOrigin = "defaults"
    82  	AccountMapping RuntimeVersionOrigin = "account-mapping"
    83  )
    84  
    85  // RuntimeVersionData describes the Kyma Version used for the cluster
    86  // provisioning or upgrade
    87  type RuntimeVersionData struct {
    88  	Version      string               `json:"version"`
    89  	Origin       RuntimeVersionOrigin `json:"origin"`
    90  	MajorVersion int                  `json:"major_version"`
    91  }
    92  
    93  func (rv RuntimeVersionData) IsEmpty() bool {
    94  	return rv.Version == ""
    95  }
    96  
    97  func NewEmptyRuntimeVersion() *RuntimeVersionData {
    98  	return &RuntimeVersionData{Version: "not-defined", Origin: Defaults, MajorVersion: 2}
    99  }
   100  
   101  func NewRuntimeVersionFromParameters(version string, majorVersion int) *RuntimeVersionData {
   102  	return &RuntimeVersionData{Version: version, Origin: Parameters, MajorVersion: majorVersion}
   103  }
   104  
   105  func NewRuntimeVersionFromDefaults(version string) *RuntimeVersionData {
   106  	defaultMajorVerNum := DetermineMajorVersion(version)
   107  	return &RuntimeVersionData{Version: version, Origin: Defaults, MajorVersion: defaultMajorVerNum}
   108  }
   109  
   110  func DetermineMajorVersion(version string) int {
   111  	splitVer := strings.Split(version, ".")
   112  	majorVerNum, _ := strconv.Atoi(splitVer[0])
   113  	return majorVerNum
   114  }
   115  
   116  func NewRuntimeVersionFromAccountMapping(version string, majorVersion int) *RuntimeVersionData {
   117  	return &RuntimeVersionData{Version: version, Origin: AccountMapping, MajorVersion: majorVersion}
   118  }
   119  
   120  type EventHub struct {
   121  	Deleted bool `json:"event_hub_deleted"`
   122  }
   123  
   124  type Instance struct {
   125  	InstanceID                  string
   126  	RuntimeID                   string
   127  	GlobalAccountID             string
   128  	SubscriptionGlobalAccountID string
   129  	SubAccountID                string
   130  	ServiceID                   string
   131  	ServiceName                 string
   132  	ServicePlanID               string
   133  	ServicePlanName             string
   134  
   135  	DashboardURL   string
   136  	Parameters     ProvisioningParameters
   137  	ProviderRegion string
   138  
   139  	InstanceDetails InstanceDetails
   140  
   141  	CreatedAt time.Time
   142  	UpdatedAt time.Time
   143  	DeletedAt time.Time
   144  	ExpiredAt *time.Time
   145  
   146  	Version      int
   147  	Provider     CloudProvider
   148  	Reconcilable bool
   149  }
   150  
   151  func (i *Instance) IsExpired() bool {
   152  	return i.ExpiredAt != nil
   153  }
   154  
   155  func (i *Instance) GetSubscriptionGlobalAccoundID() string {
   156  	if i.SubscriptionGlobalAccountID != "" {
   157  		return i.SubscriptionGlobalAccountID
   158  	} else {
   159  		return i.GlobalAccountID
   160  	}
   161  }
   162  
   163  func (i *Instance) GetInstanceDetails() (InstanceDetails, error) {
   164  	result := i.InstanceDetails
   165  	//overwrite RuntimeID in InstanceDetails with Instance.RuntimeID
   166  	//needed for runtimes suspended without clearing RuntimeID in deprovisioning operation
   167  	result.RuntimeID = i.RuntimeID
   168  	return result, nil
   169  }
   170  
   171  // OperationType defines the possible types of an asynchronous operation to a broker.
   172  type OperationType string
   173  
   174  const (
   175  	// OperationTypeProvision means provisioning OperationType
   176  	OperationTypeProvision OperationType = "provision"
   177  	// OperationTypeDeprovision means deprovision OperationType
   178  	OperationTypeDeprovision OperationType = "deprovision"
   179  	// OperationTypeUndefined means undefined OperationType
   180  	OperationTypeUndefined OperationType = ""
   181  	// OperationTypeUpgradeKyma means upgrade Kyma OperationType
   182  	OperationTypeUpgradeKyma OperationType = "upgradeKyma"
   183  	// OperationTypeUpdate means update
   184  	OperationTypeUpdate OperationType = "update"
   185  	// OperationTypeUpgradeCluster means upgrade cluster (shoot) OperationType
   186  	OperationTypeUpgradeCluster OperationType = "upgradeCluster"
   187  )
   188  
   189  type Operation struct {
   190  	// following fields are serialized to JSON and stored in the storage
   191  	InstanceDetails
   192  
   193  	ID        string        `json:"-"`
   194  	Version   int           `json:"-"`
   195  	CreatedAt time.Time     `json:"-"`
   196  	UpdatedAt time.Time     `json:"-"`
   197  	Type      OperationType `json:"-"`
   198  
   199  	InstanceID             string                    `json:"-"`
   200  	ProvisionerOperationID string                    `json:"-"`
   201  	State                  domain.LastOperationState `json:"-"`
   202  	Description            string                    `json:"-"`
   203  	ProvisioningParameters ProvisioningParameters    `json:"-"`
   204  
   205  	InputCreator ProvisionerInputCreator `json:"-"`
   206  
   207  	// OrchestrationID specifies the origin orchestration which triggers the operation, empty for OSB operations (provisioning/deprovisioning)
   208  	OrchestrationID string             `json:"-"`
   209  	FinishedStages  []string           `json:"-"`
   210  	LastError       kebError.LastError `json:"-"`
   211  
   212  	// PROVISIONING
   213  	RuntimeVersion RuntimeVersionData `json:"runtime_version"`
   214  	DashboardURL   string             `json:"dashboardURL"`
   215  
   216  	// DEPROVISIONING
   217  	// Temporary indicates that this deprovisioning operation must not remove the instance
   218  	Temporary                   bool      `json:"temporary"`
   219  	ClusterConfigurationDeleted bool      `json:"clusterConfigurationDeleted"`
   220  	Retries                     int       `json:"-"`
   221  	ReconcilerDeregistrationAt  time.Time `json:"reconcilerDeregistrationAt"`
   222  	ExcutedButNotCompleted      []string  `json:"excutedButNotCompleted"`
   223  	UserAgent                   string    `json:"userAgent,omitempty"`
   224  
   225  	// UPDATING
   226  	UpdatingParameters    UpdatingParametersDTO `json:"updating_parameters"`
   227  	CheckReconcilerStatus bool                  `json:"check_reconciler_status"`
   228  	K8sClient             client.Client         `json:"-"`
   229  
   230  	// following fields are not stored in the storage
   231  
   232  	// Last runtime state payload
   233  	LastRuntimeState RuntimeState `json:"-"`
   234  
   235  	// Flag used by the steps regarding BTP-Operator credentials update
   236  	// denotes whether the payload to reconciler differs from last runtime state
   237  	RequiresReconcilerUpdate bool `json:"-"`
   238  
   239  	// UPGRADE KYMA
   240  	orchestration.RuntimeOperation `json:"runtime_operation"`
   241  	ClusterConfigurationApplied    bool `json:"cluster_configuration_applied"`
   242  
   243  	// KymaTemplate is read from the configuration then used in the apply_kyma step
   244  	KymaTemplate string `json:"KymaTemplate"`
   245  }
   246  
   247  func (o *Operation) IsFinished() bool {
   248  	return o.State != orchestration.InProgress && o.State != orchestration.Pending && o.State != orchestration.Canceling && o.State != orchestration.Retrying
   249  }
   250  
   251  func (o *Operation) EventInfof(fmt string, args ...any) {
   252  	events.Infof(o.InstanceID, o.ID, fmt, args...)
   253  }
   254  
   255  func (o *Operation) EventErrorf(err error, fmt string, args ...any) {
   256  	events.Errorf(o.InstanceID, o.ID, err, fmt, args...)
   257  }
   258  
   259  // Orchestration holds all information about an orchestration.
   260  // Orchestration performs operations of a specific type (UpgradeKymaOperation, UpgradeClusterOperation)
   261  // on specific targets of SKRs.
   262  type Orchestration struct {
   263  	OrchestrationID string
   264  	Type            orchestration.Type
   265  	State           string
   266  	Description     string
   267  	CreatedAt       time.Time
   268  	UpdatedAt       time.Time
   269  	Parameters      orchestration.Parameters
   270  }
   271  
   272  func (o *Orchestration) IsFinished() bool {
   273  	return o.State == orchestration.Succeeded || o.State == orchestration.Failed || o.State == orchestration.Canceled
   274  }
   275  
   276  // IsCanceled returns true if orchestration's cancellation endpoint was ever triggered
   277  func (o *Orchestration) IsCanceled() bool {
   278  	return o.State == orchestration.Canceling || o.State == orchestration.Canceled
   279  }
   280  
   281  type InstanceWithOperation struct {
   282  	Instance
   283  
   284  	Type           sql.NullString
   285  	State          sql.NullString
   286  	Description    sql.NullString
   287  	OpCreatedAt    time.Time
   288  	IsSuspensionOp bool
   289  }
   290  
   291  type InstanceDetails struct {
   292  	Avs      AvsLifecycleData `json:"avs"`
   293  	EventHub EventHub         `json:"eh"`
   294  
   295  	SubAccountID      string                    `json:"sub_account_id"`
   296  	RuntimeID         string                    `json:"runtime_id"`
   297  	ShootName         string                    `json:"shoot_name"`
   298  	ShootDomain       string                    `json:"shoot_domain"`
   299  	ClusterName       string                    `json:"clusterName"`
   300  	ShootDNSProviders gardener.DNSProvidersData `json:"shoot_dns_providers"`
   301  	Monitoring        MonitoringData            `json:"monitoring"`
   302  	EDPCreated        bool                      `json:"edp_created"`
   303  
   304  	ClusterConfigurationVersion int64  `json:"cluster_configuration_version"`
   305  	Kubeconfig                  string `json:"-"`
   306  
   307  	ServiceManagerClusterID string `json:"sm_cluster_id"`
   308  
   309  	KymaResourceNamespace string `json:"kyma_resource_namespace"`
   310  	KymaResourceName      string `json:"kyma_resource_name"`
   311  
   312  	EuAccess bool `json:"eu_access"`
   313  
   314  	// CompassRuntimeId - a runtime ID created by the Compass. Existing instances has a nil value (because the field was not existing) - it means the compass runtime Id is equal to runtime ID.
   315  	// If the value is an empty string - it means the runtime was not registered by Provisioner in the Compass.
   316  	// Should be removed after the migration of compass registration is completed
   317  	CompassRuntimeId *string
   318  }
   319  
   320  // IsRegisteredInCompassByProvisioner returns true, if the runtime was registered in Compass by Provisioner
   321  func (i *InstanceDetails) IsRegisteredInCompassByProvisioner() bool {
   322  	return i.CompassRuntimeId == nil || *i.CompassRuntimeId != ""
   323  }
   324  
   325  func (i *InstanceDetails) SetCompassRuntimeIdNotRegisteredByProvisioner() {
   326  	i.CompassRuntimeId = ptr.String("")
   327  }
   328  
   329  // GetCompassRuntimeId provides a compass runtime Id registered by Provisioner or empty string if it was not provisioned by Provisioner.
   330  func (i *InstanceDetails) GetCompassRuntimeId() string {
   331  	// for backward compatibility, if CompassRuntimeID field was not set, use RuntimeId
   332  	if i.CompassRuntimeId == nil {
   333  		return i.RuntimeID
   334  	}
   335  	return *i.CompassRuntimeId
   336  }
   337  
   338  // ProvisioningOperation holds all information about provisioning operation
   339  type ProvisioningOperation struct {
   340  	Operation
   341  }
   342  
   343  type MonitoringData struct {
   344  	Username string `json:"username"`
   345  	Password string `json:"password"`
   346  }
   347  
   348  // DeprovisioningOperation holds all information about de-provisioning operation
   349  type DeprovisioningOperation struct {
   350  	Operation
   351  }
   352  
   353  func (op *Operation) TimeSinceReconcilerDeregistrationTriggered() time.Duration {
   354  	if op.ReconcilerDeregistrationAt.IsZero() {
   355  		return 0
   356  	}
   357  	return time.Since(op.ReconcilerDeregistrationAt)
   358  }
   359  
   360  type UpdatingOperation struct {
   361  	Operation
   362  }
   363  
   364  // UpgradeKymaOperation holds all information about upgrade Kyma operation
   365  type UpgradeKymaOperation struct {
   366  	Operation
   367  }
   368  
   369  // UpgradeClusterOperation holds all information about upgrade cluster (shoot) operation
   370  type UpgradeClusterOperation struct {
   371  	Operation
   372  }
   373  
   374  func NewRuntimeState(runtimeID, operationID string, kymaConfig *gqlschema.KymaConfigInput, clusterConfig *gqlschema.GardenerConfigInput) RuntimeState {
   375  	var (
   376  		kymaConfigInput    gqlschema.KymaConfigInput
   377  		clusterConfigInput gqlschema.GardenerConfigInput
   378  	)
   379  	if kymaConfig != nil {
   380  		kymaConfigInput = *kymaConfig
   381  	}
   382  	if clusterConfig != nil {
   383  		clusterConfigInput = *clusterConfig
   384  	}
   385  
   386  	return RuntimeState{
   387  		ID:            uuid.New().String(),
   388  		CreatedAt:     time.Now(),
   389  		RuntimeID:     runtimeID,
   390  		OperationID:   operationID,
   391  		KymaConfig:    kymaConfigInput,
   392  		ClusterConfig: clusterConfigInput,
   393  	}
   394  }
   395  
   396  func NewRuntimeStateWithReconcilerInput(runtimeID, operationID string, reconcilerInput *reconcilerApi.Cluster) RuntimeState {
   397  	return RuntimeState{
   398  		ID:           uuid.New().String(),
   399  		CreatedAt:    time.Now(),
   400  		RuntimeID:    runtimeID,
   401  		OperationID:  operationID,
   402  		ClusterSetup: reconcilerInput,
   403  	}
   404  }
   405  
   406  type RuntimeState struct {
   407  	ID string `json:"id"`
   408  
   409  	CreatedAt time.Time `json:"created_at"`
   410  
   411  	RuntimeID   string `json:"runtimeId"`
   412  	OperationID string `json:"operationId"`
   413  
   414  	KymaConfig    gqlschema.KymaConfigInput     `json:"kymaConfig"`
   415  	ClusterConfig gqlschema.GardenerConfigInput `json:"clusterConfig"`
   416  	ClusterSetup  *reconcilerApi.Cluster        `json:"clusterSetup,omitempty"`
   417  
   418  	KymaVersion string `json:"kyma_version"`
   419  }
   420  
   421  func (r *RuntimeState) GetKymaConfig() gqlschema.KymaConfigInput {
   422  	if r.ClusterSetup != nil {
   423  		return r.buildKymaConfigFromClusterSetup()
   424  	}
   425  	return r.KymaConfig
   426  }
   427  
   428  func (r *RuntimeState) GetKymaVersion() string {
   429  	if r.KymaVersion != "" {
   430  		return r.KymaVersion
   431  	}
   432  	if r.ClusterSetup != nil {
   433  		return r.ClusterSetup.KymaConfig.Version
   434  	}
   435  	return r.KymaConfig.Version
   436  }
   437  
   438  func (r *RuntimeState) buildKymaConfigFromClusterSetup() gqlschema.KymaConfigInput {
   439  	var components []*gqlschema.ComponentConfigurationInput
   440  	for _, cmp := range r.ClusterSetup.KymaConfig.Components {
   441  		var config []*gqlschema.ConfigEntryInput
   442  		for _, cfg := range cmp.Configuration {
   443  			configEntryInput := &gqlschema.ConfigEntryInput{
   444  				Key:    cfg.Key,
   445  				Value:  fmt.Sprint(cfg.Value),
   446  				Secret: ptr.Bool(cfg.Secret),
   447  			}
   448  			config = append(config, configEntryInput)
   449  		}
   450  
   451  		componentConfigurationInput := &gqlschema.ComponentConfigurationInput{
   452  			Component:     cmp.Component,
   453  			Namespace:     cmp.Namespace,
   454  			SourceURL:     &cmp.URL,
   455  			Configuration: config,
   456  		}
   457  		components = append(components, componentConfigurationInput)
   458  	}
   459  
   460  	profile := gqlschema.KymaProfile(r.ClusterSetup.KymaConfig.Profile)
   461  	kymaConfig := gqlschema.KymaConfigInput{
   462  		Version:    r.ClusterSetup.KymaConfig.Version,
   463  		Profile:    &profile,
   464  		Components: components,
   465  	}
   466  
   467  	return kymaConfig
   468  }
   469  
   470  // OperationStats provide number of operations per type and state
   471  type OperationStats struct {
   472  	Provisioning   map[domain.LastOperationState]int
   473  	Deprovisioning map[domain.LastOperationState]int
   474  }
   475  
   476  // InstanceStats provide number of instances per Global Account ID
   477  type InstanceStats struct {
   478  	TotalNumberOfInstances int
   479  	PerGlobalAccountID     map[string]int
   480  }
   481  
   482  // ERSContextStats provides aggregated information regarding ERSContext
   483  type ERSContextStats struct {
   484  	LicenseType map[string]int
   485  }
   486  
   487  // NewProvisioningOperation creates a fresh (just starting) instance of the ProvisioningOperation
   488  func NewProvisioningOperation(instanceID string, parameters ProvisioningParameters) (ProvisioningOperation, error) {
   489  	return NewProvisioningOperationWithID(uuid.New().String(), instanceID, parameters)
   490  }
   491  
   492  // NewProvisioningOperationWithID creates a fresh (just starting) instance of the ProvisioningOperation with provided ID
   493  func NewProvisioningOperationWithID(operationID, instanceID string, parameters ProvisioningParameters) (ProvisioningOperation, error) {
   494  	return ProvisioningOperation{
   495  		Operation: Operation{
   496  			ID:                     operationID,
   497  			Version:                0,
   498  			Description:            "Operation created",
   499  			InstanceID:             instanceID,
   500  			State:                  domain.InProgress,
   501  			CreatedAt:              time.Now(),
   502  			UpdatedAt:              time.Now(),
   503  			Type:                   OperationTypeProvision,
   504  			ProvisioningParameters: parameters,
   505  			RuntimeOperation: orchestration.RuntimeOperation{
   506  				Runtime: orchestration.Runtime{
   507  					GlobalAccountID: parameters.ErsContext.GlobalAccountID,
   508  				},
   509  			},
   510  			InstanceDetails: InstanceDetails{
   511  				SubAccountID: parameters.ErsContext.SubAccountID,
   512  				Kubeconfig:   parameters.Parameters.Kubeconfig,
   513  				EuAccess:     euaccess.IsEURestrictedAccess(parameters.PlatformRegion),
   514  			},
   515  			FinishedStages: make([]string, 0),
   516  			LastError:      kebError.LastError{},
   517  		},
   518  	}, nil
   519  }
   520  
   521  // NewDeprovisioningOperationWithID creates a fresh (just starting) instance of the DeprovisioningOperation with provided ID
   522  func NewDeprovisioningOperationWithID(operationID string, instance *Instance) (DeprovisioningOperation, error) {
   523  	details, err := instance.GetInstanceDetails()
   524  	if err != nil {
   525  		return DeprovisioningOperation{}, err
   526  	}
   527  	return DeprovisioningOperation{
   528  		Operation: Operation{
   529  			RuntimeOperation: orchestration.RuntimeOperation{
   530  				Runtime: orchestration.Runtime{GlobalAccountID: instance.GlobalAccountID, RuntimeID: instance.RuntimeID, Region: instance.ProviderRegion},
   531  			},
   532  			ID:                     operationID,
   533  			Version:                0,
   534  			Description:            "Operation created",
   535  			InstanceID:             instance.InstanceID,
   536  			State:                  orchestration.Pending,
   537  			CreatedAt:              time.Now(),
   538  			UpdatedAt:              time.Now(),
   539  			Type:                   OperationTypeDeprovision,
   540  			InstanceDetails:        details,
   541  			FinishedStages:         make([]string, 0),
   542  			ProvisioningParameters: instance.Parameters,
   543  		},
   544  	}, nil
   545  }
   546  
   547  func NewUpdateOperation(operationID string, instance *Instance, updatingParams UpdatingParametersDTO) Operation {
   548  
   549  	op := Operation{
   550  		ID:                     operationID,
   551  		Version:                0,
   552  		Description:            "Operation created",
   553  		InstanceID:             instance.InstanceID,
   554  		State:                  orchestration.Pending,
   555  		CreatedAt:              time.Now(),
   556  		UpdatedAt:              time.Now(),
   557  		Type:                   OperationTypeUpdate,
   558  		InstanceDetails:        instance.InstanceDetails,
   559  		FinishedStages:         make([]string, 0),
   560  		ProvisioningParameters: instance.Parameters,
   561  		UpdatingParameters:     updatingParams,
   562  		RuntimeOperation: orchestration.RuntimeOperation{
   563  			Runtime: orchestration.Runtime{
   564  				Region: instance.ProviderRegion},
   565  		},
   566  	}
   567  	if updatingParams.OIDC != nil {
   568  		op.ProvisioningParameters.Parameters.OIDC = updatingParams.OIDC
   569  	}
   570  
   571  	if len(updatingParams.RuntimeAdministrators) != 0 {
   572  		op.ProvisioningParameters.Parameters.RuntimeAdministrators = updatingParams.RuntimeAdministrators
   573  	}
   574  
   575  	updatingParams.UpdateAutoScaler(&op.ProvisioningParameters.Parameters)
   576  	if updatingParams.MachineType != nil && *updatingParams.MachineType != "" {
   577  		op.ProvisioningParameters.Parameters.MachineType = updatingParams.MachineType
   578  	}
   579  
   580  	return op
   581  }
   582  
   583  // NewSuspensionOperationWithID creates a fresh (just starting) instance of the DeprovisioningOperation which does not remove the instance.
   584  func NewSuspensionOperationWithID(operationID string, instance *Instance) DeprovisioningOperation {
   585  	return DeprovisioningOperation{
   586  		Operation: Operation{
   587  			ID:                     operationID,
   588  			Version:                0,
   589  			Description:            "Operation created",
   590  			InstanceID:             instance.InstanceID,
   591  			State:                  orchestration.Pending,
   592  			CreatedAt:              time.Now(),
   593  			UpdatedAt:              time.Now(),
   594  			Type:                   OperationTypeDeprovision,
   595  			InstanceDetails:        instance.InstanceDetails,
   596  			ProvisioningParameters: instance.Parameters,
   597  			FinishedStages:         make([]string, 0),
   598  			Temporary:              true,
   599  			RuntimeOperation: orchestration.RuntimeOperation{
   600  				Runtime: orchestration.Runtime{
   601  					Region: instance.ProviderRegion},
   602  			},
   603  		},
   604  	}
   605  }
   606  
   607  func (o *Operation) FinishStage(stageName string) {
   608  	if stageName == "" {
   609  		log.Warnf("Attempt to add empty stage.")
   610  		return
   611  	}
   612  
   613  	if exists := o.IsStageFinished(stageName); exists {
   614  		log.Warnf("Attempt to add stage (%s) which is already saved.", stageName)
   615  		return
   616  	}
   617  
   618  	o.FinishedStages = append(o.FinishedStages, stageName)
   619  }
   620  
   621  func (o *Operation) IsStageFinished(stage string) bool {
   622  	for _, value := range o.FinishedStages {
   623  		if value == stage {
   624  			return true
   625  		}
   626  	}
   627  	return false
   628  }
   629  
   630  type ComponentConfigurationInputList []*gqlschema.ComponentConfigurationInput
   631  
   632  func (l ComponentConfigurationInputList) DeepCopy() []*gqlschema.ComponentConfigurationInput {
   633  	var copiedList []*gqlschema.ComponentConfigurationInput
   634  	for _, component := range l {
   635  		var cpyCfg []*gqlschema.ConfigEntryInput
   636  		for _, cfg := range component.Configuration {
   637  			mapped := &gqlschema.ConfigEntryInput{
   638  				Key:   cfg.Key,
   639  				Value: cfg.Value,
   640  			}
   641  			if cfg.Secret != nil {
   642  				mapped.Secret = ptr.Bool(*cfg.Secret)
   643  			}
   644  			cpyCfg = append(cpyCfg, mapped)
   645  		}
   646  
   647  		copiedList = append(copiedList, &gqlschema.ComponentConfigurationInput{
   648  			Component:     component.Component,
   649  			Namespace:     component.Namespace,
   650  			SourceURL:     component.SourceURL,
   651  			Configuration: cpyCfg,
   652  		})
   653  	}
   654  	return copiedList
   655  }
   656  
   657  // KymaComponent represents single Kyma component
   658  type KymaComponent struct {
   659  	Name        string           `json:"name"`
   660  	ReleaseName string           `json:"release"`
   661  	Namespace   string           `json:"namespace"`
   662  	Source      *ComponentSource `json:"source,omitempty"`
   663  }
   664  
   665  type ComponentSource struct {
   666  	URL string `json:"url"`
   667  }
   668  
   669  type ConfigForPlan struct {
   670  	AdditionalComponents []KymaComponent `json:"additional-components" yaml:"additional-components"`
   671  	KymaTemplate         string          `json:"kyma-template" yaml:"kyma-template"`
   672  }
   673  
   674  func (c *ConfigForPlan) ContainsAdditionalComponent(componentName string) bool {
   675  	for _, c := range c.AdditionalComponents {
   676  		fmt.Println(c.Name)
   677  		if c.Name == componentName {
   678  			return true
   679  		}
   680  	}
   681  	return false
   682  }