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