OSM DB Update Charm
[osm/devops.git] / installers / charm / osm-update-db-operator / src / db_upgrade.py
1 # Copyright 2022 Canonical Ltd.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
13 # under the License.
14
15 """Upgrade DB charm module."""
16
17 import json
18 import logging
19
20 from pymongo import MongoClient
21
22 logger = logging.getLogger(__name__)
23
24
25 class MongoUpgrade1012:
26 """Upgrade MongoDB Database from OSM v10 to v12."""
27
28 @staticmethod
29 def _remove_namespace_from_k8s(nsrs, nsr):
30 namespace = "kube-system:"
31 if nsr["_admin"].get("deployed"):
32 k8s_list = []
33 for k8s in nsr["_admin"]["deployed"].get("K8s"):
34 if k8s.get("k8scluster-uuid"):
35 k8s["k8scluster-uuid"] = k8s["k8scluster-uuid"].replace(namespace, "", 1)
36 k8s_list.append(k8s)
37 myquery = {"_id": nsr["_id"]}
38 nsrs.update_one(myquery, {"$set": {"_admin.deployed.K8s": k8s_list}})
39
40 @staticmethod
41 def _update_nsr(osm_db):
42 """Update nsr.
43
44 Add vim_message = None if it does not exist.
45 Remove "namespace:" from k8scluster-uuid.
46 """
47 if "nsrs" not in osm_db.list_collection_names():
48 return
49 logger.info("Entering in MongoUpgrade1012._update_nsr function")
50
51 nsrs = osm_db["nsrs"]
52 for nsr in nsrs.find():
53 logger.debug(f"Updating {nsr['_id']} nsr")
54 for key, values in nsr.items():
55 if isinstance(values, list):
56 item_list = []
57 for value in values:
58 if isinstance(value, dict) and value.get("vim_info"):
59 index = list(value["vim_info"].keys())[0]
60 if not value["vim_info"][index].get("vim_message"):
61 value["vim_info"][index]["vim_message"] = None
62 item_list.append(value)
63 myquery = {"_id": nsr["_id"]}
64 nsrs.update_one(myquery, {"$set": {key: item_list}})
65 MongoUpgrade1012._remove_namespace_from_k8s(nsrs, nsr)
66
67 @staticmethod
68 def _update_vnfr(osm_db):
69 """Update vnfr.
70
71 Add vim_message to vdur if it does not exist.
72 Copy content of interfaces into interfaces_backup.
73 """
74 if "vnfrs" not in osm_db.list_collection_names():
75 return
76 logger.info("Entering in MongoUpgrade1012._update_vnfr function")
77 mycol = osm_db["vnfrs"]
78 for vnfr in mycol.find():
79 logger.debug(f"Updating {vnfr['_id']} vnfr")
80 vdur_list = []
81 for vdur in vnfr["vdur"]:
82 if vdur.get("vim_info"):
83 index = list(vdur["vim_info"].keys())[0]
84 if not vdur["vim_info"][index].get("vim_message"):
85 vdur["vim_info"][index]["vim_message"] = None
86 if vdur["vim_info"][index].get(
87 "interfaces", "Not found"
88 ) != "Not found" and not vdur["vim_info"][index].get("interfaces_backup"):
89 vdur["vim_info"][index]["interfaces_backup"] = vdur["vim_info"][index][
90 "interfaces"
91 ]
92 vdur_list.append(vdur)
93 myquery = {"_id": vnfr["_id"]}
94 mycol.update_one(myquery, {"$set": {"vdur": vdur_list}})
95
96 @staticmethod
97 def _update_k8scluster(osm_db):
98 """Remove namespace from helm-chart and helm-chart-v3 id."""
99 if "k8sclusters" not in osm_db.list_collection_names():
100 return
101 logger.info("Entering in MongoUpgrade1012._update_k8scluster function")
102 namespace = "kube-system:"
103 k8sclusters = osm_db["k8sclusters"]
104 for k8scluster in k8sclusters.find():
105 if k8scluster["_admin"].get("helm-chart") and k8scluster["_admin"]["helm-chart"].get(
106 "id"
107 ):
108 if k8scluster["_admin"]["helm-chart"]["id"].startswith(namespace):
109 k8scluster["_admin"]["helm-chart"]["id"] = k8scluster["_admin"]["helm-chart"][
110 "id"
111 ].replace(namespace, "", 1)
112 if k8scluster["_admin"].get("helm-chart-v3") and k8scluster["_admin"][
113 "helm-chart-v3"
114 ].get("id"):
115 if k8scluster["_admin"]["helm-chart-v3"]["id"].startswith(namespace):
116 k8scluster["_admin"]["helm-chart-v3"]["id"] = k8scluster["_admin"][
117 "helm-chart-v3"
118 ]["id"].replace(namespace, "", 1)
119 myquery = {"_id": k8scluster["_id"]}
120 k8sclusters.update_one(myquery, {"$set": k8scluster})
121
122 @staticmethod
123 def upgrade(mongo_uri):
124 """Upgrade nsr, vnfr and k8scluster in DB."""
125 logger.info("Entering in MongoUpgrade1012.upgrade function")
126 myclient = MongoClient(mongo_uri)
127 osm_db = myclient["osm"]
128 MongoUpgrade1012._update_nsr(osm_db)
129 MongoUpgrade1012._update_vnfr(osm_db)
130 MongoUpgrade1012._update_k8scluster(osm_db)
131
132
133 class MongoUpgrade910:
134 """Upgrade MongoDB Database from OSM v9 to v10."""
135
136 @staticmethod
137 def upgrade(mongo_uri):
138 """Add parameter alarm status = OK if not found in alarms collection."""
139 myclient = MongoClient(mongo_uri)
140 osm_db = myclient["osm"]
141 collist = osm_db.list_collection_names()
142
143 if "alarms" in collist:
144 mycol = osm_db["alarms"]
145 for x in mycol.find():
146 if not x.get("alarm_status"):
147 myquery = {"_id": x["_id"]}
148 mycol.update_one(myquery, {"$set": {"alarm_status": "ok"}})
149
150
151 class MongoPatch1837:
152 """Patch Bug 1837 on MongoDB."""
153
154 @staticmethod
155 def _update_nslcmops_params(osm_db):
156 """Updates the nslcmops collection to change the additional params to a string."""
157 logger.info("Entering in MongoPatch1837._update_nslcmops_params function")
158 if "nslcmops" in osm_db.list_collection_names():
159 nslcmops = osm_db["nslcmops"]
160 for nslcmop in nslcmops.find():
161 if nslcmop.get("operationParams"):
162 if nslcmop["operationParams"].get("additionalParamsForVnf") and isinstance(
163 nslcmop["operationParams"].get("additionalParamsForVnf"), list
164 ):
165 string_param = json.dumps(
166 nslcmop["operationParams"]["additionalParamsForVnf"]
167 )
168 myquery = {"_id": nslcmop["_id"]}
169 nslcmops.update_one(
170 myquery,
171 {
172 "$set": {
173 "operationParams": {"additionalParamsForVnf": string_param}
174 }
175 },
176 )
177 elif nslcmop["operationParams"].get("primitive_params") and isinstance(
178 nslcmop["operationParams"].get("primitive_params"), dict
179 ):
180 string_param = json.dumps(nslcmop["operationParams"]["primitive_params"])
181 myquery = {"_id": nslcmop["_id"]}
182 nslcmops.update_one(
183 myquery,
184 {"$set": {"operationParams": {"primitive_params": string_param}}},
185 )
186
187 @staticmethod
188 def _update_vnfrs_params(osm_db):
189 """Updates the vnfrs collection to change the additional params to a string."""
190 logger.info("Entering in MongoPatch1837._update_vnfrs_params function")
191 if "vnfrs" in osm_db.list_collection_names():
192 mycol = osm_db["vnfrs"]
193 for vnfr in mycol.find():
194 if vnfr.get("kdur"):
195 kdur_list = []
196 for kdur in vnfr["kdur"]:
197 if kdur.get("additionalParams") and not isinstance(
198 kdur["additionalParams"], str
199 ):
200 kdur["additionalParams"] = json.dumps(kdur["additionalParams"])
201 kdur_list.append(kdur)
202 myquery = {"_id": vnfr["_id"]}
203 mycol.update_one(
204 myquery,
205 {"$set": {"kdur": kdur_list}},
206 )
207 vnfr["kdur"] = kdur_list
208
209 @staticmethod
210 def patch(mongo_uri):
211 """Updates the database to change the additional params from dict to a string."""
212 logger.info("Entering in MongoPatch1837.patch function")
213 myclient = MongoClient(mongo_uri)
214 osm_db = myclient["osm"]
215 MongoPatch1837._update_nslcmops_params(osm_db)
216 MongoPatch1837._update_vnfrs_params(osm_db)
217
218
219 MONGODB_UPGRADE_FUNCTIONS = {
220 "9": {"10": [MongoUpgrade910.upgrade]},
221 "10": {"12": [MongoUpgrade1012.upgrade]},
222 }
223 MYSQL_UPGRADE_FUNCTIONS = {}
224 BUG_FIXES = {
225 1837: MongoPatch1837.patch,
226 }
227
228
229 class MongoUpgrade:
230 """Upgrade MongoDB Database."""
231
232 def __init__(self, mongo_uri):
233 self.mongo_uri = mongo_uri
234
235 def upgrade(self, current, target):
236 """Validates the upgrading path and upgrades the DB."""
237 self._validate_upgrade(current, target)
238 for function in MONGODB_UPGRADE_FUNCTIONS.get(current)[target]:
239 function(self.mongo_uri)
240
241 def _validate_upgrade(self, current, target):
242 """Check if the upgrade path chosen is possible."""
243 logger.info("Validating the upgrade path")
244 if current not in MONGODB_UPGRADE_FUNCTIONS:
245 raise Exception(f"cannot upgrade from {current} version.")
246 if target not in MONGODB_UPGRADE_FUNCTIONS[current]:
247 raise Exception(f"cannot upgrade from version {current} to {target}.")
248
249 def apply_patch(self, bug_number: int) -> None:
250 """Checks the bug-number and applies the fix in the database."""
251 if bug_number not in BUG_FIXES:
252 raise Exception(f"There is no patch for bug {bug_number}")
253 patch_function = BUG_FIXES[bug_number]
254 patch_function(self.mongo_uri)
255
256
257 class MysqlUpgrade:
258 """Upgrade Mysql Database."""
259
260 def __init__(self, mysql_uri):
261 self.mysql_uri = mysql_uri
262
263 def upgrade(self, current, target):
264 """Validates the upgrading path and upgrades the DB."""
265 self._validate_upgrade(current, target)
266 for function in MYSQL_UPGRADE_FUNCTIONS[current][target]:
267 function(self.mysql_uri)
268
269 def _validate_upgrade(self, current, target):
270 """Check if the upgrade path chosen is possible."""
271 logger.info("Validating the upgrade path")
272 if current not in MYSQL_UPGRADE_FUNCTIONS:
273 raise Exception(f"cannot upgrade from {current} version.")
274 if target not in MYSQL_UPGRADE_FUNCTIONS[current]:
275 raise Exception(f"cannot upgrade from version {current} to {target}.")