From 0c8def04e7d1519e0bc29be4c4c52ba495e71cc6 Mon Sep 17 00:00:00 2001 From: montesmoreno Date: Thu, 22 Dec 2016 12:16:23 +0000 Subject: [PATCH] Added support in openstack connector for additional disks, either empty or based on an image. Warning! Tested only for v2 Openstack API. Changes for v3 were not implemented Change-Id: Ice2b39d05620ca3eb90704c07d0c5919e4474793 Signed-off-by: montesmoreno --- database_utils/migrate_mano_db.sh | 16 ++- nfvo.py | 48 +++++++- openmano_schemas.py | 6 +- openmanod.py | 6 +- ...nario_vnf_additional_disk_based_image.yaml | 40 +++++++ ...ario_vnf_additional_disk_empty_volume.yaml | 40 +++++++ .../scenario_vnf_no_additional_devices.yaml | 40 +++++++ vimconn.py | 2 +- vimconn_openstack.py | 104 +++++++++++++++--- vimconn_openvim.py | 2 +- vimconn_vmware.py | 2 +- .../vnf_additional_disk_based_image.yaml | 67 +++++++++++ .../vnf_additional_disk_empty_volume.yaml | 65 +++++++++++ vnfs/examples/vnf_no_additional_devices.yaml | 60 ++++++++++ 14 files changed, 470 insertions(+), 28 deletions(-) create mode 100644 scenarios/examples/scenario_vnf_additional_disk_based_image.yaml create mode 100644 scenarios/examples/scenario_vnf_additional_disk_empty_volume.yaml create mode 100644 scenarios/examples/scenario_vnf_no_additional_devices.yaml create mode 100644 vnfs/examples/vnf_additional_disk_based_image.yaml create mode 100644 vnfs/examples/vnf_additional_disk_empty_volume.yaml create mode 100644 vnfs/examples/vnf_no_additional_devices.yaml diff --git a/database_utils/migrate_mano_db.sh b/database_utils/migrate_mano_db.sh index e69d8a5a..208ec7d0 100755 --- a/database_utils/migrate_mano_db.sh +++ b/database_utils/migrate_mano_db.sh @@ -184,6 +184,7 @@ DATABASE_TARGET_VER_NUM=0 [ $OPENMANO_VER_NUM -ge 4057 ] && DATABASE_TARGET_VER_NUM=14 #0.4.57=> 14 [ $OPENMANO_VER_NUM -ge 4059 ] && DATABASE_TARGET_VER_NUM=15 #0.4.59=> 15 [ $OPENMANO_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=16 #0.5.2 => 16 +[ $OPENMANO_VER_NUM -ge 5003 ] && DATABASE_TARGET_VER_NUM=17 #0.5.3 => 17 #TODO ... put next versions here @@ -676,12 +677,25 @@ function upgrade_to_16(){ function downgrade_from_16(){ echo " downgrade database from version 0.16 to version 0.15" echo " remove column 'config' at table 'datacenter_tenants', restoring lenght 'vim_tenant_name/id'" - echo "ALTER TABLE datacenter_tenants DROP COLUMN config" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "ALTER TABLE datacenter_tenants DROP COLUMN config;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 echo "ALTER TABLE datacenter_tenants CHANGE COLUMN vim_tenant_name vim_tenant_name VARCHAR(64) NULL DEFAULT NULL AFTER datacenter_id;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 echo "ALTER TABLE datacenter_tenants CHANGE COLUMN vim_tenant_id vim_tenant_id VARCHAR(36) NULL DEFAULT NULL COMMENT 'Tenant ID at VIM' AFTER vim_tenant_name;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 echo "DELETE FROM schema_version WHERE version_int='16';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 } +function upgrade_to_17(){ + echo " upgrade database from version 0.16 to version 0.17" + echo " add column 'extended' at table 'datacenter_flavors'" + echo "ALTER TABLE datacenters_flavors ADD extended varchar(2000) NULL COMMENT 'Extra description json format of additional devices';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) VALUES (17, '0.17', '0.5.3', 'Extra description json format of additional devices in datacenter_flavors', '2016-12-20');" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} +function downgrade_from_17(){ + echo " downgrade database from version 0.17 to version 0.16" + echo " remove column 'extended' from table 'datacenter_flavors'" + echo "ALTER TABLE datacenters_flavors DROP COLUMN extended;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "DELETE FROM schema_version WHERE version_int='17';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} + function upgrade_to_X(){ echo " change 'datacenter_nets'" echo "ALTER TABLE datacenter_nets ADD COLUMN vim_tenant_id VARCHAR(36) NOT NULL AFTER datacenter_id, DROP INDEX name_datacenter_id, ADD UNIQUE INDEX name_datacenter_id (name, datacenter_id, vim_tenant_id);" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 diff --git a/nfvo.py b/nfvo.py index d4935bf7..0d60ff72 100644 --- a/nfvo.py +++ b/nfvo.py @@ -42,6 +42,8 @@ from db_base import db_base_Exception global global_config global vimconn_imported global logger +global default_volume_size +default_volume_size = '5' #size in GB vimconn_imported={} #dictionary with VIM type as key, loaded module as value @@ -395,9 +397,11 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ #Create the flavor in VIM #Translate images at devices from MANO id to VIM id + disk_list = [] if 'extended' in flavor_dict and flavor_dict['extended']!=None and "devices" in flavor_dict['extended']: #make a copy of original devices devices_original=[] + for device in flavor_dict["extended"].get("devices",[]): dev={} dev.update(device) @@ -409,7 +413,9 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ dev_nb=0 for index in range(0,len(devices_original)) : device=devices_original[index] - if "image" not in device or "image name" not in device: + if "image" not in device and "image name" not in device: + if 'size' in device: + disk_list.append({'size': device.get('size', default_volume_size)}) continue image_dict={} image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img") @@ -425,6 +431,10 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ image_mano_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error=return_on_error ) image_dict["uuid"]=image_mano_id image_vim_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=True, return_on_error=return_on_error) + + #save disk information (image must be based on and size + disk_list.append({'image_id': image_vim_id, 'size': device.get('size', default_volume_size)}) + flavor_dict["extended"]["devices"][index]['imageRef']=image_vim_id dev_nb += 1 if len(flavor_db)>0: @@ -451,7 +461,14 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ #if reach here the flavor has been create or exist if len(flavor_db)==0: #add new vim_id at datacenters_flavors - mydb.new_row('datacenters_flavors', {'datacenter_id':vim_id, 'flavor_id':flavor_mano_id, 'vim_id': flavor_vim_id, 'created':flavor_created}) + extended_devices_yaml = None + if len(disk_list) > 0: + extended_devices = dict() + extended_devices['disks'] = disk_list + extended_devices_yaml = yaml.safe_dump(extended_devices,default_flow_style=True,width=256) + mydb.new_row('datacenters_flavors', + {'datacenter_id':vim_id, 'flavor_id':flavor_mano_id, 'vim_id': flavor_vim_id, + 'created':flavor_created,'extended': extended_devices_yaml}) elif flavor_db[0]["vim_id"]!=flavor_vim_id: #modify existing vim_id at datacenters_flavors mydb.update_rows('datacenters_flavors', UPDATE={'vim_id':flavor_vim_id}, WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id}) @@ -1921,7 +1938,28 @@ def create_instance(mydb, tenant_id, instance_dict): flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id']) if flavor_dict['extended']!=None: flavor_dict['extended']= yaml.load(flavor_dict['extended']) - flavor_id = create_or_use_flavor(mydb, {datacenter_id: vim}, flavor_dict, rollbackList, True) + flavor_id = create_or_use_flavor(mydb, {datacenter_id: vim}, flavor_dict, rollbackList, True) + + + + + #Obtain information for additional disks + extended_flavor_dict = mydb.get_rows(FROM='datacenters_flavors', SELECT=('extended',), WHERE={'vim_id': flavor_id}) + if not extended_flavor_dict: + raise NfvoException("flavor '{}' not found".format(flavor_id), HTTP_Not_Found) + return + + #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0]) + myVMDict['disks'] = None + extended_info = extended_flavor_dict[0]['extended'] + if extended_info != None: + extended_flavor_dict_yaml = yaml.load(extended_info) + if 'disks' in extended_flavor_dict_yaml: + myVMDict['disks'] = extended_flavor_dict_yaml['disks'] + + + + vm['vim_flavor_id'] = flavor_id myVMDict['imageRef'] = vm['vim_image_id'] @@ -1983,7 +2021,9 @@ def create_instance(mydb, tenant_id, instance_dict): #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False) #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>" vm_id = vim.new_vminstance(myVMDict['name'],myVMDict['description'],myVMDict.get('start', None), - myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks'], cloud_config = cloud_config) + myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks'], cloud_config = cloud_config, + disk_list = myVMDict['disks']) + vm['vim_id'] = vm_id rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id}) #put interface uuid back to scenario[vnfs][vms[[interfaces] diff --git a/openmano_schemas.py b/openmano_schemas.py index ffbacd3a..013234f5 100644 --- a/openmano_schemas.py +++ b/openmano_schemas.py @@ -24,7 +24,7 @@ ''' JSON schemas used by openmano httpserver.py module to parse the different files and messages sent through the API ''' -__author__="Alfonso Tierno, Gerardo Garcia" +__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes" __date__ ="$09-oct-2014 09:09:48$" #Basis schemas @@ -55,6 +55,7 @@ schema_version_2={"type":"integer","minimum":2,"maximum":2} #schema_version_string={"type":"string","enum": ["0.1", "2", "0.2", "3", "0.3"]} log_level_schema={"type":"string", "enum":["DEBUG", "INFO", "WARNING","ERROR","CRITICAL"]} checksum_schema={"type":"string", "pattern":"^[0-9a-fA-F]{32}$"} +size_schema={"type":"integer","minimum":1,"maximum":100} metadata_schema={ "type":"object", @@ -465,7 +466,8 @@ devices_schema={ "image": path_schema, "image name": name_schema, "image checksum": checksum_schema, - "image metadata": metadata_schema, + "image metadata": metadata_schema, + "size": size_schema, "vpci":pci_schema, "xml":xml_text_schema, }, diff --git a/openmanod.py b/openmanod.py index bbbd7d30..b50ca9dd 100755 --- a/openmanod.py +++ b/openmanod.py @@ -33,9 +33,9 @@ It loads the configuration file and launches the http_server thread that will li ''' __author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes" __date__ ="$26-aug-2014 11:09:29$" -__version__="0.5.2-r510" -version_date="Oct 2016" -database_version="0.16" #expected database schema version +__version__="0.5.3-r511" +version_date="Dec 2016" +database_version="0.17" #expected database schema version import httpserver import time diff --git a/scenarios/examples/scenario_vnf_additional_disk_based_image.yaml b/scenarios/examples/scenario_vnf_additional_disk_based_image.yaml new file mode 100644 index 00000000..66123692 --- /dev/null +++ b/scenarios/examples/scenario_vnf_additional_disk_based_image.yaml @@ -0,0 +1,40 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## +--- +schema_version: 2 +scenario: + name: vnf_additional_disk_based_image + description: Just deploy vnf_2_disks + public: false # if available for other tenants + vnfs: + vnf_2_disks: # vnf name in the scenario + #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name + #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method + vnf_name: vnf_additional_disk_based_image #can fail if several vnfs matches this name + #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}} + networks: + internal: + # Connections based on external networks (datacenter nets) must include the external network in the list of nodes + type: bridge + external: true #this will be connected outside + interfaces: + - vnf_2_disks: mgmt0 + diff --git a/scenarios/examples/scenario_vnf_additional_disk_empty_volume.yaml b/scenarios/examples/scenario_vnf_additional_disk_empty_volume.yaml new file mode 100644 index 00000000..0644a690 --- /dev/null +++ b/scenarios/examples/scenario_vnf_additional_disk_empty_volume.yaml @@ -0,0 +1,40 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## +--- +schema_version: 2 +scenario: + name: vnf_additional_disk_empty_volume + description: Just deploy vnf_2_disks + public: false # if available for other tenants + vnfs: + vnf_2_disks: # vnf name in the scenario + #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name + #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method + vnf_name: vnf_additional_disk_empty_volume #can fail if several vnfs matches this name + #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}} + networks: + internal: + # Connections based on external networks (datacenter nets) must include the external network in the list of nodes + type: bridge + external: true #this will be connected outside + interfaces: + - vnf_2_disks: mgmt0 + diff --git a/scenarios/examples/scenario_vnf_no_additional_devices.yaml b/scenarios/examples/scenario_vnf_no_additional_devices.yaml new file mode 100644 index 00000000..10ef4b2e --- /dev/null +++ b/scenarios/examples/scenario_vnf_no_additional_devices.yaml @@ -0,0 +1,40 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## +--- +schema_version: 2 +scenario: + name: vnf_no_additional_devices + description: Just deploy vnf_2_disks + public: false # if available for other tenants + vnfs: + vnf_2_disks: # vnf name in the scenario + #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name + #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method + vnf_name: vnf_no_additional_devices #can fail if several vnfs matches this name + #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}} + networks: + internal: + # Connections based on external networks (datacenter nets) must include the external network in the list of nodes + type: bridge + external: true #this will be connected outside + interfaces: + - vnf_2_disks: mgmt0 + diff --git a/vimconn.py b/vimconn.py index b5f8b070..814be65a 100644 --- a/vimconn.py +++ b/vimconn.py @@ -303,7 +303,7 @@ class vimconnector(): ''' raise vimconnNotImplemented( "Should have implemented this" ) - def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None): + def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None,disk_list=None): '''Adds a VM instance to VIM Params: start: indicates if VM must start or boot in pause mode. Ignored diff --git a/vimconn_openstack.py b/vimconn_openstack.py index 6c46dbb8..cdd11784 100644 --- a/vimconn_openstack.py +++ b/vimconn_openstack.py @@ -24,14 +24,15 @@ ''' osconnector implements all the methods to interact with openstack using the python-client. ''' -__author__="Alfonso Tierno, Gerardo Garcia, xFlow Research" -__date__ ="$24-nov-2016 09:10$" +__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research" +__date__ ="$22-jun-2014 11:19:29$" import vimconn import json import yaml import logging import netaddr +import time from novaclient import client as nClient_v2, exceptions as nvExceptions, api_versions as APIVersion import keystoneclient.v2_0.client as ksClient_v2 @@ -41,6 +42,7 @@ import keystoneclient.exceptions as ksExceptions import glanceclient.v2.client as glClient import glanceclient.client as gl1Client import glanceclient.exc as gl1Exceptions +import cinderclient.v2.client as cClient_v2 from httplib import HTTPException from neutronclient.neutron import client as neClient_v2 from neutronclient.v2_0 import client as neClient @@ -58,6 +60,9 @@ vmStatus2manoFormat={'ACTIVE':'ACTIVE', netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED' } +#global var to have a timeout creating and deleting volumes +volume_timeout = 60 + class vimconnector(vimconn.vimconnector): def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}): '''using common constructor parameters. In this case @@ -90,6 +95,7 @@ class vimconnector(vimconn.vimconnector): if self.osc_api_version == 'v3.3': self.k_creds['project_name'] = tenant_name self.k_creds['project_id'] = tenant_id + self.reload_client = True self.logger = logging.getLogger('openmano.vim.openstack') if log_level: @@ -173,11 +179,14 @@ class vimconnector(vimconn.vimconnector): raise ksExceptions.ClientException("Not enough parameters to connect to openstack") if self.osc_api_version == 'v3.3': self.nova = nClient(APIVersion(version_str='2'), **self.n_creds) + #TODO To be updated for v3 + #self.cinder = cClient.Client(**self.n_creds) self.keystone = ksClient.Client(**self.k_creds) self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL') self.neutron = neClient.Client(APIVersion(version_str='2'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds) else: self.nova = nClient_v2.Client('2', **self.n_creds) + self.cinder = cClient_v2.Client(**self.n_creds) self.keystone = ksClient_v2.Client(**self.k_creds) self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL') self.neutron = neClient_v2.Client('2.0', endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds) @@ -229,7 +238,7 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() - if osc_api_version == 'v3.3': + if self.osc_api_version == 'v3.3': project_class_list=self.keystone.projects.findall(**filter_dict) else: project_class_list=self.keystone.tenants.findall(**filter_dict) @@ -258,7 +267,7 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Deleting tenant %s from VIM", tenant_id) try: self._reload_connection() - if osc_api_version == 'v3.3': + if self.osc_api_version == 'v3.3': self.keystone.projects.delete(tenant_id) else: self.keystone.tenants.delete(tenant_id) @@ -338,7 +347,7 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() - if osc_api_version == 'v3.3' and "tenant_id" in filter_dict: + if self.osc_api_version == 'v3.3' and "tenant_id" in filter_dict: filter_dict['project_id'] = filter_dict.pop('tenant_id') net_dict=self.neutron.list_networks(**filter_dict) net_list=net_dict["networks"] @@ -649,7 +658,7 @@ class vimconnector(vimconn.vimconnector): except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: self._format_exception(e) - def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None): + def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None,disk_list=None): '''Adds a VM instance to VIM Params: start: indicates if VM must start or boot in pause mode. Ignored @@ -740,16 +749,56 @@ class vimconnector(vimconn.vimconnector): elif isinstance(cloud_config, str): userdata = cloud_config else: - userdata=None - + userdata=None + + #Create additional volumes in case these are present in disk_list + block_device_mapping = None + base_disk_index = ord('b') + if disk_list != None: + block_device_mapping = dict() + for disk in disk_list: + if 'image_id' in disk: + volume = self.cinder.volumes.create(size = disk['size'],name = name + '_vd' + + chr(base_disk_index), imageRef = disk['image_id']) + else: + volume = self.cinder.volumes.create(size=disk['size'], name=name + '_vd' + + chr(base_disk_index)) + block_device_mapping['_vd' + chr(base_disk_index)] = volume.id + base_disk_index += 1 + + #wait until volumes are with status available + keep_waiting = True + elapsed_time = 0 + while keep_waiting and elapsed_time < volume_timeout: + keep_waiting = False + for volume_id in block_device_mapping.itervalues(): + if self.cinder.volumes.get(volume_id).status != 'available': + keep_waiting = True + if keep_waiting: + time.sleep(1) + elapsed_time += 1 + + #if we exceeded the timeout rollback + if elapsed_time >= volume_timeout: + #delete the volumes we just created + for volume_id in block_device_mapping.itervalues(): + self.cinder.volumes.delete(volume_id) + + #delete ports we just created + for net_item in net_list_vim: + if 'port-id' in net_item: + self.neutron.delete_port(net_item['port_id']) + + raise vimconn.vimconnException('Timeout creating volumes for instance ' + name, + http_code=vimconn.HTTP_Request_Timeout) + server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata, - security_groups = security_groups, - availability_zone = self.config.get('availability_zone'), - key_name = self.config.get('keypair'), - userdata=userdata - ) #, description=description) - - + security_groups=security_groups, + availability_zone=self.config.get('availability_zone'), + key_name=self.config.get('keypair'), + userdata=userdata, + block_device_mapping = block_device_mapping + ) # , description=description) #print "DONE :-)", server pool_id = None @@ -867,7 +916,32 @@ class vimconnector(vimconn.vimconnector): self.neutron.delete_port(p["id"]) except Exception as e: self.logger.error("Error deleting port: " + type(e).__name__ + ": "+ str(e)) + + #commented because detaching the volumes makes the servers.delete not work properly ?!? + #dettach volumes attached + server = self.nova.servers.get(vm_id) + volumes_attached_dict = server._info['os-extended-volumes:volumes_attached'] + #for volume in volumes_attached_dict: + # self.cinder.volumes.detach(volume['id']) + self.nova.servers.delete(vm_id) + + #delete volumes. + #Although having detached them should have them in active status + #we ensure in this loop + keep_waiting = True + elapsed_time = 0 + while keep_waiting and elapsed_time < volume_timeout: + keep_waiting = False + for volume in volumes_attached_dict: + if self.cinder.volumes.get(volume['id']).status != 'available': + keep_waiting = True + else: + self.cinder.volumes.delete(volume['id']) + if keep_waiting: + time.sleep(1) + elapsed_time += 1 + return vm_id except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e: self._format_exception(e) diff --git a/vimconn_openvim.py b/vimconn_openvim.py index d4155320..241f63d0 100644 --- a/vimconn_openvim.py +++ b/vimconn_openvim.py @@ -776,7 +776,7 @@ class vimconnector(vimconn.vimconnector): #print text return -vim_response.status_code,text - def new_vminstance(self,name,description,start,image_id,flavor_id,net_list, cloud_config=None): + def new_vminstance(self,name,description,start,image_id,flavor_id,net_list, cloud_config=None, disk_list=None): '''Adds a VM instance to VIM Params: start: indicates if VM must start or boot in pause mode. Ignored diff --git a/vimconn_vmware.py b/vimconn_vmware.py index 7836eff6..02222a8d 100644 --- a/vimconn_vmware.py +++ b/vimconn_vmware.py @@ -1083,7 +1083,7 @@ class vimconnector(vimconn.vimconnector): return None def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={}, - cloud_config=None): + cloud_config=None, disk_list=None): """Adds a VM instance to VIM Params: start: indicates if VM must start or boot in pause mode. Ignored diff --git a/vnfs/examples/vnf_additional_disk_based_image.yaml b/vnfs/examples/vnf_additional_disk_based_image.yaml new file mode 100644 index 00000000..48f8ba91 --- /dev/null +++ b/vnfs/examples/vnf_additional_disk_based_image.yaml @@ -0,0 +1,67 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## +--- +vnf: + name: vnf_additional_disk_based_image + description: VNF with additional volume based on image + # class: parent # Optional. Used to organize VNFs + external-connections: + - name: mgmt0 + type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data" + VNFC: TEMPLATE-VM # Virtual Machine this interface belongs to + local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section) + description: Management interface + VNFC: # Virtual machine array + - name: TEMPLATE-VM # name of Virtual Machine + description: TEMPLATE description +# VNFC image: /path/to/imagefolder/TEMPLATE-VM.qcow2 + image name: ubuntu16.04 + image checksum: 7373edba82a31eedd182d29237b746cf + # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional + # processor: #Optional + # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz + # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"] + # hypervisor: #Optional + # type: QEMU-kvm + # version: "10002|12001|2.6.32-358.el6.x86_64" + vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed). + ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed) + disk: 5 # disk size in GiB, by default 1 + #numas: + #- paired-threads: 5 # "cores", "paired-threads", "threads" + # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order + # memory: 14 # GBytes + # interfaces: [] + bridge-ifaces: + - name: mgmt0 + vpci: "0000:00:0a.0" # Optional. Virtual PCI address + bandwidth: 1 Mbps # Optional. Informative only + # mac_address: '20:33:45:56:77:46' #avoid this option if possible + # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt + devices: # Optional, order determines device letter asignation (hda, hdb, ...) + - type: disk # "disk","cdrom","xml" + image name: TestVM + image checksum: 88d6c77b58fd40a7cb7f44b62bd5ad98 + size: 1 + # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } + # vpci: "0000:00:03.0" # Optional, not for disk or cdrom + # Additional Virtual Machines would be included here + diff --git a/vnfs/examples/vnf_additional_disk_empty_volume.yaml b/vnfs/examples/vnf_additional_disk_empty_volume.yaml new file mode 100644 index 00000000..ef0990f3 --- /dev/null +++ b/vnfs/examples/vnf_additional_disk_empty_volume.yaml @@ -0,0 +1,65 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## +--- +vnf: + name: vnf_additional_disk_empty_volume + description: VNF with additional volume based on image + # class: parent # Optional. Used to organize VNFs + external-connections: + - name: mgmt0 + type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data" + VNFC: TEMPLATE-VM # Virtual Machine this interface belongs to + local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section) + description: Management interface + VNFC: # Virtual machine array + - name: TEMPLATE-VM # name of Virtual Machine + description: TEMPLATE description +# VNFC image: /path/to/imagefolder/TEMPLATE-VM.qcow2 + image name: ubuntu16.04 + image checksum: 7373edba82a31eedd182d29237b746cf + # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional + # processor: #Optional + # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz + # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"] + # hypervisor: #Optional + # type: QEMU-kvm + # version: "10002|12001|2.6.32-358.el6.x86_64" + vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed). + ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed) + disk: 5 # disk size in GiB, by default 1 + #numas: + #- paired-threads: 5 # "cores", "paired-threads", "threads" + # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order + # memory: 14 # GBytes + # interfaces: [] + bridge-ifaces: + - name: mgmt0 + vpci: "0000:00:0a.0" # Optional. Virtual PCI address + bandwidth: 1 Mbps # Optional. Informative only + # mac_address: '20:33:45:56:77:46' #avoid this option if possible + # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt + devices: # Optional, order determines device letter asignation (hda, hdb, ...) + - type: disk # "disk","cdrom","xml" + size: 1 + # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } + # vpci: "0000:00:03.0" # Optional, not for disk or cdrom + # Additional Virtual Machines would be included here + diff --git a/vnfs/examples/vnf_no_additional_devices.yaml b/vnfs/examples/vnf_no_additional_devices.yaml new file mode 100644 index 00000000..aad2f19d --- /dev/null +++ b/vnfs/examples/vnf_no_additional_devices.yaml @@ -0,0 +1,60 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## +--- +vnf: + name: vnf_no_additional_devices + description: VNF with additional volume based on image + # class: parent # Optional. Used to organize VNFs + external-connections: + - name: mgmt0 + type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data" + VNFC: TEMPLATE-VM # Virtual Machine this interface belongs to + local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section) + description: Management interface + VNFC: # Virtual machine array + - name: TEMPLATE-VM # name of Virtual Machine + description: TEMPLATE description +# VNFC image: /path/to/imagefolder/TEMPLATE-VM.qcow2 + image name: ubuntu16.04 + image checksum: 7373edba82a31eedd182d29237b746cf + # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional + # processor: #Optional + # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz + # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"] + # hypervisor: #Optional + # type: QEMU-kvm + # version: "10002|12001|2.6.32-358.el6.x86_64" + vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed). + ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed) + disk: 5 # disk size in GiB, by default 1 + #numas: + #- paired-threads: 5 # "cores", "paired-threads", "threads" + # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order + # memory: 14 # GBytes + # interfaces: [] + bridge-ifaces: + - name: mgmt0 + vpci: "0000:00:0a.0" # Optional. Virtual PCI address + bandwidth: 1 Mbps # Optional. Informative only + # mac_address: '20:33:45:56:77:46' #avoid this option if possible + # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt + # Additional Virtual Machines would be included here + -- 2.17.1