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

     1  package postsql
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	reconcilerApi "github.com/kyma-incubator/reconciler/pkg/keb"
     8  	"github.com/kyma-project/control-plane/components/provisioner/pkg/gqlschema"
     9  	"github.com/kyma-project/kyma-environment-broker/internal"
    10  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dberr"
    11  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dbmodel"
    12  	"github.com/kyma-project/kyma-environment-broker/internal/storage/postsql"
    13  	log "github.com/sirupsen/logrus"
    14  	"k8s.io/apimachinery/pkg/util/wait"
    15  )
    16  
    17  type runtimeState struct {
    18  	postsql.Factory
    19  
    20  	cipher Cipher
    21  }
    22  
    23  func NewRuntimeStates(sess postsql.Factory, cipher Cipher) *runtimeState {
    24  	return &runtimeState{
    25  		Factory: sess,
    26  		cipher:  cipher,
    27  	}
    28  }
    29  
    30  func (s *runtimeState) Insert(runtimeState internal.RuntimeState) error {
    31  	state, err := s.runtimeStateToDB(runtimeState)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	sess := s.NewWriteSession()
    36  	return wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
    37  		err := sess.InsertRuntimeState(state)
    38  		if err != nil {
    39  			log.Errorf("while saving runtime state ID %s: %v", runtimeState.ID, err)
    40  			return false, nil
    41  		}
    42  		return true, nil
    43  	})
    44  }
    45  
    46  func (s *runtimeState) ListByRuntimeID(runtimeID string) ([]internal.RuntimeState, error) {
    47  	sess := s.NewReadSession()
    48  	states := make([]dbmodel.RuntimeStateDTO, 0)
    49  	var lastErr dberr.Error
    50  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
    51  		states, lastErr = sess.ListRuntimeStateByRuntimeID(runtimeID)
    52  		if lastErr != nil {
    53  			if dberr.IsNotFound(lastErr) {
    54  				return false, dberr.NotFound("RuntimeStates not found")
    55  			}
    56  			log.Errorf("while getting RuntimeState: %v", lastErr)
    57  			return false, nil
    58  		}
    59  		return true, nil
    60  	})
    61  	if err != nil {
    62  		return nil, lastErr
    63  	}
    64  	result, err := s.toRuntimeStates(states)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	return result, nil
    69  }
    70  
    71  func (s *runtimeState) GetByOperationID(operationID string) (internal.RuntimeState, error) {
    72  	sess := s.NewReadSession()
    73  	state := dbmodel.RuntimeStateDTO{}
    74  	var lastErr dberr.Error
    75  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
    76  		state, lastErr = sess.GetRuntimeStateByOperationID(operationID)
    77  		if lastErr != nil {
    78  			if dberr.IsNotFound(lastErr) {
    79  				return false, dberr.NotFound("RuntimeState for operation %s not found", operationID)
    80  			}
    81  			log.Errorf("while getting RuntimeState: %v", lastErr)
    82  			return false, nil
    83  		}
    84  		return true, nil
    85  	})
    86  	if err != nil {
    87  		return internal.RuntimeState{}, lastErr
    88  	}
    89  	result, err := s.toRuntimeState(&state)
    90  	if err != nil {
    91  		return internal.RuntimeState{}, fmt.Errorf("while converting runtime states: %w", err)
    92  	}
    93  
    94  	return result, nil
    95  }
    96  
    97  func (s *runtimeState) GetLatestByRuntimeID(runtimeID string) (internal.RuntimeState, error) {
    98  	sess := s.NewReadSession()
    99  	var state dbmodel.RuntimeStateDTO
   100  	var lastErr dberr.Error
   101  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   102  		state, lastErr = sess.GetLatestRuntimeStateByRuntimeID(runtimeID)
   103  		if lastErr != nil {
   104  			if dberr.IsNotFound(lastErr) {
   105  				return false, dberr.NotFound("RuntimeState for runtime %s not found", runtimeID)
   106  			}
   107  			log.Errorf("while getting RuntimeState: %v", lastErr)
   108  			return false, nil
   109  		}
   110  		return true, nil
   111  	})
   112  	if err != nil {
   113  		return internal.RuntimeState{}, lastErr
   114  	}
   115  	result, err := s.toRuntimeState(&state)
   116  	if err != nil {
   117  		return internal.RuntimeState{}, fmt.Errorf("while converting runtime state: %w", err)
   118  	}
   119  
   120  	return result, nil
   121  }
   122  
   123  func (s *runtimeState) GetLatestWithReconcilerInputByRuntimeID(runtimeID string) (internal.RuntimeState, error) {
   124  	sess := s.NewReadSession()
   125  	var state dbmodel.RuntimeStateDTO
   126  	var lastErr dberr.Error
   127  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   128  		state, lastErr = sess.GetLatestRuntimeStateWithReconcilerInputByRuntimeID(runtimeID)
   129  		if lastErr != nil {
   130  			if dberr.IsNotFound(lastErr) {
   131  				return false, dberr.NotFound("RuntimeState for runtime %s not found", runtimeID)
   132  			}
   133  			log.Errorf("while getting RuntimeState: %v", lastErr)
   134  			return false, nil
   135  		}
   136  		return true, nil
   137  	})
   138  	if err != nil {
   139  		return internal.RuntimeState{}, lastErr
   140  	}
   141  	result, err := s.toRuntimeState(&state)
   142  	if err != nil {
   143  		return internal.RuntimeState{}, fmt.Errorf("while converting runtime state: %w", err)
   144  	}
   145  
   146  	return result, nil
   147  }
   148  
   149  func (s *runtimeState) GetLatestWithKymaVersionByRuntimeID(runtimeID string) (internal.RuntimeState, error) {
   150  	sess := s.NewReadSession()
   151  	var state dbmodel.RuntimeStateDTO
   152  	var lastErr dberr.Error
   153  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   154  		state, lastErr = sess.GetLatestRuntimeStateWithKymaVersionByRuntimeID(runtimeID)
   155  		if lastErr != nil {
   156  			if dberr.IsNotFound(lastErr) {
   157  				return false, dberr.NotFound("RuntimeState for runtime %s not found", runtimeID)
   158  			}
   159  			log.Errorf("while getting RuntimeState: %v", lastErr)
   160  			return false, nil
   161  		}
   162  		return true, nil
   163  	})
   164  	if err != nil {
   165  		return internal.RuntimeState{}, lastErr
   166  	}
   167  
   168  	result, err := s.toRuntimeState(&state)
   169  	if err != nil {
   170  		return internal.RuntimeState{}, fmt.Errorf("while converting runtime state: %w", err)
   171  	}
   172  	if result.ClusterSetup != nil && result.ClusterSetup.KymaConfig.Version != "" {
   173  		return result, nil
   174  	}
   175  	if result.KymaConfig.Version != "" {
   176  		return result, nil
   177  	}
   178  	if result.KymaVersion != "" {
   179  		return result, nil
   180  	}
   181  
   182  	return internal.RuntimeState{}, fmt.Errorf("failed to find RuntimeState with kyma version for runtime %s ", runtimeID)
   183  }
   184  
   185  func (s *runtimeState) GetLatestWithOIDCConfigByRuntimeID(runtimeID string) (internal.RuntimeState, error) {
   186  	sess := s.NewReadSession()
   187  	var state dbmodel.RuntimeStateDTO
   188  	var lastErr dberr.Error
   189  	err := wait.PollImmediate(defaultRetryInterval, defaultRetryTimeout, func() (bool, error) {
   190  		state, lastErr = sess.GetLatestRuntimeStateWithOIDCConfigByRuntimeID(runtimeID)
   191  		if lastErr != nil {
   192  			if dberr.IsNotFound(lastErr) {
   193  				return false, dberr.NotFound("RuntimeState for runtime %s not found", runtimeID)
   194  			}
   195  			log.Errorf("while getting RuntimeState: %v", lastErr)
   196  			return false, nil
   197  		}
   198  		return true, nil
   199  	})
   200  	if err != nil {
   201  		return internal.RuntimeState{}, lastErr
   202  	}
   203  
   204  	result, err := s.toRuntimeState(&state)
   205  	if err != nil {
   206  		return internal.RuntimeState{}, fmt.Errorf("while converting runtime state: %w", err)
   207  	}
   208  	if result.ClusterConfig.OidcConfig != nil {
   209  		return result, nil
   210  	}
   211  
   212  	return internal.RuntimeState{}, fmt.Errorf("failed to find RuntimeState with OIDC config for runtime %s ", runtimeID)
   213  }
   214  
   215  func (s *runtimeState) runtimeStateToDB(state internal.RuntimeState) (dbmodel.RuntimeStateDTO, error) {
   216  	kymaCfg, err := json.Marshal(state.KymaConfig)
   217  	if err != nil {
   218  		return dbmodel.RuntimeStateDTO{}, fmt.Errorf("while encoding kyma config: %w", err)
   219  	}
   220  	clusterCfg, err := json.Marshal(state.ClusterConfig)
   221  	if err != nil {
   222  		return dbmodel.RuntimeStateDTO{}, fmt.Errorf("while encoding cluster config: %w", err)
   223  	}
   224  	clusterSetup, err := s.provideClusterSetup(state.ClusterSetup)
   225  	if err != nil {
   226  		return dbmodel.RuntimeStateDTO{}, err
   227  	}
   228  
   229  	encKymaCfg, err := s.cipher.Encrypt(kymaCfg)
   230  	if err != nil {
   231  		return dbmodel.RuntimeStateDTO{}, fmt.Errorf("while encrypting kyma config: %w", err)
   232  	}
   233  
   234  	return dbmodel.RuntimeStateDTO{
   235  		ID:            state.ID,
   236  		CreatedAt:     state.CreatedAt,
   237  		RuntimeID:     state.RuntimeID,
   238  		OperationID:   state.OperationID,
   239  		KymaConfig:    string(encKymaCfg),
   240  		ClusterConfig: string(clusterCfg),
   241  		ClusterSetup:  string(clusterSetup),
   242  		KymaVersion:   state.GetKymaVersion(),
   243  		K8SVersion:    state.ClusterConfig.KubernetesVersion,
   244  	}, nil
   245  }
   246  
   247  func (s *runtimeState) toRuntimeState(dto *dbmodel.RuntimeStateDTO) (internal.RuntimeState, error) {
   248  	var (
   249  		kymaCfg      gqlschema.KymaConfigInput
   250  		clusterCfg   gqlschema.GardenerConfigInput
   251  		clusterSetup *reconcilerApi.Cluster
   252  	)
   253  	if dto.KymaConfig != "" {
   254  		cfg, err := s.cipher.Decrypt([]byte(dto.KymaConfig))
   255  		if err != nil {
   256  			return internal.RuntimeState{}, fmt.Errorf("while decrypting kyma config: %w", err)
   257  		}
   258  		if err := json.Unmarshal(cfg, &kymaCfg); err != nil {
   259  			return internal.RuntimeState{}, fmt.Errorf("while unmarshall kyma config: %w", err)
   260  		}
   261  	}
   262  	if dto.ClusterConfig != "" {
   263  		if err := json.Unmarshal([]byte(dto.ClusterConfig), &clusterCfg); err != nil {
   264  			return internal.RuntimeState{}, fmt.Errorf("while unmarshall cluster config: %w", err)
   265  		}
   266  	}
   267  	if dto.ClusterSetup != "" {
   268  		setup, err := s.cipher.Decrypt([]byte(dto.ClusterSetup))
   269  		if err != nil {
   270  			return internal.RuntimeState{}, fmt.Errorf("while decrypting cluster setup: %w", err)
   271  		}
   272  		clusterSetup = &reconcilerApi.Cluster{}
   273  		if err := json.Unmarshal(setup, clusterSetup); err != nil {
   274  			return internal.RuntimeState{}, fmt.Errorf("while unmarshall cluster setup: %w", err)
   275  		}
   276  	}
   277  	return internal.RuntimeState{
   278  		ID:            dto.ID,
   279  		CreatedAt:     dto.CreatedAt,
   280  		RuntimeID:     dto.RuntimeID,
   281  		OperationID:   dto.OperationID,
   282  		KymaConfig:    kymaCfg,
   283  		ClusterConfig: clusterCfg,
   284  		ClusterSetup:  clusterSetup,
   285  		KymaVersion:   dto.KymaVersion,
   286  	}, nil
   287  }
   288  
   289  func (s *runtimeState) toRuntimeStates(states []dbmodel.RuntimeStateDTO) ([]internal.RuntimeState, error) {
   290  	result := make([]internal.RuntimeState, 0)
   291  
   292  	for _, state := range states {
   293  		r, err := s.toRuntimeState(&state)
   294  		if err != nil {
   295  			return nil, fmt.Errorf("while converting runtime states: %w", err)
   296  		}
   297  		result = append(result, r)
   298  	}
   299  
   300  	return result, nil
   301  }
   302  
   303  func (s *runtimeState) provideClusterSetup(clusterSetup *reconcilerApi.Cluster) ([]byte, error) {
   304  	marshalledClusterSetup, err := s.marshalClusterSetup(clusterSetup)
   305  	if err != nil {
   306  		return nil, fmt.Errorf("while encoding reconciler input: %w", err)
   307  	}
   308  	encryptedClusterSetup, err := s.encryptClusterSetup(marshalledClusterSetup)
   309  	if err != nil {
   310  		return nil, fmt.Errorf("while encrypting reconciler input: %w", err)
   311  	}
   312  	return encryptedClusterSetup, nil
   313  }
   314  
   315  func (s *runtimeState) marshalClusterSetup(clusterSetup *reconcilerApi.Cluster) ([]byte, error) {
   316  	var (
   317  		result []byte
   318  		err    error
   319  	)
   320  	if clusterSetup != nil {
   321  		result, err = json.Marshal(clusterSetup)
   322  		if err != nil {
   323  			return nil, err
   324  		}
   325  	} else {
   326  		result = make([]byte, 0, 0)
   327  	}
   328  	return result, nil
   329  }
   330  
   331  func (s *runtimeState) encryptClusterSetup(marshalledClusterSetup []byte) ([]byte, error) {
   332  	if string(marshalledClusterSetup) == "" {
   333  		return marshalledClusterSetup, nil
   334  	}
   335  	return s.cipher.Encrypt(marshalledClusterSetup)
   336  }