| Patricia Reinoso | 15ce47b | 2022-10-26 08:58:39 +0000 | [diff] [blame] | 1 | #!/usr/bin/python3 |
| 2 | |
| 3 | # Copyright 2022 Canonical Ltd. |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | |
| 17 | import logging |
| 18 | from osm_lcm.lcm_utils import LcmBase |
| 19 | from osm_common.dbbase import DbException |
| 20 | |
| 21 | |
| 22 | class PaasLcm(LcmBase): |
| 23 | timeout_create = 30 |
| 24 | |
| 25 | def __init__(self, msg, lcm_tasks, config, loop): |
| 26 | """Init, Connect to database, filesystem storage, and messaging |
| 27 | Args: |
| 28 | msg: Message object to be used to write the messages to Kafka Bus |
| 29 | lcm_tasks: Task object to register the tasks |
| 30 | config: two level dictionary with configuration. Top level should contain 'database', 'storage' |
| 31 | loop: Async event loop object |
| 32 | """ |
| 33 | |
| 34 | self.logger = logging.getLogger("lcm.paas") |
| 35 | self.loop = loop |
| 36 | self.lcm_tasks = lcm_tasks |
| 37 | |
| 38 | super().__init__(msg, self.logger) |
| 39 | |
| 40 | def _get_paas_by_id(self, paas_id: str) -> dict: |
| 41 | db_paas = self.db.get_one("paas", {"_id": paas_id}) |
| 42 | self.db.encrypt_decrypt_fields( |
| 43 | db_paas, |
| 44 | "decrypt", |
| 45 | ["secret"], |
| 46 | schema_version=db_paas["schema_version"], |
| 47 | salt=db_paas["_id"], |
| 48 | ) |
| 49 | return db_paas |
| 50 | |
| 51 | def _register_op_and_unlock( |
| 52 | self, paas_id, db_paas_update, action, op_id, operation |
| 53 | ): |
| 54 | """ |
| 55 | Args: |
| 56 | paas_id (str): ID of the PaaS to update. |
| 57 | db_paas_update (dict): content to update in DB. |
| 58 | action (str): 'create', 'edit', or 'delete'. |
| 59 | op_id (str): ID of the operation to unlock. |
| 60 | operation (dict): contains 'state' and 'details'. |
| 61 | """ |
| 62 | self.update_db_2("paas", paas_id, db_paas_update) |
| 63 | self.lcm_tasks.unlock_HA( |
| 64 | "paas", |
| 65 | action, |
| 66 | op_id, |
| 67 | operationState=operation["state"], |
| 68 | detailed_status=operation["details"], |
| 69 | ) |
| 70 | |
| 71 | def _set_status_connectivity_ok(self, db_paas_update: dict, operation: dict): |
| 72 | db_paas_update["_admin.operationalState"] = "ENABLED" |
| 73 | db_paas_update["_admin.detailed-status"] = "Connectivity: ok" |
| 74 | operation["details"] = "PaaS validated" |
| 75 | operation["state"] = "COMPLETED" |
| 76 | |
| 77 | def _set_status_exception_raised( |
| 78 | self, db_paas_update: dict, operation: dict, error_msg: str |
| 79 | ): |
| 80 | db_paas_update["_admin.operationalState"] = "ERROR" |
| 81 | db_paas_update["_admin.detailed-status"] = error_msg |
| 82 | operation["state"] = "FAILED" |
| 83 | operation["details"] = error_msg |
| 84 | |
| 85 | async def create(self, paas_content, order_id): |
| 86 | """HA tasks and backward compatibility: |
| 87 | If "paas_content" does not include "op_id", we a running a legacy NBI version. |
| 88 | In such a case, HA is not supported by NBI, "op_id" is None, and lock_HA() will do nothing. |
| 89 | Args: |
| 90 | paas_content (dict): Contains "op_id" and paas id ("_id") |
| 91 | order_id (str): Of the task |
| 92 | """ |
| 93 | op_id = paas_content.pop("op_id", None) |
| 94 | if not self.lcm_tasks.lock_HA("paas", "create", op_id): |
| 95 | return |
| 96 | |
| 97 | paas_id = paas_content["_id"] |
| 98 | self.logger.debug("Task paas_create={} {}".format(paas_id, "Enter")) |
| 99 | db_paas_update = {} |
| 100 | operation = {} |
| 101 | |
| 102 | try: |
| 103 | self._get_paas_by_id(paas_id) |
| 104 | self._set_status_connectivity_ok(db_paas_update, operation) |
| 105 | msg = "Task paas_create={} Done. Result: {}".format( |
| 106 | paas_id, operation["state"] |
| 107 | ) |
| 108 | self.logger.debug(msg) |
| 109 | |
| 110 | except Exception as e: |
| 111 | error_msg = "Failed with exception: {}".format(e) |
| 112 | self._set_status_exception_raised(db_paas_update, operation, error_msg) |
| 113 | self.logger.error("Task paas_create={} {}".format(paas_id, error_msg)) |
| 114 | finally: |
| 115 | try: |
| 116 | self._register_op_and_unlock( |
| 117 | paas_id, db_paas_update, "create", op_id, operation |
| 118 | ) |
| 119 | except DbException as e: |
| 120 | msg = "Task paas_create={} Cannot update database:{}".format(paas_id, e) |
| 121 | self.logger.error(msg) |
| 122 | self.lcm_tasks.remove("paas", paas_id, order_id) |
| 123 | |
| 124 | async def edit(self, paas_content, order_id): |
| 125 | """HA tasks and backward compatibility: |
| 126 | If "paas_content" does not include "op_id", we a running a legacy NBI version. |
| 127 | In such a case, HA is not supported by NBI, "op_id" is None, and lock_HA() will do nothing. |
| 128 | Args: |
| 129 | paas_content (dict): Contains "op_id" and paas id ("_id") |
| 130 | order_id (str): Of the task |
| 131 | """ |
| 132 | |
| 133 | op_id = paas_content.pop("op_id", None) |
| 134 | if not self.lcm_tasks.lock_HA("paas", "edit", op_id): |
| 135 | return |
| 136 | |
| 137 | paas_id = paas_content["_id"] |
| 138 | self.logger.debug("Task paas_edit={} {}".format(paas_id, "Enter")) |
| 139 | db_paas_update = {} |
| 140 | operation = {} |
| 141 | |
| 142 | try: |
| 143 | self._get_paas_by_id(paas_id) |
| 144 | self._set_status_connectivity_ok(db_paas_update, operation) |
| 145 | msg = "Task paas_edit={} Done. Result: {}".format( |
| 146 | paas_id, operation["state"] |
| 147 | ) |
| 148 | self.logger.debug(msg) |
| 149 | |
| 150 | except Exception as e: |
| 151 | error_msg = "Failed with exception: {}".format(e) |
| 152 | self._set_status_exception_raised(db_paas_update, operation, error_msg) |
| 153 | self.logger.error("Task paas_edit={} {}".format(paas_id, error_msg)) |
| 154 | finally: |
| 155 | try: |
| 156 | self._register_op_and_unlock( |
| 157 | paas_id, db_paas_update, "edit", op_id, operation |
| 158 | ) |
| 159 | except DbException as e: |
| 160 | msg = "Task paas_edit={} Cannot update database:{}".format(paas_id, e) |
| 161 | self.logger.error(msg) |
| 162 | self.lcm_tasks.remove("paas", paas_id, order_id) |
| 163 | |
| 164 | async def delete(self, paas_content, order_id): |
| 165 | """HA tasks and backward compatibility: |
| 166 | If "paas_content" does not include "op_id", we a running a legacy NBI version. |
| 167 | In such a case, HA is not supported by NBI, "op_id" is None, and lock_HA() will do nothing. |
| 168 | Args: |
| 169 | paas_content (dict): Contains "op_id" and paas id ("_id") |
| 170 | order_id (str): Of the task |
| 171 | """ |
| 172 | op_id = paas_content.pop("op_id", None) |
| 173 | if not self.lcm_tasks.lock_HA("paas", "delete", op_id): |
| 174 | return |
| 175 | |
| 176 | paas_id = paas_content["_id"] |
| 177 | db_paas_update = {} |
| 178 | operation = {} |
| 179 | |
| 180 | try: |
| 181 | msg = "Task paas_delete={}: Deleting paas from db".format(paas_id) |
| 182 | self.logger.debug(msg) |
| 183 | self.db.del_one("paas", {"_id": paas_id}) |
| 184 | db_paas_update = None |
| 185 | operation["state"] = "COMPLETED" |
| 186 | operation["details"] = "deleted" |
| 187 | msg = "Task paas_delete={}: Done. Result: {}".format( |
| 188 | paas_id, operation["state"] |
| 189 | ) |
| 190 | self.logger.debug(msg) |
| 191 | except Exception as e: |
| 192 | error_msg = "Failed with exception: {}".format(e) |
| 193 | self.logger.error("Task paas_delete={} {}".format(paas_id, error_msg)) |
| 194 | self._set_status_exception_raised(db_paas_update, operation, error_msg) |
| 195 | finally: |
| 196 | try: |
| 197 | self._register_op_and_unlock( |
| 198 | paas_id, db_paas_update, "delete", op_id, operation |
| 199 | ) |
| 200 | except DbException as e: |
| 201 | msg = "Task paas_delete={}: Cannot update database:{}".format( |
| 202 | paas_id, e |
| 203 | ) |
| 204 | self.logger.error(msg) |
| 205 | self.lcm_tasks.remove("paas", paas_id, order_id) |