3 # Copyright 2016 RIFT.IO Inc
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
25 gi
.require_version('RwDts', '1.0')
26 gi
.require_version('RwVnfrYang', '1.0')
27 from gi
.repository
import (
31 gi
.require_version('RwKeyspec', '1.0')
32 from gi
.repository
.RwKeyspec
import quoted_key
34 import rift
.openmano
.rift2openmano
as rift2openmano
35 import rift
.openmano
.openmano_client
as openmano_client
36 from . import nsmpluginbase
42 if sys
.version_info
< (3, 4, 4):
43 asyncio
.ensure_future
= asyncio
.async
46 DUMP_OPENMANO_DIR
= os
.path
.join(
47 os
.environ
["RIFT_VAR_ROOT"],
48 "openmano_descriptors"
52 def dump_openmano_descriptor(name
, descriptor_str
):
53 filename
= "{}_{}.yaml".format(
54 time
.strftime("%Y%m%d-%H%M%S"),
58 filepath
= os
.path
.join(
64 if not os
.path
.exists(DUMP_OPENMANO_DIR
):
65 os
.makedirs(DUMP_OPENMANO_DIR
)
67 with
open(filepath
, 'w') as hdl
:
68 hdl
.write(descriptor_str
)
71 print("Failed to dump openmano descriptor: %s" % str(e
))
75 class VNFExistError(Exception):
78 class VnfrConsoleOperdataDtsHandler(object):
79 """ registers 'D,/vnfr:vnfr-console/vnfr:vnfr[id]/vdur[id]' and handles CRUD from DTS"""
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
)))
87 def __init__(self
, project
, dts
, log
, loop
, nsr
, vnfr_id
, vdur_id
, vdu_id
):
88 self
._project
= project
95 self
._vnfr
_id
= vnfr_id
96 self
._vdur
_id
= vdur_id
101 """ Register for VNFR VDU Operational Data read from dts """
104 def on_prepare(xact_info
, action
, ks_path
, msg
):
105 """ prepare callback from dts """
106 xpath
= ks_path
.to_xpath(RwVnfrYang
.get_schema())
108 "Got VNFR VDU Opdata xact_info: %s, action: %s): %s:%s",
109 xact_info
, action
, xpath
, msg
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
)
117 console_url
= yield from self
._loop
.run_in_executor(
119 self
._nsr
._http
_api
.get_instance_vm_console_url
,
124 self
._log
.debug("Got console response: %s for NSR ID %s vdur ID %s",
129 vdur_console
= RwVnfrYang
.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur()
130 vdur_console
.id = self
._vdur
_id
132 vdur_console
.console_url
= console_url
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",
139 vdur_console
= RwVnfrYang
.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur()
140 vdur_console
.id = self
._vdur
_id
141 vdur_console
.console_url
= 'none'
143 xact_info
.respond_xpath(rsp_code
=rwdts
.XactRspCode
.ACK
,
144 xpath
=self
.vnfr_vdu_console_xpath
,
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
)
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
,
158 flags
=rwdts
.Flag
.PUBLISHER
,
163 class OpenmanoVnfr(object):
164 def __init__(self
, log
, loop
, cli_api
, http_api
, vnfr
, nsd
, ssh_key
=None):
167 self
._cli
_api
= cli_api
168 self
._http
_api
= http_api
170 self
._vnfd
_id
= vnfr
.vnfd
.id
174 self
._created
= False
177 self
._ssh
_key
= ssh_key
181 return rift2openmano
.RiftVNFD(self
._vnfr
.vnfd
)
188 def rift_vnfd_id(self
):
192 def openmano_vnfd_id(self
):
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
)
202 def openmano_vnfd_yaml(self
):
203 return yaml
.safe_dump(self
.openmano_vnfd
, default_flow_style
=False)
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"]
214 self
._vnf
_id
= openmano_vnfd
['uuid']
217 except Exception as e
:
218 self
._log
.error("Failed to create vnf on Openmano RO : %s", e
)
222 if not self
._created
:
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.")
230 self
._cli
_api
.vnf_delete(self
._vnf
_id
)
231 except Exception as e
:
235 class OpenmanoNSRecordState(Enum
):
236 """ Network Service Record State """
237 # Make sure the values match with NetworkServiceRecordState
239 INSTANTIATION_PENDING
= 102
251 class OpenmanoNsr(object):
253 INSTANCE_TERMINATE_TIMEOUT
= 60
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
261 self
._publisher
= publisher
262 self
._cli
_api
= cli_api
263 self
._http
_api
= http_api
265 self
._nsd
_msg
= nsd_msg
266 self
._nsr
_config
_msg
= nsr_config_msg
270 self
._vdur
_console
_handler
= {}
271 self
._key
_pairs
= key_pairs
272 self
._ssh
_key
= ssh_key
274 self
._nsd
_uuid
= None
275 self
._nsr
_uuid
= None
276 self
._nsd
_msg
= nsd_msg
280 self
._created
= False
282 self
._monitor
_task
= None
283 self
._rift
_vnfd
_id
= rift_vnfd_id
284 self
._state
= OpenmanoNSRecordState
.INIT
287 self
._active
_nets
= 0
291 return rift2openmano
.RiftNSD(self
._nsd
_msg
)
294 def rift_vnfd_id(self
):
295 return self
._rift
_vnfd
_id
302 def nsr_config_msg(self
):
303 return self
._nsr
_config
_msg
308 return {v
.rift_vnfd_id
: v
.vnfd
for v
in self
._vnfrs
}
312 return {v
.rift_vnfd_id
: v
.openmano_vnfd_id
for v
in self
._vnfrs
}
320 return self
._key
_pairs
332 return self
._http
_api
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)
341 def openmano_scaling_yaml(self
):
342 self
._log
.debug("Creating Openmano Scaling Descriptor %s")
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
))
349 def get_ssh_key_pairs(self
):
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
)
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
)
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'])
366 cloud_config
["key-pairs"] = key_pairs
369 for user_entry
in self
._nsr
_config
_msg
.user
:
370 self
._log
.debug("User present is %s",user_entry
)
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
)
379 for user_entry
in self
._nsd
_msg
.user
:
380 self
._log
.debug("User present in NSD is %s",user_entry
)
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
)
389 cloud_config
["users"] = users
391 self
._log
.debug("Cloud config formed is %s",cloud_config
)
396 def openmano_instance_create_yaml(self
):
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
404 cloud_config
= self
.get_ssh_key_pairs()
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
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"
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
451 self
._log
.debug("Gateway Address {}".format(gateway_ip_addr
))
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']))
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"]
473 openmano_instance_create
["networks"][vld_msg
.name
]["sites"].append(network
)
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
)))
479 return yaml
.safe_dump(openmano_instance_create
, default_flow_style
=False,width
=1000)
482 def scaling_instance_create_yaml(self
, scaleout
=False):
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
489 scaling_instance_create
["scenario"] = self
._nsd
_uuid
+ "__" +group_list
.name
491 scaling_instance_create
["scenario"] = self
._nsd
_uuid
492 scaling_instance_create
["description"] = self
._nsr
_config
_msg
.description
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
512 if vld_msg
.vim_network_name
:
513 network
["netmap-use"] = vld_msg
.vim_network_name
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"]
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
)))
527 return yaml
.safe_dump(scaling_instance_create
, default_flow_style
=False, width
=1000)
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
)
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
)
543 def remove_vnf(self
,vnf
):
544 self
._log
.debug("Unpublishing VNFR - {}".format(vnf
))
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 !")
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))
560 yield from asyncio
.sleep(1, loop
=self
._loop
)
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(
569 self
._cli
_api
.ns_vim_network_delete
,
572 yield from self
._publisher
.unpublish_vlr(None, vlr
.vlr_msg
)
573 yield from asyncio
.sleep(1, loop
=self
._loop
)
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
)
583 def add_nsr(self
, nsr
, vnfr
):
584 self
._nsrs
[vnfr
.id] = nsr
587 if not self
._created
:
588 self
._log
.debug("NSD wasn't created. Skipping delete.")
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.
597 self
._log
.debug("Fetching Instance Scenario List before Deleting Scenario")
599 instances
= self
.http_api
.instances()
601 scenarios_instances
= False
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
609 self
._log
.debug("Scenario Instances Dependency Exists : %s", scenarios_instances
)
611 if not scenarios_instances
:
613 self
._cli
_api
.ns_delete(self
._nsd
_uuid
)
614 except Exception as e
:
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
:
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")
629 deleted_vnf_id_list
.append(vnfr
.vnfr
.vnfd
.id)
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
639 self
._nsd
_uuid
= yaml
.load(nsd_yaml
)['uuid']
640 fpath
= dump_openmano_descriptor(
641 "{}_nsd".format(self
._nsd
_msg
.name
),
645 self
._log
.debug("Dumped Openmano NS descriptor to: %s", fpath
)
648 except Exception as e
:
649 self
._log
.error("Failed to create scenario on Openmano RO : %s", e
)
653 def scaling_scenario_create(self
):
654 self
._log
.debug("Creating scaling openmano scenario")
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
660 self
._nsd
_uuid
= yaml
.load(nsd_yaml
)['uuid']
662 fpath
= dump_openmano_descriptor(
663 "{}_sgd".format(self
._nsd
_msg
.name
),
664 self
.scaling_instance_create_yaml
,
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)))
677 results
= yield from self
._dts
.query_read(xpath
, rwdts
.XactFlag
.MERGE
)
679 for result
in results
:
680 entry
= yield from result
681 nsr_op
= entry
.result
688 def instance_monitor_task(self
):
689 self
._log
.debug("Starting Instance monitoring task")
691 start_time
= time
.time()
693 nsr
= yield from self
.get_nsr_opdata()
698 yield from asyncio
.sleep(1, loop
=self
._loop
)
701 instance_resp_json
= yield from self
._loop
.run_in_executor(
703 self
._http
_api
.get_instance
,
707 self
._log
.debug("Got instance response: %s for NSR ID %s",
711 for vnf
in instance_resp_json
['vnfs']:
712 for vm
in vnf
['vms']:
713 if vm
['status'] == 'ACTIVE':
715 for net
in instance_resp_json
['nets']:
716 if net
['status'] == 'ACTIVE':
719 nsr
.orchestration_progress
.vms
.active
= active_vms
720 nsr
.orchestration_progress
.networks
.active
= active_nets
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
726 yield from self
._publisher
.publish_nsr_opdata(None, nsr
)
728 except openmano_client
.InstanceStatusError
as e
:
729 self
._log
.error("Could not get NS instance status: %s", str(e
))
733 def all_vms_active(vnf
):
734 for vm
in vnf
["vms"]:
735 vm_status
= vm
["status"]
737 if vm_status
!= "ACTIVE":
738 self
._log
.debug("VM is not yet active: %s (status: %s)", vm_uuid
, vm_status
)
743 def any_vm_active_nomgmtip(vnf
):
744 for vm
in vnf
["vms"]:
745 vm_status
= vm
["status"]
747 if vm_status
!= "ACTIVE":
748 self
._log
.debug("VM is not yet active: %s (status: %s)", vm_uuid
, vm_status
)
753 def any_vms_error(vnf
):
754 for vm
in vnf
["vms"]:
755 vm_status
= vm
["status"]
756 vm_vim_info
= vm
["vim_info"]
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']
764 def get_vnf_ip_address(vnf
):
765 if "ip_address" in vnf
:
766 return vnf
["ip_address"].strip()
769 cp_info_list
= get_ext_cp_info(vnf
)
771 for cp_name
, ip
, mac
in cp_info_list
:
772 for vld
in self
.nsd
.vlds
:
773 if not vld
.mgmt_network
:
776 for vld_cp
in vld
.vnfd_connection_point_ref
:
777 if vld_cp
.vnfd_connection_point_ref
== cp_name
:
781 def get_vnf_mac_address(vnf
):
782 if "mac_address" in vnf
:
783 return vnf
["mac_address"].strip()
786 def get_ext_cp_info(vnf
):
788 for vm
in vnf
["vms"]:
789 if "interfaces" not in vm
:
792 for intf
in vm
["interfaces"]:
793 if "external_name" not in intf
:
796 if not intf
["external_name"]:
799 ip_address
= intf
["ip_address"]
800 if ip_address
is None:
801 ip_address
= "0.0.0.0"
803 mac_address
= intf
["mac_address"]
804 if mac_address
is None:
805 mac_address
="00:00:00:00:00:00"
807 cp_info_list
.append((intf
["external_name"], ip_address
, mac_address
))
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
819 for vnf
in instance_resp_json
["vnfs"]:
820 if vnf
["vnf_name"].endswith(openmano_vnfr_suffix
):
823 self
._log
.warning("Could not find vnf status with name that ends with: %s",
824 openmano_vnfr_suffix
)
827 for vnfr
in self
._vnfrs
:
828 if vnfr
in active_vnfs
:
829 # Skipping, so we don't re-publish the same VNF message.
832 vnfr_msg
= vnfr
.vnfr
.vnfr_msg
.deep_copy()
833 vnfr_msg
.operational_status
= "init"
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
)
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
)
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
)
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
)
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
)
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']))
872 self
._log
.debug("All VMs in VNF are active. Marking as running.")
873 vnfr_msg
.operational_status
= "running"
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
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']
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
892 vdur_msg
= vnfr_msg
.vdur
.add()
893 vdur_msg
.vim_id
= vm
["vim_vm_id"]
894 vdur_msg
.id = vm
["uuid"]
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()
901 cp
.short_name
= cp_name
902 cp
.ip_address
= cp_ip
903 cp
.mac_address
= cp_mac_addr
905 yield from self
._publisher
.publish_vnfr(None, vnfr_msg
)
906 active_vnfs
.append(vnfr
)
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
))
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")
921 def deploy(self
,nsr_msg
):
922 if self
._nsd
_uuid
is None:
923 raise ValueError("Cannot deploy an uncreated nsd")
925 self
._log
.debug("Deploying openmano instance scenario")
927 name_uuid_map
= yield from self
._loop
.run_in_executor(
929 self
._cli
_api
.ns_instance_list
,
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
]
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
,
941 self
._log
.debug("Dumped Openmano instance Scenario Cretae to: %s", fpath
)
943 self
._nsr
_uuid
= yield from self
._loop
.run_in_executor(
945 self
._cli
_api
.ns_instance_scenario_create
,
946 self
.openmano_instance_create_yaml
)
948 self
._state
= OpenmanoNSRecordState
.INSTANTIATION_PENDING
950 self
._monitor
_task
= asyncio
.ensure_future(
951 self
.instance_monitor_task(), loop
=self
._loop
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
963 self
._nsr
_uuid
= yield from self
._loop
.run_in_executor(
965 self
._cli
_api
.ns_instance_scenario_create
,
966 self
.scaling_instance_create_yaml
)
968 self
._state
= OpenmanoNSRecordState
.INSTANTIATION_PENDING
970 self
._monitor
_task
= asyncio
.ensure_future(
971 self
.instance_monitor_task(), loop
=self
._loop
974 self
._state
= OpenmanoNSRecordState
.INIT
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):
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")
987 if self
._monitor
_task
is not None:
988 self
._monitor
_task
.cancel()
989 self
._monitor
_task
= None
991 self
._log
.debug("Terminating openmano nsr")
992 self
._cli
_api
.ns_terminate(self
._nsr
_uuid
)
995 def create_vlr(self
,vlr
):
996 self
._log
.error("Creating openmano vim network VLR name %s, VLR DC: %s",vlr
.vld_msg
.name
,
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
1007 if ip_profile_params
.ip_version
== "ipv6":
1008 ip_profile
['ip_version'] = "IPv6"
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
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
),
1028 self
._log
.error("Dumped Openmano VIM Net create to: %s", fpath
)
1030 vim_network_uuid
= yield from self
._loop
.run_in_executor(
1032 self
._cli
_api
.ns_vim_network_create
,
1034 vlr
.datacenter_name
)
1035 self
._vlrs
.append(vlr
)
1039 class OpenmanoNsPlugin(nsmpluginbase
.NsmPluginBase
):
1041 RW Implentation of the NsmPluginBase
1043 def __init__(self
, dts
, log
, loop
, publisher
, ro_account
, project
):
1047 self
._publisher
= publisher
1048 self
._project
= project
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
1056 self
._set
_ro
_account
(ro_account
)
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(
1062 ro_account
.openmano
.host
,
1063 ro_account
.openmano
.port
,
1064 ro_account
.openmano
.tenant_id
,
1067 self
._http
_api
= openmano_client
.OpenmanoHttpAPI(
1069 ro_account
.openmano
.host
,
1070 ro_account
.openmano
.port
,
1071 ro_account
.openmano
.tenant_id
,
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
]
1083 def create_nsr(self
, nsr_config_msg
, nsd_msg
, key_pairs
=None, ssh_key
=None):
1085 Create Network service record
1087 openmano_nsr
= OpenmanoNsr(
1100 self
.log
.debug("NSR created in openmano nsm %s", openmano_nsr
)
1101 self
._openmano
_nsrs
[nsr_config_msg
.id] = openmano_nsr
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
)
1111 def instantiate_ns(self
, nsr
, xact
):
1113 Instantiate NSR with the passed nsr id
1115 yield from nsr
.instantiate(xact
)
1118 def instantiate_vnf(self
, nsr
, vnfr
, scaleout
=False):
1120 Instantiate NSR with the passed nsr id
1122 openmano_nsr
= self
._openmano
_nsrs
[nsr
.id]
1124 self
._log
.debug("Scaleout set as True. Creating Scaling VNFR : {}".format(vnfr
))
1125 openmano_vnf_nsr
= OpenmanoNsr(
1133 openmano_nsr
.nsd_msg
,
1134 openmano_nsr
.nsr_config_msg
,
1135 openmano_nsr
.key_pairs
,
1137 rift_vnfd_id
=vnfr
.vnfd
.id,
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
)
1148 yield from openmano_nsr
.add_nsr(openmano_vnf_nsr
, vnfr
)
1149 except Exception as e
:
1150 self
.log
.exception(str(e
))
1152 yield from openmano_vnf_nsr
.add_vnfr(vnfr
)
1153 except Exception as e
:
1154 self
.log
.exception(str(e
))
1156 yield from openmano_vnf_nsr
.scaling_scenario_create()
1157 except Exception as e
:
1158 self
.log
.exception(str(e
))
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
))
1164 self
._log
.debug("Creating constituent VNFR - {}; for NSR - {}".format(vnfr
, nsr
))
1165 yield from openmano_nsr
.add_vnfr(vnfr
)
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"
1172 self
._log
.debug("Attempting to publish openmano vnf: %s", vnfr_msg
)
1173 yield from self
._publisher
.publish_vnfr(None, vnfr_msg
)
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
)
1181 def instantiate_vl(self
, nsr
, vlr
):
1183 Instantiate NSR with the passed nsr id
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
)
1191 yield from openmano_nsr
.add_vlr(vlr
)
1194 def terminate_ns(self
, nsr
):
1196 Terminate the network service
1198 self
._log
.debug("Terminate Received for Openamno NSR - {}".format(nsr
))
1200 openmano_nsr
= self
._openmano
_nsrs
[nsr_id
]
1202 for _
,handler
in openmano_nsr
._vdur
_console
_handler
.items():
1203 handler
._regh
.deregister()
1205 yield from self
._loop
.run_in_executor(
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
)
1215 del self
._openmano
_nsrs
[nsr_id
]
1217 def terminate(self
, openmano_nsr
):
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
))
1226 def terminate_vnf(self
, nsr
, vnfr
, scalein
=False):
1228 Terminate the network service
1231 self
._log
.debug("Terminating Scaling VNFR - {}".format(vnfr
))
1232 openmano_vnf_nsr
= self
._openmano
_nsr
_by
_vnfr
_id
[vnfr
.id]
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
))
1240 yield from openmano_vnf_nsr
.remove_vnf(vnfr
)
1243 def terminate_vl(self
, vlr
):
1245 Terminate the virtual link
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
)
1252 yield from openmano_nsr
.remove_vlr(vlr
)