1 # -*- coding: utf-8 -*-
4 # Copyright 2018 Telefonica S.A.
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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
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
26 __author__
= "Alfonso Tierno"
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")}
34 def __init__(self
, db
, msg
, fs
, lcm_tasks
, ro_config
, loop
):
36 Init, Connect to database, filesystem storage, and messaging
37 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
41 self
.logger
= logging
.getLogger('lcm.vim')
43 self
.lcm_tasks
= lcm_tasks
44 self
.ro_config
= ro_config
46 super().__init
__(db
, msg
, fs
, self
.logger
)
48 async def create(self
, vim_content
, order_id
):
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
):
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")
67 operationState_HA
= ''
68 detailed_status_HA
= ''
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"]})
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"])
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"]
83 raise LcmException("sdn-controller={} is not available. Not deployed at RO".format(
84 vim_content
["config"]["sdn-controller"]))
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)
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
))
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
)
111 if vim_content
.get("vim_password"):
112 vim_content
["vim_password"] = self
.db
.decrypt(vim_content
["vim_password"],
113 schema_version
=schema_version
,
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"]
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
,
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'
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"]))
145 except (ROclient
.ROClientException
, DbException
) as e
:
146 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
148 except Exception as e
:
149 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
))
169 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
171 async def edit(self
, vim_content
, order_id
):
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
):
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")
190 operationState_HA
= ''
191 detailed_status_HA
= ''
192 step
= "Getting vim-id='{}' from db".format(vim_id
)
194 # wait for any previous tasks in process
195 await self
.lcm_tasks
.waitfor_related_HA('vim', 'edit', op_id
)
197 db_vim
= self
.db
.get_one("vim_accounts", {"_id": vim_id
})
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"]})
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"])
208 if db_sdn
.get("_admin") and db_sdn
["_admin"].get("deployed") and db_sdn
["_admin"]["deployed"].get(
210 RO_sdn_id
= db_sdn
["_admin"]["deployed"]["RO"]
212 raise LcmException("sdn-controller={} is not available. Not deployed at RO".format(
213 vim_content
["config"]["sdn-controller"]))
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)
229 vim_RO
["config"]["sdn-controller"] = RO_sdn_id
230 # TODO make a deep update of sdn-port-mapping
232 await RO
.edit("vim", RO_vim_id
, descriptor
=vim_RO
)
234 step
= "Editing vim-account at RO tenant"
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
,
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
,
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'
272 self
.logger
.debug(logging_text
+ "Exit Ok RO_vim_id={}".format(RO_vim_id
))
275 except (ROclient
.ROClientException
, DbException
) as e
:
276 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
278 except Exception as e
:
279 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
))
299 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
301 async def delete(self
, vim_content
, order_id
):
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
):
310 vim_id
= vim_content
["_id"]
311 logging_text
= "Task vim_delete={} ".format(vim_id
)
312 self
.logger
.debug(logging_text
+ "Enter")
317 operationState_HA
= ''
318 detailed_status_HA
= ''
319 step
= "Getting vim from db"
321 # wait for any previous tasks in process
322 await self
.lcm_tasks
.waitfor_related_HA('vim', 'delete', op_id
)
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"
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
))
337 step
= "Deleting vim from RO"
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
))
347 self
.logger
.error(logging_text
+ "Nothing to remove at RO")
348 self
.db
.del_one("vim_accounts", {"_id": vim_id
})
350 self
.logger
.debug(logging_text
+ "Exit Ok")
353 except (ROclient
.ROClientException
, DbException
) as e
:
354 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
356 except Exception as e
:
357 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
360 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
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
)
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
)
380 class WimLcm(LcmBase
):
381 # values that are encrypted at wim config because they are passwords
382 wim_config_encrypted
= ()
384 def __init__(self
, db
, msg
, fs
, lcm_tasks
, ro_config
, loop
):
386 Init, Connect to database, filesystem storage, and messaging
387 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
391 self
.logger
= logging
.getLogger('lcm.vim')
393 self
.lcm_tasks
= lcm_tasks
394 self
.ro_config
= ro_config
396 super().__init
__(db
, msg
, fs
, self
.logger
)
398 async def create(self
, wim_content
, order_id
):
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
)
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")
415 operationState_HA
= ''
416 detailed_status_HA
= ''
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
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
))
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
)
444 if wim_content
.get("wim_password"):
445 wim_content
["wim_password"] = self
.db
.decrypt(wim_content
["wim_password"],
446 schema_version
=schema_version
,
448 wim_account_RO
= {"name": wim_content
["name"],
449 "user": wim_content
["user"],
450 "password": wim_content
["password"]
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
,
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'
470 self
.logger
.debug(logging_text
+ "Exit Ok WIM account created at RO_wim_account_id={}".format(desc
["uuid"]))
473 except (ROclient
.ROClientException
, DbException
) as e
:
474 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
476 except Exception as e
:
477 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
)
498 async def edit(self
, wim_content
, order_id
):
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
):
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")
516 step
= "Getting wim-id='{}' from db".format(wim_id
)
517 operationState_HA
= ''
518 detailed_status_HA
= ''
520 # wait for any previous tasks in process
521 await self
.lcm_tasks
.waitfor_related_HA('wim', 'edit', op_id
)
523 db_wim
= self
.db
.get_one("wim_accounts", {"_id": wim_id
})
525 if db_wim
.get("_admin") and db_wim
["_admin"].get("deployed") and db_wim
["_admin"]["deployed"].get("RO"):
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
542 await RO
.edit("wim", RO_wim_id
, descriptor
=wim_RO
)
544 step
= "Editing wim-account at RO tenant"
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
,
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
,
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'
578 self
.logger
.debug(logging_text
+ "Exit Ok RO_wim_id={}".format(RO_wim_id
))
581 except (ROclient
.ROClientException
, DbException
) as e
:
582 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
584 except Exception as e
:
585 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
)
606 async def delete(self
, wim_content
, order_id
):
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
):
615 wim_id
= wim_content
["_id"]
616 logging_text
= "Task wim_delete={} ".format(wim_id
)
617 self
.logger
.debug(logging_text
+ "Enter")
622 step
= "Getting wim from db"
623 operationState_HA
= ''
624 detailed_status_HA
= ''
626 # wait for any previous tasks in process
627 await self
.lcm_tasks
.waitfor_related_HA('wim', 'delete', op_id
)
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"
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
))
642 step
= "Deleting wim from RO"
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
))
652 self
.logger
.error(logging_text
+ "Nohing to remove at RO")
653 self
.db
.del_one("wim_accounts", {"_id": wim_id
})
655 self
.logger
.debug(logging_text
+ "Exit Ok")
658 except (ROclient
.ROClientException
, DbException
) as e
:
659 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
661 except Exception as e
:
662 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
665 self
.lcm_tasks
.remove("wim_account", wim_id
, order_id
)
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
)
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
)
685 class SdnLcm(LcmBase
):
687 def __init__(self
, db
, msg
, fs
, lcm_tasks
, ro_config
, loop
):
689 Init, Connect to database, filesystem storage, and messaging
690 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
694 self
.logger
= logging
.getLogger('lcm.sdn')
696 self
.lcm_tasks
= lcm_tasks
697 self
.ro_config
= ro_config
699 super().__init
__(db
, msg
, fs
, self
.logger
)
701 async def create(self
, sdn_content
, order_id
):
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
)
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")
719 operationState_HA
= ''
720 detailed_status_HA
= ''
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
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
)
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
)
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'
750 except (ROclient
.ROClientException
, DbException
) as e
:
751 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
753 except Exception as e
:
754 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
)
775 async def edit(self
, sdn_content
, order_id
):
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
):
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")
792 operationState_HA
= ''
793 detailed_status_HA
= ''
794 step
= "Getting sdn from db"
796 # wait for any previous tasks in process
797 await self
.lcm_tasks
.waitfor_related_HA('sdn', 'edit', op_id
)
799 db_sdn
= self
.db
.get_one("sdns", {"_id": sdn_id
})
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
)
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'
820 self
.logger
.debug(logging_text
+ "Exit Ok RO_sdn_id={}".format(RO_sdn_id
))
823 except (ROclient
.ROClientException
, DbException
) as e
:
824 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
826 except Exception as e
:
827 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
)
848 async def delete(self
, sdn_content
, order_id
):
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
):
857 sdn_id
= sdn_content
["_id"]
858 logging_text
= "Task sdn_delete={} ".format(sdn_id
)
859 self
.logger
.debug(logging_text
+ "Enter")
864 operationState_HA
= ''
865 detailed_status_HA
= ''
866 step
= "Getting sdn from db"
868 # wait for any previous tasks in process
869 await self
.lcm_tasks
.waitfor_related_HA('sdn', 'delete', op_id
)
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"
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
))
885 self
.logger
.error(logging_text
+ "Skipping. There is not RO information at database")
886 self
.db
.del_one("sdns", {"_id": sdn_id
})
888 self
.logger
.debug("sdn_delete task sdn_id={} Exit Ok".format(sdn_id
))
891 except (ROclient
.ROClientException
, DbException
) as e
:
892 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
894 except Exception as e
:
895 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
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
)
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
)