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