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 }