6a19cb93dd1ed9c04c0fd9a9946181d0a3edc995
[osm/SO.git] / rwlaunchpad / plugins / rwnsm / rift / tasklets / rwnsmtasklet / openmano_nsm.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #test
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19 import asyncio
20 import os
21 import sys
22 import time
23 import yaml
24
25 import gi
26 gi.require_version('RwDts', '1.0')
27 gi.require_version('RwVnfrYang', '1.0')
28 from gi.repository import (
29 RwDts as rwdts,
30 RwVnfrYang,
31 )
32
33 import rift.openmano.rift2openmano as rift2openmano
34 import rift.openmano.openmano_client as openmano_client
35 from . import rwnsmplugin
36 from enum import Enum
37
38
39 import rift.tasklets
40
41 if sys.version_info < (3, 4, 4):
42 asyncio.ensure_future = asyncio.async
43
44
45 DUMP_OPENMANO_DIR = os.path.join(
46 os.environ["RIFT_ARTIFACTS"],
47 "openmano_descriptors"
48 )
49
50
51 def dump_openmano_descriptor(name, descriptor_str):
52 filename = "{}_{}.yaml".format(
53 time.strftime("%Y%m%d-%H%M%S"),
54 name
55 )
56
57 filepath = os.path.join(
58 DUMP_OPENMANO_DIR,
59 filename
60 )
61
62 try:
63 if not os.path.exists(DUMP_OPENMANO_DIR):
64 os.makedirs(DUMP_OPENMANO_DIR)
65
66 with open(filepath, 'w') as hdl:
67 hdl.write(descriptor_str)
68
69 except OSError as e:
70 print("Failed to dump openmano descriptor: %s" % str(e))
71
72 return filepath
73
74 class VnfrConsoleOperdataDtsHandler(object):
75 """ registers 'D,/vnfr:vnfr-console/vnfr:vnfr[id]/vdur[id]' and handles CRUD from DTS"""
76 @property
77 def vnfr_vdu_console_xpath(self):
78 """ path for resource-mgr"""
79 return ("D,/rw-vnfr:vnfr-console/rw-vnfr:vnfr[rw-vnfr:id='{}']/rw-vnfr:vdur[vnfr:id='{}']".format(self._vnfr_id,self._vdur_id))
80
81 def __init__(self, dts, log, loop, nsr, vnfr_id, vdur_id, vdu_id):
82 self._dts = dts
83 self._log = log
84 self._loop = loop
85 self._regh = None
86 self._nsr = nsr
87
88 self._vnfr_id = vnfr_id
89 self._vdur_id = vdur_id
90 self._vdu_id = vdu_id
91
92 @asyncio.coroutine
93 def register(self):
94 """ Register for VNFR VDU Operational Data read from dts """
95
96 @asyncio.coroutine
97 def on_prepare(xact_info, action, ks_path, msg):
98 """ prepare callback from dts """
99 xpath = ks_path.to_xpath(RwVnfrYang.get_schema())
100 self._log.debug(
101 "Got VNFR VDU Opdata xact_info: %s, action: %s): %s:%s",
102 xact_info, action, xpath, msg
103 )
104
105 if action == rwdts.QueryAction.READ:
106 schema = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur.schema()
107 path_entry = schema.keyspec_to_entry(ks_path)
108
109 try:
110 console_url = yield from self._loop.run_in_executor(
111 None,
112 self._nsr._http_api.get_instance_vm_console_url,
113 self._nsr._nsr_uuid,
114 self._vdur_id,
115 )
116
117 self._log.debug("Got console response: %s for NSR ID %s vdur ID %s",
118 console_url,
119 self._nsr._nsr_uuid,
120 self._vdur_id
121 )
122 vdur_console = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur()
123 vdur_console.id = self._vdur_id
124 if console_url:
125 vdur_console.console_url = console_url
126 else:
127 vdur_console.console_url = 'none'
128 self._log.debug("Recevied console URL for vdu {} is {}".format(self._vdu_id,vdur_console))
129 except openmano_client.InstanceStatusError as e:
130 self._log.error("Could not get NS instance console URL: %s",
131 str(e))
132 vdur_console = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur()
133 vdur_console.id = self._vdur_id
134 vdur_console.console_url = 'none'
135
136 xact_info.respond_xpath(rsp_code=rwdts.XactRspCode.ACK,
137 xpath=self.vnfr_vdu_console_xpath,
138 msg=vdur_console)
139 else:
140 #raise VnfRecordError("Not supported operation %s" % action)
141 self._log.error("Not supported operation %s" % action)
142 xact_info.respond_xpath(rsp_code=rwdts.XactRspCode.ACK)
143 return
144
145 self._log.debug("Registering for VNFR VDU using xpath: %s",
146 self.vnfr_vdu_console_xpath)
147 hdl = rift.tasklets.DTS.RegistrationHandler(on_prepare=on_prepare,)
148 with self._dts.group_create() as group:
149 self._regh = group.register(xpath=self.vnfr_vdu_console_xpath,
150 handler=hdl,
151 flags=rwdts.Flag.PUBLISHER,
152 )
153
154
155
156 class OpenmanoVnfr(object):
157 def __init__(self, log, loop, cli_api, vnfr, nsd):
158 self._log = log
159 self._loop = loop
160 self._cli_api = cli_api
161 self._vnfr = vnfr
162 self._vnfd_id = vnfr.vnfd.id
163
164 self._vnf_id = None
165
166 self._created = False
167
168 self.nsd = nsd
169
170 @property
171 def vnfd(self):
172 return rift2openmano.RiftVNFD(self._vnfr.vnfd)
173
174 @property
175 def vnfr(self):
176 return self._vnfr
177
178 @property
179 def rift_vnfd_id(self):
180 return self._vnfd_id
181
182 @property
183 def openmano_vnfd_id(self):
184 return self._vnf_id
185
186 @property
187 def openmano_vnfd(self):
188 self._log.debug("Converting vnfd %s from rift to openmano", self.vnfd.id)
189 openmano_vnfd = rift2openmano.rift2openmano_vnfd(self.vnfd, self.nsd)
190 return openmano_vnfd
191
192 @property
193 def openmano_vnfd_yaml(self):
194 return yaml.safe_dump(self.openmano_vnfd, default_flow_style=False)
195
196 @asyncio.coroutine
197 def create(self):
198 self._log.debug("Creating openmano vnfd")
199 openmano_vnfd = self.openmano_vnfd
200 name = openmano_vnfd["vnf"]["name"]
201
202 # If the name already exists, get the openmano vnfd id
203 name_uuid_map = yield from self._loop.run_in_executor(
204 None,
205 self._cli_api.vnf_list,
206 )
207
208 if name in name_uuid_map:
209 vnf_id = name_uuid_map[name]
210 self._log.debug("Vnf already created. Got existing openmano vnfd id: %s", vnf_id)
211 self._vnf_id = vnf_id
212 return
213
214 self._vnf_id, _ = yield from self._loop.run_in_executor(
215 None,
216 self._cli_api.vnf_create,
217 self.openmano_vnfd_yaml,
218 )
219
220 fpath = dump_openmano_descriptor(
221 "{}_vnf".format(name),
222 self.openmano_vnfd_yaml
223 )
224
225 self._log.debug("Dumped Openmano VNF descriptor to: %s", fpath)
226
227 self._created = True
228
229 @asyncio.coroutine
230 def delete(self):
231 if not self._created:
232 return
233
234 self._log.debug("Deleting openmano vnfd")
235 if self._vnf_id is None:
236 self._log.warning("Openmano vnf id not set. Cannot delete.")
237 return
238
239 yield from self._loop.run_in_executor(
240 None,
241 self._cli_api.vnf_delete,
242 self._vnf_id,
243 )
244
245
246 class OpenmanoNSRecordState(Enum):
247 """ Network Service Record State """
248 # Make sure the values match with NetworkServiceRecordState
249 INIT = 101
250 INSTANTIATION_PENDING = 102
251 RUNNING = 106
252 SCALING_OUT = 107
253 SCALING_IN = 108
254 TERMINATE = 109
255 TERMINATE_RCVD = 110
256 TERMINATED = 114
257 FAILED = 115
258 VL_INSTANTIATE = 116
259 VL_TERMINATE = 117
260
261
262 class OpenmanoNsr(object):
263 TIMEOUT_SECS = 300
264
265 def __init__(self, dts, log, loop, publisher, cli_api, http_api, nsd_msg, nsr_config_msg,key_pairs, rift_vnfd_id=None):
266 self._dts = dts
267 self._log = log
268 self._loop = loop
269 self._publisher = publisher
270 self._cli_api = cli_api
271 self._http_api = http_api
272
273 self._nsd_msg = nsd_msg
274 self._nsr_config_msg = nsr_config_msg
275
276 self._vlrs = []
277 self._vnfrs = []
278 self._nsrs = {}
279 self._vdur_console_handler = {}
280 self._key_pairs = key_pairs
281
282 self._nsd_uuid = None
283 self._nsr_uuid = None
284
285 self._nsr_msg = None
286
287 self._created = False
288
289 self._monitor_task = None
290 self._rift_vnfd_id = rift_vnfd_id
291 self._state = OpenmanoNSRecordState.INIT
292
293 @property
294 def nsd(self):
295 return rift2openmano.RiftNSD(self._nsd_msg)
296
297 @property
298 def nsd_msg(self):
299 return self._nsd_msg
300
301 @property
302 def nsr_config_msg(self):
303 return self._nsr_config_msg
304
305 @property
306 def nsr_msg(self):
307 return self._nsr_msg
308
309 @property
310 def key_pairs(self):
311 return self._key_pairs
312
313 @property
314 def vnfds(self):
315 return {v.rift_vnfd_id: v.vnfd for v in self._vnfrs}
316
317 @property
318 def vnfr_ids(self):
319 return {v.rift_vnfd_id: v.openmano_vnfd_id for v in self._vnfrs}
320
321 @property
322 def vnfrs(self):
323 return self._vnfrs
324
325 @property
326 def openmano_nsd_yaml(self):
327 self._log.debug("Converting nsd %s from rift to openmano", self.nsd.id)
328 openmano_nsd = rift2openmano.rift2openmano_nsd(self.nsd, self.vnfds,self.vnfr_ids)
329 return yaml.safe_dump(openmano_nsd, default_flow_style=False)
330
331 @property
332 def scaling_group_nsd_yaml(self):
333 self._log.debug("Creating Scaling Group Scenarion Descriptor for VNF %s", self._rift_vnfd_id)
334 openmano_vnfd_nsd = rift2openmano.rift2openmano_vnfd_nsd(self.nsd, self.vnfds, self.vnfr_ids, self._rift_vnfd_id)
335 return yaml.safe_dump(vnfd_nsd, default_flow_style=False)
336
337 @property
338 def get_ssh_key_pairs(self):
339 cloud_config = {}
340 key_pairs = list()
341 for authorized_key in self._nsr_config_msg.ssh_authorized_key:
342 self._log.debug("Key pair ref present is %s",authorized_key.key_pair_ref)
343 if authorized_key.key_pair_ref in self._key_pairs:
344 key_pairs.append(self._key_pairs[authorized_key.key_pair_ref].key)
345
346 for authorized_key in self._nsd_msg.key_pair:
347 self._log.debug("Key pair NSD is %s",authorized_key)
348 key_pairs.append(authorized_key.key)
349
350 if key_pairs:
351 cloud_config["key-pairs"] = key_pairs
352
353 users = list()
354 for user_entry in self._nsr_config_msg.user:
355 self._log.debug("User present is %s",user_entry)
356 user = {}
357 user["name"] = user_entry.name
358 user["key-pairs"] = list()
359 for ssh_key in user_entry.ssh_authorized_key:
360 if ssh_key.key_pair_ref in self._key_pairs:
361 user["key-pairs"].append(self._key_pairs[ssh_key.key_pair_ref].key)
362 users.append(user)
363
364 for user_entry in self._nsd_msg.user:
365 self._log.debug("User present in NSD is %s",user_entry)
366 user = {}
367 user["name"] = user_entry.name
368 user["key-pairs"] = list()
369 for ssh_key in user_entry.key_pair:
370 user["key-pairs"].append(ssh_key.key)
371 users.append(user)
372
373 if users:
374 cloud_config["users"] = users
375
376 self._log.debug("Cloud config formed is %s",cloud_config)
377 return cloud_config
378
379
380 @property
381 def openmano_instance_create_yaml(self):
382 self._log.debug("Creating instance-scenario-create input file for nsd %s with name %s", self.nsd.id, self._nsr_config_msg.name, self._rift_vnfd_id)
383 openmano_instance_create = {}
384 openmano_instance_create["name"] = self._nsr_config_msg.name
385 openmano_instance_create["description"] = self._nsr_config_msg.description
386 openmano_instance_create["scenario"] = self._nsd_uuid
387
388 #cloud_config = self.get_ssh_key_pairs()
389 #if cloud_config:
390 # openmano_instance_create["cloud-config"] = cloud_config
391 if self._nsr_config_msg.has_field("om_datacenter"):
392 openmano_instance_create["datacenter"] = self._nsr_config_msg.om_datacenter
393 openmano_instance_create["vnfs"] = {}
394 for vnfr in self._vnfrs:
395 if "om_datacenter" in vnfr.vnfr.vnfr_msg:
396 vnfr_name = vnfr.vnfr.vnfd.name + "__" + str(vnfr.vnfr.vnfr_msg.member_vnf_index_ref)
397 openmano_instance_create["vnfs"][vnfr_name] = {"datacenter": vnfr.vnfr.vnfr_msg.om_datacenter}
398 openmano_instance_create["networks"] = {}
399 for vld_msg in self._nsd_msg.vld:
400 openmano_instance_create["networks"][vld_msg.name] = {}
401 openmano_instance_create["networks"][vld_msg.name]["sites"] = list()
402 for vlr in self._vlrs:
403 if vlr.vld_msg.name == vld_msg.name:
404 self._log.debug("Received VLR name %s, VLR DC: %s for VLD: %s",vlr.vld_msg.name,
405 vlr.om_datacenter_name,vld_msg.name)
406 #network["vim-network-name"] = vld_msg.name
407 network = {}
408 ip_profile = {}
409 if vld_msg.vim_network_name:
410 network["netmap-use"] = vld_msg.vim_network_name
411 elif vlr._ip_profile and vlr._ip_profile.has_field("ip_profile_params"):
412 ip_profile_params = vlr._ip_profile.ip_profile_params
413 if ip_profile_params.ip_version == "ipv6":
414 ip_profile['ip-version'] = "IPv6"
415 else:
416 ip_profile['ip-version'] = "IPv4"
417 if ip_profile_params.has_field('subnet_address'):
418 ip_profile['subnet-address'] = ip_profile_params.subnet_address
419 if ip_profile_params.has_field('gateway_address'):
420 ip_profile['gateway-address'] = ip_profile_params.gateway_address
421 if ip_profile_params.has_field('dns_server') and len(ip_profile_params.dns_server) > 0:
422 ip_profile['dns-address'] = ip_profile_params.dns_server[0].address
423 if ip_profile_params.has_field('dhcp_params'):
424 ip_profile['dhcp'] = {}
425 ip_profile['dhcp']['enabled'] = ip_profile_params.dhcp_params.enabled
426 ip_profile['dhcp']['start-address'] = ip_profile_params.dhcp_params.start_address
427 ip_profile['dhcp']['count'] = ip_profile_params.dhcp_params.count
428 else:
429 network["netmap-create"] = vlr.name
430 if vlr.om_datacenter_name:
431 network["datacenter"] = vlr.om_datacenter_name
432 elif vld_msg.has_field("om_datacenter"):
433 network["datacenter"] = vld_msg.om_datacenter
434 elif "datacenter" in openmano_instance_create:
435 network["datacenter"] = openmano_instance_create["datacenter"]
436 if network:
437 openmano_instance_create["networks"][vld_msg.name]["sites"].append(network)
438 if ip_profile:
439 openmano_instance_create["networks"][vld_msg.name]['ip-profile'] = ip_profile
440
441 return yaml.safe_dump(openmano_instance_create, default_flow_style=False,width=1000)
442
443 @property
444 def scaling_instance_create_yaml(self):
445 self._log.debug("Creating instance-scenario-create input file for nsd %s with name %s", self.nsd.id, self._nsr_config_msg.name)
446 scaling_instance_create = {}
447 scaling_instance_create["vnfs"] = {}
448 scaling_instance_create["name"] = self._nsr_config_msg.name+"scal1"
449 scaling_instance_create["description"] = "Scaling Group Instance Scenario File"
450 scaling_instance_create["scenario"] = self._rift_vnfd_id
451
452 if self._nsr_config_msg.has_field("om_datacenter"):
453 scaling_instance_create["datacenter"] = self._nsr_config_msg.om_datacenter
454 scaling_instance_create["vnfs"] = {}
455 for vnfr in self._vnfrs:
456 if "om_datacenter" in vnfr.vnfr.vnfr_msg:
457 vnfr_name = vnfr.vnfr.vnfd.name + "__" + str(vnfr.vnfr.vnfr_msg.member_vnf_index_ref)
458 scaling_instance_create["vnfs"][vnfr_name] = {"datacenter": vnfr.vnfr.vnfr_msg.om_datacenter}
459 scaling_instance_create["networks"] = {}
460 for vld_msg in self._nsd_msg.vld:
461 scaling_instance_create["networks"][vld_msg.name] = {}
462 scaling_instance_create["networks"][vld_msg.name]["sites"] = list()
463 for vlr in self._vlrs:
464 if vlr.vld_msg.name == vld_msg.name:
465 self._log.debug("Received VLR name %s, VLR DC: %s for VLD: %s",vlr.vld_msg.name,
466 vlr.om_datacenter_name,vld_msg.name)
467 #network["vim-network-name"] = vld_msg.name
468 network = {}
469 ip_profile = {}
470 if vld_msg.vim_network_name:
471 network["netmap-use"] = vld_msg.vim_network_name
472 return yaml.safe_dump(scaling_instance_create, default_flow_style=False,width=1000)
473
474
475 @asyncio.coroutine
476 def add_vlr(self, vlr):
477 self._vlrs.append(vlr)
478 yield from self._publisher.publish_vlr(None, vlr.vlr_msg)
479 yield from asyncio.sleep(1, loop=self._loop)
480
481 @asyncio.coroutine
482 def remove_vlr(self, vlr):
483 if vlr in self._vlrs:
484 self._vlrs.remove(vlr)
485 yield from self._publisher.unpublish_vlr(None, vlr.vlr_msg)
486 yield from asyncio.sleep(1, loop=self._loop)
487
488 @asyncio.coroutine
489 def delete_vlr(self, vlr):
490 if vlr in self._vlrs:
491 self._vlrs.remove(vlr)
492 if not vlr.vld_msg.vim_network_name:
493 yield from self._loop.run_in_executor(
494 None,
495 self._cli_api.ns_vim_network_delete,
496 vlr.name,
497 vlr.om_datacenter_name)
498 yield from self._publisher.unpublish_vlr(None, vlr.vlr_msg)
499 yield from asyncio.sleep(1, loop=self._loop)
500
501 @asyncio.coroutine
502 def add_vnfr(self, vnfr):
503 vnfr = OpenmanoVnfr(self._log, self._loop, self._cli_api, vnfr, nsd=self.nsd)
504 yield from vnfr.create()
505 self._vnfrs.append(vnfr)
506
507 @asyncio.coroutine
508 def add_nsr(self, nsr, vnfr):
509 self._nsrs[vnfr.id] = nsr
510
511 @asyncio.coroutine
512 def delete(self):
513 if not self._created:
514 self._log.debug("NSD wasn't created. Skipping delete.")
515 return
516
517 self._log.debug("Deleting openmano nsr")
518
519 yield from self._loop.run_in_executor(
520 None,
521 self._cli_api.ns_delete,
522 self._nsd_uuid,
523 )
524
525 self._log.debug("Deleting openmano vnfrs")
526 for vnfr in self._vnfrs:
527 yield from vnfr.delete()
528
529
530 @asyncio.coroutine
531 def create(self):
532 self._log.debug("Creating openmano scenario")
533 name_uuid_map = yield from self._loop.run_in_executor(
534 None,
535 self._cli_api.ns_list,
536 )
537
538 if self._nsd_msg.name in name_uuid_map:
539 self._log.debug("Found existing openmano scenario")
540 self._nsd_uuid = name_uuid_map[self._nsd_msg.name]
541 return
542
543
544 # Use the nsd uuid as the scenario name to rebind to existing
545 # scenario on reload or to support muliple instances of the name
546 # nsd
547 self._nsd_uuid, _ = yield from self._loop.run_in_executor(
548 None,
549 self._cli_api.ns_create,
550 self.openmano_nsd_yaml,
551 self._nsd_msg.name
552 )
553 fpath = dump_openmano_descriptor(
554 "{}_nsd".format(self._nsd_msg.name),
555 self.openmano_nsd_yaml,
556 )
557
558 self._log.debug("Dumped Openmano NS descriptor to: %s", fpath)
559
560 self._created = True
561
562 @asyncio.coroutine
563 def scaling_scenario_create(self):
564 self._log.debug("Creating Openmano Scenario for the Scaling Group VNF")
565 self._vnfd_nsd_uuid, _ = yield from self._loop.run_in_executor(
566 None,
567 self._cli_api.ns_create,
568 self.scaling_group_nsd_yaml,
569 self._rift_vnfd_id
570 )
571 fpath = dump_openmano_descriptor(
572 "{}_scaling_group_nsd".format(self._rift_vnfd_id),
573 self.scaling_group_nsd_yaml,
574 )
575 self._log.debug("Dumped Scaling group scenario to '%s'", fpath)
576 self._created = True
577
578 @asyncio.coroutine
579 def instance_monitor_task(self):
580 self._log.debug("Starting Instance monitoring task")
581
582 start_time = time.time()
583 active_vnfs = []
584
585 while True:
586 yield from asyncio.sleep(1, loop=self._loop)
587
588 try:
589 instance_resp_json = yield from self._loop.run_in_executor(
590 None,
591 self._http_api.get_instance,
592 self._nsr_uuid,
593 )
594
595 self._log.debug("Got instance response: %s for NSR ID %s",
596 instance_resp_json,
597 self._nsr_uuid)
598
599 except openmano_client.InstanceStatusError as e:
600 self._log.error("Could not get NS instance status: %s", str(e))
601 continue
602
603 def all_vms_active(vnf):
604 for vm in vnf["vms"]:
605 vm_status = vm["status"]
606 vm_uuid = vm["uuid"]
607 if vm_status != "ACTIVE":
608 self._log.debug("VM is not yet active: %s (status: %s)", vm_uuid, vm_status)
609 return False
610
611 return True
612
613 def any_vm_active_nomgmtip(vnf):
614 for vm in vnf["vms"]:
615 vm_status = vm["status"]
616 vm_uuid = vm["uuid"]
617 if vm_status != "ACTIVE":
618 self._log.debug("VM is not yet active: %s (status: %s)", vm_uuid, vm_status)
619 return False
620
621 return True
622
623 def any_vms_error(vnf):
624 for vm in vnf["vms"]:
625 vm_status = vm["status"]
626 vm_vim_info = vm["vim_info"]
627 vm_uuid = vm["uuid"]
628 if vm_status == "ERROR":
629 self._log.error("VM Error: %s (vim_info: %s)", vm_uuid, vm_vim_info)
630 return True
631
632 return False
633
634 def get_vnf_ip_address(vnf):
635 if "ip_address" in vnf:
636 return vnf["ip_address"].strip()
637 return None
638
639 def get_vnf_mac_address(vnf):
640 if "mac_address" in vnf:
641 return vnf["mac_address"].strip()
642 return None
643
644 def get_ext_cp_info(vnf):
645 cp_info_list = []
646 for vm in vnf["vms"]:
647 if "interfaces" not in vm:
648 continue
649
650 for intf in vm["interfaces"]:
651 if "external_name" not in intf:
652 continue
653
654 if not intf["external_name"]:
655 continue
656
657 ip_address = intf["ip_address"]
658 if ip_address is None:
659 ip_address = "0.0.0.0"
660
661 mac_address = intf["mac_address"]
662 if mac_address is None:
663 mac_address="00:00:00:00:00:00"
664
665 cp_info_list.append((intf["external_name"], ip_address, mac_address))
666
667 return cp_info_list
668
669 def get_vnf_status(vnfr):
670 # When we create an openmano descriptor we use <name>__<idx>
671 # to come up with openmano constituent VNF name. Use this
672 # knowledge to map the vnfr back.
673 openmano_vnfr_suffix = "__{}".format(
674 vnfr.vnfr.vnfr_msg.member_vnf_index_ref
675 )
676
677 for vnf in instance_resp_json["vnfs"]:
678 if vnf["vnf_name"].endswith(openmano_vnfr_suffix):
679 return vnf
680
681 self._log.warning("Could not find vnf status with name that ends with: %s",
682 openmano_vnfr_suffix)
683 return None
684
685 for vnfr in self._vnfrs:
686 if vnfr in active_vnfs:
687 # Skipping, so we don't re-publish the same VNF message.
688 continue
689
690 vnfr_msg = vnfr.vnfr.vnfr_msg.deep_copy()
691 vnfr_msg.operational_status = "init"
692
693 try:
694 vnf_status = get_vnf_status(vnfr)
695 self._log.debug("Found VNF status: %s", vnf_status)
696 if vnf_status is None:
697 self._log.error("Could not find VNF status from openmano")
698 self._state = OpenmanoNSRecordState.FAILED
699 vnfr_msg.operational_status = "failed"
700 yield from self._publisher.publish_vnfr(None, vnfr_msg)
701 return
702
703 # If there was a VNF that has a errored VM, then just fail the VNF and stop monitoring.
704 if any_vms_error(vnf_status):
705 self._log.debug("VM was found to be in error state. Marking as failed.")
706 self._state = OpenmanoNSRecordState.FAILED
707 vnfr_msg.operational_status = "failed"
708 yield from self._publisher.publish_vnfr(None, vnfr_msg)
709 return
710
711 if (time.time() - start_time) > OpenmanoNsr.TIMEOUT_SECS:
712 self._log.error("NSR timed out before reaching running state")
713 self._state = OpenmanoNSRecordState.FAILED
714 vnfr_msg.operational_status = "failed"
715 yield from self._publisher.publish_vnfr(None, vnfr_msg)
716 return
717
718 if all_vms_active(vnf_status):
719 vnf_ip_address = get_vnf_ip_address(vnf_status)
720 vnf_mac_address = get_vnf_mac_address(vnf_status)
721
722 if vnf_ip_address is None:
723 self._log.warning("No IP address obtained "
724 "for VNF: {}, will retry.".format(
725 vnf_status['vnf_name']))
726 continue
727
728 self._log.debug("All VMs in VNF are active. Marking as running.")
729 vnfr_msg.operational_status = "running"
730
731 self._log.debug("Got VNF ip address: %s, mac-address: %s", vnf_ip_address, vnf_mac_address)
732 vnfr_msg.mgmt_interface.ip_address = vnf_ip_address
733 vnfr_msg.vnf_configuration.config_access.mgmt_ip_address = vnf_ip_address
734
735
736 for vm in vnf_status["vms"]:
737 if vm["uuid"] not in self._vdur_console_handler:
738 vdur_console_handler = VnfrConsoleOperdataDtsHandler(self._dts, self._log, self._loop,
739 self, vnfr_msg.id,vm["uuid"],vm["name"])
740 yield from vdur_console_handler.register()
741 self._vdur_console_handler[vm["uuid"]] = vdur_console_handler
742
743 vdur_msg = vnfr_msg.vdur.add()
744 vdur_msg.vim_id = vm["vim_vm_id"]
745 vdur_msg.id = vm["uuid"]
746
747 # Add connection point information for the config manager
748 cp_info_list = get_ext_cp_info(vnf_status)
749 for (cp_name, cp_ip, cp_mac_addr) in cp_info_list:
750 cp = vnfr_msg.connection_point.add()
751 cp.name = cp_name
752 cp.short_name = cp_name
753 cp.ip_address = cp_ip
754 cp.mac_address = cp_mac_addr
755
756 yield from self._publisher.publish_vnfr(None, vnfr_msg)
757 active_vnfs.append(vnfr)
758
759
760 except Exception as e:
761 vnfr_msg.operational_status = "failed"
762 self._state = OpenmanoNSRecordState.FAILED
763 yield from self._publisher.publish_vnfr(None, vnfr_msg)
764 self._log.exception("Caught exception publishing vnfr info: %s", str(e))
765 return
766
767 if len(active_vnfs) == len(self._vnfrs):
768 self._state = OpenmanoNSRecordState.RUNNING
769 self._log.info("All VNF's are active. Exiting NSR monitoring task")
770 return
771
772 @asyncio.coroutine
773 def deploy(self,nsr_msg):
774 if self._nsd_uuid is None:
775 raise ValueError("Cannot deploy an uncreated nsd")
776
777 self._log.debug("Deploying openmano scenario")
778
779 name_uuid_map = yield from self._loop.run_in_executor(
780 None,
781 self._cli_api.ns_instance_list,
782 )
783
784 if self._nsr_config_msg.name in name_uuid_map:
785 self._log.debug("Found existing instance with nsr name: %s", self._nsr_config_msg.name)
786 self._nsr_uuid = name_uuid_map[self._nsr_config_msg.name]
787 else:
788 self._nsr_msg = nsr_msg
789 fpath = dump_openmano_descriptor(
790 "{}_instance_sce_create".format(self._nsr_config_msg.name),
791 self.openmano_instance_create_yaml,
792 )
793 self._log.debug("Dumped Openmano NS Scenario Cretae to: %s", fpath)
794
795 self._nsr_uuid = yield from self._loop.run_in_executor(
796 None,
797 self._cli_api.ns_instance_scenario_create,
798 self.scaling_instance_create_yaml)
799
800
801 self._state = OpenmanoNSRecordState.INSTANTIATION_PENDING
802
803 self._monitor_task = asyncio.ensure_future(
804 self.instance_monitor_task(), loop=self._loop
805 )
806
807 @asyncio.coroutine
808 def scaling_scenario_deploy(self, nsr_msg):
809 self._log.debug("Deploying Scaling scenario")
810 self._nsr_msg = nsr_msg
811 self._rift_vnfd_id = rift_vnfd_id
812 fpath = dump_openmano_descriptor(
813 "{}_scale_instance".format(self._nsr_config_msg.name),
814 self.scaling_instance_create_yaml
815 )
816 self._state = OpenmanoNSRecordState.INIT
817
818 self._monitor_task = asyncio.ensure_future(
819 self.instance_monitor_task(), loop=self._loop
820 )
821
822 @asyncio.coroutine
823 def terminate(self):
824
825 for _,handler in self._vdur_console_handler.items():
826 handler._regh.deregister()
827
828 if self._nsr_uuid is None:
829 self._log.warning("Cannot terminate an un-instantiated nsr")
830 return
831
832 if self._monitor_task is not None:
833 self._monitor_task.cancel()
834 self._monitor_task = None
835
836 self._log.debug("Terminating openmano nsr")
837 yield from self._loop.run_in_executor(
838 None,
839 self._cli_api.ns_terminate,
840 self._nsr_uuid,
841 )
842
843 @asyncio.coroutine
844 def create_vlr(self,vlr):
845 self._log.debug("Creating openmano vim network VLR name %s, VLR DC: %s",vlr.vld_msg.name,
846 vlr.om_datacenter_name)
847 net_create = {}
848 net = {}
849 net['name'] = vlr.name
850 net['shared'] = True
851 net['type'] = 'bridge'
852 self._log.debug("Received ip profile is %s",vlr._ip_profile)
853 if vlr._ip_profile and vlr._ip_profile.has_field("ip_profile_params"):
854 ip_profile_params = vlr._ip_profile.ip_profile_params
855 ip_profile = {}
856 if ip_profile_params.ip_version == "ipv6":
857 ip_profile['ip_version'] = "IPv6"
858 else:
859 ip_profile['ip_version'] = "IPv4"
860 if ip_profile_params.has_field('subnet_address'):
861 ip_profile['subnet_address'] = ip_profile_params.subnet_address
862 if ip_profile_params.has_field('gateway_address'):
863 ip_profile['gateway_address'] = ip_profile_params.gateway_address
864 if ip_profile_params.has_field('dns_server') and len(ip_profile_params.dns_server) > 0:
865 ip_profile['dns_address'] = ip_profile_params.dns_server[0].address
866 if ip_profile_params.has_field('dhcp_params'):
867 ip_profile['dhcp_enabled'] = ip_profile_params.dhcp_params.enabled
868 ip_profile['dhcp_start_address'] = ip_profile_params.dhcp_params.start_address
869 ip_profile['dhcp_count'] = ip_profile_params.dhcp_params.count
870 net['ip_profile'] = ip_profile
871 net_create["network"]= net
872
873 net_create_msg = yaml.safe_dump(net_create,default_flow_style=False)
874 fpath = dump_openmano_descriptor(
875 "{}_vim_net_create_{}".format(self._nsr_config_msg.name,vlr.name),
876 net_create_msg)
877 self._log.debug("Dumped Openmano VIM Net create to: %s", fpath)
878
879 vim_network_uuid = yield from self._loop.run_in_executor(
880 None,
881 self._cli_api.ns_vim_network_create,
882 net_create_msg,
883 vlr.om_datacenter_name)
884 self._vlrs.append(vlr)
885
886
887
888
889 class OpenmanoNsPlugin(rwnsmplugin.NsmPluginBase):
890 """
891 RW Implentation of the NsmPluginBase
892 """
893 def __init__(self, dts, log, loop, publisher, ro_account):
894 self._dts = dts
895 self._log = log
896 self._loop = loop
897 self._publisher = publisher
898 self._cli_api = None
899 self._http_api = None
900 self._openmano_nsrs = {}
901 self._vnfr_uptime_tasks = {}
902
903 self._set_ro_account(ro_account)
904
905 def _set_ro_account(self, ro_account):
906 self._log.debug("Setting openmano plugin cloud account: %s", ro_account)
907 self._cli_api = openmano_client.OpenmanoCliAPI(
908 self.log,
909 ro_account.openmano.host,
910 ro_account.openmano.port,
911 ro_account.openmano.tenant_id,
912 )
913
914 self._http_api = openmano_client.OpenmanoHttpAPI(
915 self.log,
916 ro_account.openmano.host,
917 ro_account.openmano.port,
918 ro_account.openmano.tenant_id,
919 )
920
921 def set_state(self, nsr_id, state):
922 # Currently we update only during terminate to
923 # decide how to handle VL terminate
924 if state.value == OpenmanoNSRecordState.TERMINATE.value:
925 self._openmano_nsrs[nsr_id]._state = \
926 [member.value for name, member in \
927 OpenmanoNSRecordState.__members__.items() \
928 if member.value == state.value]
929
930 def create_nsr(self, nsr_config_msg, nsd_msg, key_pairs=None):
931 """
932 Create Network service record
933 """
934 openmano_nsr = OpenmanoNsr(
935 self._dts,
936 self._log,
937 self._loop,
938 self._publisher,
939 self._cli_api,
940 self._http_api,
941 nsd_msg,
942 nsr_config_msg,
943 key_pairs
944 )
945 self._openmano_nsrs[nsr_config_msg.id] = openmano_nsr
946
947 @asyncio.coroutine
948 def deploy(self, nsr_msg):
949 self._log.debug("Received NSR Deploy msg : %s", nsr_msg)
950 openmano_nsr = self._openmano_nsrs[nsr_msg.ns_instance_config_ref]
951 yield from openmano_nsr.create()
952 yield from openmano_nsr.deploy(nsr_msg)
953
954 @asyncio.coroutine
955 def deploy(self, nsr_msg):
956 self._log.debug("Received Scale out msg")
957 openmano_nsr = self._openmano_nsrs[nsr_msg.ns_instance_config_ref]
958 yield from openmano_nsr.scaling_scenario_create()
959 yield from openmano_nsr.scaling_scenario_deploy(nsr_msg)
960
961 @asyncio.coroutine
962 def instantiate_ns(self, nsr, xact):
963 """
964 Instantiate NSR with the passed nsr id
965 """
966 yield from nsr.instantiate(xact)
967
968 @asyncio.coroutine
969 def instantiate_vnf(self, nsr, vnfr, scaleout=False):
970 """
971 Instantiate NSR with the passed nsr id
972 """
973 openmano_nsr = self._openmano_nsrs[nsr.id]
974 if scaleout:
975 openmano_vnf_nsr = OpenmanoNsr(
976 self._dts,
977 self._log,
978 self._loop,
979 self._publisher,
980 self._cli_api,
981 self._http_api,
982 openmano_nsr.nsd_msg,
983 openmano_nsr.nsr_config_msg,
984 openmano_nsr.key_pairs,
985 vnfr.vnfd.id
986 )
987 # Add new nsr to parent nsr
988 try:
989 yield from openmano_nsr.add_nsr(openmano_vnf_nsr, vnfr)
990 except Exception as e:
991 self.log.exception("Add VNFR Error ", str(e))
992 try:
993 yield from openmano_vnf_nsr.add_vnfr(vnfr)
994 except Exception as e:
995 self.log.exception("Scenario Create Error", str(e))
996 try:
997 yield from openmano_vnf_nsr.create()
998 except Exception as e:
999 self.log.exception("Starting instance scenario create ", str(e))
1000 try:
1001 yield from openmano_vnf_nsr.deploy(openmano_vnf_nsr.nsr_msg)
1002 except Exception as e:
1003 self.log.exception("Unable to deploy scaling scenario ", str(e))
1004 else:
1005 yield from openmano_nsr.add_vnfr(vnfr)
1006
1007 # TODO: Create a task to monitor nsr/vnfr status
1008 vnfr_msg = vnfr.vnfr_msg.deep_copy()
1009 vnfr_msg.operational_status = "init"
1010
1011 self._log.debug("Attempting to publish openmano vnf: %s", vnfr_msg)
1012 with self._dts.transaction() as xact:
1013 yield from self._publisher.publish_vnfr(xact, vnfr_msg)
1014 self._log.debug("Creating a task to update uptime for vnfr: %s", vnfr.id)
1015 self._vnfr_uptime_tasks[vnfr.id] = self._loop.create_task(self.vnfr_uptime_update(vnfr))
1016 with self._dts.transaction() as xact:
1017 yield from openmano_vnf_nsr._publisher.publish_vnfr(xact, vnfr_msg)
1018
1019 def vnfr_uptime_update(self, vnfr):
1020 try:
1021 vnfr_ = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict({'id': vnfr.id})
1022 while True:
1023 vnfr_.uptime = int(time.time()) - vnfr._create_time
1024 yield from self._publisher.publish_vnfr(None, vnfr_)
1025 yield from asyncio.sleep(2, loop=self._loop)
1026 except asyncio.CancelledError:
1027 self._log.debug("Received cancellation request for vnfr_uptime_update task")
1028
1029 @asyncio.coroutine
1030 def instantiate_vl(self, nsr, vlr):
1031 """
1032 Instantiate NSR with the passed nsr id
1033 """
1034 self._log.debug("Received instantiate VL for NSR {}; VLR {}".format(nsr.id,vlr))
1035 openmano_nsr = self._openmano_nsrs[nsr.id]
1036 if openmano_nsr._state == OpenmanoNSRecordState.RUNNING:
1037 yield from openmano_nsr.create_vlr(vlr)
1038 yield from self._publisher.publish_vlr(None, vlr.vlr_msg)
1039 else:
1040 yield from openmano_nsr.add_vlr(vlr)
1041
1042 @asyncio.coroutine
1043 def terminate_ns(self, nsr):
1044 """
1045 Terminate the network service
1046 """
1047 nsr_id = nsr.id
1048 openmano_nsr = self._openmano_nsrs[nsr_id]
1049
1050 yield from openmano_nsr.terminate()
1051 yield from openmano_nsr.delete()
1052
1053 with self._dts.transaction() as xact:
1054 for vnfr in openmano_nsr.vnfrs:
1055 self._log.debug("Unpublishing VNFR: %s", vnfr.vnfr.vnfr_msg)
1056 yield from self._publisher.unpublish_vnfr(xact, vnfr.vnfr.vnfr_msg)
1057
1058 del self._openmano_nsrs[nsr_id]
1059
1060 @asyncio.coroutine
1061 def terminate_vnf(self, vnfr):
1062 """
1063 Terminate the network service
1064 """
1065 if vnfr.id in self._vnfr_uptime_tasks:
1066 self._vnfr_uptime_tasks[vnfr.id].cancel()
1067
1068 @asyncio.coroutine
1069 def terminate_vl(self, vlr):
1070 """
1071 Terminate the virtual link
1072 """
1073 self._log.debug("Received terminate VL for VLR {}".format(vlr))
1074 openmano_nsr = self._openmano_nsrs[vlr._nsr_id]
1075 if openmano_nsr._state == OpenmanoNSRecordState.RUNNING:
1076 yield from openmano_nsr.delete_vlr(vlr)
1077 else:
1078 yield from openmano_nsr.remove_vlr(vlr)