+++ /dev/null
-# -*- coding: utf-8 -*-
-
-##
-# 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
-##
-
-'''
-osconnector implements all the methods to interact with openstack using the python-client.
-'''
-__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
-import yaml
-import random
-
-from novaclient import client as nClient_v2, exceptions as nvExceptions
-from novaclient import api_versions
-import keystoneclient.v2_0.client as ksClient_v2
-from novaclient.v2.client import Client as nClient
-import keystoneclient.v3.client as ksClient
-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
-from neutronclient.common import exceptions as neExceptions
-from requests.exceptions import ConnectionError
-
-'''contain the openstack virtual machine status to openmano status'''
-vmStatus2manoFormat={'ACTIVE':'ACTIVE',
- 'PAUSED':'PAUSED',
- 'SUSPENDED': 'SUSPENDED',
- 'SHUTOFF':'INACTIVE',
- 'BUILD':'BUILD',
- 'ERROR':'ERROR','DELETED':'DELETED'
- }
-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
-server_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={}, persistent_info={}):
- '''using common constructor parameters. In this case
- 'url' is the keystone authorization url,
- 'url_admin' is not use
- '''
- self.osc_api_version = 'v2.0'
- if config.get('APIversion') == 'v3.3':
- self.osc_api_version = 'v3.3'
- vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config)
-
- self.persistent_info = persistent_info
- self.k_creds={}
- self.n_creds={}
- if self.config.get("insecure"):
- self.k_creds["insecure"] = True
- self.n_creds["insecure"] = True
- if not url:
- raise TypeError, 'url param can not be NoneType'
- self.k_creds['auth_url'] = url
- self.n_creds['auth_url'] = url
- if tenant_name:
- self.k_creds['tenant_name'] = tenant_name
- self.n_creds['project_id'] = tenant_name
- if tenant_id:
- self.k_creds['tenant_id'] = tenant_id
- self.n_creds['tenant_id'] = tenant_id
- if user:
- self.k_creds['username'] = user
- self.n_creds['username'] = user
- if passwd:
- self.k_creds['password'] = passwd
- self.n_creds['api_key'] = passwd
- if self.osc_api_version == 'v3.3':
- self.k_creds['project_name'] = tenant_name
- self.k_creds['project_id'] = tenant_id
- if config.get('region_name'):
- self.k_creds['region_name'] = config.get('region_name')
- self.n_creds['region_name'] = config.get('region_name')
-
- self.reload_client = True
- self.logger = logging.getLogger('openmano.vim.openstack')
- if log_level:
- self.logger.setLevel( getattr(logging, log_level) )
-
- def __setitem__(self,index, value):
- '''Set individuals parameters
- Throw TypeError, KeyError
- '''
- if index=='tenant_id':
- self.reload_client=True
- self.tenant_id = value
- if self.osc_api_version == 'v3.3':
- if value:
- self.k_creds['project_id'] = value
- self.n_creds['project_id'] = value
- else:
- del self.k_creds['project_id']
- del self.n_creds['project_id']
- else:
- if value:
- self.k_creds['tenant_id'] = value
- self.n_creds['tenant_id'] = value
- else:
- del self.k_creds['tenant_id']
- del self.n_creds['tenant_id']
- elif index=='tenant_name':
- self.reload_client=True
- self.tenant_name = value
- if self.osc_api_version == 'v3.3':
- if value:
- self.k_creds['project_name'] = value
- self.n_creds['project_name'] = value
- else:
- del self.k_creds['project_name']
- del self.n_creds['project_name']
- else:
- if value:
- self.k_creds['tenant_name'] = value
- self.n_creds['project_id'] = value
- else:
- del self.k_creds['tenant_name']
- del self.n_creds['project_id']
- elif index=='user':
- self.reload_client=True
- self.user = value
- if value:
- self.k_creds['username'] = value
- self.n_creds['username'] = value
- else:
- del self.k_creds['username']
- del self.n_creds['username']
- elif index=='passwd':
- self.reload_client=True
- self.passwd = value
- if value:
- self.k_creds['password'] = value
- self.n_creds['api_key'] = value
- else:
- del self.k_creds['password']
- del self.n_creds['api_key']
- elif index=='url':
- self.reload_client=True
- self.url = value
- if value:
- self.k_creds['auth_url'] = value
- self.n_creds['auth_url'] = value
- else:
- raise TypeError, 'url param can not be NoneType'
- else:
- vimconn.vimconnector.__setitem__(self,index, value)
-
- def _reload_connection(self):
- '''Called before any operation, it check if credentials has changed
- Throw keystoneclient.apiclient.exceptions.AuthorizationFailure
- '''
- #TODO control the timing and possible token timeout, but it seams that python client does this task for us :-)
- if self.reload_client:
- #test valid params
- if len(self.n_creds) <4:
- raise ksExceptions.ClientException("Not enough parameters to connect to openstack")
- if self.osc_api_version == 'v3.3':
- self.nova = nClient(api_version=api_versions.APIVersion(version_str='2.0'), **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(api_version=api_versions.APIVersion(version_str='2.0'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
- else:
- self.nova = nClient_v2.Client(version='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)
- self.glance_endpoint = self.keystone.service_catalog.url_for(service_type='image', endpoint_type='publicURL')
- self.glance = glClient.Client(self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds) #TODO check k_creds vs n_creds
- self.reload_client = False
-
- def __net_os2mano(self, net_list_dict):
- '''Transform the net openstack format to mano format
- net_list_dict can be a list of dict or a single dict'''
- if type(net_list_dict) is dict:
- net_list_=(net_list_dict,)
- elif type(net_list_dict) is list:
- net_list_=net_list_dict
- else:
- raise TypeError("param net_list_dict must be a list or a dictionary")
- for net in net_list_:
- if net.get('provider:network_type') == "vlan":
- net['type']='data'
- else:
- net['type']='bridge'
-
-
-
- def _format_exception(self, exception):
- '''Transform a keystone, nova, neutron exception into a vimconn exception'''
- if isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError,
- ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed
- )):
- raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
- elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException,
- neExceptions.NeutronException, nvExceptions.BadRequest)):
- raise vimconn.vimconnUnexpectedResponse(type(exception).__name__ + ": " + str(exception))
- elif isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound)):
- raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + str(exception))
- elif isinstance(exception, nvExceptions.Conflict):
- raise vimconn.vimconnConflictException(type(exception).__name__ + ": " + str(exception))
- else: # ()
- raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
-
- def get_tenant_list(self, filter_dict={}):
- '''Obtain tenants of VIM
- filter_dict can contain the following keys:
- name: filter by tenant name
- id: filter by tenant uuid/id
- <other VIM specific>
- Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
- '''
- self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict))
- try:
- self._reload_connection()
- 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)
- project_list=[]
- for project in project_class_list:
- project_list.append(project.to_dict())
- return project_list
- except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
- def new_tenant(self, tenant_name, tenant_description):
- '''Adds a new tenant to openstack VIM. Returns the tenant identifier'''
- self.logger.debug("Adding a new tenant name: %s", tenant_name)
- try:
- self._reload_connection()
- if self.osc_api_version == 'v3.3':
- project=self.keystone.projects.create(tenant_name, tenant_description)
- else:
- project=self.keystone.tenants.create(tenant_name, tenant_description)
- return project.id
- except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
- def delete_tenant(self, tenant_id):
- '''Delete a tenant from openstack VIM. Returns the old tenant identifier'''
- self.logger.debug("Deleting tenant %s from VIM", tenant_id)
- try:
- self._reload_connection()
- if self.osc_api_version == 'v3.3':
- self.keystone.projects.delete(tenant_id)
- else:
- self.keystone.tenants.delete(tenant_id)
- return tenant_id
- except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
- def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None):
- '''Adds a tenant network to VIM. Returns the network identifier'''
- self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
- #self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile))
- try:
- new_net = None
- self._reload_connection()
- network_dict = {'name': net_name, 'admin_state_up': True}
- if net_type=="data" or net_type=="ptp":
- if self.config.get('dataplane_physical_net') == None:
- raise vimconn.vimconnConflictException("You must provide a 'dataplane_physical_net' at config value before creating sriov network")
- network_dict["provider:physical_network"] = self.config['dataplane_physical_net'] #"physnet_sriov" #TODO physical
- network_dict["provider:network_type"] = "vlan"
- if vlan!=None:
- network_dict["provider:network_type"] = vlan
- network_dict["shared"]=shared
- new_net=self.neutron.create_network({'network':network_dict})
- #print new_net
- #create subnetwork, even if there is no profile
- if not ip_profile:
- ip_profile = {}
- if 'subnet_address' not in ip_profile:
- #Fake subnet is required
- subnet_rand = random.randint(0, 255)
- ip_profile['subnet_address'] = "192.168.{}.0/24".format(subnet_rand)
- if 'ip_version' not in ip_profile:
- ip_profile['ip_version'] = "IPv4"
- subnet={"name":net_name+"-subnet",
- "network_id": new_net["network"]["id"],
- "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6,
- "cidr": ip_profile['subnet_address']
- }
- if 'gateway_address' in ip_profile:
- subnet['gateway_ip'] = ip_profile['gateway_address']
- if ip_profile.get('dns_address'):
- #TODO: manage dns_address as a list of addresses separated by commas
- subnet['dns_nameservers'] = []
- subnet['dns_nameservers'].append(ip_profile['dns_address'])
- if 'dhcp_enabled' in ip_profile:
- subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
- if 'dhcp_start_address' in ip_profile:
- subnet['allocation_pools']=[]
- subnet['allocation_pools'].append(dict())
- subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address']
- if 'dhcp_count' in ip_profile:
- #parts = ip_profile['dhcp_start_address'].split('.')
- #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
- ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
- ip_int += ip_profile['dhcp_count'] - 1
- ip_str = str(netaddr.IPAddress(ip_int))
- subnet['allocation_pools'][0]['end'] = ip_str
- #self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet))
- self.neutron.create_subnet({"subnet": subnet} )
- return new_net["network"]["id"]
- except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
- if new_net:
- self.neutron.delete_network(new_net['network']['id'])
- self._format_exception(e)
-
- def get_network_list(self, filter_dict={}):
- '''Obtain tenant networks of VIM
- Filter_dict can be:
- name: network name
- id: network uuid
- shared: boolean
- tenant_id: tenant
- admin_state_up: boolean
- status: 'ACTIVE'
- Returns the network list of dictionaries
- '''
- self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict))
- try:
- self._reload_connection()
- 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"]
- self.__net_os2mano(net_list)
- return net_list
- except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
- self._format_exception(e)
-
- def get_network(self, net_id):
- '''Obtain details of network from VIM
- Returns the network information from a network id'''
- self.logger.debug(" Getting tenant network %s from VIM", net_id)
- filter_dict={"id": net_id}
- net_list = self.get_network_list(filter_dict)
- if len(net_list)==0:
- raise vimconn.vimconnNotFoundException("Network '{}' not found".format(net_id))
- elif len(net_list)>1:
- raise vimconn.vimconnConflictException("Found more than one network with this criteria")
- net = net_list[0]
- subnets=[]
- for subnet_id in net.get("subnets", () ):
- try:
- subnet = self.neutron.show_subnet(subnet_id)
- except Exception as e:
- self.logger.error("osconnector.get_network(): Error getting subnet %s %s" % (net_id, str(e)))
- subnet = {"id": subnet_id, "fault": str(e)}
- subnets.append(subnet)
- net["subnets"] = subnets
- return net
-
- def delete_network(self, net_id):
- '''Deletes a tenant network from VIM. Returns the old network identifier'''
- self.logger.debug("Deleting network '%s' from VIM", net_id)
- try:
- self._reload_connection()
- #delete VM ports attached to this networks before the network
- ports = self.neutron.list_ports(network_id=net_id)
- for p in ports['ports']:
- try:
- self.neutron.delete_port(p["id"])
- except Exception as e:
- self.logger.error("Error deleting port %s: %s", p["id"], str(e))
- self.neutron.delete_network(net_id)
- return net_id
- except (neExceptions.ConnectionFailed, neExceptions.NetworkNotFoundClient, neExceptions.NeutronException,
- ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
- self._format_exception(e)
-
- def refresh_nets_status(self, net_list):
- '''Get the status of the networks
- Params: the list of network identifiers
- Returns a dictionary with:
- net_id: #VIM id of this network
- status: #Mandatory. Text with one of:
- # DELETED (not found at vim)
- # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
- # OTHER (Vim reported other status not understood)
- # ERROR (VIM indicates an ERROR status)
- # ACTIVE, INACTIVE, DOWN (admin down),
- # BUILD (on building process)
- #
- error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
- vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
-
- '''
- net_dict={}
- for net_id in net_list:
- net = {}
- try:
- net_vim = self.get_network(net_id)
- if net_vim['status'] in netStatus2manoFormat:
- net["status"] = netStatus2manoFormat[ net_vim['status'] ]
- else:
- net["status"] = "OTHER"
- net["error_msg"] = "VIM status reported " + net_vim['status']
-
- if net['status'] == "ACTIVE" and not net_vim['admin_state_up']:
- net['status'] = 'DOWN'
- try:
- net['vim_info'] = yaml.safe_dump(net_vim, default_flow_style=True, width=256)
- except yaml.representer.RepresenterError:
- net['vim_info'] = str(net_vim)
- if net_vim.get('fault'): #TODO
- net['error_msg'] = str(net_vim['fault'])
- except vimconn.vimconnNotFoundException as e:
- self.logger.error("Exception getting net status: %s", str(e))
- net['status'] = "DELETED"
- net['error_msg'] = str(e)
- except vimconn.vimconnException as e:
- self.logger.error("Exception getting net status: %s", str(e))
- net['status'] = "VIM_ERROR"
- net['error_msg'] = str(e)
- net_dict[net_id] = net
- return net_dict
-
- def get_flavor(self, flavor_id):
- '''Obtain flavor details from the VIM. Returns the flavor dict details'''
- self.logger.debug("Getting flavor '%s'", flavor_id)
- try:
- self._reload_connection()
- flavor = self.nova.flavors.find(id=flavor_id)
- #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
- return flavor.to_dict()
- except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
- def get_flavor_id_from_data(self, flavor_dict):
- """Obtain flavor id that match the flavor description
- Returns the flavor_id or raises a vimconnNotFoundException
- """
- try:
- self._reload_connection()
- numa=None
- numas = flavor_dict.get("extended",{}).get("numas")
- if numas:
- #TODO
- raise vimconn.vimconnNotFoundException("Flavor with EPA still not implemted")
- # if len(numas) > 1:
- # raise vimconn.vimconnNotFoundException("Cannot find any flavor with more than one numa")
- # numa=numas[0]
- # numas = extended.get("numas")
- for flavor in self.nova.flavors.list():
- epa = flavor.get_keys()
- if epa:
- continue
- #TODO
- if flavor.ram != flavor_dict["ram"]:
- continue
- if flavor.vcpus != flavor_dict["vcpus"]:
- continue
- if flavor.disk != flavor_dict["disk"]:
- continue
- return flavor.id
- raise vimconn.vimconnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict)))
- except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
-
- def new_flavor(self, flavor_data, change_name_if_used=True):
- '''Adds a tenant flavor to openstack VIM
- if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition
- Returns the flavor identifier
- '''
- self.logger.debug("Adding flavor '%s'", str(flavor_data))
- retry=0
- max_retries=3
- name_suffix = 0
- name=flavor_data['name']
- while retry<max_retries:
- retry+=1
- try:
- self._reload_connection()
- if change_name_if_used:
- #get used names
- fl_names=[]
- fl=self.nova.flavors.list()
- for f in fl:
- fl_names.append(f.name)
- while name in fl_names:
- name_suffix += 1
- name = flavor_data['name']+"-" + str(name_suffix)
-
- ram = flavor_data.get('ram',64)
- vcpus = flavor_data.get('vcpus',1)
- numa_properties=None
-
- extended = flavor_data.get("extended")
- if extended:
- numas=extended.get("numas")
- if numas:
- numa_nodes = len(numas)
- if numa_nodes > 1:
- return -1, "Can not add flavor with more than one numa"
- numa_properties = {"hw:numa_nodes":str(numa_nodes)}
- numa_properties["hw:mem_page_size"] = "large"
- numa_properties["hw:cpu_policy"] = "dedicated"
- numa_properties["hw:numa_mempolicy"] = "strict"
- for numa in numas:
- #overwrite ram and vcpus
- ram = numa['memory']*1024
- if 'paired-threads' in numa:
- vcpus = numa['paired-threads']*2
- numa_properties["hw:cpu_threads_policy"] = "prefer"
- elif 'cores' in numa:
- vcpus = numa['cores']
- #numa_properties["hw:cpu_threads_policy"] = "prefer"
- elif 'threads' in numa:
- vcpus = numa['threads']
- numa_properties["hw:cpu_policy"] = "isolated"
- for interface in numa.get("interfaces",() ):
- if interface["dedicated"]=="yes":
- raise vimconn.vimconnException("Passthrough interfaces are not supported for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable)
- #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"' when a way to connect it is available
-
- #create flavor
- new_flavor=self.nova.flavors.create(name,
- ram,
- vcpus,
- flavor_data.get('disk',1),
- is_public=flavor_data.get('is_public', True)
- )
- #add metadata
- if numa_properties:
- new_flavor.set_keys(numa_properties)
- return new_flavor.id
- except nvExceptions.Conflict as e:
- if change_name_if_used and retry < max_retries:
- continue
- self._format_exception(e)
- #except nvExceptions.BadRequest as e:
- except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
- def delete_flavor(self,flavor_id):
- '''Deletes a tenant flavor from openstack VIM. Returns the old flavor_id
- '''
- try:
- self._reload_connection()
- self.nova.flavors.delete(flavor_id)
- return flavor_id
- #except nvExceptions.BadRequest as e:
- except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
-
- def new_image(self,image_dict):
- '''
- Adds a tenant image to VIM. imge_dict is a dictionary with:
- name: name
- disk_format: qcow2, vhd, vmdk, raw (by default), ...
- location: path or URI
- public: "yes" or "no"
- metadata: metadata of the image
- Returns the image_id
- '''
- #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:
- retry+=1
- try:
- self._reload_connection()
- #determine format http://docs.openstack.org/developer/glance/formats.html
- if "disk_format" in image_dict:
- disk_format=image_dict["disk_format"]
- else: #autodiscover based on extension
- if image_dict['location'][-6:]==".qcow2":
- disk_format="qcow2"
- elif image_dict['location'][-4:]==".vhd":
- disk_format="vhd"
- elif image_dict['location'][-5:]==".vmdk":
- disk_format="vmdk"
- elif image_dict['location'][-4:]==".vdi":
- disk_format="vdi"
- elif image_dict['location'][-4:]==".iso":
- disk_format="iso"
- elif image_dict['location'][-4:]==".aki":
- disk_format="aki"
- elif image_dict['location'][-4:]==".ari":
- disk_format="ari"
- elif image_dict['location'][-4:]==".ami":
- disk_format="ami"
- else:
- 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",
- 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",
- 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
- new_image_nova=self.nova.images.find(id=new_image.id)
- new_image_nova.metadata.setdefault('location',image_dict['location'])
- metadata_to_load = image_dict.get('metadata')
- if metadata_to_load:
- for k,v in yaml.load(metadata_to_load).iteritems():
- new_image_nova.metadata.setdefault(k,v)
- return new_image.id
- except (nvExceptions.Conflict, ksExceptions.ClientException, nvExceptions.ClientException) as e:
- self._format_exception(e)
- except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, ConnectionError) as e:
- if retry==max_retries:
- continue
- self._format_exception(e)
- except IOError as e: #can not open the file
- raise vimconn.vimconnConnectionException(type(e).__name__ + ": " + str(e)+ " for " + image_dict['location'],
- http_code=vimconn.HTTP_Bad_Request)
-
- def delete_image(self, image_id):
- '''Deletes a tenant image from openstack VIM. Returns the old id
- '''
- try:
- self._reload_connection()
- self.nova.images.delete(image_id)
- return image_id
- except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: #TODO remove
- self._format_exception(e)
-
- def get_image_id_from_path(self, path):
- '''Get the image id from image path in the VIM database. Returns the image_id'''
- try:
- self._reload_connection()
- images = self.nova.images.list()
- for image in images:
- if image.metadata.get("location")==path:
- return image.id
- raise vimconn.vimconnNotFoundException("image with location '{}' not found".format( path))
- except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
- self._format_exception(e)
-
- def get_image_list(self, filter_dict={}):
- '''Obtain tenant images from VIM
- Filter_dict can be:
- id: image id
- name: image name
- checksum: image checksum
- Returns the image list of dictionaries:
- [{<the fields at Filter_dict plus some VIM specific>}, ...]
- List can be empty
- '''
- self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict))
- try:
- self._reload_connection()
- filter_dict_os=filter_dict.copy()
- #First we filter by the available filter fields: name, id. The others are removed.
- filter_dict_os.pop('checksum',None)
- image_list=self.nova.images.findall(**filter_dict_os)
- if len(image_list)==0:
- return []
- #Then we filter by the rest of filter fields: checksum
- filtered_list = []
- for image in image_list:
- image_class=self.glance.images.get(image.id)
- if 'checksum' not in filter_dict or image_class['checksum']==filter_dict.get('checksum'):
- filtered_list.append(image_class.copy())
- return filtered_list
- 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,disk_list=None):
- '''Adds a VM instance to VIM
- Params:
- start: indicates if VM must start or boot in pause mode. Ignored
- image_id,flavor_id: iamge and flavor uuid
- net_list: list of interfaces, each one is a dictionary with:
- name:
- net_id: network uuid to connect
- vpci: virtual vcpi to assign, ignored because openstack lack #TODO
- model: interface model, ignored #TODO
- mac_address: used for SR-IOV ifaces #TODO for other types
- use: 'data', 'bridge', 'mgmt'
- type: 'virtual', 'PF', 'VF', 'VFnotShared'
- vim_id: filled/added by this function
- floating_ip: True/False (or it can be None)
- #TODO ip, security groups
- Returns the instance identifier
- '''
- self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'",image_id, flavor_id,str(net_list))
- try:
- metadata={}
- net_list_vim=[]
- external_network=[] #list of external networks to be connected to instance, later on used to create floating_ip
- self._reload_connection()
- metadata_vpci={} #For a specific neutron plugin
- for net in net_list:
- if not net.get("net_id"): #skip non connected iface
- continue
- if net["type"]=="virtual" or net["type"]=="VF":
- port_dict={
- "network_id": net["net_id"],
- "name": net.get("name"),
- "admin_state_up": True
- }
- if net["type"]=="virtual":
- if "vpci" in net:
- metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]]
- else: # for VF
- if "vpci" in net:
- if "VF" not in metadata_vpci:
- metadata_vpci["VF"]=[]
- metadata_vpci["VF"].append([ net["vpci"], "" ])
- port_dict["binding:vnic_type"]="direct"
- if not port_dict["name"]:
- port_dict["name"]=name
- if net.get("mac_address"):
- port_dict["mac_address"]=net["mac_address"]
- if net.get("port_security") == False:
- port_dict["port_security_enabled"]=net["port_security"]
- new_port = self.neutron.create_port({"port": port_dict })
- net["mac_adress"] = new_port["port"]["mac_address"]
- net["vim_id"] = new_port["port"]["id"]
- net["ip"] = new_port["port"].get("fixed_ips", [{}])[0].get("ip_address")
- net_list_vim.append({"port-id": new_port["port"]["id"]})
- else: # for PF
- self.logger.warn("new_vminstance: Warning, can not connect a passthrough interface ")
- #TODO insert this when openstack consider passthrough ports as openstack neutron ports
- if net.get('floating_ip', False):
- net['exit_on_floating_ip_error'] = True
- external_network.append(net)
- elif net['use'] == 'mgmt' and self.config.get('use_floating_ip'):
- net['exit_on_floating_ip_error'] = False
- external_network.append(net)
-
- if metadata_vpci:
- metadata = {"pci_assignement": json.dumps(metadata_vpci)}
- if len(metadata["pci_assignement"]) >255:
- #limit the metadata size
- #metadata["pci_assignement"] = metadata["pci_assignement"][0:255]
- self.logger.warn("Metadata deleted since it exceeds the expected length (255) ")
- metadata = {}
-
- self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s",
- name, image_id, flavor_id, str(net_list_vim), description, str(metadata))
-
- security_groups = self.config.get('security_groups')
- if type(security_groups) is str:
- security_groups = ( security_groups, )
- #cloud config
- userdata=None
- config_drive = None
- if isinstance(cloud_config, dict):
- if cloud_config.get("user-data"):
- userdata=cloud_config["user-data"]
- if cloud_config.get("boot-data-drive") != None:
- config_drive = cloud_config["boot-data-drive"]
- if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
- if userdata:
- raise vimconn.vimconnConflictException("Cloud-config cannot contain both 'userdata' and 'config-files'/'users'/'key-pairs'")
- userdata_dict={}
- #default user
- if cloud_config.get("key-pairs"):
- userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
- userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"] }]
- if cloud_config.get("users"):
- if "users" not in userdata_dict:
- userdata_dict["users"] = [ "default" ]
- for user in cloud_config["users"]:
- user_info = {
- "name" : user["name"],
- "sudo": "ALL = (ALL)NOPASSWD:ALL"
- }
- if "user-info" in user:
- user_info["gecos"] = user["user-info"]
- if user.get("key-pairs"):
- user_info["ssh-authorized-keys"] = user["key-pairs"]
- userdata_dict["users"].append(user_info)
-
- if cloud_config.get("config-files"):
- userdata_dict["write_files"] = []
- for file in cloud_config["config-files"]:
- file_info = {
- "path" : file["dest"],
- "content": file["content"]
- }
- if file.get("encoding"):
- file_info["encoding"] = file["encoding"]
- if file.get("permissions"):
- file_info["permissions"] = file["permissions"]
- if file.get("owner"):
- file_info["owner"] = file["owner"]
- userdata_dict["write_files"].append(file_info)
- userdata = "#cloud-config\n"
- userdata += yaml.safe_dump(userdata_dict, indent=4, default_flow_style=False)
- self.logger.debug("userdata: %s", userdata)
- elif isinstance(cloud_config, str):
- userdata = cloud_config
-
- #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,
- config_drive = config_drive,
- block_device_mapping = block_device_mapping
- ) # , description=description)
- #print "DONE :-)", server
- pool_id = None
- floating_ips = self.neutron.list_floatingips().get("floatingips", ())
- for floating_network in external_network:
- try:
- # wait until vm is active
- elapsed_time = 0
- while elapsed_time < server_timeout:
- status = self.nova.servers.get(server.id).status
- if status == 'ACTIVE':
- break
- time.sleep(1)
- elapsed_time += 1
-
- #if we exceeded the timeout rollback
- if elapsed_time >= server_timeout:
- raise vimconn.vimconnException('Timeout creating instance ' + name,
- http_code=vimconn.HTTP_Request_Timeout)
-
- assigned = False
- while(assigned == False):
- if floating_ips:
- ip = floating_ips.pop(0)
- if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id:
- free_floating_ip = ip.get("floating_ip_address")
- try:
- fix_ip = floating_network.get('ip')
- server.add_floating_ip(free_floating_ip, fix_ip)
- assigned = True
- except Exception as e:
- raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
- else:
- #Find the external network
- external_nets = list()
- for net in self.neutron.list_networks()['networks']:
- if net['router:external']:
- external_nets.append(net)
-
- if len(external_nets) == 0:
- raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
- "network is present",
- http_code=vimconn.HTTP_Conflict)
- if len(external_nets) > 1:
- raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
- "external networks are present",
- http_code=vimconn.HTTP_Conflict)
-
- pool_id = external_nets[0].get('id')
- param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
- try:
- #self.logger.debug("Creating floating IP")
- new_floating_ip = self.neutron.create_floatingip(param)
- free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
- fix_ip = floating_network.get('ip')
- server.add_floating_ip(free_floating_ip, fix_ip)
- assigned=True
- except Exception as e:
- raise vimconn.vimconnException(type(e).__name__ + ": Cannot assign floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
- except Exception as e:
- if not floating_network['exit_on_floating_ip_error']:
- self.logger.warn("Cannot create floating_ip. %s", str(e))
- continue
- self.delete_vminstance(server.id)
- raise
-
- return server.id
-# except nvExceptions.NotFound as e:
-# error_value=-vimconn.HTTP_Not_Found
-# error_text= "vm instance %s not found" % vm_id
- except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
- # delete the volumes we just created
- if block_device_mapping != None:
- 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'])
- self._format_exception(e)
- except TypeError as e:
- raise vimconn.vimconnException(type(e).__name__ + ": "+ str(e), http_code=vimconn.HTTP_Bad_Request)
-
- def get_vminstance(self,vm_id):
- '''Returns the VM instance information from VIM'''
- #self.logger.debug("Getting VM from VIM")
- try:
- self._reload_connection()
- server = self.nova.servers.find(id=vm_id)
- #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
- return server.to_dict()
- except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
- self._format_exception(e)
-
- def get_vminstance_console(self,vm_id, console_type="vnc"):
- '''
- Get a console for the virtual machine
- Params:
- vm_id: uuid of the VM
- console_type, can be:
- "novnc" (by default), "xvpvnc" for VNC types,
- "rdp-html5" for RDP types, "spice-html5" for SPICE types
- Returns dict with the console parameters:
- protocol: ssh, ftp, http, https, ...
- server: usually ip address
- port: the http, ssh, ... port
- suffix: extra text, e.g. the http path and query string
- '''
- self.logger.debug("Getting VM CONSOLE from VIM")
- try:
- self._reload_connection()
- server = self.nova.servers.find(id=vm_id)
- if console_type == None or console_type == "novnc":
- console_dict = server.get_vnc_console("novnc")
- elif console_type == "xvpvnc":
- console_dict = server.get_vnc_console(console_type)
- elif console_type == "rdp-html5":
- console_dict = server.get_rdp_console(console_type)
- elif console_type == "spice-html5":
- console_dict = server.get_spice_console(console_type)
- else:
- raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), http_code=vimconn.HTTP_Bad_Request)
-
- console_dict1 = console_dict.get("console")
- if console_dict1:
- console_url = console_dict1.get("url")
- if console_url:
- #parse console_url
- protocol_index = console_url.find("//")
- suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
- port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
- if protocol_index < 0 or port_index<0 or suffix_index<0:
- return -vimconn.HTTP_Internal_Server_Error, "Unexpected response from VIM"
- console_dict={"protocol": console_url[0:protocol_index],
- "server": console_url[protocol_index+2:port_index],
- "port": console_url[port_index:suffix_index],
- "suffix": console_url[suffix_index+1:]
- }
- protocol_index += 2
- return console_dict
- raise vimconn.vimconnUnexpectedResponse("Unexpected response from VIM")
-
- except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest, ConnectionError) as e:
- self._format_exception(e)
-
- def delete_vminstance(self, vm_id):
- '''Removes a VM instance from VIM. Returns the old identifier
- '''
- #print "osconnector: Getting VM from VIM"
- try:
- self._reload_connection()
- #delete VM ports attached to this networks before the virtual machine
- ports = self.neutron.list_ports(device_id=vm_id)
- for p in ports['ports']:
- try:
- 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)
- #TODO insert exception vimconn.HTTP_Unauthorized
- #if reaching here is because an exception
-
- def refresh_vms_status(self, vm_list):
- '''Get the status of the virtual machines and their interfaces/ports
- Params: the list of VM identifiers
- Returns a dictionary with:
- vm_id: #VIM id of this Virtual Machine
- status: #Mandatory. Text with one of:
- # DELETED (not found at vim)
- # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
- # OTHER (Vim reported other status not understood)
- # ERROR (VIM indicates an ERROR status)
- # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
- # CREATING (on building process), ERROR
- # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
- #
- error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
- vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
- interfaces:
- - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
- mac_address: #Text format XX:XX:XX:XX:XX:XX
- vim_net_id: #network id where this interface is connected
- vim_interface_id: #interface/port VIM id
- ip_address: #null, or text with IPv4, IPv6 address
- '''
- vm_dict={}
- self.logger.debug("refresh_vms status: Getting tenant VM instance information from VIM")
- for vm_id in vm_list:
- vm={}
- try:
- vm_vim = self.get_vminstance(vm_id)
- if vm_vim['status'] in vmStatus2manoFormat:
- vm['status'] = vmStatus2manoFormat[ vm_vim['status'] ]
- else:
- vm['status'] = "OTHER"
- vm['error_msg'] = "VIM status reported " + vm_vim['status']
- try:
- vm['vim_info'] = yaml.safe_dump(vm_vim, default_flow_style=True, width=256)
- except yaml.representer.RepresenterError:
- vm['vim_info'] = str(vm_vim)
- vm["interfaces"] = []
- if vm_vim.get('fault'):
- vm['error_msg'] = str(vm_vim['fault'])
- #get interfaces
- try:
- self._reload_connection()
- port_dict=self.neutron.list_ports(device_id=vm_id)
- for port in port_dict["ports"]:
- interface={}
- try:
- interface['vim_info'] = yaml.safe_dump(port, default_flow_style=True, width=256)
- except yaml.representer.RepresenterError:
- interface['vim_info'] = str(port)
- interface["mac_address"] = port.get("mac_address")
- interface["vim_net_id"] = port["network_id"]
- interface["vim_interface_id"] = port["id"]
- ips=[]
- #look for floating ip address
- floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
- if floating_ip_dict.get("floatingips"):
- ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
-
- for subnet in port["fixed_ips"]:
- ips.append(subnet["ip_address"])
- interface["ip_address"] = ";".join(ips)
- vm["interfaces"].append(interface)
- except Exception as e:
- self.logger.error("Error getting vm interface information " + type(e).__name__ + ": "+ str(e))
- except vimconn.vimconnNotFoundException as e:
- self.logger.error("Exception getting vm status: %s", str(e))
- vm['status'] = "DELETED"
- vm['error_msg'] = str(e)
- except vimconn.vimconnException as e:
- self.logger.error("Exception getting vm status: %s", str(e))
- vm['status'] = "VIM_ERROR"
- vm['error_msg'] = str(e)
- vm_dict[vm_id] = vm
- return vm_dict
-
- def action_vminstance(self, vm_id, action_dict):
- '''Send and action over a VM instance from VIM
- Returns the vm_id if the action was successfully sent to the VIM'''
- self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
- try:
- self._reload_connection()
- server = self.nova.servers.find(id=vm_id)
- if "start" in action_dict:
- if action_dict["start"]=="rebuild":
- server.rebuild()
- else:
- if server.status=="PAUSED":
- server.unpause()
- elif server.status=="SUSPENDED":
- server.resume()
- elif server.status=="SHUTOFF":
- server.start()
- elif "pause" in action_dict:
- server.pause()
- elif "resume" in action_dict:
- server.resume()
- elif "shutoff" in action_dict or "shutdown" in action_dict:
- server.stop()
- elif "forceOff" in action_dict:
- server.stop() #TODO
- elif "terminate" in action_dict:
- server.delete()
- elif "createImage" in action_dict:
- server.create_image()
- #"path":path_schema,
- #"description":description_schema,
- #"name":name_schema,
- #"metadata":metadata_schema,
- #"imageRef": id_schema,
- #"disk": {"oneOf":[{"type": "null"}, {"type":"string"}] },
- elif "rebuild" in action_dict:
- server.rebuild(server.image['id'])
- elif "reboot" in action_dict:
- server.reboot() #reboot_type='SOFT'
- elif "console" in action_dict:
- console_type = action_dict["console"]
- if console_type == None or console_type == "novnc":
- console_dict = server.get_vnc_console("novnc")
- elif console_type == "xvpvnc":
- console_dict = server.get_vnc_console(console_type)
- elif console_type == "rdp-html5":
- console_dict = server.get_rdp_console(console_type)
- elif console_type == "spice-html5":
- console_dict = server.get_spice_console(console_type)
- else:
- raise vimconn.vimconnException("console type '{}' not allowed".format(console_type),
- http_code=vimconn.HTTP_Bad_Request)
- try:
- console_url = console_dict["console"]["url"]
- #parse console_url
- protocol_index = console_url.find("//")
- suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
- port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
- if protocol_index < 0 or port_index<0 or suffix_index<0:
- raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
- console_dict2={"protocol": console_url[0:protocol_index],
- "server": console_url[protocol_index+2 : port_index],
- "port": int(console_url[port_index+1 : suffix_index]),
- "suffix": console_url[suffix_index+1:]
- }
- return console_dict2
- except Exception as e:
- raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
-
- return vm_id
- except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
- self._format_exception(e)
- #TODO insert exception vimconn.HTTP_Unauthorized
-
-#NOT USED FUNCTIONS
-
- def new_external_port(self, port_data):
- #TODO openstack if needed
- '''Adds a external port to VIM'''
- '''Returns the port identifier'''
- return -vimconn.HTTP_Internal_Server_Error, "osconnector.new_external_port() not implemented"
-
- def connect_port_network(self, port_id, network_id, admin=False):
- #TODO openstack if needed
- '''Connects a external port to a network'''
- '''Returns status code of the VIM response'''
- return -vimconn.HTTP_Internal_Server_Error, "osconnector.connect_port_network() not implemented"
-
- def new_user(self, user_name, user_passwd, tenant_id=None):
- '''Adds a new user to openstack VIM'''
- '''Returns the user identifier'''
- self.logger.debug("osconnector: Adding a new user to VIM")
- try:
- self._reload_connection()
- user=self.keystone.users.create(user_name, user_passwd, tenant_id=tenant_id)
- #self.keystone.tenants.add_user(self.k_creds["username"], #role)
- return user.id
- except ksExceptions.ConnectionError as e:
- error_value=-vimconn.HTTP_Bad_Request
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- except ksExceptions.ClientException as e: #TODO remove
- error_value=-vimconn.HTTP_Bad_Request
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- #TODO insert exception vimconn.HTTP_Unauthorized
- #if reaching here is because an exception
- if self.debug:
- self.logger.debug("new_user " + error_text)
- return error_value, error_text
-
- def delete_user(self, user_id):
- '''Delete a user from openstack VIM'''
- '''Returns the user identifier'''
- if self.debug:
- print "osconnector: Deleting a user from VIM"
- try:
- self._reload_connection()
- self.keystone.users.delete(user_id)
- return 1, user_id
- except ksExceptions.ConnectionError as e:
- error_value=-vimconn.HTTP_Bad_Request
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- except ksExceptions.NotFound as e:
- error_value=-vimconn.HTTP_Not_Found
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- except ksExceptions.ClientException as e: #TODO remove
- error_value=-vimconn.HTTP_Bad_Request
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- #TODO insert exception vimconn.HTTP_Unauthorized
- #if reaching here is because an exception
- if self.debug:
- print "delete_tenant " + error_text
- return error_value, error_text
-
- def get_hosts_info(self):
- '''Get the information of deployed hosts
- Returns the hosts content'''
- if self.debug:
- print "osconnector: Getting Host info from VIM"
- try:
- h_list=[]
- self._reload_connection()
- hypervisors = self.nova.hypervisors.list()
- for hype in hypervisors:
- h_list.append( hype.to_dict() )
- return 1, {"hosts":h_list}
- except nvExceptions.NotFound as e:
- error_value=-vimconn.HTTP_Not_Found
- error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
- except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
- error_value=-vimconn.HTTP_Bad_Request
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- #TODO insert exception vimconn.HTTP_Unauthorized
- #if reaching here is because an exception
- if self.debug:
- print "get_hosts_info " + error_text
- return error_value, error_text
-
- def get_hosts(self, vim_tenant):
- '''Get the hosts and deployed instances
- Returns the hosts content'''
- r, hype_dict = self.get_hosts_info()
- if r<0:
- return r, hype_dict
- hypervisors = hype_dict["hosts"]
- try:
- servers = self.nova.servers.list()
- for hype in hypervisors:
- for server in servers:
- if server.to_dict()['OS-EXT-SRV-ATTR:hypervisor_hostname']==hype['hypervisor_hostname']:
- if 'vm' in hype:
- hype['vm'].append(server.id)
- else:
- hype['vm'] = [server.id]
- return 1, hype_dict
- except nvExceptions.NotFound as e:
- error_value=-vimconn.HTTP_Not_Found
- error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
- except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
- error_value=-vimconn.HTTP_Bad_Request
- error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
- #TODO insert exception vimconn.HTTP_Unauthorized
- #if reaching here is because an exception
- if self.debug:
- print "get_hosts " + error_text
- return error_value, error_text
-
-