change imports as a module with osm_lcm prefix
[osm/LCM.git] / osm_lcm / vim_sdn.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2018 Telefonica S.A.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
16 # under the License.
17 ##
18
19 import logging
20 import logging.handlers
21 from osm_lcm import ROclient
22 from osm_lcm.lcm_utils import LcmException, LcmBase
23 from osm_common.dbbase import DbException
24 from copy import deepcopy
25
26 __author__ = "Alfonso Tierno"
27
28
29 class VimLcm(LcmBase):
30 # values that are encrypted at vim config because they are passwords
31 vim_config_encrypted = {"1.1": ("admin_password", "nsx_password", "vcenter_password"),
32 "default": ("admin_password", "nsx_password", "vcenter_password", "vrops_password")}
33
34 def __init__(self, db, msg, fs, lcm_tasks, ro_config, loop):
35 """
36 Init, Connect to database, filesystem storage, and messaging
37 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
38 :return: None
39 """
40
41 self.logger = logging.getLogger('lcm.vim')
42 self.loop = loop
43 self.lcm_tasks = lcm_tasks
44 self.ro_config = ro_config
45
46 super().__init__(db, msg, fs, self.logger)
47
48 async def create(self, vim_content, order_id):
49
50 # HA tasks and backward compatibility:
51 # If 'vim_content' does not include 'op_id', we a running a legacy NBI version.
52 # In such a case, HA is not supported by NBI, 'op_id' is None, and lock_HA() will do nothing.
53 # Register 'create' task here for related future HA operations
54 op_id = vim_content.pop('op_id', None)
55 if not self.lcm_tasks.lock_HA('vim', 'create', op_id):
56 return
57
58 vim_id = vim_content["_id"]
59 vim_content.pop("op_id", None)
60 logging_text = "Task vim_create={} ".format(vim_id)
61 self.logger.debug(logging_text + "Enter")
62
63 db_vim = None
64 db_vim_update = {}
65 exc = None
66 RO_sdn_id = None
67 operationState_HA = ''
68 detailed_status_HA = ''
69 try:
70 step = "Getting vim-id='{}' from db".format(vim_id)
71 db_vim = self.db.get_one("vim_accounts", {"_id": vim_id})
72 if vim_content.get("config") and vim_content["config"].get("sdn-controller"):
73 step = "Getting sdn-controller-id='{}' from db".format(vim_content["config"]["sdn-controller"])
74 db_sdn = self.db.get_one("sdns", {"_id": vim_content["config"]["sdn-controller"]})
75
76 # If the VIM account has an associated SDN account, also
77 # wait for any previous tasks in process for the SDN
78 await self.lcm_tasks.waitfor_related_HA('sdn', 'ANY', db_sdn["_id"])
79
80 if db_sdn.get("_admin") and db_sdn["_admin"].get("deployed") and db_sdn["_admin"]["deployed"].get("RO"):
81 RO_sdn_id = db_sdn["_admin"]["deployed"]["RO"]
82 else:
83 raise LcmException("sdn-controller={} is not available. Not deployed at RO".format(
84 vim_content["config"]["sdn-controller"]))
85
86 step = "Creating vim at RO"
87 db_vim_update["_admin.deployed.RO"] = None
88 db_vim_update["_admin.detailed-status"] = step
89 self.update_db_2("vim_accounts", vim_id, db_vim_update)
90 RO = ROclient.ROClient(self.loop, **self.ro_config)
91 vim_RO = deepcopy(vim_content)
92 vim_RO.pop("_id", None)
93 vim_RO.pop("_admin", None)
94 schema_version = vim_RO.pop("schema_version", None)
95 vim_RO.pop("schema_type", None)
96 vim_RO.pop("vim_tenant_name", None)
97 vim_RO["type"] = vim_RO.pop("vim_type")
98 vim_RO.pop("vim_user", None)
99 vim_RO.pop("vim_password", None)
100 if RO_sdn_id:
101 vim_RO["config"]["sdn-controller"] = RO_sdn_id
102 desc = await RO.create("vim", descriptor=vim_RO)
103 RO_vim_id = desc["uuid"]
104 db_vim_update["_admin.deployed.RO"] = RO_vim_id
105 self.logger.debug(logging_text + "VIM created at RO_vim_id={}".format(RO_vim_id))
106
107 step = "Creating vim_account at RO"
108 db_vim_update["_admin.detailed-status"] = step
109 self.update_db_2("vim_accounts", vim_id, db_vim_update)
110
111 if vim_content.get("vim_password"):
112 vim_content["vim_password"] = self.db.decrypt(vim_content["vim_password"],
113 schema_version=schema_version,
114 salt=vim_id)
115 vim_account_RO = {"vim_tenant_name": vim_content["vim_tenant_name"],
116 "vim_username": vim_content["vim_user"],
117 "vim_password": vim_content["vim_password"]
118 }
119 if vim_RO.get("config"):
120 vim_account_RO["config"] = vim_RO["config"]
121 if "sdn-controller" in vim_account_RO["config"]:
122 del vim_account_RO["config"]["sdn-controller"]
123 if "sdn-port-mapping" in vim_account_RO["config"]:
124 del vim_account_RO["config"]["sdn-port-mapping"]
125 vim_config_encrypted_keys = self.vim_config_encrypted.get(schema_version) or \
126 self.vim_config_encrypted.get("default")
127 for p in vim_config_encrypted_keys:
128 if vim_account_RO["config"].get(p):
129 vim_account_RO["config"][p] = self.db.decrypt(vim_account_RO["config"][p],
130 schema_version=schema_version,
131 salt=vim_id)
132
133 desc = await RO.attach("vim_account", RO_vim_id, descriptor=vim_account_RO)
134 db_vim_update["_admin.deployed.RO-account"] = desc["uuid"]
135 db_vim_update["_admin.operationalState"] = "ENABLED"
136 db_vim_update["_admin.detailed-status"] = "Done"
137 # Mark the VIM 'create' HA task as successful
138 operationState_HA = 'COMPLETED'
139 detailed_status_HA = 'Done'
140
141 # await asyncio.sleep(15) # TODO remove. This is for test
142 self.logger.debug(logging_text + "Exit Ok VIM account created at RO_vim_account_id={}".format(desc["uuid"]))
143 return
144
145 except (ROclient.ROClientException, DbException) as e:
146 self.logger.error(logging_text + "Exit Exception {}".format(e))
147 exc = e
148 except Exception as e:
149 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
150 exc = e
151 finally:
152 if exc and db_vim:
153 db_vim_update["_admin.operationalState"] = "ERROR"
154 db_vim_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
155 # Mark the VIM 'create' HA task as erroneous
156 operationState_HA = 'FAILED'
157 detailed_status_HA = "ERROR {}: {}".format(step, exc)
158 try:
159 if db_vim_update:
160 self.update_db_2("vim_accounts", vim_id, db_vim_update)
161 # Register the VIM 'create' HA task either
162 # succesful or erroneous, or do nothing (if legacy NBI)
163 self.lcm_tasks.register_HA('vim', 'create', op_id,
164 operationState=operationState_HA,
165 detailed_status=detailed_status_HA)
166 except DbException as e:
167 self.logger.error(logging_text + "Cannot update database: {}".format(e))
168
169 self.lcm_tasks.remove("vim_account", vim_id, order_id)
170
171 async def edit(self, vim_content, order_id):
172
173 # HA tasks and backward compatibility:
174 # If 'vim_content' does not include 'op_id', we a running a legacy NBI version.
175 # In such a case, HA is not supported by NBI, and the HA check always returns True
176 op_id = vim_content.pop('op_id', None)
177 if not self.lcm_tasks.lock_HA('vim', 'edit', op_id):
178 return
179
180 vim_id = vim_content["_id"]
181 vim_content.pop("op_id", None)
182 logging_text = "Task vim_edit={} ".format(vim_id)
183 self.logger.debug(logging_text + "Enter")
184
185 db_vim = None
186 exc = None
187 RO_sdn_id = None
188 RO_vim_id = None
189 db_vim_update = {}
190 operationState_HA = ''
191 detailed_status_HA = ''
192 step = "Getting vim-id='{}' from db".format(vim_id)
193 try:
194 # wait for any previous tasks in process
195 await self.lcm_tasks.waitfor_related_HA('vim', 'edit', op_id)
196
197 db_vim = self.db.get_one("vim_accounts", {"_id": vim_id})
198
199 if db_vim.get("_admin") and db_vim["_admin"].get("deployed") and db_vim["_admin"]["deployed"].get("RO"):
200 if vim_content.get("config") and vim_content["config"].get("sdn-controller"):
201 step = "Getting sdn-controller-id='{}' from db".format(vim_content["config"]["sdn-controller"])
202 db_sdn = self.db.get_one("sdns", {"_id": vim_content["config"]["sdn-controller"]})
203
204 # If the VIM account has an associated SDN account, also
205 # wait for any previous tasks in process for the SDN
206 await self.lcm_tasks.waitfor_related_HA('sdn', 'ANY', db_sdn["_id"])
207
208 if db_sdn.get("_admin") and db_sdn["_admin"].get("deployed") and db_sdn["_admin"]["deployed"].get(
209 "RO"):
210 RO_sdn_id = db_sdn["_admin"]["deployed"]["RO"]
211 else:
212 raise LcmException("sdn-controller={} is not available. Not deployed at RO".format(
213 vim_content["config"]["sdn-controller"]))
214
215 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
216 step = "Editing vim at RO"
217 RO = ROclient.ROClient(self.loop, **self.ro_config)
218 vim_RO = deepcopy(vim_content)
219 vim_RO.pop("_id", None)
220 vim_RO.pop("_admin", None)
221 schema_version = vim_RO.pop("schema_version", None)
222 vim_RO.pop("schema_type", None)
223 vim_RO.pop("vim_tenant_name", None)
224 if "vim_type" in vim_RO:
225 vim_RO["type"] = vim_RO.pop("vim_type")
226 vim_RO.pop("vim_user", None)
227 vim_RO.pop("vim_password", None)
228 if RO_sdn_id:
229 vim_RO["config"]["sdn-controller"] = RO_sdn_id
230 # TODO make a deep update of sdn-port-mapping
231 if vim_RO:
232 await RO.edit("vim", RO_vim_id, descriptor=vim_RO)
233
234 step = "Editing vim-account at RO tenant"
235 vim_account_RO = {}
236 if "config" in vim_content:
237 if "sdn-controller" in vim_content["config"]:
238 del vim_content["config"]["sdn-controller"]
239 if "sdn-port-mapping" in vim_content["config"]:
240 del vim_content["config"]["sdn-port-mapping"]
241 if not vim_content["config"]:
242 del vim_content["config"]
243 if "vim_tenant_name" in vim_content:
244 vim_account_RO["vim_tenant_name"] = vim_content["vim_tenant_name"]
245 if "vim_password" in vim_content:
246 vim_account_RO["vim_password"] = vim_content["vim_password"]
247 if vim_content.get("vim_password"):
248 vim_account_RO["vim_password"] = self.db.decrypt(vim_content["vim_password"],
249 schema_version=schema_version,
250 salt=vim_id)
251 if "config" in vim_content:
252 vim_account_RO["config"] = vim_content["config"]
253 if vim_content.get("config"):
254 vim_config_encrypted_keys = self.vim_config_encrypted.get(schema_version) or \
255 self.vim_config_encrypted.get("default")
256 for p in vim_config_encrypted_keys:
257 if vim_content["config"].get(p):
258 vim_account_RO["config"][p] = self.db.decrypt(vim_content["config"][p],
259 schema_version=schema_version,
260 salt=vim_id)
261
262 if "vim_user" in vim_content:
263 vim_content["vim_username"] = vim_content["vim_user"]
264 # vim_account must be edited always even if empty in order to ensure changes are translated to RO
265 # vim_thread. RO will remove and relaunch a new thread for this vim_account
266 await RO.edit("vim_account", RO_vim_id, descriptor=vim_account_RO)
267 db_vim_update["_admin.operationalState"] = "ENABLED"
268 # Mark the VIM 'edit' HA task as successful
269 operationState_HA = 'COMPLETED'
270 detailed_status_HA = 'Done'
271
272 self.logger.debug(logging_text + "Exit Ok RO_vim_id={}".format(RO_vim_id))
273 return
274
275 except (ROclient.ROClientException, DbException) as e:
276 self.logger.error(logging_text + "Exit Exception {}".format(e))
277 exc = e
278 except Exception as e:
279 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
280 exc = e
281 finally:
282 if exc and db_vim:
283 db_vim_update["_admin.operationalState"] = "ERROR"
284 db_vim_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
285 # Mark the VIM 'edit' HA task as erroneous
286 operationState_HA = 'FAILED'
287 detailed_status_HA = "ERROR {}: {}".format(step, exc)
288 try:
289 if db_vim_update:
290 self.update_db_2("vim_accounts", vim_id, db_vim_update)
291 # Register the VIM 'edit' HA task either
292 # succesful or erroneous, or do nothing (if legacy NBI)
293 self.lcm_tasks.register_HA('vim', 'edit', op_id,
294 operationState=operationState_HA,
295 detailed_status=detailed_status_HA)
296 except DbException as e:
297 self.logger.error(logging_text + "Cannot update database: {}".format(e))
298
299 self.lcm_tasks.remove("vim_account", vim_id, order_id)
300
301 async def delete(self, vim_content, order_id):
302
303 # HA tasks and backward compatibility:
304 # If 'vim_content' does not include 'op_id', we a running a legacy NBI version.
305 # In such a case, HA is not supported by NBI, and the HA check always returns True
306 op_id = vim_content.pop('op_id', None)
307 if not self.lcm_tasks.lock_HA('vim', 'delete', op_id):
308 return
309
310 vim_id = vim_content["_id"]
311 logging_text = "Task vim_delete={} ".format(vim_id)
312 self.logger.debug(logging_text + "Enter")
313
314 db_vim = None
315 db_vim_update = {}
316 exc = None
317 operationState_HA = ''
318 detailed_status_HA = ''
319 step = "Getting vim from db"
320 try:
321 # wait for any previous tasks in process
322 await self.lcm_tasks.waitfor_related_HA('vim', 'delete', op_id)
323
324 db_vim = self.db.get_one("vim_accounts", {"_id": vim_id})
325 if db_vim.get("_admin") and db_vim["_admin"].get("deployed") and db_vim["_admin"]["deployed"].get("RO"):
326 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
327 RO = ROclient.ROClient(self.loop, **self.ro_config)
328 step = "Detaching vim from RO tenant"
329 try:
330 await RO.detach("vim_account", RO_vim_id)
331 except ROclient.ROClientException as e:
332 if e.http_code == 404: # not found
333 self.logger.debug(logging_text + "RO_vim_id={} already detached".format(RO_vim_id))
334 else:
335 raise
336
337 step = "Deleting vim from RO"
338 try:
339 await RO.delete("vim", RO_vim_id)
340 except ROclient.ROClientException as e:
341 if e.http_code == 404: # not found
342 self.logger.debug(logging_text + "RO_vim_id={} already deleted".format(RO_vim_id))
343 else:
344 raise
345 else:
346 # nothing to delete
347 self.logger.error(logging_text + "Nothing to remove at RO")
348 self.db.del_one("vim_accounts", {"_id": vim_id})
349 db_vim = None
350 self.logger.debug(logging_text + "Exit Ok")
351 return
352
353 except (ROclient.ROClientException, DbException) as e:
354 self.logger.error(logging_text + "Exit Exception {}".format(e))
355 exc = e
356 except Exception as e:
357 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
358 exc = e
359 finally:
360 self.lcm_tasks.remove("vim_account", vim_id, order_id)
361 if exc and db_vim:
362 db_vim_update["_admin.operationalState"] = "ERROR"
363 db_vim_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
364 # Mark the VIM 'delete' HA task as erroneous
365 operationState_HA = 'FAILED'
366 detailed_status_HA = "ERROR {}: {}".format(step, exc)
367 self.lcm_tasks.register_HA('vim', 'delete', op_id,
368 operationState=operationState_HA,
369 detailed_status=detailed_status_HA)
370 try:
371 if db_vim and db_vim_update:
372 self.update_db_2("vim_accounts", vim_id, db_vim_update)
373 # If the VIM 'delete' HA task was succesful, the DB entry has been deleted,
374 # which means that there is nowhere to register this task, so do nothing here.
375 except DbException as e:
376 self.logger.error(logging_text + "Cannot update database: {}".format(e))
377 self.lcm_tasks.remove("vim_account", vim_id, order_id)
378
379
380 class WimLcm(LcmBase):
381 # values that are encrypted at wim config because they are passwords
382 wim_config_encrypted = ()
383
384 def __init__(self, db, msg, fs, lcm_tasks, ro_config, loop):
385 """
386 Init, Connect to database, filesystem storage, and messaging
387 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
388 :return: None
389 """
390
391 self.logger = logging.getLogger('lcm.vim')
392 self.loop = loop
393 self.lcm_tasks = lcm_tasks
394 self.ro_config = ro_config
395
396 super().__init__(db, msg, fs, self.logger)
397
398 async def create(self, wim_content, order_id):
399
400 # HA tasks and backward compatibility:
401 # If 'wim_content' does not include 'op_id', we a running a legacy NBI version.
402 # In such a case, HA is not supported by NBI, 'op_id' is None, and lock_HA() will do nothing.
403 # Register 'create' task here for related future HA operations
404 op_id = wim_content.pop('op_id', None)
405 self.lcm_tasks.lock_HA('wim', 'create', op_id)
406
407 wim_id = wim_content["_id"]
408 wim_content.pop("op_id", None)
409 logging_text = "Task wim_create={} ".format(wim_id)
410 self.logger.debug(logging_text + "Enter")
411
412 db_wim = None
413 db_wim_update = {}
414 exc = None
415 operationState_HA = ''
416 detailed_status_HA = ''
417 try:
418 step = "Getting wim-id='{}' from db".format(wim_id)
419 db_wim = self.db.get_one("wim_accounts", {"_id": wim_id})
420 db_wim_update["_admin.deployed.RO"] = None
421
422 step = "Creating wim at RO"
423 db_wim_update["_admin.detailed-status"] = step
424 self.update_db_2("wim_accounts", wim_id, db_wim_update)
425 RO = ROclient.ROClient(self.loop, **self.ro_config)
426 wim_RO = deepcopy(wim_content)
427 wim_RO.pop("_id", None)
428 wim_RO.pop("_admin", None)
429 schema_version = wim_RO.pop("schema_version", None)
430 wim_RO.pop("schema_type", None)
431 wim_RO.pop("wim_tenant_name", None)
432 wim_RO["type"] = wim_RO.pop("wim_type")
433 wim_RO.pop("wim_user", None)
434 wim_RO.pop("wim_password", None)
435 desc = await RO.create("wim", descriptor=wim_RO)
436 RO_wim_id = desc["uuid"]
437 db_wim_update["_admin.deployed.RO"] = RO_wim_id
438 self.logger.debug(logging_text + "WIM created at RO_wim_id={}".format(RO_wim_id))
439
440 step = "Creating wim_account at RO"
441 db_wim_update["_admin.detailed-status"] = step
442 self.update_db_2("wim_accounts", wim_id, db_wim_update)
443
444 if wim_content.get("wim_password"):
445 wim_content["wim_password"] = self.db.decrypt(wim_content["wim_password"],
446 schema_version=schema_version,
447 salt=wim_id)
448 wim_account_RO = {"name": wim_content["name"],
449 "user": wim_content["user"],
450 "password": wim_content["password"]
451 }
452 if wim_RO.get("config"):
453 wim_account_RO["config"] = wim_RO["config"]
454 if "wim_port_mapping" in wim_account_RO["config"]:
455 del wim_account_RO["config"]["wim_port_mapping"]
456 for p in self.wim_config_encrypted:
457 if wim_account_RO["config"].get(p):
458 wim_account_RO["config"][p] = self.db.decrypt(wim_account_RO["config"][p],
459 schema_version=schema_version,
460 salt=wim_id)
461
462 desc = await RO.attach("wim_account", RO_wim_id, descriptor=wim_account_RO)
463 db_wim_update["_admin.deployed.RO-account"] = desc["uuid"]
464 db_wim_update["_admin.operationalState"] = "ENABLED"
465 db_wim_update["_admin.detailed-status"] = "Done"
466 # Mark the WIM 'create' HA task as successful
467 operationState_HA = 'COMPLETED'
468 detailed_status_HA = 'Done'
469
470 self.logger.debug(logging_text + "Exit Ok WIM account created at RO_wim_account_id={}".format(desc["uuid"]))
471 return
472
473 except (ROclient.ROClientException, DbException) as e:
474 self.logger.error(logging_text + "Exit Exception {}".format(e))
475 exc = e
476 except Exception as e:
477 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
478 exc = e
479 finally:
480 if exc and db_wim:
481 db_wim_update["_admin.operationalState"] = "ERROR"
482 db_wim_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
483 # Mark the WIM 'create' HA task as erroneous
484 operationState_HA = 'FAILED'
485 detailed_status_HA = "ERROR {}: {}".format(step, exc)
486 try:
487 if db_wim_update:
488 self.update_db_2("wim_accounts", wim_id, db_wim_update)
489 # Register the WIM 'create' HA task either
490 # succesful or erroneous, or do nothing (if legacy NBI)
491 self.lcm_tasks.register_HA('wim', 'create', op_id,
492 operationState=operationState_HA,
493 detailed_status=detailed_status_HA)
494 except DbException as e:
495 self.logger.error(logging_text + "Cannot update database: {}".format(e))
496 self.lcm_tasks.remove("wim_account", wim_id, order_id)
497
498 async def edit(self, wim_content, order_id):
499
500 # HA tasks and backward compatibility:
501 # If 'wim_content' does not include 'op_id', we a running a legacy NBI version.
502 # In such a case, HA is not supported by NBI, and the HA check always returns True
503 op_id = wim_content.pop('op_id', None)
504 if not self.lcm_tasks.lock_HA('wim', 'edit', op_id):
505 return
506
507 wim_id = wim_content["_id"]
508 wim_content.pop("op_id", None)
509 logging_text = "Task wim_edit={} ".format(wim_id)
510 self.logger.debug(logging_text + "Enter")
511
512 db_wim = None
513 exc = None
514 RO_wim_id = None
515 db_wim_update = {}
516 step = "Getting wim-id='{}' from db".format(wim_id)
517 operationState_HA = ''
518 detailed_status_HA = ''
519 try:
520 # wait for any previous tasks in process
521 await self.lcm_tasks.waitfor_related_HA('wim', 'edit', op_id)
522
523 db_wim = self.db.get_one("wim_accounts", {"_id": wim_id})
524
525 if db_wim.get("_admin") and db_wim["_admin"].get("deployed") and db_wim["_admin"]["deployed"].get("RO"):
526
527 RO_wim_id = db_wim["_admin"]["deployed"]["RO"]
528 step = "Editing wim at RO"
529 RO = ROclient.ROClient(self.loop, **self.ro_config)
530 wim_RO = deepcopy(wim_content)
531 wim_RO.pop("_id", None)
532 wim_RO.pop("_admin", None)
533 schema_version = wim_RO.pop("schema_version", None)
534 wim_RO.pop("schema_type", None)
535 wim_RO.pop("wim_tenant_name", None)
536 if "wim_type" in wim_RO:
537 wim_RO["type"] = wim_RO.pop("wim_type")
538 wim_RO.pop("wim_user", None)
539 wim_RO.pop("wim_password", None)
540 # TODO make a deep update of wim_port_mapping
541 if wim_RO:
542 await RO.edit("wim", RO_wim_id, descriptor=wim_RO)
543
544 step = "Editing wim-account at RO tenant"
545 wim_account_RO = {}
546 if "config" in wim_content:
547 if "wim_port_mapping" in wim_content["config"]:
548 del wim_content["config"]["wim_port_mapping"]
549 if not wim_content["config"]:
550 del wim_content["config"]
551 if "wim_tenant_name" in wim_content:
552 wim_account_RO["wim_tenant_name"] = wim_content["wim_tenant_name"]
553 if "wim_password" in wim_content:
554 wim_account_RO["wim_password"] = wim_content["wim_password"]
555 if wim_content.get("wim_password"):
556 wim_account_RO["wim_password"] = self.db.decrypt(wim_content["wim_password"],
557 schema_version=schema_version,
558 salt=wim_id)
559 if "config" in wim_content:
560 wim_account_RO["config"] = wim_content["config"]
561 if wim_content.get("config"):
562 for p in self.wim_config_encrypted:
563 if wim_content["config"].get(p):
564 wim_account_RO["config"][p] = self.db.decrypt(wim_content["config"][p],
565 schema_version=schema_version,
566 salt=wim_id)
567
568 if "wim_user" in wim_content:
569 wim_content["wim_username"] = wim_content["wim_user"]
570 # wim_account must be edited always even if empty in order to ensure changes are translated to RO
571 # wim_thread. RO will remove and relaunch a new thread for this wim_account
572 await RO.edit("wim_account", RO_wim_id, descriptor=wim_account_RO)
573 db_wim_update["_admin.operationalState"] = "ENABLED"
574 # Mark the WIM 'edit' HA task as successful
575 operationState_HA = 'COMPLETED'
576 detailed_status_HA = 'Done'
577
578 self.logger.debug(logging_text + "Exit Ok RO_wim_id={}".format(RO_wim_id))
579 return
580
581 except (ROclient.ROClientException, DbException) as e:
582 self.logger.error(logging_text + "Exit Exception {}".format(e))
583 exc = e
584 except Exception as e:
585 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
586 exc = e
587 finally:
588 if exc and db_wim:
589 db_wim_update["_admin.operationalState"] = "ERROR"
590 db_wim_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
591 # Mark the WIM 'edit' HA task as erroneous
592 operationState_HA = 'FAILED'
593 detailed_status_HA = "ERROR {}: {}".format(step, exc)
594 try:
595 if db_wim_update:
596 self.update_db_2("wim_accounts", wim_id, db_wim_update)
597 # Register the WIM 'edit' HA task either
598 # succesful or erroneous, or do nothing (if legacy NBI)
599 self.lcm_tasks.register_HA('wim', 'edit', op_id,
600 operationState=operationState_HA,
601 detailed_status=detailed_status_HA)
602 except DbException as e:
603 self.logger.error(logging_text + "Cannot update database: {}".format(e))
604 self.lcm_tasks.remove("wim_account", wim_id, order_id)
605
606 async def delete(self, wim_content, order_id):
607
608 # HA tasks and backward compatibility:
609 # If 'vim_content' does not include 'op_id', we a running a legacy NBI version.
610 # In such a case, HA is not supported by NBI, and the HA check always returns True
611 op_id = wim_content.pop('op_id', None)
612 if not self.lcm_tasks.lock_HA('wim', 'delete', op_id):
613 return
614
615 wim_id = wim_content["_id"]
616 logging_text = "Task wim_delete={} ".format(wim_id)
617 self.logger.debug(logging_text + "Enter")
618
619 db_wim = None
620 db_wim_update = {}
621 exc = None
622 step = "Getting wim from db"
623 operationState_HA = ''
624 detailed_status_HA = ''
625 try:
626 # wait for any previous tasks in process
627 await self.lcm_tasks.waitfor_related_HA('wim', 'delete', op_id)
628
629 db_wim = self.db.get_one("wim_accounts", {"_id": wim_id})
630 if db_wim.get("_admin") and db_wim["_admin"].get("deployed") and db_wim["_admin"]["deployed"].get("RO"):
631 RO_wim_id = db_wim["_admin"]["deployed"]["RO"]
632 RO = ROclient.ROClient(self.loop, **self.ro_config)
633 step = "Detaching wim from RO tenant"
634 try:
635 await RO.detach("wim_account", RO_wim_id)
636 except ROclient.ROClientException as e:
637 if e.http_code == 404: # not found
638 self.logger.debug(logging_text + "RO_wim_id={} already detached".format(RO_wim_id))
639 else:
640 raise
641
642 step = "Deleting wim from RO"
643 try:
644 await RO.delete("wim", RO_wim_id)
645 except ROclient.ROClientException as e:
646 if e.http_code == 404: # not found
647 self.logger.debug(logging_text + "RO_wim_id={} already deleted".format(RO_wim_id))
648 else:
649 raise
650 else:
651 # nothing to delete
652 self.logger.error(logging_text + "Nohing to remove at RO")
653 self.db.del_one("wim_accounts", {"_id": wim_id})
654 db_wim = None
655 self.logger.debug(logging_text + "Exit Ok")
656 return
657
658 except (ROclient.ROClientException, DbException) as e:
659 self.logger.error(logging_text + "Exit Exception {}".format(e))
660 exc = e
661 except Exception as e:
662 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
663 exc = e
664 finally:
665 self.lcm_tasks.remove("wim_account", wim_id, order_id)
666 if exc and db_wim:
667 db_wim_update["_admin.operationalState"] = "ERROR"
668 db_wim_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
669 # Mark the WIM 'delete' HA task as erroneous
670 operationState_HA = 'FAILED'
671 detailed_status_HA = "ERROR {}: {}".format(step, exc)
672 self.lcm_tasks.register_HA('wim', 'delete', op_id,
673 operationState=operationState_HA,
674 detailed_status=detailed_status_HA)
675 try:
676 if db_wim and db_wim_update:
677 self.update_db_2("wim_accounts", wim_id, db_wim_update)
678 # If the WIM 'delete' HA task was succesful, the DB entry has been deleted,
679 # which means that there is nowhere to register this task, so do nothing here.
680 except DbException as e:
681 self.logger.error(logging_text + "Cannot update database: {}".format(e))
682 self.lcm_tasks.remove("wim_account", wim_id, order_id)
683
684
685 class SdnLcm(LcmBase):
686
687 def __init__(self, db, msg, fs, lcm_tasks, ro_config, loop):
688 """
689 Init, Connect to database, filesystem storage, and messaging
690 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
691 :return: None
692 """
693
694 self.logger = logging.getLogger('lcm.sdn')
695 self.loop = loop
696 self.lcm_tasks = lcm_tasks
697 self.ro_config = ro_config
698
699 super().__init__(db, msg, fs, self.logger)
700
701 async def create(self, sdn_content, order_id):
702
703 # HA tasks and backward compatibility:
704 # If 'sdn_content' does not include 'op_id', we a running a legacy NBI version.
705 # In such a case, HA is not supported by NBI, 'op_id' is None, and lock_HA() will do nothing.
706 # Register 'create' task here for related future HA operations
707 op_id = sdn_content.pop('op_id', None)
708 self.lcm_tasks.lock_HA('sdn', 'create', op_id)
709
710 sdn_id = sdn_content["_id"]
711 sdn_content.pop("op_id", None)
712 logging_text = "Task sdn_create={} ".format(sdn_id)
713 self.logger.debug(logging_text + "Enter")
714
715 db_sdn = None
716 db_sdn_update = {}
717 RO_sdn_id = None
718 exc = None
719 operationState_HA = ''
720 detailed_status_HA = ''
721 try:
722 step = "Getting sdn from db"
723 db_sdn = self.db.get_one("sdns", {"_id": sdn_id})
724 db_sdn_update["_admin.deployed.RO"] = None
725
726 step = "Creating sdn at RO"
727 db_sdn_update["_admin.detailed-status"] = step
728 self.update_db_2("sdns", sdn_id, db_sdn_update)
729
730 RO = ROclient.ROClient(self.loop, **self.ro_config)
731 sdn_RO = deepcopy(sdn_content)
732 sdn_RO.pop("_id", None)
733 sdn_RO.pop("_admin", None)
734 schema_version = sdn_RO.pop("schema_version", None)
735 sdn_RO.pop("schema_type", None)
736 sdn_RO.pop("description", None)
737 if sdn_RO.get("password"):
738 sdn_RO["password"] = self.db.decrypt(sdn_RO["password"], schema_version=schema_version, salt=sdn_id)
739
740 desc = await RO.create("sdn", descriptor=sdn_RO)
741 RO_sdn_id = desc["uuid"]
742 db_sdn_update["_admin.deployed.RO"] = RO_sdn_id
743 db_sdn_update["_admin.operationalState"] = "ENABLED"
744 self.logger.debug(logging_text + "Exit Ok RO_sdn_id={}".format(RO_sdn_id))
745 # Mark the SDN 'create' HA task as successful
746 operationState_HA = 'COMPLETED'
747 detailed_status_HA = 'Done'
748 return
749
750 except (ROclient.ROClientException, DbException) as e:
751 self.logger.error(logging_text + "Exit Exception {}".format(e))
752 exc = e
753 except Exception as e:
754 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
755 exc = e
756 finally:
757 if exc and db_sdn:
758 db_sdn_update["_admin.operationalState"] = "ERROR"
759 db_sdn_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
760 # Mark the SDN 'create' HA task as erroneous
761 operationState_HA = 'FAILED'
762 detailed_status_HA = "ERROR {}: {}".format(step, exc)
763 try:
764 if db_sdn and db_sdn_update:
765 self.update_db_2("sdns", sdn_id, db_sdn_update)
766 # Register the SDN 'create' HA task either
767 # succesful or erroneous, or do nothing (if legacy NBI)
768 self.lcm_tasks.register_HA('sdn', 'create', op_id,
769 operationState=operationState_HA,
770 detailed_status=detailed_status_HA)
771 except DbException as e:
772 self.logger.error(logging_text + "Cannot update database: {}".format(e))
773 self.lcm_tasks.remove("sdn", sdn_id, order_id)
774
775 async def edit(self, sdn_content, order_id):
776
777 # HA tasks and backward compatibility:
778 # If 'sdn_content' does not include 'op_id', we a running a legacy NBI version.
779 # In such a case, HA is not supported by NBI, and the HA check always returns True
780 op_id = sdn_content.pop('op_id', None)
781 if not self.lcm_tasks.lock_HA('sdn', 'edit', op_id):
782 return
783
784 sdn_id = sdn_content["_id"]
785 sdn_content.pop("op_id", None)
786 logging_text = "Task sdn_edit={} ".format(sdn_id)
787 self.logger.debug(logging_text + "Enter")
788
789 db_sdn = None
790 db_sdn_update = {}
791 exc = None
792 operationState_HA = ''
793 detailed_status_HA = ''
794 step = "Getting sdn from db"
795 try:
796 # wait for any previous tasks in process
797 await self.lcm_tasks.waitfor_related_HA('sdn', 'edit', op_id)
798
799 db_sdn = self.db.get_one("sdns", {"_id": sdn_id})
800 RO_sdn_id = None
801 if db_sdn.get("_admin") and db_sdn["_admin"].get("deployed") and db_sdn["_admin"]["deployed"].get("RO"):
802 RO_sdn_id = db_sdn["_admin"]["deployed"]["RO"]
803 RO = ROclient.ROClient(self.loop, **self.ro_config)
804 step = "Editing sdn at RO"
805 sdn_RO = deepcopy(sdn_content)
806 sdn_RO.pop("_id", None)
807 sdn_RO.pop("_admin", None)
808 schema_version = sdn_RO.pop("schema_version", None)
809 sdn_RO.pop("schema_type", None)
810 sdn_RO.pop("description", None)
811 if sdn_RO.get("password"):
812 sdn_RO["password"] = self.db.decrypt(sdn_RO["password"], schema_version=schema_version, salt=sdn_id)
813 if sdn_RO:
814 await RO.edit("sdn", RO_sdn_id, descriptor=sdn_RO)
815 db_sdn_update["_admin.operationalState"] = "ENABLED"
816 # Mark the SDN 'edit' HA task as successful
817 operationState_HA = 'COMPLETED'
818 detailed_status_HA = 'Done'
819
820 self.logger.debug(logging_text + "Exit Ok RO_sdn_id={}".format(RO_sdn_id))
821 return
822
823 except (ROclient.ROClientException, DbException) as e:
824 self.logger.error(logging_text + "Exit Exception {}".format(e))
825 exc = e
826 except Exception as e:
827 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
828 exc = e
829 finally:
830 if exc and db_sdn:
831 db_sdn["_admin.operationalState"] = "ERROR"
832 db_sdn["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
833 # Mark the SDN 'edit' HA task as erroneous
834 operationState_HA = 'FAILED'
835 detailed_status_HA = "ERROR {}: {}".format(step, exc)
836 try:
837 if db_sdn_update:
838 self.update_db_2("sdns", sdn_id, db_sdn_update)
839 # Register the SDN 'edit' HA task either
840 # succesful or erroneous, or do nothing (if legacy NBI)
841 self.lcm_tasks.register_HA('sdn', 'edit', op_id,
842 operationState=operationState_HA,
843 detailed_status=detailed_status_HA)
844 except DbException as e:
845 self.logger.error(logging_text + "Cannot update database: {}".format(e))
846 self.lcm_tasks.remove("sdn", sdn_id, order_id)
847
848 async def delete(self, sdn_content, order_id):
849
850 # HA tasks and backward compatibility:
851 # If 'vim_content' does not include 'op_id', we a running a legacy NBI version.
852 # In such a case, HA is not supported by NBI, and the HA check always returns True
853 op_id = sdn_content.pop('op_id', None)
854 if not self.lcm_tasks.lock_HA('sdn', 'delete', op_id):
855 return
856
857 sdn_id = sdn_content["_id"]
858 logging_text = "Task sdn_delete={} ".format(sdn_id)
859 self.logger.debug(logging_text + "Enter")
860
861 db_sdn = None
862 db_sdn_update = {}
863 exc = None
864 operationState_HA = ''
865 detailed_status_HA = ''
866 step = "Getting sdn from db"
867 try:
868 # wait for any previous tasks in process
869 await self.lcm_tasks.waitfor_related_HA('sdn', 'delete', op_id)
870
871 db_sdn = self.db.get_one("sdns", {"_id": sdn_id})
872 if db_sdn.get("_admin") and db_sdn["_admin"].get("deployed") and db_sdn["_admin"]["deployed"].get("RO"):
873 RO_sdn_id = db_sdn["_admin"]["deployed"]["RO"]
874 RO = ROclient.ROClient(self.loop, **self.ro_config)
875 step = "Deleting sdn from RO"
876 try:
877 await RO.delete("sdn", RO_sdn_id)
878 except ROclient.ROClientException as e:
879 if e.http_code == 404: # not found
880 self.logger.debug(logging_text + "RO_sdn_id={} already deleted".format(RO_sdn_id))
881 else:
882 raise
883 else:
884 # nothing to delete
885 self.logger.error(logging_text + "Skipping. There is not RO information at database")
886 self.db.del_one("sdns", {"_id": sdn_id})
887 db_sdn = None
888 self.logger.debug("sdn_delete task sdn_id={} Exit Ok".format(sdn_id))
889 return
890
891 except (ROclient.ROClientException, DbException) as e:
892 self.logger.error(logging_text + "Exit Exception {}".format(e))
893 exc = e
894 except Exception as e:
895 self.logger.critical(logging_text + "Exit Exception {}".format(e), exc_info=True)
896 exc = e
897 finally:
898 if exc and db_sdn:
899 db_sdn["_admin.operationalState"] = "ERROR"
900 db_sdn["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc)
901 # Mark the SDN 'delete' HA task as erroneous
902 operationState_HA = 'FAILED'
903 detailed_status_HA = "ERROR {}: {}".format(step, exc)
904 self.lcm_tasks.register_HA('sdn', 'delete', op_id,
905 operationState=operationState_HA,
906 detailed_status=detailed_status_HA)
907 try:
908 if db_sdn and db_sdn_update:
909 self.update_db_2("sdns", sdn_id, db_sdn_update)
910 # If the SDN 'delete' HA task was succesful, the DB entry has been deleted,
911 # which means that there is nowhere to register this task, so do nothing here.
912 except DbException as e:
913 self.logger.error(logging_text + "Cannot update database: {}".format(e))
914 self.lcm_tasks.remove("sdn", sdn_id, order_id)