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