d821fb21fc47a4e7f83a318c511722ded491391d
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
21 import logging
.handlers
23 from lcm_utils
import LcmException
, LcmBase
24 from osm_common
.dbbase
import DbException
25 from copy
import deepcopy
27 __author__
= "Alfonso Tierno"
30 class VimLcm(LcmBase
):
31 # values that are encrypted at vim config because they are passwords
32 vim_config_encrypted
= ("admin_password", "nsx_password", "vcenter_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
):
49 vim_id
= vim_content
["_id"]
50 logging_text
= "Task vim_create={} ".format(vim_id
)
51 self
.logger
.debug(logging_text
+ "Enter")
57 step
= "Getting vim-id='{}' from db".format(vim_id
)
58 db_vim
= self
.db
.get_one("vim_accounts", {"_id": vim_id
})
59 db_vim_update
["_admin.deployed.RO"] = None
60 if vim_content
.get("config") and vim_content
["config"].get("sdn-controller"):
61 step
= "Getting sdn-controller-id='{}' from db".format(vim_content
["config"]["sdn-controller"])
62 db_sdn
= self
.db
.get_one("sdns", {"_id": vim_content
["config"]["sdn-controller"]})
63 if db_sdn
.get("_admin") and db_sdn
["_admin"].get("deployed") and db_sdn
["_admin"]["deployed"].get("RO"):
64 RO_sdn_id
= db_sdn
["_admin"]["deployed"]["RO"]
66 raise LcmException("sdn-controller={} is not available. Not deployed at RO".format(
67 vim_content
["config"]["sdn-controller"]))
69 step
= "Creating vim at RO"
70 db_vim_update
["_admin.detailed-status"] = step
71 self
.update_db_2("vim_accounts", vim_id
, db_vim_update
)
72 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
73 vim_RO
= deepcopy(vim_content
)
74 vim_RO
.pop("_id", None)
75 vim_RO
.pop("_admin", None)
76 schema_version
= vim_RO
.pop("schema_version", None)
77 vim_RO
.pop("schema_type", None)
78 vim_RO
.pop("vim_tenant_name", None)
79 vim_RO
["type"] = vim_RO
.pop("vim_type")
80 vim_RO
.pop("vim_user", None)
81 vim_RO
.pop("vim_password", None)
83 vim_RO
["config"]["sdn-controller"] = RO_sdn_id
84 desc
= await RO
.create("vim", descriptor
=vim_RO
)
85 RO_vim_id
= desc
["uuid"]
86 db_vim_update
["_admin.deployed.RO"] = RO_vim_id
88 step
= "Creating vim_account at RO"
89 db_vim_update
["_admin.detailed-status"] = step
90 self
.update_db_2("vim_accounts", vim_id
, db_vim_update
)
92 if vim_content
.get("vim_password"):
93 vim_content
["vim_password"] = self
.db
.decrypt(vim_content
["vim_password"],
94 schema_version
=schema_version
,
96 vim_account_RO
= {"vim_tenant_name": vim_content
["vim_tenant_name"],
97 "vim_username": vim_content
["vim_user"],
98 "vim_password": vim_content
["vim_password"]
100 if vim_RO
.get("config"):
101 vim_account_RO
["config"] = vim_RO
["config"]
102 if "sdn-controller" in vim_account_RO
["config"]:
103 del vim_account_RO
["config"]["sdn-controller"]
104 if "sdn-port-mapping" in vim_account_RO
["config"]:
105 del vim_account_RO
["config"]["sdn-port-mapping"]
106 for p
in self
.vim_config_encrypted
:
107 if vim_account_RO
["config"].get(p
):
108 vim_account_RO
["config"][p
] = self
.db
.decrypt(vim_account_RO
["config"][p
],
109 schema_version
=schema_version
,
112 desc
= await RO
.attach_datacenter(RO_vim_id
, descriptor
=vim_account_RO
)
113 db_vim_update
["_admin.deployed.RO-account"] = desc
["uuid"]
114 db_vim_update
["_admin.operationalState"] = "ENABLED"
115 db_vim_update
["_admin.detailed-status"] = "Done"
117 # await asyncio.sleep(15) # TODO remove. This is for test
118 self
.logger
.debug(logging_text
+ "Exit Ok RO_vim_id={}".format(RO_vim_id
))
121 except (ROclient
.ROClientException
, DbException
) as e
:
122 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
124 except Exception as e
:
125 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
129 db_vim_update
["_admin.operationalState"] = "ERROR"
130 db_vim_update
["_admin.detailed-status"] = "ERROR {}: {}".format(step
, exc
)
132 self
.update_db_2("vim_accounts", vim_id
, db_vim_update
)
133 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
135 async def edit(self
, vim_content
, order_id
):
136 vim_id
= vim_content
["_id"]
137 logging_text
= "Task vim_edit={} ".format(vim_id
)
138 self
.logger
.debug(logging_text
+ "Enter")
144 step
= "Getting vim-id='{}' from db".format(vim_id
)
146 db_vim
= self
.db
.get_one("vim_accounts", {"_id": vim_id
})
148 # look if previous tasks in process
149 task_name
, task_dependency
= self
.lcm_tasks
.lookfor_related("vim_account", vim_id
, order_id
)
151 step
= "Waiting for related tasks to be completed: {}".format(task_name
)
152 self
.logger
.debug(logging_text
+ step
)
153 # TODO write this to database
154 _
, pending
= await asyncio
.wait(task_dependency
, timeout
=3600)
156 raise LcmException("Timeout waiting related tasks to be completed")
158 if db_vim
.get("_admin") and db_vim
["_admin"].get("deployed") and db_vim
["_admin"]["deployed"].get("RO"):
159 if vim_content
.get("config") and vim_content
["config"].get("sdn-controller"):
160 step
= "Getting sdn-controller-id='{}' from db".format(vim_content
["config"]["sdn-controller"])
161 db_sdn
= self
.db
.get_one("sdns", {"_id": vim_content
["config"]["sdn-controller"]})
163 # look if previous tasks in process
164 task_name
, task_dependency
= self
.lcm_tasks
.lookfor_related("sdn", db_sdn
["_id"])
166 step
= "Waiting for related tasks to be completed: {}".format(task_name
)
167 self
.logger
.debug(logging_text
+ step
)
168 # TODO write this to database
169 _
, pending
= await asyncio
.wait(task_dependency
, timeout
=3600)
171 raise LcmException("Timeout waiting related tasks to be completed")
173 if db_sdn
.get("_admin") and db_sdn
["_admin"].get("deployed") and db_sdn
["_admin"]["deployed"].get(
175 RO_sdn_id
= db_sdn
["_admin"]["deployed"]["RO"]
177 raise LcmException("sdn-controller={} is not available. Not deployed at RO".format(
178 vim_content
["config"]["sdn-controller"]))
180 RO_vim_id
= db_vim
["_admin"]["deployed"]["RO"]
181 step
= "Editing vim at RO"
182 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
183 vim_RO
= deepcopy(vim_content
)
184 vim_RO
.pop("_id", None)
185 vim_RO
.pop("_admin", None)
186 schema_version
= vim_RO
.pop("schema_version", None)
187 vim_RO
.pop("schema_type", None)
188 vim_RO
.pop("vim_tenant_name", None)
189 if "vim_type" in vim_RO
:
190 vim_RO
["type"] = vim_RO
.pop("vim_type")
191 vim_RO
.pop("vim_user", None)
192 vim_RO
.pop("vim_password", None)
194 vim_RO
["config"]["sdn-controller"] = RO_sdn_id
195 # TODO make a deep update of sdn-port-mapping
197 await RO
.edit("vim", RO_vim_id
, descriptor
=vim_RO
)
199 step
= "Editing vim-account at RO tenant"
201 if "config" in vim_content
:
202 if "sdn-controller" in vim_content
["config"]:
203 del vim_content
["config"]["sdn-controller"]
204 if "sdn-port-mapping" in vim_content
["config"]:
205 del vim_content
["config"]["sdn-port-mapping"]
206 if not vim_content
["config"]:
207 del vim_content
["config"]
208 if "vim_tenant_name" in vim_content
:
209 vim_account_RO
["vim_tenant_name"] = vim_content
["vim_tenant_name"]
210 if "vim_password" in vim_content
:
211 vim_account_RO
["vim_password"] = vim_content
["vim_password"]
212 if vim_content
.get("vim_password"):
213 vim_account_RO
["vim_password"] = self
.db
.decrypt(vim_content
["vim_password"],
214 schema_version
=schema_version
,
216 if "config" in vim_content
:
217 vim_account_RO
["config"] = vim_content
["config"]
218 if vim_content
.get("config"):
219 for p
in self
.vim_config_encrypted
:
220 if vim_content
["config"].get(p
):
221 vim_account_RO
["config"][p
] = self
.db
.decrypt(vim_content
["config"][p
],
222 schema_version
=schema_version
,
225 if "vim_user" in vim_content
:
226 vim_content
["vim_username"] = vim_content
["vim_user"]
227 # vim_account must be edited always even if empty in order to ensure changes are translated to RO
228 # vim_thread. RO will remove and relaunch a new thread for this vim_account
229 await RO
.edit("vim_account", RO_vim_id
, descriptor
=vim_account_RO
)
230 db_vim_update
["_admin.operationalState"] = "ENABLED"
232 self
.logger
.debug(logging_text
+ "Exit Ok RO_vim_id={}".format(RO_vim_id
))
235 except (ROclient
.ROClientException
, DbException
) as e
:
236 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
238 except Exception as e
:
239 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
243 db_vim_update
["_admin.operationalState"] = "ERROR"
244 db_vim_update
["_admin.detailed-status"] = "ERROR {}: {}".format(step
, exc
)
246 self
.update_db_2("vim_accounts", vim_id
, db_vim_update
)
247 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
249 async def delete(self
, vim_id
, order_id
):
250 logging_text
= "Task vim_delete={} ".format(vim_id
)
251 self
.logger
.debug(logging_text
+ "Enter")
255 step
= "Getting vim from db"
257 db_vim
= self
.db
.get_one("vim_accounts", {"_id": vim_id
})
258 if db_vim
.get("_admin") and db_vim
["_admin"].get("deployed") and db_vim
["_admin"]["deployed"].get("RO"):
259 RO_vim_id
= db_vim
["_admin"]["deployed"]["RO"]
260 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
261 step
= "Detaching vim from RO tenant"
263 await RO
.detach_datacenter(RO_vim_id
)
264 except ROclient
.ROClientException
as e
:
265 if e
.http_code
== 404: # not found
266 self
.logger
.debug(logging_text
+ "RO_vim_id={} already detached".format(RO_vim_id
))
270 step
= "Deleting vim from RO"
272 await RO
.delete("vim", RO_vim_id
)
273 except ROclient
.ROClientException
as e
:
274 if e
.http_code
== 404: # not found
275 self
.logger
.debug(logging_text
+ "RO_vim_id={} already deleted".format(RO_vim_id
))
280 self
.logger
.error(logging_text
+ "Nohing to remove at RO")
281 self
.db
.del_one("vim_accounts", {"_id": vim_id
})
282 self
.logger
.debug(logging_text
+ "Exit Ok")
285 except (ROclient
.ROClientException
, DbException
) as e
:
286 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
288 except Exception as e
:
289 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
292 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
294 db_vim_update
["_admin.operationalState"] = "ERROR"
295 db_vim_update
["_admin.detailed-status"] = "ERROR {}: {}".format(step
, exc
)
297 self
.update_db_2("vim_accounts", vim_id
, db_vim_update
)
298 self
.lcm_tasks
.remove("vim_account", vim_id
, order_id
)
301 class SdnLcm(LcmBase
):
303 def __init__(self
, db
, msg
, fs
, lcm_tasks
, ro_config
, loop
):
305 Init, Connect to database, filesystem storage, and messaging
306 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
310 self
.logger
= logging
.getLogger('lcm.sdn')
312 self
.lcm_tasks
= lcm_tasks
313 self
.ro_config
= ro_config
315 super().__init
__(db
, msg
, fs
, self
.logger
)
317 async def create(self
, sdn_content
, order_id
):
318 sdn_id
= sdn_content
["_id"]
319 logging_text
= "Task sdn_create={} ".format(sdn_id
)
320 self
.logger
.debug(logging_text
+ "Enter")
326 step
= "Getting sdn from db"
327 db_sdn
= self
.db
.get_one("sdns", {"_id": sdn_id
})
328 db_sdn_update
["_admin.deployed.RO"] = None
330 step
= "Creating sdn at RO"
331 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
332 sdn_RO
= deepcopy(sdn_content
)
333 sdn_RO
.pop("_id", None)
334 sdn_RO
.pop("_admin", None)
335 schema_version
= sdn_RO
.pop("schema_version", None)
336 sdn_RO
.pop("schema_type", None)
337 sdn_RO
.pop("description", None)
338 if sdn_RO
.get("password"):
339 sdn_RO
["password"] = self
.db
.decrypt(sdn_RO
["password"], schema_version
=schema_version
, salt
=sdn_id
)
341 desc
= await RO
.create("sdn", descriptor
=sdn_RO
)
342 RO_sdn_id
= desc
["uuid"]
343 db_sdn_update
["_admin.deployed.RO"] = RO_sdn_id
344 db_sdn_update
["_admin.operationalState"] = "ENABLED"
345 self
.logger
.debug(logging_text
+ "Exit Ok RO_sdn_id={}".format(RO_sdn_id
))
348 except (ROclient
.ROClientException
, DbException
) as e
:
349 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
351 except Exception as e
:
352 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
356 db_sdn_update
["_admin.operationalState"] = "ERROR"
357 db_sdn_update
["_admin.detailed-status"] = "ERROR {}: {}".format(step
, exc
)
359 self
.update_db_2("sdns", sdn_id
, db_sdn_update
)
360 self
.lcm_tasks
.remove("sdn", sdn_id
, order_id
)
362 async def edit(self
, sdn_content
, order_id
):
363 sdn_id
= sdn_content
["_id"]
364 logging_text
= "Task sdn_edit={} ".format(sdn_id
)
365 self
.logger
.debug(logging_text
+ "Enter")
369 step
= "Getting sdn from db"
371 db_sdn
= self
.db
.get_one("sdns", {"_id": sdn_id
})
372 if db_sdn
.get("_admin") and db_sdn
["_admin"].get("deployed") and db_sdn
["_admin"]["deployed"].get("RO"):
373 RO_sdn_id
= db_sdn
["_admin"]["deployed"]["RO"]
374 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
375 step
= "Editing sdn at RO"
376 sdn_RO
= deepcopy(sdn_content
)
377 sdn_RO
.pop("_id", None)
378 sdn_RO
.pop("_admin", None)
379 schema_version
= sdn_RO
.pop("schema_version", None)
380 sdn_RO
.pop("schema_type", None)
381 sdn_RO
.pop("description", None)
382 if sdn_RO
.get("password"):
383 sdn_RO
["password"] = self
.db
.decrypt(sdn_RO
["password"], schema_version
=schema_version
, salt
=sdn_id
)
385 await RO
.edit("sdn", RO_sdn_id
, descriptor
=sdn_RO
)
386 db_sdn_update
["_admin.operationalState"] = "ENABLED"
388 self
.logger
.debug(logging_text
+ "Exit Ok RO_sdn_id".format(RO_sdn_id
))
391 except (ROclient
.ROClientException
, DbException
) as e
:
392 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
394 except Exception as e
:
395 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
399 db_sdn
["_admin.operationalState"] = "ERROR"
400 db_sdn
["_admin.detailed-status"] = "ERROR {}: {}".format(step
, exc
)
402 self
.update_db_2("sdns", sdn_id
, db_sdn_update
)
403 self
.lcm_tasks
.remove("sdn", sdn_id
, order_id
)
405 async def delete(self
, sdn_id
, order_id
):
406 logging_text
= "Task sdn_delete={} ".format(sdn_id
)
407 self
.logger
.debug(logging_text
+ "Enter")
411 step
= "Getting sdn from db"
413 db_sdn
= self
.db
.get_one("sdns", {"_id": sdn_id
})
414 if db_sdn
.get("_admin") and db_sdn
["_admin"].get("deployed") and db_sdn
["_admin"]["deployed"].get("RO"):
415 RO_sdn_id
= db_sdn
["_admin"]["deployed"]["RO"]
416 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
417 step
= "Deleting sdn from RO"
419 await RO
.delete("sdn", RO_sdn_id
)
420 except ROclient
.ROClientException
as e
:
421 if e
.http_code
== 404: # not found
422 self
.logger
.debug(logging_text
+ "RO_sdn_id={} already deleted".format(RO_sdn_id
))
427 self
.logger
.error(logging_text
+ "Skipping. There is not RO information at database")
428 self
.db
.del_one("sdns", {"_id": sdn_id
})
429 self
.logger
.debug("sdn_delete task sdn_id={} Exit Ok".format(sdn_id
))
432 except (ROclient
.ROClientException
, DbException
) as e
:
433 self
.logger
.error(logging_text
+ "Exit Exception {}".format(e
))
435 except Exception as e
:
436 self
.logger
.critical(logging_text
+ "Exit Exception {}".format(e
), exc_info
=True)
440 db_sdn
["_admin.operationalState"] = "ERROR"
441 db_sdn
["_admin.detailed-status"] = "ERROR {}: {}".format(step
, exc
)
443 self
.update_db_2("sdns", sdn_id
, db_sdn_update
)
444 self
.lcm_tasks
.remove("sdn", sdn_id
, order_id
)