github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/storage/driver/postsql/operation.go (about)

     1  package postsql
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/kyma-project/kyma-environment-broker/common/storage"
    10  	"github.com/kyma-project/kyma-environment-broker/internal"
    11  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dberr"
    12  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dbmodel"
    13  	"github.com/kyma-project/kyma-environment-broker/internal/storage/postsql"
    14  
    15  	"github.com/pivotal-cf/brokerapi/v8/domain"
    16  	log "github.com/sirupsen/logrus"
    17  	"k8s.io/apimachinery/pkg/util/wait"
    18  )
    19  
    20  const (
    21  	Retrying   = "retrying" // to signal a retry sign before marking it to pending
    22  	Succeeded  = "succeeded"
    23  	Failed     = "failed"
    24  	InProgress = "in progress"
    25  )
    26  
    27  type operations struct {
    28  	postsql.Factory
    29  	cipher Cipher
    30  }
    31  
    32  func NewOperation(sess postsql.Factory, cipher Cipher) *operations {
    33  	return &operations{
    34  		Factory: sess,
    35  		cipher:  cipher,
    36  	}
    37  }
    38  
    39  // InsertProvisioningOperation insert new ProvisioningOperation to storage
    40  func (s *operations) InsertProvisioningOperation(operation internal.ProvisioningOperation) error {
    41  	dto, err := s.provisioningOperationToDTO(&operation)
    42  	if err != nil {
    43  		return fmt.Errorf("while inserting provisioning operation (id: %s): %w", operation.ID, err)
    44  	}
    45  
    46  	return s.insert(dto)
    47  }
    48  
    49  // InsertOperation insert new Operation to storage
    50  func (s *operations) InsertOperation(operation internal.Operation) error {
    51  	dto, err := s.operationToDTO(&operation)
    52  
    53  	if err != nil {
    54  		return fmt.Errorf("while inserting operation (id: %s): %w", operation.ID, err)
    55  	}
    56  
    57  	return s.insert(dto)
    58  }
    59  
    60  // GetOperationByInstanceID fetches the latest Operation by given instanceID, returns error if not found
    61  func (s *operations) GetOperationByInstanceID(instanceID string) (*internal.Operation, error) {
    62  
    63  	op, err := s.getByInstanceID(instanceID)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	var operation internal.Operation
    69  	err = json.Unmarshal([]byte(op.Data), &operation)
    70  	if err != nil {
    71  		return nil, fmt.Errorf("unable to unmarshall provisioning data: %w", err)
    72  	}
    73  
    74  	ret, err := s.toOperation(op, operation)
    75  	if err != nil {
    76  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
    77  	}
    78  
    79  	return &ret, nil
    80  }
    81  
    82  // GetProvisioningOperationByID fetches the ProvisioningOperation by given ID, returns error if not found
    83  func (s *operations) GetProvisioningOperationByID(operationID string) (*internal.ProvisioningOperation, error) {
    84  	operation, err := s.getByID(operationID)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("while getting operation by ID: %w", err)
    87  	}
    88  
    89  	ret, err := s.toProvisioningOperation(operation)
    90  	if err != nil {
    91  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
    92  	}
    93  
    94  	return ret, nil
    95  }
    96  
    97  // GetProvisioningOperationByInstanceID fetches the latest ProvisioningOperation by given instanceID, returns error if not found
    98  func (s *operations) GetProvisioningOperationByInstanceID(instanceID string) (*internal.ProvisioningOperation, error) {
    99  
   100  	operation, err := s.getByTypeAndInstanceID(instanceID, internal.OperationTypeProvision)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	ret, err := s.toProvisioningOperation(operation)
   105  	if err != nil {
   106  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   107  	}
   108  
   109  	return ret, nil
   110  }
   111  
   112  // UpdateOperation updates Operation, fails if not exists or optimistic locking failure occurs.
   113  func (s *operations) UpdateOperation(op internal.Operation) (*internal.Operation, error) {
   114  	op.UpdatedAt = time.Now()
   115  	dto, err := s.operationToDTO(&op)
   116  
   117  	if err != nil {
   118  		return nil, fmt.Errorf("while converting Operation to DTO: %w", err)
   119  	}
   120  
   121  	lastErr := s.update(dto)
   122  	op.Version = op.Version + 1
   123  
   124  	return &op, lastErr
   125  }
   126  
   127  // UpdateProvisioningOperation updates ProvisioningOperation, fails if not exists or optimistic locking failure occurs.
   128  func (s *operations) UpdateProvisioningOperation(op internal.ProvisioningOperation) (*internal.ProvisioningOperation, error) {
   129  	op.UpdatedAt = time.Now()
   130  	dto, err := s.provisioningOperationToDTO(&op)
   131  
   132  	if err != nil {
   133  		return nil, fmt.Errorf("while converting Operation to DTO: %w", err)
   134  	}
   135  
   136  	lastErr := s.update(dto)
   137  	op.Version = op.Version + 1
   138  
   139  	return &op, lastErr
   140  }
   141  
   142  func (s *operations) ListProvisioningOperationsByInstanceID(instanceID string) ([]internal.ProvisioningOperation, error) {
   143  
   144  	operations, err := s.listOperationsByInstanceIdAndType(instanceID, internal.OperationTypeProvision)
   145  	if err != nil {
   146  		return nil, fmt.Errorf("while loading operations list: %w", err)
   147  	}
   148  
   149  	ret, err := s.toProvisioningOperationList(operations)
   150  	if err != nil {
   151  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   152  	}
   153  
   154  	return ret, nil
   155  }
   156  
   157  func (s *operations) ListOperationsByInstanceID(instanceID string) ([]internal.Operation, error) {
   158  
   159  	operations, err := s.listOperationsByInstanceId(instanceID)
   160  	if err != nil {
   161  		return nil, fmt.Errorf("while loading operations list: %w", err)
   162  	}
   163  
   164  	ret, err := s.toOperationList(operations)
   165  	if err != nil {
   166  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   167  	}
   168  
   169  	return ret, nil
   170  }
   171  
   172  // InsertDeprovisioningOperation insert new DeprovisioningOperation to storage
   173  func (s *operations) InsertDeprovisioningOperation(operation internal.DeprovisioningOperation) error {
   174  
   175  	dto, err := s.deprovisioningOperationToDTO(&operation)
   176  	if err != nil {
   177  		return fmt.Errorf("while converting Operation to DTO: %w", err)
   178  	}
   179  
   180  	return s.insert(dto)
   181  }
   182  
   183  // GetDeprovisioningOperationByID fetches the DeprovisioningOperation by given ID, returns error if not found
   184  func (s *operations) GetDeprovisioningOperationByID(operationID string) (*internal.DeprovisioningOperation, error) {
   185  	operation, err := s.getByID(operationID)
   186  	if err != nil {
   187  		return nil, fmt.Errorf("while getting operation by ID: %w", err)
   188  	}
   189  
   190  	ret, err := s.toDeprovisioningOperation(operation)
   191  	if err != nil {
   192  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   193  	}
   194  
   195  	return ret, nil
   196  }
   197  
   198  // GetDeprovisioningOperationByInstanceID fetches the latest DeprovisioningOperation by given instanceID, returns error if not found
   199  func (s *operations) GetDeprovisioningOperationByInstanceID(instanceID string) (*internal.DeprovisioningOperation, error) {
   200  	operation, err := s.getByTypeAndInstanceID(instanceID, internal.OperationTypeDeprovision)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  	ret, err := s.toDeprovisioningOperation(operation)
   205  	if err != nil {
   206  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   207  	}
   208  
   209  	return ret, nil
   210  }
   211  
   212  // UpdateDeprovisioningOperation updates DeprovisioningOperation, fails if not exists or optimistic locking failure occurs.
   213  func (s *operations) UpdateDeprovisioningOperation(operation internal.DeprovisioningOperation) (*internal.DeprovisioningOperation, error) {
   214  	operation.UpdatedAt = time.Now()
   215  
   216  	dto, err := s.deprovisioningOperationToDTO(&operation)
   217  	if err != nil {
   218  		return nil, fmt.Errorf("while converting Operation to DTO: %w", err)
   219  	}
   220  
   221  	lastErr := s.update(dto)
   222  	operation.Version = operation.Version + 1
   223  	return &operation, lastErr
   224  }
   225  
   226  // ListDeprovisioningOperationsByInstanceID
   227  func (s *operations) ListDeprovisioningOperationsByInstanceID(instanceID string) ([]internal.DeprovisioningOperation, error) {
   228  	operations, err := s.listOperationsByInstanceIdAndType(instanceID, internal.OperationTypeDeprovision)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  
   233  	ret, err := s.toDeprovisioningOperationList(operations)
   234  	if err != nil {
   235  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   236  	}
   237  
   238  	return ret, nil
   239  }
   240  
   241  // ListDeprovisioningOperations lists deprovisioning operations
   242  func (s *operations) ListDeprovisioningOperations() ([]internal.DeprovisioningOperation, error) {
   243  	var lastErr dberr.Error
   244  
   245  	operations, err := s.listOperationsByType(internal.OperationTypeDeprovision)
   246  	if err != nil {
   247  		return nil, lastErr
   248  	}
   249  
   250  	ret, err := s.toDeprovisioningOperationList(operations)
   251  	if err != nil {
   252  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   253  	}
   254  
   255  	return ret, nil
   256  }
   257  
   258  // InsertUpgradeKymaOperation insert new UpgradeKymaOperation to storage
   259  func (s *operations) InsertUpgradeKymaOperation(operation internal.UpgradeKymaOperation) error {
   260  	dto, err := s.upgradeKymaOperationToDTO(&operation)
   261  	if err != nil {
   262  		return fmt.Errorf("while inserting upgrade kyma operation (id: %s): %w", operation.Operation.ID, err)
   263  	}
   264  
   265  	return s.insert(dto)
   266  }
   267  
   268  // GetUpgradeKymaOperationByID fetches the UpgradeKymaOperation by given ID, returns error if not found
   269  func (s *operations) GetUpgradeKymaOperationByID(operationID string) (*internal.UpgradeKymaOperation, error) {
   270  	operation, err := s.getByID(operationID)
   271  	if err != nil {
   272  		return nil, fmt.Errorf("while getting operation by ID: %w", err)
   273  	}
   274  
   275  	ret, err := s.toUpgradeKymaOperation(operation)
   276  	if err != nil {
   277  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   278  	}
   279  
   280  	return ret, nil
   281  }
   282  
   283  // GetUpgradeKymaOperationByInstanceID fetches the latest UpgradeKymaOperation by given instanceID, returns error if not found
   284  func (s *operations) GetUpgradeKymaOperationByInstanceID(instanceID string) (*internal.UpgradeKymaOperation, error) {
   285  	operation, err := s.getByTypeAndInstanceID(instanceID, internal.OperationTypeUpgradeKyma)
   286  	if err != nil {
   287  		return nil, err
   288  	}
   289  	ret, err := s.toUpgradeKymaOperation(operation)
   290  	if err != nil {
   291  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   292  	}
   293  
   294  	return ret, nil
   295  }
   296  
   297  func (s *operations) ListUpgradeKymaOperations() ([]internal.UpgradeKymaOperation, error) {
   298  	var operations []dbmodel.OperationDTO
   299  
   300  	operations, err := s.listOperationsByType(internal.OperationTypeUpgradeKyma)
   301  	if err != nil {
   302  		return nil, err
   303  	}
   304  	ret, err := s.toUpgradeKymaOperationList(operations)
   305  	if err != nil {
   306  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   307  	}
   308  
   309  	return ret, nil
   310  }
   311  
   312  func (s *operations) ListUpgradeKymaOperationsByInstanceID(instanceID string) ([]internal.UpgradeKymaOperation, error) {
   313  	operations, err := s.listOperationsByInstanceIdAndType(instanceID, internal.OperationTypeUpgradeKyma)
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  
   318  	ret, err := s.toUpgradeKymaOperationList(operations)
   319  	if err != nil {
   320  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   321  	}
   322  
   323  	return ret, nil
   324  }
   325  
   326  // UpdateUpgradeKymaOperation updates UpgradeKymaOperation, fails if not exists or optimistic locking failure occurs.
   327  func (s *operations) UpdateUpgradeKymaOperation(operation internal.UpgradeKymaOperation) (*internal.UpgradeKymaOperation, error) {
   328  	operation.UpdatedAt = time.Now()
   329  	dto, err := s.upgradeKymaOperationToDTO(&operation)
   330  	if err != nil {
   331  		return nil, fmt.Errorf("while converting Operation to DTO: %w", err)
   332  	}
   333  
   334  	err = s.update(dto)
   335  	operation.Version = operation.Version + 1
   336  	return &operation, err
   337  }
   338  
   339  // GetLastOperation returns Operation for given instance ID which is not in 'pending' state. Returns an error if the operation does not exist.
   340  func (s *operations) GetLastOperation(instanceID string) (*internal.Operation, error) {
   341  	session := s.NewReadSession()
   342  	operation := dbmodel.OperationDTO{}
   343  	op := internal.Operation{}
   344  	var lastErr dberr.Error
   345  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   346  		operation, lastErr = session.GetLastOperation(instanceID)
   347  		if lastErr != nil {
   348  			if dberr.IsNotFound(lastErr) {
   349  				lastErr = dberr.NotFound("Operation with instance_id %s not exist", instanceID)
   350  				return false, lastErr
   351  			}
   352  			log.Errorf("while reading operation from the storage: %v", lastErr)
   353  			return false, nil
   354  		}
   355  		return true, nil
   356  	})
   357  	if err != nil {
   358  		return nil, lastErr
   359  	}
   360  	err = json.Unmarshal([]byte(operation.Data), &op)
   361  	if err != nil {
   362  		return nil, fmt.Errorf("while unmarshalling operation data: %w", err)
   363  	}
   364  	op, err = s.toOperation(&operation, op)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  	return &op, nil
   369  }
   370  
   371  // GetOperationByID returns Operation with given ID. Returns an error if the operation does not exist.
   372  func (s *operations) GetOperationByID(operationID string) (*internal.Operation, error) {
   373  	op := internal.Operation{}
   374  	dto, err := s.getByID(operationID)
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  
   379  	op, err = s.toOperation(dto, op)
   380  	if err != nil {
   381  		return nil, err
   382  	}
   383  
   384  	err = json.Unmarshal([]byte(dto.Data), &op)
   385  	if err != nil {
   386  		return nil, fmt.Errorf("unable to unmarshall operation data")
   387  	}
   388  	return &op, nil
   389  }
   390  
   391  func (s *operations) GetNotFinishedOperationsByType(operationType internal.OperationType) ([]internal.Operation, error) {
   392  	session := s.NewReadSession()
   393  	operations := make([]dbmodel.OperationDTO, 0)
   394  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   395  		dto, err := session.GetNotFinishedOperationsByType(operationType)
   396  		if err != nil {
   397  			log.Errorf("while getting operations from the storage: %v", err)
   398  			return false, nil
   399  		}
   400  		operations = dto
   401  		return true, nil
   402  	})
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	return s.toOperations(operations)
   407  }
   408  
   409  func (s *operations) GetOperationStatsByPlan() (map[string]internal.OperationStats, error) {
   410  	entries, err := s.NewReadSession().GetOperationStats()
   411  	if err != nil {
   412  		return nil, err
   413  	}
   414  	result := make(map[string]internal.OperationStats)
   415  
   416  	for _, e := range entries {
   417  		if e.PlanID == "" {
   418  			continue
   419  		}
   420  		if _, ok := result[e.PlanID]; !ok {
   421  			result[e.PlanID] = internal.OperationStats{
   422  				Provisioning:   make(map[domain.LastOperationState]int),
   423  				Deprovisioning: make(map[domain.LastOperationState]int),
   424  			}
   425  		}
   426  		switch internal.OperationType(e.Type) {
   427  		case internal.OperationTypeProvision:
   428  			result[e.PlanID].Provisioning[domain.LastOperationState(e.State)] += 1
   429  		case internal.OperationTypeDeprovision:
   430  			result[e.PlanID].Deprovisioning[domain.LastOperationState(e.State)] += 1
   431  		}
   432  	}
   433  	return result, nil
   434  }
   435  
   436  func calFailedStatusForOrchestration(entries []dbmodel.OperationStatEntry) ([]string, int) {
   437  	var result []string
   438  	resultPerInstanceID := make(map[string][]string)
   439  
   440  	for _, entry := range entries {
   441  		resultPerInstanceID[entry.InstanceID] = append(resultPerInstanceID[entry.InstanceID], entry.State)
   442  	}
   443  
   444  	var invalidFailed, failedFound bool
   445  
   446  	for instanceID, statuses := range resultPerInstanceID {
   447  
   448  		invalidFailed = false
   449  		failedFound = false
   450  		for _, status := range statuses {
   451  			if status == Failed {
   452  				failedFound = true
   453  			}
   454  			//In Progress/Retrying/Succeeded means new operation for same instance_id is ongoing/succeeded.
   455  			if status == Succeeded || status == Retrying || status == InProgress {
   456  				invalidFailed = true
   457  			}
   458  		}
   459  		if failedFound && !invalidFailed {
   460  			log.Info("calFailedStatusForOrchestration() append ", instanceID)
   461  			result = append(result, instanceID)
   462  		}
   463  	}
   464  
   465  	return result, len(result)
   466  }
   467  
   468  func (s *operations) GetOperationStatsForOrchestration(orchestrationID string) (map[string]int, error) {
   469  	entries, err := s.NewReadSession().GetOperationStatsForOrchestration(orchestrationID)
   470  	if err != nil {
   471  		return map[string]int{}, err
   472  	}
   473  
   474  	result := make(map[string]int)
   475  	_, failedNum := calFailedStatusForOrchestration(entries)
   476  	result[Failed] = failedNum
   477  
   478  	for _, entry := range entries {
   479  		if entry.State != Failed {
   480  			result[entry.State] += 1
   481  		}
   482  	}
   483  	return result, nil
   484  }
   485  
   486  func (s *operations) GetOperationsForIDs(operationIDList []string) ([]internal.Operation, error) {
   487  	session := s.NewReadSession()
   488  	operations := make([]dbmodel.OperationDTO, 0)
   489  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   490  		dto, err := session.GetOperationsForIDs(operationIDList)
   491  		if err != nil {
   492  			log.Errorf("while getting operations from the storage: %v", err)
   493  			return false, nil
   494  		}
   495  		operations = dto
   496  		return true, nil
   497  	})
   498  	if err != nil {
   499  		return nil, err
   500  	}
   501  	return s.toOperations(operations)
   502  }
   503  
   504  func (s *operations) ListOperations(filter dbmodel.OperationFilter) ([]internal.Operation, int, int, error) {
   505  	session := s.NewReadSession()
   506  
   507  	var (
   508  		lastErr     error
   509  		size, total int
   510  		operations  = make([]dbmodel.OperationDTO, 0)
   511  	)
   512  
   513  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   514  		operations, size, total, lastErr = session.ListOperations(filter)
   515  		if lastErr != nil {
   516  			log.Errorf("while getting operations from the storage: %v", lastErr)
   517  			return false, nil
   518  		}
   519  		return true, nil
   520  	})
   521  	if err != nil {
   522  		return nil, -1, -1, err
   523  	}
   524  
   525  	result, err := s.toOperations(operations)
   526  
   527  	return result, size, total, err
   528  }
   529  
   530  func (s *operations) fetchFailedStatusForOrchestration(entries []dbmodel.OperationDTO) ([]dbmodel.OperationDTO, int, int) {
   531  	resPerInstanceID := make(map[string][]dbmodel.OperationDTO)
   532  	for _, entry := range entries {
   533  		resPerInstanceID[entry.InstanceID] = append(resPerInstanceID[entry.InstanceID], entry)
   534  	}
   535  
   536  	var failedDatas []dbmodel.OperationDTO
   537  	for _, datas := range resPerInstanceID {
   538  		var invalidFailed bool
   539  		var failedFound bool
   540  		var faildEntry dbmodel.OperationDTO
   541  		for _, data := range datas {
   542  			if data.State == Succeeded || data.State == Retrying || data.State == InProgress {
   543  				invalidFailed = true
   544  				break
   545  			}
   546  			if data.State == Failed {
   547  				failedFound = true
   548  				if faildEntry.InstanceID == "" {
   549  					faildEntry = data
   550  				} else if faildEntry.CreatedAt.Before(data.CreatedAt) {
   551  					faildEntry = data
   552  				}
   553  			}
   554  		}
   555  		if failedFound && !invalidFailed {
   556  			failedDatas = append(failedDatas, faildEntry)
   557  		}
   558  	}
   559  	return failedDatas, len(failedDatas), len(failedDatas)
   560  }
   561  
   562  func (s *operations) showUpgradeKymaOperationDTOByOrchestrationID(orchestrationID string, filter dbmodel.OperationFilter) ([]dbmodel.OperationDTO, int, int, error) {
   563  	session := s.NewReadSession()
   564  	var (
   565  		operations        = make([]dbmodel.OperationDTO, 0)
   566  		lastErr           error
   567  		count, totalCount int
   568  	)
   569  	failedFilterFound, _ := s.searchFilter(filter, Failed)
   570  	if failedFilterFound {
   571  		filter.States = []string{}
   572  	}
   573  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   574  		operations, count, totalCount, lastErr = session.ListOperationsByOrchestrationID(orchestrationID, filter)
   575  		if lastErr != nil {
   576  			if dberr.IsNotFound(lastErr) {
   577  				lastErr = dberr.NotFound("Operations for orchestration ID %s not exist", orchestrationID)
   578  				return false, lastErr
   579  			}
   580  			log.Errorf("while reading operation from the storage: %v", lastErr)
   581  			return false, nil
   582  		}
   583  		return true, nil
   584  	})
   585  	if err != nil {
   586  		return nil, -1, -1, fmt.Errorf("while getting operation by ID: %w", lastErr)
   587  	}
   588  	if failedFilterFound {
   589  		operations, count, totalCount = s.fetchFailedStatusForOrchestration(operations)
   590  	}
   591  	return operations, count, totalCount, nil
   592  }
   593  
   594  func (s *operations) ListUpgradeKymaOperationsByOrchestrationID(orchestrationID string, filter dbmodel.OperationFilter) ([]internal.UpgradeKymaOperation, int, int, error) {
   595  	var (
   596  		operations        = make([]dbmodel.OperationDTO, 0)
   597  		err               error
   598  		count, totalCount int
   599  	)
   600  	states, filterFailedFound := s.excludeFailedInFilterStates(filter, Failed)
   601  	if filterFailedFound {
   602  		filter.States = states
   603  	}
   604  
   605  	//excluded "failed" states
   606  	if !filterFailedFound || (filterFailedFound && len(filter.States) > 0) {
   607  		operations, count, totalCount, err = s.showUpgradeKymaOperationDTOByOrchestrationID(orchestrationID, filter)
   608  		if err != nil {
   609  			return nil, -1, -1, fmt.Errorf("while getting operation by ID: %w", err)
   610  		}
   611  	}
   612  
   613  	//only for "failed" states
   614  	if filterFailedFound {
   615  		filter = dbmodel.OperationFilter{States: []string{"failed"}}
   616  		failedOperations, failedCount, failedtotalCount, err := s.showUpgradeKymaOperationDTOByOrchestrationID(orchestrationID, filter)
   617  		if err != nil {
   618  			return nil, -1, -1, fmt.Errorf("while getting operation by ID: %w", err)
   619  		}
   620  		operations = append(operations, failedOperations...)
   621  		count = count + failedCount
   622  		totalCount = totalCount + failedtotalCount
   623  	}
   624  	ret, err := s.toUpgradeKymaOperationList(operations)
   625  	if err != nil {
   626  		return nil, -1, -1, fmt.Errorf("while converting DTO to Operation: %w", err)
   627  	}
   628  
   629  	return ret, count, totalCount, nil
   630  }
   631  
   632  func (s *operations) ListOperationsByOrchestrationID(orchestrationID string, filter dbmodel.OperationFilter) ([]internal.Operation, int, int, error) {
   633  	session := s.NewReadSession()
   634  	var (
   635  		operations        = make([]dbmodel.OperationDTO, 0)
   636  		lastErr           error
   637  		count, totalCount int
   638  	)
   639  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   640  		operations, count, totalCount, lastErr = session.ListOperationsByOrchestrationID(orchestrationID, filter)
   641  		if lastErr != nil {
   642  			if dberr.IsNotFound(lastErr) {
   643  				lastErr = dberr.NotFound("Operations for orchestration ID %s not exist", orchestrationID)
   644  				return false, lastErr
   645  			}
   646  			log.Errorf("while reading operation from the storage: %v", lastErr)
   647  			return false, nil
   648  		}
   649  		return true, nil
   650  	})
   651  	if err != nil {
   652  		return nil, -1, -1, fmt.Errorf("while getting operation by ID: %w", lastErr)
   653  	}
   654  	ret, err := s.toOperationList(operations)
   655  	if err != nil {
   656  		return nil, -1, -1, fmt.Errorf("while converting DTO to Operation: %w", err)
   657  	}
   658  
   659  	return ret, count, totalCount, nil
   660  }
   661  
   662  func (s *operations) excludeFailedInFilterStates(filter dbmodel.OperationFilter, state string) ([]string, bool) {
   663  	failedFilterFound, failedFilterIndex := s.searchFilter(filter, state)
   664  
   665  	if failedFilterFound {
   666  		filter.States = s.removeIndex(filter.States, failedFilterIndex)
   667  	}
   668  	return filter.States, failedFilterFound
   669  }
   670  
   671  func (s *operations) searchFilter(filter dbmodel.OperationFilter, inputState string) (bool, int) {
   672  	var filterFound bool
   673  	var filterIndex int
   674  	for index, state := range filter.States {
   675  		if strings.Contains(state, inputState) {
   676  			filterFound = true
   677  			filterIndex = index
   678  			break
   679  		}
   680  	}
   681  	return filterFound, filterIndex
   682  }
   683  
   684  func (s *operations) removeIndex(arr []string, index int) []string {
   685  	return append(arr[:index], arr[index+1:]...)
   686  }
   687  
   688  func (s *operations) ListOperationsInTimeRange(from, to time.Time) ([]internal.Operation, error) {
   689  	session := s.NewReadSession()
   690  	operations := make([]dbmodel.OperationDTO, 0)
   691  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   692  		var err error
   693  		operations, err = session.ListOperationsInTimeRange(from, to)
   694  		if err != nil {
   695  			if dberr.IsNotFound(err) {
   696  				return true, nil
   697  			}
   698  			return false, fmt.Errorf("while listing the operations from the storage: %w", err)
   699  		}
   700  		return true, nil
   701  	})
   702  	if err != nil {
   703  		return nil, fmt.Errorf("while getting operations in range %v-%v: %w", from.Format(time.RFC822), to.Format(time.RFC822), err)
   704  	}
   705  	ret, err := s.toOperationList(operations)
   706  	if err != nil {
   707  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   708  	}
   709  
   710  	return ret, nil
   711  }
   712  
   713  func (s *operations) InsertUpdatingOperation(operation internal.UpdatingOperation) error {
   714  	dto, err := s.updateOperationToDTO(&operation)
   715  	if err != nil {
   716  		return fmt.Errorf("while converting update operation (id: %s): %w", operation.Operation.ID, err)
   717  	}
   718  
   719  	return s.insert(dto)
   720  }
   721  
   722  func (s *operations) GetUpdatingOperationByID(operationID string) (*internal.UpdatingOperation, error) {
   723  	operation, err := s.getByID(operationID)
   724  	if err != nil {
   725  		return nil, fmt.Errorf("while getting operation by ID: %w", err)
   726  	}
   727  
   728  	ret, err := s.toUpdateOperation(operation)
   729  	if err != nil {
   730  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   731  	}
   732  
   733  	return ret, nil
   734  }
   735  
   736  func (s *operations) UpdateUpdatingOperation(operation internal.UpdatingOperation) (*internal.UpdatingOperation, error) {
   737  	session := s.NewWriteSession()
   738  	operation.UpdatedAt = time.Now()
   739  	dto, err := s.updateOperationToDTO(&operation)
   740  	if err != nil {
   741  		return nil, fmt.Errorf("while converting Operation to DTO: %w", err)
   742  	}
   743  
   744  	var lastErr error
   745  	_ = wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   746  		lastErr = session.UpdateOperation(dto)
   747  		if lastErr != nil && dberr.IsNotFound(lastErr) {
   748  			_, lastErr = s.NewReadSession().GetOperationByID(operation.Operation.ID)
   749  			if lastErr != nil {
   750  				log.Errorf("while getting operation: %v", lastErr)
   751  				return false, nil
   752  			}
   753  
   754  			// the operation exists but the version is different
   755  			lastErr = dberr.Conflict("operation update conflict, operation ID: %s", operation.Operation.ID)
   756  			log.Warn(lastErr.Error())
   757  			return false, lastErr
   758  		}
   759  		return true, nil
   760  	})
   761  	operation.Version = operation.Version + 1
   762  	return &operation, lastErr
   763  }
   764  
   765  // ListUpdatingOperationsByInstanceID Lists all update operations for the given instance
   766  func (s *operations) ListUpdatingOperationsByInstanceID(instanceID string) ([]internal.UpdatingOperation, error) {
   767  	session := s.NewReadSession()
   768  	operations := []dbmodel.OperationDTO{}
   769  	var lastErr dberr.Error
   770  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   771  		operations, lastErr = session.GetOperationsByTypeAndInstanceID(instanceID, internal.OperationTypeUpdate)
   772  		if lastErr != nil {
   773  			log.Errorf("while reading operation from the storage: %v", lastErr)
   774  			return false, nil
   775  		}
   776  		return true, nil
   777  	})
   778  	if err != nil {
   779  		return nil, lastErr
   780  	}
   781  	ret, err := s.toUpdateOperationList(operations)
   782  	if err != nil {
   783  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   784  	}
   785  
   786  	return ret, nil
   787  }
   788  
   789  // InsertUpgradeClusterOperation insert new UpgradeClusterOperation to storage
   790  func (s *operations) InsertUpgradeClusterOperation(operation internal.UpgradeClusterOperation) error {
   791  	dto, err := s.upgradeClusterOperationToDTO(&operation)
   792  	if err != nil {
   793  		return fmt.Errorf("while converting upgrade cluser operation (id: %s): %w", operation.Operation.ID, err)
   794  	}
   795  
   796  	return s.insert(dto)
   797  }
   798  
   799  // UpdateUpgradeClusterOperation updates UpgradeClusterOperation, fails if not exists or optimistic locking failure occurs.
   800  func (s *operations) UpdateUpgradeClusterOperation(operation internal.UpgradeClusterOperation) (*internal.UpgradeClusterOperation, error) {
   801  	session := s.NewWriteSession()
   802  	operation.UpdatedAt = time.Now()
   803  	dto, err := s.upgradeClusterOperationToDTO(&operation)
   804  	if err != nil {
   805  		return nil, fmt.Errorf("while converting Operation to DTO: %w", err)
   806  	}
   807  
   808  	var lastErr error
   809  	_ = wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   810  		lastErr = session.UpdateOperation(dto)
   811  		if lastErr != nil && dberr.IsNotFound(lastErr) {
   812  			_, lastErr = s.NewReadSession().GetOperationByID(operation.Operation.ID)
   813  			if lastErr != nil {
   814  				log.Errorf("while getting operation: %v", lastErr)
   815  				return false, nil
   816  			}
   817  
   818  			// the operation exists but the version is different
   819  			lastErr = dberr.Conflict("operation update conflict, operation ID: %s", operation.Operation.ID)
   820  			log.Warn(lastErr.Error())
   821  			return false, lastErr
   822  		}
   823  		return true, nil
   824  	})
   825  	operation.Version = operation.Version + 1
   826  	return &operation, lastErr
   827  }
   828  
   829  // GetUpgradeClusterOperationByID fetches the UpgradeClusterOperation by given ID, returns error if not found
   830  func (s *operations) GetUpgradeClusterOperationByID(operationID string) (*internal.UpgradeClusterOperation, error) {
   831  	operation, err := s.getByID(operationID)
   832  	if err != nil {
   833  		return nil, fmt.Errorf("while getting operation by ID: %w", err)
   834  	}
   835  	ret, err := s.toUpgradeClusterOperation(operation)
   836  	if err != nil {
   837  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   838  	}
   839  
   840  	return ret, nil
   841  }
   842  
   843  // ListUpgradeClusterOperationsByInstanceID Lists all upgrade cluster operations for the given instance
   844  func (s *operations) ListUpgradeClusterOperationsByInstanceID(instanceID string) ([]internal.UpgradeClusterOperation, error) {
   845  	session := s.NewReadSession()
   846  	operations := []dbmodel.OperationDTO{}
   847  	var lastErr dberr.Error
   848  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   849  		operations, lastErr = session.GetOperationsByTypeAndInstanceID(instanceID, internal.OperationTypeUpgradeCluster)
   850  		if lastErr != nil {
   851  			log.Errorf("while reading operation from the storage: %v", lastErr)
   852  			return false, nil
   853  		}
   854  		return true, nil
   855  	})
   856  	if err != nil {
   857  		return nil, lastErr
   858  	}
   859  	ret, err := s.toUpgradeClusterOperationList(operations)
   860  	if err != nil {
   861  		return nil, fmt.Errorf("while converting DTO to Operation: %w", err)
   862  	}
   863  
   864  	return ret, nil
   865  }
   866  
   867  // ListUpgradeClusterOperationsByOrchestrationID Lists upgrade cluster operations for the given orchestration, according to filter(s) and/or pagination
   868  func (s *operations) ListUpgradeClusterOperationsByOrchestrationID(orchestrationID string, filter dbmodel.OperationFilter) ([]internal.UpgradeClusterOperation, int, int, error) {
   869  	session := s.NewReadSession()
   870  	var (
   871  		operations        = make([]dbmodel.OperationDTO, 0)
   872  		lastErr           error
   873  		count, totalCount int
   874  	)
   875  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   876  		operations, count, totalCount, lastErr = session.ListOperationsByOrchestrationID(orchestrationID, filter)
   877  		if lastErr != nil {
   878  			if dberr.IsNotFound(lastErr) {
   879  				lastErr = dberr.NotFound("Operations for orchestration ID %s not exist", orchestrationID)
   880  				return false, lastErr
   881  			}
   882  			log.Errorf("while reading operation from the storage: %v", lastErr)
   883  			return false, nil
   884  		}
   885  		return true, nil
   886  	})
   887  	if err != nil {
   888  		return nil, -1, -1, fmt.Errorf("while getting operation by ID: %w", lastErr)
   889  	}
   890  	ret, err := s.toUpgradeClusterOperationList(operations)
   891  	if err != nil {
   892  		return nil, -1, -1, fmt.Errorf("while converting DTO to Operation: %w", err)
   893  	}
   894  
   895  	return ret, count, totalCount, nil
   896  }
   897  
   898  func (s *operations) operationToDB(op internal.Operation) (dbmodel.OperationDTO, error) {
   899  	err := s.cipher.EncryptSMCreds(&op.ProvisioningParameters)
   900  	if err != nil {
   901  		return dbmodel.OperationDTO{}, fmt.Errorf("while encrypting basic auth: %w", err)
   902  	}
   903  	err = s.cipher.EncryptKubeconfig(&op.ProvisioningParameters)
   904  	if err != nil {
   905  		return dbmodel.OperationDTO{}, fmt.Errorf("while encrypting kubeconfig: %w", err)
   906  	}
   907  	pp, err := json.Marshal(op.ProvisioningParameters)
   908  	if err != nil {
   909  		return dbmodel.OperationDTO{}, fmt.Errorf("while marshal provisioning parameters: %w", err)
   910  	}
   911  
   912  	return dbmodel.OperationDTO{
   913  		ID:                     op.ID,
   914  		Type:                   op.Type,
   915  		TargetOperationID:      op.ProvisionerOperationID,
   916  		State:                  string(op.State),
   917  		Description:            op.Description,
   918  		UpdatedAt:              op.UpdatedAt,
   919  		CreatedAt:              op.CreatedAt,
   920  		Version:                op.Version,
   921  		InstanceID:             op.InstanceID,
   922  		OrchestrationID:        storage.StringToSQLNullString(op.OrchestrationID),
   923  		ProvisioningParameters: storage.StringToSQLNullString(string(pp)),
   924  		FinishedStages:         storage.StringToSQLNullString(strings.Join(op.FinishedStages, ",")),
   925  	}, nil
   926  }
   927  
   928  func (s *operations) toOperation(dto *dbmodel.OperationDTO, existingOp internal.Operation) (internal.Operation, error) {
   929  	provisioningParameters := internal.ProvisioningParameters{}
   930  	if dto.ProvisioningParameters.Valid {
   931  		err := json.Unmarshal([]byte(dto.ProvisioningParameters.String), &provisioningParameters)
   932  		if err != nil {
   933  			return internal.Operation{}, fmt.Errorf("while unmarshal provisioning parameters: %w", err)
   934  		}
   935  	}
   936  	err := s.cipher.DecryptSMCreds(&provisioningParameters)
   937  	if err != nil {
   938  		return internal.Operation{}, fmt.Errorf("while decrypting basic auth: %w", err)
   939  	}
   940  
   941  	err = s.cipher.DecryptKubeconfig(&provisioningParameters)
   942  	if err != nil {
   943  		log.Warn("decrypting skipped because kubeconfig is in a plain text")
   944  	}
   945  
   946  	stages := make([]string, 0)
   947  	finishedSteps := storage.SQLNullStringToString(dto.FinishedStages)
   948  	for _, s := range strings.Split(finishedSteps, ",") {
   949  		if s != "" {
   950  			stages = append(stages, s)
   951  		}
   952  	}
   953  
   954  	existingOp.ID = dto.ID
   955  	existingOp.CreatedAt = dto.CreatedAt
   956  	existingOp.UpdatedAt = dto.UpdatedAt
   957  	existingOp.Type = dto.Type
   958  	existingOp.ProvisionerOperationID = dto.TargetOperationID
   959  	existingOp.State = domain.LastOperationState(dto.State)
   960  	existingOp.InstanceID = dto.InstanceID
   961  	existingOp.Description = dto.Description
   962  	existingOp.Version = dto.Version
   963  	existingOp.OrchestrationID = storage.SQLNullStringToString(dto.OrchestrationID)
   964  	existingOp.ProvisioningParameters = provisioningParameters
   965  	existingOp.FinishedStages = stages
   966  
   967  	return existingOp, nil
   968  }
   969  
   970  func (s *operations) toOperations(op []dbmodel.OperationDTO) ([]internal.Operation, error) {
   971  	operations := make([]internal.Operation, 0)
   972  	for _, o := range op {
   973  		operation := internal.Operation{}
   974  		operation, err := s.toOperation(&o, operation)
   975  		if err != nil {
   976  			return nil, err
   977  		}
   978  		err = json.Unmarshal([]byte(o.Data), &operation)
   979  		if err != nil {
   980  			return nil, fmt.Errorf("unable to unmarshall operation data: %w", err)
   981  		}
   982  		operations = append(operations, operation)
   983  	}
   984  	return operations, nil
   985  }
   986  
   987  func (s *operations) toProvisioningOperation(op *dbmodel.OperationDTO) (*internal.ProvisioningOperation, error) {
   988  	if op.Type != internal.OperationTypeProvision {
   989  		return nil, fmt.Errorf("expected operation type Provisioning, but was %s", op.Type)
   990  	}
   991  	var operation internal.ProvisioningOperation
   992  	var err error
   993  	err = json.Unmarshal([]byte(op.Data), &operation)
   994  	if err != nil {
   995  		return nil, fmt.Errorf("unable to unmarshall provisioning data: %w", err)
   996  	}
   997  	operation.Operation, err = s.toOperation(op, operation.Operation)
   998  	if err != nil {
   999  		return nil, err
  1000  	}
  1001  	return &operation, nil
  1002  }
  1003  
  1004  func (s *operations) toProvisioningOperationList(ops []dbmodel.OperationDTO) ([]internal.ProvisioningOperation, error) {
  1005  	result := make([]internal.ProvisioningOperation, 0)
  1006  
  1007  	for _, op := range ops {
  1008  		o, err := s.toProvisioningOperation(&op)
  1009  		if err != nil {
  1010  			return nil, fmt.Errorf("while converting to upgrade kyma operation: %w", err)
  1011  		}
  1012  		result = append(result, *o)
  1013  	}
  1014  
  1015  	return result, nil
  1016  }
  1017  
  1018  func (s *operations) toDeprovisioningOperationList(ops []dbmodel.OperationDTO) ([]internal.DeprovisioningOperation, error) {
  1019  	result := make([]internal.DeprovisioningOperation, 0)
  1020  
  1021  	for _, op := range ops {
  1022  		o, err := s.toDeprovisioningOperation(&op)
  1023  		if err != nil {
  1024  			return nil, fmt.Errorf("while converting to upgrade kyma operation: %w", err)
  1025  		}
  1026  		result = append(result, *o)
  1027  	}
  1028  
  1029  	return result, nil
  1030  }
  1031  
  1032  func (s *operations) operationToDTO(op *internal.Operation) (dbmodel.OperationDTO, error) {
  1033  	serialized, err := json.Marshal(op)
  1034  	if err != nil {
  1035  		return dbmodel.OperationDTO{}, fmt.Errorf("while serializing operation data %v: %w", op, err)
  1036  	}
  1037  
  1038  	ret, err := s.operationToDB(*op)
  1039  	if err != nil {
  1040  		return dbmodel.OperationDTO{}, fmt.Errorf("while converting to operationDB %v: %w", op, err)
  1041  	}
  1042  
  1043  	ret.Data = string(serialized)
  1044  	return ret, nil
  1045  }
  1046  
  1047  func (s *operations) provisioningOperationToDTO(op *internal.ProvisioningOperation) (dbmodel.OperationDTO, error) {
  1048  	serialized, err := json.Marshal(op)
  1049  	if err != nil {
  1050  		return dbmodel.OperationDTO{}, fmt.Errorf("while serializing provisioning data %v: %w", op, err)
  1051  	}
  1052  
  1053  	ret, err := s.operationToDB(op.Operation)
  1054  	if err != nil {
  1055  		return dbmodel.OperationDTO{}, fmt.Errorf("while converting to operationDB %v: %w", op, err)
  1056  	}
  1057  	ret.Data = string(serialized)
  1058  	ret.Type = internal.OperationTypeProvision
  1059  	return ret, nil
  1060  }
  1061  
  1062  func (s *operations) toDeprovisioningOperation(op *dbmodel.OperationDTO) (*internal.DeprovisioningOperation, error) {
  1063  	if op.Type != internal.OperationTypeDeprovision {
  1064  		return nil, fmt.Errorf(fmt.Sprintf("expected operation type Deprovision, but was %s", op.Type))
  1065  	}
  1066  	var operation internal.DeprovisioningOperation
  1067  	var err error
  1068  	err = json.Unmarshal([]byte(op.Data), &operation)
  1069  	if err != nil {
  1070  		return nil, fmt.Errorf("unable to unmarshall provisioning data: %w", err)
  1071  	}
  1072  	operation.Operation, err = s.toOperation(op, operation.Operation)
  1073  	if err != nil {
  1074  		return nil, err
  1075  	}
  1076  
  1077  	return &operation, nil
  1078  }
  1079  
  1080  func (s *operations) deprovisioningOperationToDTO(op *internal.DeprovisioningOperation) (dbmodel.OperationDTO, error) {
  1081  	serialized, err := json.Marshal(op)
  1082  	if err != nil {
  1083  		return dbmodel.OperationDTO{}, fmt.Errorf("while serializing deprovisioning data %v: %w", op, err)
  1084  	}
  1085  
  1086  	ret, err := s.operationToDB(op.Operation)
  1087  	if err != nil {
  1088  		return dbmodel.OperationDTO{}, fmt.Errorf("while converting to operationDB %v: %w", op, err)
  1089  	}
  1090  	ret.Data = string(serialized)
  1091  	ret.Type = internal.OperationTypeDeprovision
  1092  	return ret, nil
  1093  }
  1094  
  1095  func (s *operations) toUpgradeKymaOperation(op *dbmodel.OperationDTO) (*internal.UpgradeKymaOperation, error) {
  1096  	if op.Type != internal.OperationTypeUpgradeKyma {
  1097  		return nil, fmt.Errorf("expected operation type Upgrade Kyma, but was %s", op.Type)
  1098  	}
  1099  	var operation internal.UpgradeKymaOperation
  1100  	var err error
  1101  	err = json.Unmarshal([]byte(op.Data), &operation)
  1102  	if err != nil {
  1103  		return nil, fmt.Errorf("unable to unmarshall upgrade kyma data: %w", err)
  1104  	}
  1105  	operation.Operation, err = s.toOperation(op, operation.Operation)
  1106  	if err != nil {
  1107  		return nil, err
  1108  	}
  1109  	operation.RuntimeOperation.ID = op.ID
  1110  	if op.OrchestrationID.Valid {
  1111  		operation.OrchestrationID = op.OrchestrationID.String
  1112  	}
  1113  
  1114  	return &operation, nil
  1115  }
  1116  
  1117  func (s *operations) toOperationList(ops []dbmodel.OperationDTO) ([]internal.Operation, error) {
  1118  	result := make([]internal.Operation, 0)
  1119  
  1120  	for _, op := range ops {
  1121  
  1122  		var operation internal.Operation
  1123  		var err error
  1124  		err = json.Unmarshal([]byte(op.Data), &operation)
  1125  		if err != nil {
  1126  			return nil, fmt.Errorf("unable to unmarshall operation data: %w", err)
  1127  		}
  1128  
  1129  		o, err := s.toOperation(&op, operation)
  1130  		if err != nil {
  1131  			return nil, fmt.Errorf("while converting to upgrade kyma operation: %w", err)
  1132  		}
  1133  		result = append(result, o)
  1134  	}
  1135  
  1136  	return result, nil
  1137  }
  1138  
  1139  func (s *operations) toUpgradeKymaOperationList(ops []dbmodel.OperationDTO) ([]internal.UpgradeKymaOperation, error) {
  1140  	result := make([]internal.UpgradeKymaOperation, 0)
  1141  
  1142  	for _, op := range ops {
  1143  		o, err := s.toUpgradeKymaOperation(&op)
  1144  		if err != nil {
  1145  			return nil, fmt.Errorf("while converting to upgrade kyma operation: %w", err)
  1146  		}
  1147  		result = append(result, *o)
  1148  	}
  1149  
  1150  	return result, nil
  1151  }
  1152  
  1153  func (s *operations) upgradeKymaOperationToDTO(op *internal.UpgradeKymaOperation) (dbmodel.OperationDTO, error) {
  1154  	serialized, err := json.Marshal(op)
  1155  	if err != nil {
  1156  		return dbmodel.OperationDTO{}, fmt.Errorf("while serializing upgrade kyma data %v: %w", op, err)
  1157  	}
  1158  
  1159  	ret, err := s.operationToDB(op.Operation)
  1160  	if err != nil {
  1161  		return dbmodel.OperationDTO{}, fmt.Errorf("while converting to operationDB %v: %w", op, err)
  1162  	}
  1163  	ret.Data = string(serialized)
  1164  	ret.Type = internal.OperationTypeUpgradeKyma
  1165  	ret.OrchestrationID = storage.StringToSQLNullString(op.OrchestrationID)
  1166  	return ret, nil
  1167  }
  1168  
  1169  func (s *operations) toUpgradeClusterOperation(op *dbmodel.OperationDTO) (*internal.UpgradeClusterOperation, error) {
  1170  	if op.Type != internal.OperationTypeUpgradeCluster {
  1171  		return nil, fmt.Errorf("expected operation type upgradeCluster, but was %s", op.Type)
  1172  	}
  1173  	var operation internal.UpgradeClusterOperation
  1174  	var err error
  1175  	err = json.Unmarshal([]byte(op.Data), &operation)
  1176  	if err != nil {
  1177  		return nil, fmt.Errorf("unable to unmarshall upgrade cluster data: %w", err)
  1178  	}
  1179  	operation.Operation, err = s.toOperation(op, operation.Operation)
  1180  	if err != nil {
  1181  		return nil, err
  1182  	}
  1183  	operation.RuntimeOperation.ID = op.ID
  1184  	if op.OrchestrationID.Valid {
  1185  		operation.OrchestrationID = op.OrchestrationID.String
  1186  	}
  1187  
  1188  	return &operation, nil
  1189  }
  1190  
  1191  func (s *operations) toUpgradeClusterOperationList(ops []dbmodel.OperationDTO) ([]internal.UpgradeClusterOperation, error) {
  1192  	result := make([]internal.UpgradeClusterOperation, 0)
  1193  
  1194  	for _, op := range ops {
  1195  		o, err := s.toUpgradeClusterOperation(&op)
  1196  		if err != nil {
  1197  			return nil, fmt.Errorf("while converting to upgrade cluster operation: %w", err)
  1198  		}
  1199  		result = append(result, *o)
  1200  	}
  1201  
  1202  	return result, nil
  1203  }
  1204  
  1205  func (s *operations) upgradeClusterOperationToDTO(op *internal.UpgradeClusterOperation) (dbmodel.OperationDTO, error) {
  1206  	serialized, err := json.Marshal(op)
  1207  	if err != nil {
  1208  		return dbmodel.OperationDTO{}, fmt.Errorf("while serializing upgradeCluster data %v: %w", op, err)
  1209  	}
  1210  
  1211  	ret, err := s.operationToDB(op.Operation)
  1212  	if err != nil {
  1213  		return dbmodel.OperationDTO{}, fmt.Errorf("while converting to operationDB %v: %w", op, err)
  1214  	}
  1215  	ret.Data = string(serialized)
  1216  	ret.Type = internal.OperationTypeUpgradeCluster
  1217  	ret.OrchestrationID = storage.StringToSQLNullString(op.OrchestrationID)
  1218  	return ret, nil
  1219  }
  1220  
  1221  func (s *operations) updateOperationToDTO(op *internal.UpdatingOperation) (dbmodel.OperationDTO, error) {
  1222  	serialized, err := json.Marshal(op)
  1223  	if err != nil {
  1224  		return dbmodel.OperationDTO{}, fmt.Errorf("while serializing update data %v: %w", op, err)
  1225  	}
  1226  
  1227  	ret, err := s.operationToDB(op.Operation)
  1228  	if err != nil {
  1229  		return dbmodel.OperationDTO{}, fmt.Errorf("while converting to operationDB %v: %w", op, err)
  1230  	}
  1231  	ret.Data = string(serialized)
  1232  	ret.Type = internal.OperationTypeUpdate
  1233  	ret.OrchestrationID = storage.StringToSQLNullString(op.OrchestrationID)
  1234  	return ret, nil
  1235  }
  1236  
  1237  func (s *operations) toUpdateOperation(op *dbmodel.OperationDTO) (*internal.UpdatingOperation, error) {
  1238  	if op.Type != internal.OperationTypeUpdate {
  1239  		return nil, fmt.Errorf(fmt.Sprintf("expected operation type update, but was %s", op.Type))
  1240  	}
  1241  	var operation internal.UpdatingOperation
  1242  	var err error
  1243  	err = json.Unmarshal([]byte(op.Data), &operation)
  1244  	if err != nil {
  1245  		return nil, fmt.Errorf("unable to unmarshall provisioning data")
  1246  	}
  1247  	operation.Operation, err = s.toOperation(op, operation.Operation)
  1248  	if err != nil {
  1249  		return nil, err
  1250  	}
  1251  
  1252  	return &operation, nil
  1253  }
  1254  
  1255  func (s *operations) toUpdateOperationList(ops []dbmodel.OperationDTO) ([]internal.UpdatingOperation, error) {
  1256  	result := make([]internal.UpdatingOperation, 0)
  1257  
  1258  	for _, op := range ops {
  1259  		o, err := s.toUpdateOperation(&op)
  1260  		if err != nil {
  1261  			return nil, fmt.Errorf("while converting to upgrade cluster operation: %w", err)
  1262  		}
  1263  		result = append(result, *o)
  1264  	}
  1265  
  1266  	return result, nil
  1267  }
  1268  
  1269  func (s *operations) getByID(id string) (*dbmodel.OperationDTO, error) {
  1270  	var lastErr dberr.Error
  1271  	session := s.NewReadSession()
  1272  	operation := dbmodel.OperationDTO{}
  1273  
  1274  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1275  		operation, lastErr = session.GetOperationByID(id)
  1276  		if lastErr != nil {
  1277  			if dberr.IsNotFound(lastErr) {
  1278  				lastErr = dberr.NotFound("Operation with id %s not exist", id)
  1279  				return false, lastErr
  1280  			}
  1281  			log.Errorf("while reading operation from the storage: %v", lastErr)
  1282  			return false, nil
  1283  		}
  1284  		return true, nil
  1285  	})
  1286  
  1287  	if err != nil {
  1288  		return nil, err
  1289  	}
  1290  
  1291  	return &operation, nil
  1292  }
  1293  
  1294  func (s *operations) insert(dto dbmodel.OperationDTO) error {
  1295  	session := s.NewWriteSession()
  1296  	var lastErr error
  1297  	_ = wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1298  		lastErr = session.InsertOperation(dto)
  1299  		if lastErr != nil {
  1300  			log.Errorf("while insert operation: %v", lastErr)
  1301  			return false, nil
  1302  		}
  1303  		// TODO: insert link to orchestration
  1304  		return true, nil
  1305  	})
  1306  	return lastErr
  1307  }
  1308  
  1309  func (s *operations) getByInstanceID(id string) (*dbmodel.OperationDTO, error) {
  1310  	session := s.NewReadSession()
  1311  	operation := dbmodel.OperationDTO{}
  1312  	var lastErr dberr.Error
  1313  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1314  		operation, lastErr = session.GetOperationByInstanceID(id)
  1315  		if lastErr != nil {
  1316  			if dberr.IsNotFound(lastErr) {
  1317  				lastErr = dberr.NotFound("operation does not exist")
  1318  				return false, lastErr
  1319  			}
  1320  			log.Errorf("while reading operation from the storage: %v", lastErr)
  1321  			return false, nil
  1322  		}
  1323  		return true, nil
  1324  	})
  1325  
  1326  	return &operation, err
  1327  }
  1328  
  1329  func (s *operations) getByTypeAndInstanceID(id string, opType internal.OperationType) (*dbmodel.OperationDTO, error) {
  1330  	session := s.NewReadSession()
  1331  	operation := dbmodel.OperationDTO{}
  1332  	var lastErr dberr.Error
  1333  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1334  		operation, lastErr = session.GetOperationByTypeAndInstanceID(id, opType)
  1335  		if lastErr != nil {
  1336  			if dberr.IsNotFound(lastErr) {
  1337  				lastErr = dberr.NotFound("operation does not exist")
  1338  				return false, lastErr
  1339  			}
  1340  			log.Errorf("while reading operation from the storage: %v", lastErr)
  1341  			return false, nil
  1342  		}
  1343  		return true, nil
  1344  	})
  1345  
  1346  	return &operation, err
  1347  }
  1348  
  1349  func (s *operations) update(operation dbmodel.OperationDTO) error {
  1350  	session := s.NewWriteSession()
  1351  
  1352  	var lastErr error
  1353  	_ = wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1354  		lastErr = session.UpdateOperation(operation)
  1355  		if lastErr != nil && dberr.IsNotFound(lastErr) {
  1356  			_, lastErr = s.NewReadSession().GetOperationByID(operation.ID)
  1357  			if lastErr != nil {
  1358  				log.Errorf("while getting operation: %v", lastErr)
  1359  				return false, nil
  1360  			}
  1361  
  1362  			// the operation exists but the version is different
  1363  			lastErr = dberr.Conflict("operation update conflict, operation ID: %s", operation.ID)
  1364  			log.Warn(lastErr.Error())
  1365  			return false, lastErr
  1366  		}
  1367  		return true, nil
  1368  	})
  1369  	return lastErr
  1370  }
  1371  
  1372  func (s *operations) listOperationsByInstanceIdAndType(instanceId string, operationType internal.OperationType) ([]dbmodel.OperationDTO, error) {
  1373  	session := s.NewReadSession()
  1374  	operations := []dbmodel.OperationDTO{}
  1375  	var lastErr dberr.Error
  1376  
  1377  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1378  		operations, lastErr = session.GetOperationsByTypeAndInstanceID(instanceId, operationType)
  1379  		if lastErr != nil {
  1380  			log.Errorf("while reading operation from the storage: %v", lastErr)
  1381  			return false, nil
  1382  		}
  1383  		return true, nil
  1384  	})
  1385  	if err != nil {
  1386  		return nil, lastErr
  1387  	}
  1388  	return operations, lastErr
  1389  }
  1390  
  1391  func (s *operations) listOperationsByType(operationType internal.OperationType) ([]dbmodel.OperationDTO, error) {
  1392  	session := s.NewReadSession()
  1393  	operations := []dbmodel.OperationDTO{}
  1394  	var lastErr dberr.Error
  1395  
  1396  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1397  		operations, lastErr = session.ListOperationsByType(operationType)
  1398  		if lastErr != nil {
  1399  			log.Errorf("while reading operation from the storage: %v", lastErr)
  1400  			return false, nil
  1401  		}
  1402  		return true, nil
  1403  	})
  1404  	if err != nil {
  1405  		return nil, lastErr
  1406  	}
  1407  	return operations, lastErr
  1408  }
  1409  
  1410  func (s *operations) listOperationsByInstanceId(instanceId string) ([]dbmodel.OperationDTO, error) {
  1411  	session := s.NewReadSession()
  1412  	operations := []dbmodel.OperationDTO{}
  1413  	var lastErr dberr.Error
  1414  
  1415  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
  1416  		operations, lastErr = session.GetOperationsByInstanceID(instanceId)
  1417  		if lastErr != nil {
  1418  			log.Errorf("while reading operation from the storage: %v", lastErr)
  1419  			return false, nil
  1420  		}
  1421  		return true, nil
  1422  	})
  1423  	if err != nil {
  1424  		return nil, lastErr
  1425  	}
  1426  	return operations, lastErr
  1427  }