github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/storage/postsql/write.go (about) 1 package postsql 2 3 import ( 4 "time" 5 6 "github.com/google/uuid" 7 "github.com/kyma-project/kyma-environment-broker/common/events" 8 "github.com/kyma-project/kyma-environment-broker/internal/storage/dbmodel" 9 10 "github.com/gocraft/dbr" 11 "github.com/kyma-project/kyma-environment-broker/internal/storage/dberr" 12 "github.com/lib/pq" 13 ) 14 15 const ( 16 UniqueViolationErrorCode = "23505" 17 ) 18 19 type writeSession struct { 20 session *dbr.Session 21 transaction *dbr.Tx 22 } 23 24 func (ws writeSession) InsertInstance(instance dbmodel.InstanceDTO) dberr.Error { 25 _, err := ws.insertInto(InstancesTableName). 26 Pair("instance_id", instance.InstanceID). 27 Pair("runtime_id", instance.RuntimeID). 28 Pair("global_account_id", instance.GlobalAccountID). 29 Pair("subscription_global_account_id", instance.SubscriptionGlobalAccountID). 30 Pair("sub_account_id", instance.SubAccountID). 31 Pair("service_id", instance.ServiceID). 32 Pair("service_name", instance.ServiceName). 33 Pair("service_plan_id", instance.ServicePlanID). 34 Pair("service_plan_name", instance.ServicePlanName). 35 Pair("dashboard_url", instance.DashboardURL). 36 Pair("provisioning_parameters", instance.ProvisioningParameters). 37 Pair("provider_region", instance.ProviderRegion). 38 Pair("provider", instance.Provider). 39 Pair("deleted_at", instance.DeletedAt). 40 Pair("expired_at", instance.ExpiredAt). 41 Pair("version", instance.Version). 42 Exec() 43 44 if err != nil { 45 if err, ok := err.(*pq.Error); ok { 46 if err.Code == UniqueViolationErrorCode { 47 return dberr.AlreadyExists("operation with id %s already exist", instance.InstanceID) 48 } 49 } 50 return dberr.Internal("Failed to insert record to Instance table: %s", err) 51 } 52 53 return nil 54 } 55 56 func (ws writeSession) DeleteInstance(instanceID string) dberr.Error { 57 _, err := ws.deleteFrom(InstancesTableName). 58 Where(dbr.Eq("instance_id", instanceID)). 59 Exec() 60 61 if err != nil { 62 return dberr.Internal("Failed to delete record from Instance table: %s", err) 63 } 64 return nil 65 } 66 67 func (ws writeSession) UpdateInstance(instance dbmodel.InstanceDTO) dberr.Error { 68 res, err := ws.update(InstancesTableName). 69 Where(dbr.Eq("instance_id", instance.InstanceID)). 70 Where(dbr.Eq("version", instance.Version)). 71 Set("instance_id", instance.InstanceID). 72 Set("runtime_id", instance.RuntimeID). 73 Set("global_account_id", instance.GlobalAccountID). 74 Set("subscription_global_account_id", instance.SubscriptionGlobalAccountID). 75 Set("service_id", instance.ServiceID). 76 Set("service_plan_id", instance.ServicePlanID). 77 Set("dashboard_url", instance.DashboardURL). 78 Set("provisioning_parameters", instance.ProvisioningParameters). 79 Set("provider_region", instance.ProviderRegion). 80 Set("provider", instance.Provider). 81 Set("updated_at", time.Now()). 82 Set("deleted_at", instance.DeletedAt). 83 Set("version", instance.Version+1). 84 Set("expired_at", instance.ExpiredAt). 85 Exec() 86 if err != nil { 87 return dberr.Internal("Failed to update record to Instance table: %s", err) 88 } 89 rAffected, err := res.RowsAffected() 90 if err != nil { 91 // the optimistic locking requires numbers of rows affected 92 return dberr.Internal("the DB driver does not support RowsAffected operation") 93 } 94 if rAffected == int64(0) { 95 return dberr.NotFound("Cannot find Instance with ID:'%s' Version: %v", instance.InstanceID, instance.Version) 96 } 97 98 return nil 99 } 100 101 func (ws writeSession) InsertOperation(op dbmodel.OperationDTO) dberr.Error { 102 _, err := ws.insertInto(OperationTableName). 103 Pair("id", op.ID). 104 Pair("instance_id", op.InstanceID). 105 Pair("version", op.Version). 106 Pair("created_at", op.CreatedAt). 107 Pair("updated_at", op.UpdatedAt). 108 Pair("description", op.Description). 109 Pair("state", op.State). 110 Pair("target_operation_id", op.TargetOperationID). 111 Pair("type", op.Type). 112 Pair("data", op.Data). 113 Pair("orchestration_id", op.OrchestrationID.String). 114 Pair("provisioning_parameters", op.ProvisioningParameters.String). 115 Pair("finished_stages", op.FinishedStages). 116 Exec() 117 118 if err != nil { 119 if err, ok := err.(*pq.Error); ok { 120 if err.Code == UniqueViolationErrorCode { 121 return dberr.AlreadyExists("operation with id %s already exist", op.ID) 122 } 123 } 124 return dberr.Internal("Failed to insert record to operations table: %s", err) 125 } 126 127 return nil 128 } 129 130 func (ws writeSession) InsertOrchestration(o dbmodel.OrchestrationDTO) dberr.Error { 131 _, err := ws.insertInto(OrchestrationTableName). 132 Pair("orchestration_id", o.OrchestrationID). 133 Pair("created_at", o.CreatedAt). 134 Pair("updated_at", o.UpdatedAt). 135 Pair("description", o.Description). 136 Pair("state", o.State). 137 Pair("type", o.Type). 138 Pair("parameters", o.Parameters). 139 Exec() 140 141 if err != nil { 142 if err, ok := err.(*pq.Error); ok { 143 if err.Code == UniqueViolationErrorCode { 144 return dberr.AlreadyExists("Orchestration with id %s already exist", o.OrchestrationID) 145 } 146 } 147 return dberr.Internal("Failed to insert record to orchestration table: %s", err) 148 } 149 150 return nil 151 } 152 153 func (ws writeSession) UpdateOrchestration(o dbmodel.OrchestrationDTO) dberr.Error { 154 res, err := ws.update(OrchestrationTableName). 155 Where(dbr.Eq("orchestration_id", o.OrchestrationID)). 156 Set("created_at", o.CreatedAt). 157 Set("updated_at", o.UpdatedAt). 158 Set("description", o.Description). 159 Set("state", o.State). 160 Set("type", o.Type). 161 Set("parameters", o.Parameters). 162 Exec() 163 164 if err != nil { 165 if err == dbr.ErrNotFound { 166 return dberr.NotFound("Cannot find Orchestration with ID:'%s'", o.OrchestrationID) 167 } 168 return dberr.Internal("Failed to update record to Orchestration table: %s", err) 169 } 170 rAffected, e := res.RowsAffected() 171 if e != nil { 172 // the optimistic locking requires numbers of rows affected 173 return dberr.Internal("the DB driver does not support RowsAffected operation") 174 } 175 if rAffected == int64(0) { 176 return dberr.NotFound("Cannot find Orchestration with ID:'%s'", o.OrchestrationID) 177 } 178 179 return nil 180 } 181 182 func (ws writeSession) InsertRuntimeState(state dbmodel.RuntimeStateDTO) dberr.Error { 183 _, err := ws.insertInto(RuntimeStateTableName). 184 Pair("id", state.ID). 185 Pair("operation_id", state.OperationID). 186 Pair("runtime_id", state.RuntimeID). 187 Pair("created_at", state.CreatedAt). 188 Pair("kyma_version", state.KymaVersion). 189 Pair("k8s_version", state.K8SVersion). 190 Pair("kyma_config", state.KymaConfig). 191 Pair("cluster_config", state.ClusterConfig). 192 Pair("cluster_setup", state.ClusterSetup). 193 Exec() 194 195 if err != nil { 196 if err, ok := err.(*pq.Error); ok { 197 if err.Code == UniqueViolationErrorCode { 198 return dberr.AlreadyExists("RuntimeState with id %s already exist", state.ID) 199 } 200 } 201 return dberr.Internal("Failed to insert record to RuntimeState table: %s", err) 202 } 203 204 return nil 205 } 206 207 func (ws writeSession) UpdateOperation(op dbmodel.OperationDTO) dberr.Error { 208 res, err := ws.update(OperationTableName). 209 Where(dbr.Eq("id", op.ID)). 210 Where(dbr.Eq("version", op.Version)). 211 Set("instance_id", op.InstanceID). 212 Set("version", op.Version+1). 213 Set("created_at", op.CreatedAt). 214 Set("updated_at", op.UpdatedAt). 215 Set("description", op.Description). 216 Set("state", op.State). 217 Set("target_operation_id", op.TargetOperationID). 218 Set("type", op.Type). 219 Set("data", op.Data). 220 Set("orchestration_id", op.OrchestrationID.String). 221 Set("provisioning_parameters", op.ProvisioningParameters.String). 222 Set("finished_stages", op.FinishedStages). 223 Exec() 224 225 if err != nil { 226 if err == dbr.ErrNotFound { 227 return dberr.NotFound("Cannot find Operation with ID:'%s'", op.ID) 228 } 229 return dberr.Internal("Failed to update record to Operation table: %s", err) 230 } 231 rAffected, e := res.RowsAffected() 232 if e != nil { 233 // the optimistic locking requires numbers of rows affected 234 return dberr.Internal("the DB driver does not support RowsAffected operation") 235 } 236 if rAffected == int64(0) { 237 return dberr.NotFound("Cannot find Operation with ID:'%s' Version: %v", op.ID, op.Version) 238 } 239 240 return nil 241 } 242 243 func (ws writeSession) InsertEvent(level events.EventLevel, message, instanceID, operationID string) dberr.Error { 244 _, err := ws.insertInto("events"). 245 Pair("id", uuid.NewString()). 246 Pair("level", level). 247 Pair("instance_id", instanceID). 248 Pair("operation_id", operationID). 249 Pair("message", message). 250 Pair("created_at", time.Now()). 251 Exec() 252 if err != nil { 253 return dberr.Internal("Failed to insert event: %s", err) 254 } 255 return nil 256 } 257 258 func (ws writeSession) DeleteEvents(until time.Time) dberr.Error { 259 _, err := ws.deleteFrom("events"). 260 Where(dbr.Lte("created_at", until)). 261 Exec() 262 if err != nil { 263 return dberr.Internal("failed to delete events created until %v: %v", until.Format(time.RFC1123Z), err) 264 } 265 return nil 266 } 267 268 func (ws writeSession) Commit() dberr.Error { 269 err := ws.transaction.Commit() 270 if err != nil { 271 return dberr.Internal("Failed to commit transaction: %s", err) 272 } 273 274 return nil 275 } 276 277 func (ws writeSession) RollbackUnlessCommitted() { 278 ws.transaction.RollbackUnlessCommitted() 279 } 280 281 func (ws writeSession) insertInto(table string) *dbr.InsertStmt { 282 if ws.transaction != nil { 283 return ws.transaction.InsertInto(table) 284 } 285 286 return ws.session.InsertInto(table) 287 } 288 289 func (ws writeSession) deleteFrom(table string) *dbr.DeleteStmt { 290 if ws.transaction != nil { 291 return ws.transaction.DeleteFrom(table) 292 } 293 294 return ws.session.DeleteFrom(table) 295 } 296 297 func (ws writeSession) update(table string) *dbr.UpdateStmt { 298 if ws.transaction != nil { 299 return ws.transaction.Update(table) 300 } 301 302 return ws.session.Update(table) 303 }