backend/bms_app/services/status_handlers/operation.py (62 lines of code) (raw):

# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from bms_app.models import ( FINISHED_OPERATION_STATUSES, OperationDetails, OperationStatus, Wave, db ) from .operation_detail import ( DeploymentOperationDetailStatusHandler, FailOverOperationDetailStatusHandler, PreRestoreOperationDetailStatusHandler, RestoreOperationDetailStatusHandler, RollbackOperationDetailStatusHandler, RollbackRestoreOperationDetailStatusHandler ) class BaseOperationStatusHandler: """Base class to process operation status changes.""" OP_DETAILS_STATUS_HANDLER = None def __init__(self, operation, completed_at): self.operation = operation self.completed_at = completed_at def set_status(self, status): self.operation.status = status db.session.add(self.operation) def terminate(self): # check if operation status has been processed in the expected way # if operation if not in one of expected status # it means that something went wrong # and it make sense to mark operation as failed if self.operation.status not in FINISHED_OPERATION_STATUSES: self._fail_all_operation_details() self.finish() def finish(self): """Make all necessary actions to finish operation.""" agg_status = self._calc_aggregated_operation_status() self.operation.status = agg_status self.operation.completed_at = self.completed_at self._post_finish() db.session.add(self.operation) def _post_finish(self): pass def _fail_all_operation_details(self): """Set all OperationDetails.status to FAILED.""" qs = db.session.query(OperationDetails) \ .filter(OperationDetails.operation_id == self.operation.id) \ .all() # use OperationDetailStatusHandler to set source_db status correctly for op_detail in qs: self.OP_DETAILS_STATUS_HANDLER( op_detail, self.completed_at ).set_fail() def _calc_aggregated_operation_status(self): """Return aggregated operation status: 'COMPLETE/FAILED' FAILED - if at least one target/mapping is failed COMPLETE - if all are complete/successful """ failed = OperationDetails.query.filter( OperationDetails.operation_id == self.operation.id, OperationDetails.status != OperationStatus.COMPLETE ).count() return OperationStatus.FAILED if failed else OperationStatus.COMPLETE class DeploymentOperationStatusHandler(BaseOperationStatusHandler): """Handler to process Wave Operation status/step changes.""" OP_DETAILS_STATUS_HANDLER = DeploymentOperationDetailStatusHandler def _post_finish(self): self._handle_wave() def _handle_wave(self): """Set wave.is_running = False.""" Wave.query.filter(Wave.id == self.operation.wave_id) \ .update({'is_running': False}) class PreRestoreOperationStatusHandler(BaseOperationStatusHandler): """Handler to process Pre_restore Operation status/step changes.""" OP_DETAILS_STATUS_HANDLER = PreRestoreOperationDetailStatusHandler class RestoreOperationStatusHandler(BaseOperationStatusHandler): """Handler to process Restore Operation status/step changes.""" OP_DETAILS_STATUS_HANDLER = RestoreOperationDetailStatusHandler class RollbackOperationStatusHandler(DeploymentOperationStatusHandler): """Handler to process Rollback Operation status/step changes.""" OP_DETAILS_STATUS_HANDLER = RollbackOperationDetailStatusHandler class RollbackRestoreOperationStatusHandler(BaseOperationStatusHandler): """Handler to process Rollback Operation status/step changes.""" OP_DETAILS_STATUS_HANDLER = RollbackRestoreOperationDetailStatusHandler class FailOverOperationStatusHandler(BaseOperationStatusHandler): """Handler to process FailOver Operation status/step changes.""" OP_DETAILS_STATUS_HANDLER = FailOverOperationDetailStatusHandler