if not url:
raise TypeError, 'url param can not be NoneType'
self.persistent_info = persistent_info
+ self.availability_zone = persistent_info.get('availability_zone', None)
self.session = persistent_info.get('session', {'reload_client': True})
self.nova = self.session.get('nova')
self.neutron = self.session.get('neutron')
self.cinder = self.session.get('cinder')
self.glance = self.session.get('glance')
+ self.glancev1 = self.session.get('glancev1')
self.keystone = self.session.get('keystone')
self.api_version3 = self.session.get('api_version3')
else:
self.keystone = ksClient_v2.Client(session=sess)
self.session['keystone'] = self.keystone
- self.nova = self.session['nova'] = nClient.Client("2.1", session=sess)
+ # In order to enable microversion functionality an explicit microversion must be specified in 'config'.
+ # This implementation approach is due to the warning message in
+ # https://developer.openstack.org/api-guide/compute/microversions.html
+ # where it is stated that microversion backwards compatibility is not guaranteed and clients should
+ # always require an specific microversion.
+ # To be able to use 'device role tagging' functionality define 'microversion: 2.32' in datacenter config
+ version = self.config.get("microversion")
+ if not version:
+ version = "2.1"
+ self.nova = self.session['nova'] = nClient.Client(str(version), session=sess)
self.neutron = self.session['neutron'] = neClient.Client('2.0', session=sess)
self.cinder = self.session['cinder'] = cClient.Client(2, session=sess)
self.glance = self.session['glance'] = glClient.Client(2, session=sess)
+ self.glancev1 = self.session['glancev1'] = glClient.Client('1', session=sess)
self.session['reload_client'] = False
self.persistent_info['session'] = self.session
+ # add availablity zone info inside self.persistent_info
+ self._set_availablity_zones()
+ self.persistent_info['availability_zone'] = self.availability_zone
def __net_os2mano(self, net_list_dict):
'''Transform the net openstack format to mano format
metadata: metadata of the image
Returns the image_id
'''
- # ALF TODO: revise and change for the new method or session
- #using version 1 of glance client
- glancev1 = gl1Client.Client('1',self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds) #TODO check k_creds vs n_creds
retry=0
max_retries=3
while retry<max_retries:
disk_format="raw"
self.logger.debug("new_image: '%s' loading from '%s'", image_dict['name'], image_dict['location'])
if image_dict['location'][0:4]=="http":
- new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
+ new_image = self.glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
container_format="bare", location=image_dict['location'], disk_format=disk_format)
else: #local path
with open(image_dict['location']) as fimage:
- new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
+ new_image = self.glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
container_format="bare", data=fimage, disk_format=disk_format)
#insert metadata. We cannot use 'new_image.properties.setdefault'
#because nova and glance are "INDEPENDENT" and we are using nova for reading metadata
raise vimconn.vimconnException('Timeout waiting for instance ' + vm_id + ' to get ' + status,
http_code=vimconn.HTTP_Request_Timeout)
- def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None,disk_list=None):
+ def _get_openstack_availablity_zones(self):
+ """
+ Get from openstack availability zones available
+ :return:
+ """
+ try:
+ openstack_availability_zone = self.nova.availability_zones.list()
+ openstack_availability_zone = [str(zone.zoneName) for zone in openstack_availability_zone
+ if zone.zoneName != 'internal']
+ return openstack_availability_zone
+ except Exception as e:
+ return None
+
+ def _set_availablity_zones(self):
+ """
+ Set vim availablity zone
+ :return:
+ """
+
+ if 'availability_zone' in self.config:
+ vim_availability_zones = self.config.get('availability_zone')
+ if isinstance(vim_availability_zones, str):
+ self.availability_zone = [vim_availability_zones]
+ elif isinstance(vim_availability_zones, list):
+ self.availability_zone = vim_availability_zones
+ else:
+ self.availability_zone = self._get_openstack_availablity_zones()
+
+ def _get_vm_availavility_zone(self, availavility_zone_index, nfv_availability_zones):
+ """
+ Return a list with all availability zones create during datacenter attach.
+ :return: List with availability zones
+ """
+ openstack_avilability_zone = self.availability_zone
+
+ # check if VIM offer enough availability zones describe in the VNFC
+ if self.availability_zone and availavility_zone_index is not None \
+ and 0 <= len(nfv_availability_zones) <= len(self.availability_zone):
+
+ if nfv_availability_zones:
+ vnf_azone = nfv_availability_zones[availavility_zone_index]
+ zones_available = []
+
+ for nfv_zone in nfv_availability_zones:
+ for vim_zone in openstack_avilability_zone:
+ if nfv_zone is vim_zone:
+ zones_available.append(nfv_zone)
+
+ if len(zones_available) == len(openstack_avilability_zone) and vnf_azone in openstack_avilability_zone:
+ return vnf_azone
+ else:
+ return openstack_avilability_zone[availavility_zone_index]
+ else:
+ raise vimconn.vimconnConflictException("No enough availablity zones for this deployment")
+ return None
+
+ def new_vminstance(self, name, description, start, image_id, flavor_id, net_list,cloud_config=None,disk_list=None,
+ availavility_zone_index=None, nfv_availability_zones=None):
'''Adds a VM instance to VIM
Params:
start: indicates if VM must start or boot in pause mode. Ignored
type: 'virtual', 'PF', 'VF', 'VFnotShared'
vim_id: filled/added by this function
floating_ip: True/False (or it can be None)
+ 'cloud_config': (optional) dictionary with:
+ 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
+ 'users': (optional) list of users to be inserted, each item is a dict with:
+ 'name': (mandatory) user name,
+ 'key-pairs': (optional) list of strings with the public key to be inserted to the user
+ 'user-data': (optional) string is a text script to be passed directly to cloud-init
+ 'config-files': (optional). List of files to be transferred. Each item is a dict with:
+ 'dest': (mandatory) string with the destination absolute path
+ 'encoding': (optional, by default text). Can be one of:
+ 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
+ 'content' (mandatory): string with the content of the file
+ 'permissions': (optional) string with file permissions, typically octal notation '0644'
+ 'owner': (optional) file owner, string with the format 'owner:group'
+ 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
+ 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
+ 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
+ 'size': (mandatory) string with the size of the disk in GB
+ availavility_zone_index:counter for instance order in vim availability_zones availables
+ nfv_availability_zones: Lost given by user in the VNFC descriptor.
#TODO ip, security groups
Returns the instance identifier
'''
net["ip"] = fixed_ips[0].get("ip_address")
else:
net["ip"] = None
- net_list_vim.append({"port-id": new_port["port"]["id"]})
+
+ port = {"port-id": new_port["port"]["id"]}
+ if float(self.nova.api_version.get_string()) >= 2.32:
+ port["tag"] = new_port["port"]["name"]
+ net_list_vim.append(port)
if net.get('floating_ip', False):
net['exit_on_floating_ip_error'] = True
raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
http_code=vimconn.HTTP_Request_Timeout)
-
- self.logger.debug("nova.servers.create({}, {}, {}, nics={}, meta={}, security_groups={}," \
- "availability_zone={}, key_name={}, userdata={}, config_drive={}, " \
- "block_device_mapping={})".format(name, image_id, flavor_id, net_list_vim,
- metadata, security_groups, self.config.get('availability_zone'),
- self.config.get('keypair'), userdata, config_drive, block_device_mapping))
+ # get availability Zone
+ vm_av_zone = self._get_vm_availavility_zone(availavility_zone_index, nfv_availability_zones)
+
+ self.logger.debug("nova.servers.create({}, {}, {}, nics={}, meta={}, security_groups={}, "
+ "availability_zone={}, key_name={}, userdata={}, config_drive={}, "
+ "block_device_mapping={})".format(name, image_id, flavor_id, net_list_vim, metadata,
+ security_groups, vm_av_zone, self.config.get('keypair'),
+ userdata, config_drive, block_device_mapping))
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'),
+ availability_zone=vm_av_zone,
key_name=self.config.get('keypair'),
userdata=userdata,
config_drive=config_drive,