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