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 }