# limitations under the License.
#
-import json
import logging
-import ipaddress
-from keystoneclient import v3 as ksclientv3
-from keystoneclient.v2_0 import client as ksclientv2
-from novaclient import client as nova_client
-from neutronclient.neutron import client as ntclient
-from glanceclient.v2 import client as glclient
-from ceilometerclient import client as ceilo_client
-from cinderclient.v2 import client as cinder_client
+from . import session as sess_drv
+from . import keystone as ks_drv
+from . import nova as nv_drv
+from . import neutron as nt_drv
+from . import glance as gl_drv
+from . import ceilometer as ce_drv
+from . import cinder as ci_drv
+from . import utils as drv_utils
# Exceptions
-import novaclient.exceptions as NovaException
import keystoneclient.exceptions as KeystoneExceptions
import neutronclient.common.exceptions as NeutronException
-import glanceclient.exc as GlanceException
-import cinderclient.exceptions as CinderException
-logger = logging.getLogger('rwcal.openstack.drv')
-logger.setLevel(logging.DEBUG)
class ValidationError(Exception):
pass
-class KeystoneDriver(object):
+class DriverUtilities(object):
"""
- Driver base-class for keystoneclient APIs
+ Class with utility method
"""
- def __init__(self, ksclient):
+ def __init__(self, driver):
"""
- Constructor for KeystoneDriver base class
- Arguments: None
- Returns: None
- """
- self.ksclient = ksclient
-
- def get_username(self):
- """
- Returns the username associated with keystoneclient connection
- """
- return self._username
-
- def get_password(self):
- """
- Returns the password associated with keystoneclient connection
- """
- return self._password
-
- def get_tenant_name(self):
- """
- Returns the tenant name associated with keystoneclient connection
- """
- return self._tenant_name
-
- def get_user_domain_name(self):
- """
- Returns None as this field does not exist for v2.
- """
- return None;
-
- def get_project_domain_name(self):
- """
- Returns None as this field does not exist for v2.
- """
- return None;
-
- def _get_keystone_connection(self):
- """
- Returns object of class python-keystoneclient class
- """
- if not hasattr(self, '_keystone_connection'):
- self._keystone_connection = self.ksclient(**self._get_keystone_credentials())
- return self._keystone_connection
-
- def is_auth_token_valid(self, token_expiry, time_fmt):
- """
- Performs validity on auth_token
- Arguments:
- token_expiry (string): Expiry time for token
- time_fmt (string) : Format for expiry string in auth_ref
-
- Returns:
- True/False (Boolean): (auth_token is valid or auth_token is invalid)
- """
- import time
- import datetime
- import dateutil.parser
- try:
- now = datetime.datetime.timetuple(datetime.datetime.utcnow())
- expires_at = dateutil.parser.parse(token_expiry)
- t_now = time.mktime(now)
- t_expiry = time.mktime(expires_at.timetuple())
-
- if (t_expiry <= t_now) or ((t_expiry - t_now) < 300 ):
- ### Token has expired or about to expire (5 minute)
- delattr(self, '_keystone_connection')
- return False
- else:
- return True
- except Exception as e:
- logger.error("Received except %s during auth_token validity check" %str(e))
- logger.info("Can not validate the auth_token. Assuming invalid")
- return False
-
-
- def get_service_endpoint(self, service_type, endpoint_type):
- """
- Returns requested type of endpoint for requested service type
- Arguments:
- service_type (string): Service Type (e.g. computev3, image, network)
- endpoint_type(string): Endpoint Type (e.g. publicURL,adminURL,internalURL)
- Returns:
- service_endpoint(string): Service endpoint string
- """
- endpoint_kwargs = {'service_type' : service_type,
- 'endpoint_type' : endpoint_type}
- try:
- ksconn = self._get_keystone_connection()
- service_endpoint = ksconn.service_catalog.url_for(**endpoint_kwargs)
- except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure) as e:
- raise
- except Exception as e:
- logger.error("OpenstackDriver: Service Catalog discovery operation failed for service_type: %s, endpoint_type: %s. Exception: %s" %(service_type, endpoint_type, str(e)))
- raise
- return service_endpoint
-
-
- def get_raw_token(self):
- """
- Returns a valid raw_auth_token string
-
- Returns (string): raw_auth_token string
- """
- ksconn = self._get_keystone_connection()
- try:
- raw_token = ksconn.get_raw_token_from_identity_service(auth_url = self._auth_url,
- token = self.get_auth_token())
- except KeystoneExceptions.AuthorizationFailure as e:
- logger.error("OpenstackDriver: get_raw_token_from_identity_service Failure. Exception: %s" %(str(e)))
- return None
-
- except Exception as e:
- logger.error("OpenstackDriver: Could not retrieve raw_token. Exception: %s" %(str(e)))
-
- return raw_token
-
- def get_tenant_id(self):
- """
- Returns tenant_id for the project/tenant. Tenant name is provided during
- class instantiation
-
- Returns (string): Tenant ID
- """
- ksconn = self._get_keystone_connection()
- return ksconn.tenant_id
-
- def get_security_mode(self):
- """
- Returns certificate_validation policy in case of SSL/TLS connection.
- This policy is provided during class instantiation
-
- Returns (boolean):
- The boolean returned are designed to match the python-client class instantiation ("insecure") value.
- for nova/neutron/glance/keystone clients
-
- True: No certificate validation required -- Insecure mode
- False: Certificate validation required -- Secure mode
- """
- return self._insecure
-
- def tenant_list(self):
- """
- Returns list of tenants
- """
- pass
-
- def tenant_create(self, name):
- """
- Create a new tenant
- """
- pass
-
- def tenant_delete(self, tenant_id):
- """
- Deletes a tenant identified by tenant_id
- """
- pass
-
- def roles_list(self):
- pass
-
- def roles_create(self):
- pass
-
- def roles_delete(self):
- pass
-
-class KeystoneDriverV2(KeystoneDriver):
- """
- Driver class for keystoneclient V2 APIs
- """
- def __init__(self, username, password, auth_url,tenant_name, insecure):
- """
- Constructor for KeystoneDriverV3 class
- Arguments:
- username (string) : Username
- password (string) : Password
- auth_url (string) : Authentication URL
- tenant_name(string): Tenant Name
-
- Returns: None
- """
- self._username = username
- self._password = password
- self._auth_url = auth_url
- self._tenant_name = tenant_name
- self._insecure = insecure
- super(KeystoneDriverV2, self).__init__(ksclientv2.Client)
-
- def _get_keystone_credentials(self):
- """
- Returns the dictionary of kwargs required to instantiate python-keystoneclient class
- """
- creds = {}
- #creds['user_domain'] = self._domain_name
- creds['username'] = self._username
- creds['password'] = self._password
- creds['auth_url'] = self._auth_url
- creds['tenant_name'] = self._tenant_name
- creds['insecure'] = self.get_security_mode()
- return creds
-
- def get_auth_token(self):
- """
- Returns a valid auth_token
-
- Returns (string): auth_token string
- """
- ksconn = self._get_keystone_connection()
- return ksconn.auth_token
-
- def is_auth_token_valid(self):
- """
- Performs validity on auth_token
- Arguments:
-
- Returns:
- True/False (Boolean): (auth_token is valid or auth_token is invalid)
- """
- ksconn = self._get_keystone_connection()
- result = super(KeystoneDriverV2, self).is_auth_token_valid(ksconn.auth_ref['token']['expires'],
- "%Y-%m-%dT%H:%M:%SZ")
- return result
-
-
-class KeystoneDriverV3(KeystoneDriver):
- """
- Driver class for keystoneclient V3 APIs
- """
- def __init__(self, username, password, auth_url,tenant_name, insecure, user_domain_name = None, project_domain_name = None):
- """
- Constructor for KeystoneDriverV3 class
- Arguments:
- username (string) : Username
- password (string) : Password
- auth_url (string) : Authentication URL
- tenant_name(string): Tenant Name
-
- Returns: None
- """
- self._username = username
- self._password = password
- self._auth_url = auth_url
- self._tenant_name = tenant_name
- self._insecure = insecure
- self._user_domain_name = user_domain_name
- self._project_domain_name = project_domain_name
- super(KeystoneDriverV3, self).__init__(ksclientv3.Client)
-
- def _get_keystone_credentials(self):
- """
- Returns the dictionary of kwargs required to instantiate python-keystoneclient class
- """
- creds = {}
- creds['username'] = self._username
- creds['password'] = self._password
- creds['auth_url'] = self._auth_url
- creds['project_name'] = self._tenant_name
- creds['insecure'] = self._insecure
- creds['user_domain_name'] = self._user_domain_name
- creds['project_domain_name'] = self._project_domain_name
- return creds
-
- def get_user_domain_name(self):
- """
- Returns the domain_name of the associated OpenStack user account
- """
- return self._user_domain_name;
-
- def get_project_domain_name(self):
- """
- Returns the domain_name of the associated OpenStack project
- """
- return self._project_domain_name;
-
- def get_auth_token(self):
- """
- Returns a valid auth_token
-
- Returns (string): auth_token string
- """
- ksconn = self._get_keystone_connection()
- return ksconn.auth_ref['auth_token']
-
- def is_auth_token_valid(self):
- """
- Performs validity on auth_token
- Arguments:
-
- Returns:
- True/False (Boolean): (auth_token is valid or auth_token is invalid)
- """
- ksconn = self._get_keystone_connection()
- result = super(KeystoneDriverV3, self).is_auth_token_valid(ksconn.auth_ref['expires_at'],
- "%Y-%m-%dT%H:%M:%S.%fZ")
- return result
-
-class NovaDriver(object):
- """
- Driver for openstack nova_client
- """
- def __init__(self, ks_drv, service_name, version):
- """
- Constructor for NovaDriver
- Arguments: KeystoneDriver class object
- """
- self.ks_drv = ks_drv
- self._service_name = service_name
- self._version = version
-
- def _get_nova_credentials(self):
- """
- Returns a dictionary of kwargs required to instantiate python-novaclient class
- """
- creds = {}
- creds['version'] = self._version
- creds['bypass_url'] = self.ks_drv.get_service_endpoint(self._service_name, "publicURL")
- creds['username'] = self.ks_drv.get_username()
- creds['project_id'] = self.ks_drv.get_tenant_name()
- creds['auth_token'] = self.ks_drv.get_auth_token()
- creds['insecure'] = self.ks_drv.get_security_mode()
- creds['user_domain_name'] = self.ks_drv.get_user_domain_name()
- creds['project_domain_name'] = self.ks_drv.get_project_domain_name()
-
- return creds
-
- def _get_nova_connection(self):
- """
- Returns an object of class python-novaclient
- """
- if not hasattr(self, '_nova_connection'):
- self._nova_connection = nova_client.Client(**self._get_nova_credentials())
- else:
- # Reinitialize if auth_token is no longer valid
- if not self.ks_drv.is_auth_token_valid():
- self._nova_connection = nova_client.Client(**self._get_nova_credentials())
- return self._nova_connection
-
- def _flavor_get(self, flavor_id):
- """
- Get flavor by flavor_id
- Arguments:
- flavor_id(string): UUID of flavor_id
-
- Returns:
- dictionary of flavor parameters
- """
- nvconn = self._get_nova_connection()
- try:
- flavor = nvconn.flavors.get(flavor_id)
- except Exception as e:
- logger.info("OpenstackDriver: Did not find flavor with flavor_id : %s. Exception: %s"%(flavor_id, str(e)))
- raise
-
- try:
- extra_specs = flavor.get_keys()
- except Exception as e:
- logger.info("OpenstackDriver: Could not get the EPA attributes for flavor with flavor_id : %s. Exception: %s"%(flavor_id, str(e)))
- raise
-
- response = flavor.to_dict()
- assert 'extra_specs' not in response, "Key extra_specs present as flavor attribute"
- response['extra_specs'] = extra_specs
- return response
-
- def flavor_get(self, flavor_id):
- """
- Get flavor by flavor_id
- Arguments:
- flavor_id(string): UUID of flavor_id
-
- Returns:
- dictionary of flavor parameters
- """
- return self._flavor_get(flavor_id)
-
- def flavor_list(self):
- """
- Returns list of all flavors (dictionary per flavor)
-
- Arguments:
- None
- Returns:
- A list of dictionaries. Each dictionary contains attributes for a single flavor instance
- """
- flavors = []
- flavor_info = []
- nvconn = self._get_nova_connection()
- try:
- flavors = nvconn.flavors.list()
- except Exception as e:
- logger.error("OpenstackDriver: List Flavor operation failed. Exception: %s"%(str(e)))
- raise
- if flavors:
- flavor_info = [ self.flavor_get(flv.id) for flv in flavors ]
- return flavor_info
-
- def flavor_create(self, name, ram, vcpu, disk, extra_specs):
- """
- Create a new flavor
-
- Arguments:
- name (string): Name of the new flavor
- ram (int) : Memory in MB
- vcpus (int) : Number of VCPUs
- disk (int) : Secondary storage size in GB
- extra_specs (dictionary): EPA attributes dictionary
-
- Returns:
- flavor_id (string): UUID of flavor created
- """
- nvconn = self._get_nova_connection()
- try:
- flavor = nvconn.flavors.create(name = name,
- ram = ram,
- vcpus = vcpu,
- disk = disk,
- flavorid = 'auto',
- ephemeral = 0,
- swap = 0,
- rxtx_factor = 1.0,
- is_public = True)
- except Exception as e:
- logger.error("OpenstackDriver: Create Flavor operation failed. Exception: %s"%(str(e)))
- raise
-
- if extra_specs:
- try:
- flavor.set_keys(extra_specs)
- except Exception as e:
- logger.error("OpenstackDriver: Set Key operation failed for flavor: %s. Exception: %s" %(flavor.id, str(e)))
- raise
- return flavor.id
-
- def flavor_delete(self, flavor_id):
- """
- Deletes a flavor identified by flavor_id
-
- Arguments:
- flavor_id (string): UUID of flavor to be deleted
-
- Returns: None
- """
- assert flavor_id == self._flavor_get(flavor_id)['id']
- nvconn = self._get_nova_connection()
- try:
- nvconn.flavors.delete(flavor_id)
- except Exception as e:
- logger.error("OpenstackDriver: Delete flavor operation failed for flavor: %s. Exception: %s" %(flavor_id, str(e)))
- raise
-
-
- def server_list(self):
- """
- Returns a list of available VMs for the project
-
- Arguments: None
-
- Returns:
- A list of dictionaries. Each dictionary contains attributes associated
- with individual VM
- """
- servers = []
- server_info = []
- nvconn = self._get_nova_connection()
- try:
- servers = nvconn.servers.list()
- except Exception as e:
- logger.error("OpenstackDriver: List Server operation failed. Exception: %s" %(str(e)))
- raise
- server_info = [ server.to_dict() for server in servers]
- return server_info
-
- def _nova_server_get(self, server_id):
- """
- Returns a dictionary of attributes associated with VM identified by service_id
-
- Arguments:
- server_id (string): UUID of the VM/server for which information is requested
-
- Returns:
- A dictionary object with attributes associated with VM identified by server_id
- """
- nvconn = self._get_nova_connection()
- try:
- server = nvconn.servers.get(server = server_id)
- except Exception as e:
- logger.info("OpenstackDriver: Get Server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
- raise
- else:
- return server.to_dict()
-
- def server_get(self, server_id):
- """
- Returns a dictionary of attributes associated with VM identified by service_id
-
- Arguments:
- server_id (string): UUID of the VM/server for which information is requested
-
- Returns:
- A dictionary object with attributes associated with VM identified by server_id
- """
- return self._nova_server_get(server_id)
-
- def server_create(self, **kwargs):
- """
- Creates a new VM/server instance
-
- Arguments:
- A dictionary of following key-value pairs
- {
- server_name(string) : Name of the VM/Server
- flavor_id (string) : UUID of the flavor to be used for VM
- image_id (string) : UUID of the image to be used VM/Server instance,
- This could be None if volumes (with images) are being used
- network_list(List) : A List of network_ids. A port will be created in these networks
- port_list (List) : A List of port-ids. These ports will be added to VM.
- metadata (dict) : A dictionary of arbitrary key-value pairs associated with VM/server
- userdata (string) : A script which shall be executed during first boot of the VM
- availability_zone (string) : A name of the availability zone where instance should be launched
- scheduler_hints (string) : Openstack scheduler_hints to be passed to nova scheduler
- }
- Returns:
- server_id (string): UUID of the VM/server created
-
- """
- nics = []
- if 'network_list' in kwargs:
- for network_id in kwargs['network_list']:
- nics.append({'net-id': network_id})
-
- if 'port_list' in kwargs:
- for port_id in kwargs['port_list']:
- nics.append({'port-id': port_id})
-
- nvconn = self._get_nova_connection()
-
-
- try:
- server = nvconn.servers.create(kwargs['name'],
- kwargs['image_id'],
- kwargs['flavor_id'],
- meta = kwargs['metadata'],
- files = kwargs['files'],
- reservation_id = None,
- min_count = None,
- max_count = None,
- userdata = kwargs['userdata'],
- security_groups = kwargs['security_groups'],
- availability_zone = kwargs['availability_zone'],
- block_device_mapping_v2 = kwargs['block_device_mapping_v2'],
- nics = nics,
- scheduler_hints = kwargs['scheduler_hints'],
- config_drive = kwargs['config_drive'])
- except Exception as e:
- logger.info("OpenstackDriver: Create Server operation failed. Exception: %s" %(str(e)))
- raise
- return server.to_dict()['id']
-
- def server_delete(self, server_id):
- """
- Deletes a server identified by server_id
-
- Arguments:
- server_id (string): UUID of the server to be deleted
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.delete(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Delete server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
- raise
-
- def server_start(self, server_id):
- """
- Starts a server identified by server_id
-
- Arguments:
- server_id (string): UUID of the server to be started
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.start(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Start Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
- raise
-
- def server_stop(self, server_id):
- """
- Arguments:
- server_id (string): UUID of the server to be stopped
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.stop(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Stop Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
- raise
-
- def server_pause(self, server_id):
- """
- Arguments:
- server_id (string): UUID of the server to be paused
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.pause(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Pause Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
- raise
-
- def server_unpause(self, server_id):
- """
- Arguments:
- server_id (string): UUID of the server to be unpaused
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.unpause(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Resume Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
- raise
-
-
- def server_suspend(self, server_id):
- """
- Arguments:
- server_id (string): UUID of the server to be suspended
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.suspend(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Suspend Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
-
-
- def server_resume(self, server_id):
- """
- Arguments:
- server_id (string): UUID of the server to be resumed
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.resume(server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Resume Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
- raise
-
- def server_reboot(self, server_id, reboot_type):
- """
- Arguments:
- server_id (string) : UUID of the server to be rebooted
- reboot_type(string):
- 'SOFT': Soft Reboot
- 'HARD': Hard Reboot
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.reboot(server_id, reboot_type)
- except Exception as e:
- logger.error("OpenstackDriver: Reboot Server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
- raise
-
- def server_console(self, server_id, console_type = 'novnc'):
- """
- Arguments:
- server_id (string) : UUID of the server to be rebooted
- console_type(string):
- 'novnc',
- 'xvpvnc'
- Returns:
- A dictionary object response for console information
- """
- nvconn = self._get_nova_connection()
- try:
- console_info = nvconn.servers.get_vnc_console(server_id, console_type)
- except Exception as e:
- logger.error("OpenstackDriver: Server Get-Console operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
- raise
- return console_info
-
- def server_rebuild(self, server_id, image_id):
- """
- Arguments:
- server_id (string) : UUID of the server to be rebooted
- image_id (string) : UUID of the image to use
- Returns: None
- """
-
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.rebuild(server_id, image_id)
- except Exception as e:
- logger.error("OpenstackDriver: Rebuild Server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
- raise
-
-
- def server_add_port(self, server_id, port_id):
- """
- Arguments:
- server_id (string): UUID of the server
- port_id (string): UUID of the port to be attached
-
- Returns: None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.interface_attach(server_id,
- port_id,
- net_id = None,
- fixed_ip = None)
- except Exception as e:
- logger.error("OpenstackDriver: Server Port Add operation failed for server_id : %s, port_id : %s. Exception: %s" %(server_id, port_id, str(e)))
- raise
-
- def server_delete_port(self, server_id, port_id):
- """
- Arguments:
- server_id (string): UUID of the server
- port_id (string): UUID of the port to be deleted
- Returns: None
-
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.interface_detach(server_id, port_id)
- except Exception as e:
- logger.error("OpenstackDriver: Server Port Delete operation failed for server_id : %s, port_id : %s. Exception: %s" %(server_id, port_id, str(e)))
- raise
-
- def floating_ip_list(self):
- """
- Arguments:
- None
- Returns:
- List of objects of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
- """
- nvconn = self._get_nova_connection()
- try:
- ip_list = nvconn.floating_ips.list()
- except Exception as e:
- logger.error("OpenstackDriver: Floating IP List operation failed. Exception: %s" %str(e))
- raise
-
- return ip_list
-
- def floating_ip_create(self, pool):
- """
- Arguments:
- pool (string): Name of the pool (optional)
- Returns:
- An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
- """
- nvconn = self._get_nova_connection()
- try:
- floating_ip = nvconn.floating_ips.create(pool)
- except Exception as e:
- logger.error("OpenstackDriver: Floating IP Create operation failed. Exception: %s" %str(e))
- raise
-
- return floating_ip
-
- def floating_ip_delete(self, floating_ip):
- """
- Arguments:
- floating_ip: An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
- Returns:
- None
- """
- nvconn = self._get_nova_connection()
- try:
- floating_ip = nvconn.floating_ips.delete(floating_ip)
- except Exception as e:
- logger.error("OpenstackDriver: Floating IP Delete operation failed. Exception: %s" %str(e))
- raise
-
- def floating_ip_assign(self, server_id, floating_ip, fixed_ip):
- """
- Arguments:
- server_id (string) : UUID of the server
- floating_ip (string): IP address string for floating-ip
- fixed_ip (string) : IP address string for the fixed-ip with which floating ip will be associated
- Returns:
- None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.add_floating_ip(server_id, floating_ip, fixed_ip)
- except Exception as e:
- logger.error("OpenstackDriver: Assign Floating IP operation failed. Exception: %s" %str(e))
- raise
-
- def floating_ip_release(self, server_id, floating_ip):
- """
- Arguments:
- server_id (string) : UUID of the server
- floating_ip (string): IP address string for floating-ip
- Returns:
- None
- """
- nvconn = self._get_nova_connection()
- try:
- nvconn.servers.remove_floating_ip(server_id, floating_ip)
- except Exception as e:
- logger.error("OpenstackDriver: Release Floating IP operation failed. Exception: %s" %str(e))
- raise
-
- def volume_list(self, server_id):
- """
- List of volumes attached to the server
-
- Arguments:
- None
- Returns:
- List of dictionary objects where dictionary is representation of class (novaclient.v2.volumes.Volume)
- """
- nvconn = self._get_nova_connection()
- try:
- volumes = nvconn.volumes.get_server_volumes(server_id=server_id)
- except Exception as e:
- logger.error("OpenstackDriver: Get volume information failed. Exception: %s" %str(e))
- raise
-
- volume_info = [v.to_dict() for v in volumes]
- return volume_info
-
-
- def group_list(self):
- """
- List of Server Affinity and Anti-Affinity Groups
-
- Arguments:
- None
- Returns:
- List of dictionary objects where dictionary is representation of class (novaclient.v2.server_groups.ServerGroup)
- """
- nvconn = self._get_nova_connection()
- try:
- group_list = nvconn.server_groups.list()
- except Exception as e:
- logger.error("OpenstackDriver: Server Group List operation failed. Exception: %s" %str(e))
- raise
-
- group_info = [ group.to_dict() for group in group_list ]
- return group_info
-
-
-
-class NovaDriverV2(NovaDriver):
- """
- Driver class for novaclient V2 APIs
- """
- def __init__(self, ks_drv):
- """
- Constructor for NovaDriver
- Arguments: KeystoneDriver class object
- """
- super(NovaDriverV2, self).__init__(ks_drv, 'compute', '2.0')
-
-class NovaDriverV21(NovaDriver):
- """
- Driver class for novaclient V2 APIs
- """
- def __init__(self, ks_drv):
- """
- Constructor for NovaDriver
- Arguments: KeystoneDriver class object
- """
- super(NovaDriverV21, self).__init__(ks_drv, 'compute', '2.1')
-
-class GlanceDriver(object):
- """
- Driver for openstack glance-client
- """
- def __init__(self, ks_drv, service_name, version):
- """
- Constructor for GlanceDriver
- Arguments: KeystoneDriver class object
- """
- self.ks_drv = ks_drv
- self._service_name = service_name
- self._version = version
-
- def _get_glance_credentials(self):
- """
- Returns a dictionary of kwargs required to instantiate python-glanceclient class
-
- Arguments: None
-
- Returns:
- A dictionary object of arguments
- """
- creds = {}
- creds['version'] = self._version
- creds['endpoint'] = self.ks_drv.get_service_endpoint(self._service_name, 'publicURL')
- creds['token'] = self.ks_drv.get_auth_token()
- creds['insecure'] = self.ks_drv.get_security_mode()
- return creds
-
- def _get_glance_connection(self):
- """
- Returns a object of class python-glanceclient
- """
- if not hasattr(self, '_glance_connection'):
- self._glance_connection = glclient.Client(**self._get_glance_credentials())
- else:
- # Reinitialize if auth_token is no longer valid
- if not self.ks_drv.is_auth_token_valid():
- self._glance_connection = glclient.Client(**self._get_glance_credentials())
- return self._glance_connection
-
- def image_list(self):
- """
- Returns list of dictionaries. Each dictionary contains attributes associated with
- image
-
- Arguments: None
-
- Returns: List of dictionaries.
- """
- glconn = self._get_glance_connection()
- images = []
- try:
- image_info = glconn.images.list()
- except Exception as e:
- logger.error("OpenstackDriver: List Image operation failed. Exception: %s" %(str(e)))
- raise
- images = [ img for img in image_info ]
- return images
-
- def image_create(self, **kwargs):
- """
- Creates an image
- Arguments:
- A dictionary of kwargs with following keys
- {
- 'name'(string) : Name of the image
- 'location'(string) : URL (http://....) where image is located
- 'disk_format'(string) : Disk format
- Possible values are 'ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso'
- 'container_format'(string): Container format
- Possible values are 'ami', 'ari', 'aki', 'bare', 'ovf'
- 'tags' : A list of user tags
- 'checksum' : The image md5 checksum
- }
- Returns:
- image_id (string) : UUID of the image
-
- """
- glconn = self._get_glance_connection()
- try:
- image = glconn.images.create(**kwargs)
- except Exception as e:
- logger.error("OpenstackDriver: Create Image operation failed. Exception: %s" %(str(e)))
- raise
-
- return image.id
-
- def image_upload(self, image_id, fd):
- """
- Upload the image
-
- Arguments:
- image_id: UUID of the image
- fd : File descriptor for the image file
- Returns: None
- """
- glconn = self._get_glance_connection()
- try:
- glconn.images.upload(image_id, fd)
- except Exception as e:
- logger.error("OpenstackDriver: Image upload operation failed. Exception: %s" %(str(e)))
- raise
-
- def image_add_location(self, image_id, location, metadata):
- """
- Add image URL location
-
- Arguments:
- image_id : UUID of the image
- location : http URL for the image
-
- Returns: None
- """
- glconn = self._get_glance_connection()
- try:
- image = glconn.images.add_location(image_id, location, metadata)
- except Exception as e:
- logger.error("OpenstackDriver: Image location add operation failed. Exception: %s" %(str(e)))
- raise
-
- def image_update(self):
- pass
-
- def image_delete(self, image_id):
- """
- Delete an image
-
- Arguments:
- image_id: UUID of the image
-
- Returns: None
-
- """
- assert image_id == self._image_get(image_id)['id']
- glconn = self._get_glance_connection()
- try:
- glconn.images.delete(image_id)
- except Exception as e:
- logger.error("OpenstackDriver: Delete Image operation failed for image_id : %s. Exception: %s" %(image_id, str(e)))
- raise
-
-
- def _image_get(self, image_id):
- """
- Returns a dictionary object of VM image attributes
-
- Arguments:
- image_id (string): UUID of the image
-
- Returns:
- A dictionary of the image attributes
- """
- glconn = self._get_glance_connection()
- try:
- image = glconn.images.get(image_id)
- except GlanceException.HTTPBadRequest:
- # RIFT-14241: The get image request occasionally returns the below message. Retry in case of bad request exception.
- # Error code 400.: Message: Bad request syntax ('0').: Error code explanation: 400 = Bad request syntax or unsupported method. (HTTP 400)
- logger.warning("OpenstackDriver: Got bad request response during get_image request. Retrying.")
- image = glconn.images.get(image_id)
- except Exception as e:
- logger.error("OpenstackDriver: Get Image operation failed for image_id : %s. Exception: %s" %(image_id, str(e)))
- raise
-
- return image
-
- def image_get(self, image_id):
- """
- Returns a dictionary object of VM image attributes
-
- Arguments:
- image_id (string): UUID of the image
-
- Returns:
- A dictionary of the image attributes
- """
- return self._image_get(image_id)
-
-class GlanceDriverV2(GlanceDriver):
- """
- Driver for openstack glance-client V2
- """
- def __init__(self, ks_drv):
- super(GlanceDriverV2, self).__init__(ks_drv, 'image', 2)
-
-class NeutronDriver(object):
- """
- Driver for openstack neutron neutron-client
- """
- def __init__(self, ks_drv, service_name, version):
- """
- Constructor for NeutronDriver
- Arguments: KeystoneDriver class object
- """
- self.ks_drv = ks_drv
- self._service_name = service_name
- self._version = version
-
- def _get_neutron_credentials(self):
- """
- Returns a dictionary of kwargs required to instantiate python-neutronclient class
-
- Returns:
- Dictionary of kwargs
- """
- creds = {}
- creds['api_version'] = self._version
- creds['endpoint_url'] = self.ks_drv.get_service_endpoint(self._service_name, 'publicURL')
- creds['token'] = self.ks_drv.get_auth_token()
- creds['tenant_name'] = self.ks_drv.get_tenant_name()
- creds['insecure'] = self.ks_drv.get_security_mode()
- return creds
-
- def _get_neutron_connection(self):
- """
- Returns an object of class python-neutronclient
- """
- if not hasattr(self, '_neutron_connection'):
- self._neutron_connection = ntclient.Client(**self._get_neutron_credentials())
- else:
- # Reinitialize if auth_token is no longer valid
- if not self.ks_drv.is_auth_token_valid():
- self._neutron_connection = ntclient.Client(**self._get_neutron_credentials())
- return self._neutron_connection
-
- def network_list(self):
- """
- Returns list of dictionaries. Each dictionary contains the attributes for a network
- under project
-
- Arguments: None
-
- Returns:
- A list of dictionaries
- """
- networks = []
- ntconn = self._get_neutron_connection()
- try:
- networks = ntconn.list_networks()
- except Exception as e:
- logger.error("OpenstackDriver: List Network operation failed. Exception: %s" %(str(e)))
- raise
- return networks['networks']
-
- def network_create(self, **kwargs):
- """
- Creates a new network for the project
-
- Arguments:
- A dictionary with following key-values
- {
- name (string) : Name of the network
- admin_state_up(Boolean) : True/False (Defaults: True)
- external_router(Boolean) : Connectivity with external router. True/False (Defaults: False)
- shared(Boolean) : Shared among tenants. True/False (Defaults: False)
- physical_network(string) : The physical network where this network object is implemented (optional).
- network_type : The type of physical network that maps to this network resource (optional).
- Possible values are: 'flat', 'vlan', 'vxlan', 'gre'
- segmentation_id : An isolated segment on the physical network. The network_type attribute
- defines the segmentation model. For example, if the network_type value
- is vlan, this ID is a vlan identifier. If the network_type value is gre,
- this ID is a gre key.
- }
- """
- params = {'network':
- {'name' : kwargs['name'],
- 'admin_state_up' : kwargs['admin_state_up'],
- 'tenant_id' : self.ks_drv.get_tenant_id(),
- 'shared' : kwargs['shared'],
- #'port_security_enabled': port_security_enabled,
- 'router:external' : kwargs['external_router']}}
-
- if 'physical_network' in kwargs:
- params['network']['provider:physical_network'] = kwargs['physical_network']
- if 'network_type' in kwargs:
- params['network']['provider:network_type'] = kwargs['network_type']
- if 'segmentation_id' in kwargs:
- params['network']['provider:segmentation_id'] = kwargs['segmentation_id']
-
- ntconn = self._get_neutron_connection()
- try:
- logger.debug("Calling neutron create_network() with params: %s", str(params))
- net = ntconn.create_network(params)
- except Exception as e:
- logger.error("OpenstackDriver: Create Network operation failed. Exception: %s" %(str(e)))
- raise
- logger.debug("Got create_network response from neutron connection: %s", str(net))
- network_id = net['network']['id']
- if not network_id:
- raise Exception("Empty network id returned from create_network. (params: %s)" % str(params))
-
- return network_id
-
- def network_delete(self, network_id):
- """
- Deletes a network identified by network_id
-
- Arguments:
- network_id (string): UUID of the network
-
- Returns: None
- """
- assert network_id == self._network_get(network_id)['id']
- ntconn = self._get_neutron_connection()
- try:
- ntconn.delete_network(network_id)
- except Exception as e:
- logger.error("OpenstackDriver: Delete Network operation failed. Exception: %s" %(str(e)))
- raise
-
- def _network_get(self, network_id):
- """
- Returns a dictionary object describing the attributes of the network
-
- Arguments:
- network_id (string): UUID of the network
-
- Returns:
- A dictionary object of the network attributes
- """
- ntconn = self._get_neutron_connection()
- network = ntconn.list_networks(id = network_id)['networks']
- if not network:
- raise NeutronException.NotFound("Network with id %s not found"%(network_id))
-
- return network[0]
-
- def network_get(self, network_id):
- """
- Returns a dictionary object describing the attributes of the network
-
- Arguments:
- network_id (string): UUID of the network
-
- Returns:
- A dictionary object of the network attributes
- """
- return self._network_get(network_id)
-
- def subnet_create(self, **kwargs):
- """
- Creates a subnet on the network
-
+ Constructor of DriverUtilities class
Arguments:
- A dictionary with following key value pairs
- {
- network_id(string) : UUID of the network where subnet needs to be created
- subnet_cidr(string) : IPv4 address prefix (e.g. '1.1.1.0/24') for the subnet
- ip_version (integer): 4 for IPv4 and 6 for IPv6
-
- }
-
- Returns:
- subnet_id (string): UUID of the created subnet
+ driver: Object of OpenstackDriver
"""
- params = {}
- params['network_id'] = kwargs['network_id']
- params['ip_version'] = kwargs['ip_version']
-
- # if params['ip_version'] == 6:
- # assert 0, "IPv6 is not supported"
+ self.flavor_utils = drv_utils.FlavorUtils(driver)
+ self.network_utils = drv_utils.NetworkUtils(driver)
+ self.image_utils = drv_utils.ImageUtils(driver)
+ self.compute_utils = drv_utils.ComputeUtils(driver)
- if 'subnetpool_id' in kwargs:
- params['subnetpool_id'] = kwargs['subnetpool_id']
- else:
- params['cidr'] = kwargs['cidr']
-
- if 'gateway_ip' in kwargs:
- params['gateway_ip'] = kwargs['gateway_ip']
- else:
- params['gateway_ip'] = None
-
- if 'dhcp_params' in kwargs:
- params['enable_dhcp'] = kwargs['dhcp_params']['enable_dhcp']
- if 'start_address' in kwargs['dhcp_params'] and 'count' in kwargs['dhcp_params']:
- end_address = (ipaddress.IPv4Address(kwargs['dhcp_params']['start_address']) + kwargs['dhcp_params']['count']).compressed
- params['allocation_pools'] = [ {'start': kwargs['dhcp_params']['start_address'] ,
- 'end' : end_address} ]
-
- if 'dns_server' in kwargs:
- params['dns_nameservers'] = []
- for server in kwargs['dns_server']:
- params['dns_nameservers'].append(server)
-
- ntconn = self._get_neutron_connection()
- try:
- subnet = ntconn.create_subnet({'subnets': [params]})
- except Exception as e:
- logger.error("OpenstackDriver: Create Subnet operation failed. Exception: %s" %(str(e)))
- raise
-
- return subnet['subnets'][0]['id']
-
- def subnet_list(self):
- """
- Returns a list of dictionaries. Each dictionary contains attributes describing the subnet
-
- Arguments: None
+ @property
+ def flavor(self):
+ return self.flavor_utils
- Returns:
- A dictionary of the objects of subnet attributes
- """
- ntconn = self._get_neutron_connection()
- try:
- subnets = ntconn.list_subnets()['subnets']
- except Exception as e:
- logger.error("OpenstackDriver: List Subnet operation failed. Exception: %s" %(str(e)))
- raise
- return subnets
+ @property
+ def compute(self):
+ return self.compute_utils
+
+ @property
+ def network(self):
+ return self.network_utils
+
+ @property
+ def image(self):
+ return self.image_utils
- def _subnet_get(self, subnet_id):
+
+class OpenstackDriver(object):
+ """
+ Driver for openstack nova, neutron, glance, keystone, swift, cinder services
+ """
+ def __init__(self, logger = None, **kwargs):
"""
- Returns a dictionary object describing the attributes of a subnet.
-
+ OpenstackDriver Driver constructor
Arguments:
- subnet_id (string): UUID of the subnet
-
- Returns:
- A dictionary object of the subnet attributes
- """
- ntconn = self._get_neutron_connection()
- subnets = ntconn.list_subnets(id=subnet_id)
- if not subnets['subnets']:
- logger.error("OpenstackDriver: Get subnet operation failed for subnet_id: %s" %(subnet_id))
- #raise NeutronException.NotFound("Could not find subnet_id %s" %(subnet_id))
- return {'cidr': ''}
+ logger: (instance of logging.Logger)
+ kwargs: A dictionary of
+ {
+ username (string) : Username for project/tenant.
+ password (string) : Password
+ auth_url (string) : Keystone Authentication URL.
+ project (string) : Openstack project name
+ mgmt_network(string, optional) : Management network name. Each VM created with this cloud-account will
+ have a default interface into management network.
+ cert_validate (boolean, optional) : In case of SSL/TLS connection if certificate validation is required or not.
+ user_domain : Domain name for user
+ project_domain : Domain name for project
+ region : Region name
+ }
+ """
+
+ if logger is None:
+ self.log = logging.getLogger('rwcal.openstack.driver')
+ self.log.setLevel(logging.DEBUG)
else:
- return subnets['subnets'][0]
-
- def subnet_get(self, subnet_id):
- """
- Returns a dictionary object describing the attributes of a subnet.
-
- Arguments:
- subnet_id (string): UUID of the subnet
-
- Returns:
- A dictionary object of the subnet attributes
- """
- return self._subnet_get(subnet_id)
-
- def subnet_delete(self, subnet_id):
- """
- Deletes a subnet identified by subnet_id
-
- Arguments:
- subnet_id (string): UUID of the subnet to be deleted
-
- Returns: None
- """
- ntconn = self._get_neutron_connection()
- assert subnet_id == self._subnet_get(self,subnet_id)
- try:
- ntconn.delete_subnet(subnet_id)
- except Exception as e:
- logger.error("OpenstackDriver: Delete Subnet operation failed for subnet_id : %s. Exception: %s" %(subnet_id, str(e)))
- raise
-
- def port_list(self, **kwargs):
- """
- Returns a list of dictionaries. Each dictionary contains attributes describing the port
-
- Arguments:
- kwargs (dictionary): A dictionary for filters for port_list operation
-
- Returns:
- A dictionary of the objects of port attributes
-
- """
- ports = []
- ntconn = self._get_neutron_connection()
-
- kwargs['tenant_id'] = self.ks_drv.get_tenant_id()
-
- try:
- ports = ntconn.list_ports(**kwargs)
- except Exception as e:
- logger.info("OpenstackDriver: List Port operation failed. Exception: %s" %(str(e)))
- raise
- return ports['ports']
-
- def port_create(self, **kwargs):
- """
- Create a port in network
-
- Arguments:
- A dictionary of following
- {
- name (string) : Name of the port
- network_id(string) : UUID of the network_id identifying the network to which port belongs
- subnet_id(string) : UUID of the subnet_id from which IP-address will be assigned to port
- vnic_type(string) : Possible values are "normal", "direct", "macvtap"
- }
- Returns:
- port_id (string) : UUID of the port
- """
- params = {
- "port": {
- "admin_state_up" : kwargs['admin_state_up'],
- "name" : kwargs['name'],
- "network_id" : kwargs['network_id'],
- "fixed_ips" : [ {"subnet_id": kwargs['subnet_id']}],
- "binding:vnic_type" : kwargs['port_type'],
- "port_security_enabled" : kwargs['port_security_enabled']}}
-
- ntconn = self._get_neutron_connection()
- try:
- port = ntconn.create_port(params)
- except Exception as e:
- logger.error("OpenstackDriver: Port Create operation failed. Exception: %s" %(str(e)))
- raise
- return port['port']['id']
-
- def _port_get(self, port_id):
- """
- Returns a dictionary object describing the attributes of the port
-
- Arguments:
- port_id (string): UUID of the port
-
- Returns:
- A dictionary object of the port attributes
- """
- ntconn = self._get_neutron_connection()
- port = ntconn.list_ports(id=port_id)['ports']
- if not port:
- raise NeutronException.NotFound("Could not find port_id %s" %(port_id))
- return port[0]
-
- def port_get(self, port_id):
- """
- Returns a dictionary object describing the attributes of the port
-
- Arguments:
- port_id (string): UUID of the port
-
- Returns:
- A dictionary object of the port attributes
- """
- return self._port_get(port_id)
+ self.log = logger
+
+ args = dict(auth_url = kwargs['auth_url'],
+ username = kwargs['username'],
+ password = kwargs['password'],
+ project_name = kwargs['project'],
+ project_domain_name = kwargs['project_domain'] if 'project_domain' in kwargs else None,
+ user_domain_name = kwargs['user_domain'] if 'user_domain' in kwargs else None,)
+
+ cert_validate = kwargs['cert_validate'] if 'cert_validate' in kwargs else False
+ region = kwargs['region_name'] if 'region_name' in kwargs else False
+ mgmt_network = kwargs['mgmt_network'] if 'mgmt_network' in kwargs else None
+
+ discover = ks_drv.KeystoneVersionDiscover(kwargs['auth_url'],
+ cert_validate,
+ logger = self.log)
+ (major, minor) = discover.get_version()
+
+ self.sess_drv = sess_drv.SessionDriver(auth_method = 'password',
+ version = str(major),
+ cert_validate = cert_validate,
+ logger = self.log,
+ **args)
+
+ self.ks_drv = ks_drv.KeystoneDriver(str(major),
+ self.sess_drv,
+ logger = self.log)
+
+ self.nova_drv = nv_drv.NovaDriver(self.sess_drv,
+ region_name = region,
+ logger = self.log)
+
+ self.neutron_drv = nt_drv.NeutronDriver(self.sess_drv,
+ region_name = region,
+ logger = self.log)
+
+ self.glance_drv = gl_drv.GlanceDriver(self.sess_drv,
+ region_name = region,
+ logger = self.log)
+
+ try:
+ self.cinder_drv = ci_drv.CinderDriver(self.sess_drv,
+ region_name = region,
+ logger = self.log)
+ except Exception:
+ self.cinder_drv = None
+
+ self.ceilo_drv = ce_drv.CeilometerDriver(self.sess_drv,
+ region_name = region,
+ logger = self.log)
+
+ self.utils = DriverUtilities(self)
+
+ self._mgmt_network = mgmt_network
+
+ self._cache = dict(neutron = dict(),
+ nova = dict(),
+ cinder = dict(),
+ glance = dict())
+ self.build_resource_cache()
- def port_delete(self, port_id):
- """
- Deletes a port identified by port_id
+ @property
+ def nova_cache(self):
+ return self._cache['nova']
- Arguments:
- port_id (string) : UUID of the port
+ @property
+ def neutron_cache(self):
+ return self._cache['neutron']
+
+ @property
+ def glance_cache(self):
+ return self._cache['glance']
- Returns: None
- """
- assert port_id == self._port_get(port_id)['id']
- ntconn = self._get_neutron_connection()
+ @property
+ def cinder_cache(self):
+ return self._cache['cinder']
+
+ def build_resource_cache(self):
try:
- ntconn.delete_port(port_id)
- except Exception as e:
- logger.error("Port Delete operation failed for port_id : %s. Exception: %s" %(port_id, str(e)))
+ self.build_network_resource_cache()
+ except KeyError:
raise
+ self.build_nova_resource_cache()
+ self.build_cinder_resource_cache()
+ self.build_glance_resource_cache()
- def security_group_list(self):
- """
- Returns a list of dictionaries. Each dictionary contains attributes describing the security group
-
- Arguments:
- None
-
- Returns:
- A dictionary of the objects of security group attributes
- """
- ntconn = self._get_neutron_connection()
+ def _cache_populate(self, method, datatype, *args, **kwargs):
try:
- group_list = ntconn.list_security_groups(tenant_id=self.ks_drv.get_tenant_id())
+ rsp = method(*args, **kwargs)
except Exception as e:
- logger.error("List Security group operation, Exception: %s" %(str(e)))
- raise
-
- if 'security_groups' in group_list:
- return group_list['security_groups']
+ self.log.exception("Exception %s occured during execution of %s",
+ str(e), method)
+ return datatype
else:
- return []
-
- def subnetpool_list(self, **kwargs):
- """
- Returns a list of dictionaries. Each dictionary contains attributes describing a subnet prefix pool
-
- Arguments:
- None
-
- Returns:
- A dictionary of the objects of subnet prefix pool
- """
- ntconn = self._get_neutron_connection()
+ return rsp
+
+ def _build_nova_security_group_list(self):
+ self.log.info("Building Nova security group cache")
+ self.nova_cache['security_groups'] = self._cache_populate(self.nova_drv.security_group_list,
+ list())
+ return self.nova_cache['security_groups']
+
+ def _build_nova_affinity_group_list(self):
+ self.log.info("Building Nova affinity/anti-affinity group cache")
+ self.nova_cache['affinity_groups'] = self._cache_populate(self.nova_server_group_list,
+ list())
+ return self.nova_cache['affinity_groups']
+
+ def _build_neutron_security_group_list(self):
+ self.log.info("Discovering neutron security group")
+ self.neutron_cache['security_groups'] = self._cache_populate(self.neutron_security_group_list,
+ list())
+ return self.neutron_cache['security_groups']
+
+ def _build_neutron_subnet_prefix_list(self):
+ self.log.info("Discovering subnet prefix pools")
+ self.neutron_cache['subnet_pool'] = self._cache_populate(self.neutron_subnetpool_list,
+ list())
+ return self.neutron_cache['subnet_pool']
+
+ def _get_neutron_mgmt_network(self):
+ if self._mgmt_network:
+ self.log.info("Discovering management network %s", self._mgmt_network)
+ network_list = self._cache_populate(self.neutron_drv.network_get,
+ None,
+ **{'network_name': self._mgmt_network})
+ if network_list:
+ self.neutron_cache['mgmt_net'] = network_list['id']
+ else:
+ msg = "Could not find management network %s" % self._mgmt_network
+ self.log.error(msg)
+ raise KeyError(msg)
+
+
+ def _build_glance_image_list(self):
+ self.log.info("Discovering images")
+ self.glance_cache['images'] = self._cache_populate(self.glance_image_list,
+ list())
+
+ return self.glance_cache['images']
+
+ def _build_cinder_volume_list(self):
+ self.log.info("Discovering volumes")
+ self.cinder_cache['volumes'] = self._cache_populate(self.cinder_volume_list,
+ list())
+ return self.cinder_cache['volumes']
+
+ def build_nova_resource_cache(self):
+ self.log.info("Building nova resource cache")
+ self._build_nova_security_group_list()
+ self._build_nova_affinity_group_list()
+
+
+ def build_network_resource_cache(self):
+ self.log.info("Building network resource cache")
try:
- pool_list = ntconn.list_subnetpools(**kwargs)
- except Exception as e:
- logger.error("List SubnetPool operation, Exception: %s" %(str(e)))
+ self._get_neutron_mgmt_network()
+ except KeyError:
raise
+ self._build_neutron_security_group_list()
+ self._build_neutron_subnet_prefix_list()
- if 'subnetpools' in pool_list:
- return pool_list['subnetpools']
- else:
- return []
-
-class NeutronDriverV2(NeutronDriver):
- """
- Driver for openstack neutron neutron-client v2
- """
- def __init__(self, ks_drv):
- """
- Constructor for NeutronDriver
- Arguments: KeystoneDriver class object
- """
- super(NeutronDriverV2, self).__init__(ks_drv, 'network', '2.0')
-
-
+ def build_cinder_resource_cache(self):
+ self.log.info("Building cinder resource cache")
+ if self.cinder_drv is not None:
+ self._build_cinder_volume_list()
-class CeilometerDriver(object):
- """
- Driver for openstack ceilometer client
- """
-
- def __init__(self, ks_drv, service_name, version):
- """
- Constructor for CeilometerDriver
- Arguments: KeystoneDriver class object
- """
- self.ks_drv = ks_drv
- self._service_name = service_name
- self._version = version
- self._client = None
+ def build_glance_resource_cache(self):
+ self.log.info("Building glance resource cache")
+ self._build_glance_image_list()
+
@property
- def version(self):
- """The version of the ceilometer client used by the driver"""
- return self._version
+ def _nova_affinity_group(self):
+ if 'affinity_groups' in self.nova_cache:
+ return self.nova_cache['affinity_groups']
+ else:
+ return self._build_nova_affinity_group_list()
@property
- def client(self):
- """The instance of ceilometer client used by the driver"""
- if self._client is None or not self.ks_drv.is_auth_token_valid():
- self._client = ceilo_client.Client(**self.credentials)
-
- return self._client
-
+ def _nova_security_groups(self):
+ if 'security_groups' in self.nova_cache:
+ return self.nova_cache['security_groups']
+ else:
+ return self._build_nova_security_group_list()
+
@property
- def auth_token(self):
- """The authorization token for the ceilometer client"""
- try:
- return self.ks_drv.get_auth_token()
- except KeystoneExceptions.EndpointNotFound as e:
- logger.error("OpenstackDriver: unable to get authorization token for ceilometer. Exception: %s" %(str(e)))
- raise
-
+ def mgmt_network(self):
+ return self._mgmt_network
+
@property
- def security_mode(self):
- """The security mode for the ceilometer client"""
- try:
- return self.ks_drv.get_security_mode()
- except KeystoneExceptions.EndpointNotFound as e:
- logger.error("OpenstackDriver: unable to get security mode for ceilometer. Exception: %s" %(str(e)))
- raise
+ def _mgmt_network_id(self):
+ if 'mgmt_net' in self.neutron_cache:
+ return self.neutron_cache['mgmt_net']
+ else:
+ return list()
@property
- def endpoint(self):
- """The service endpoint for the ceilometer client"""
- try:
- return self.ks_drv.get_service_endpoint(self._service_name, "publicURL")
- except KeystoneExceptions.EndpointNotFound as e:
- logger.error("OpenstackDriver: unable to get endpoint for ceilometer. Exception: %s" %(str(e)))
- raise
+ def _neutron_security_groups(self):
+ if 'security_groups' in self.neutron_cache:
+ return self.neutron_cache['security_groups']
+ else:
+ return self._build_neutron_security_group_list()
@property
- def credentials(self):
- """A dictionary of credentials for the ceilometer client"""
- return dict(
- version=self.version,
- endpoint=self.endpoint,
- token=self.auth_token,
- insecure=self.security_mode,
- )
-
+ def _neutron_subnet_prefix_pool(self):
+ if 'subnet_pool' in self.neutron_cache:
+ return self.neutron_cache['subnet_pool']
+ else:
+ return self._build_neutron_subnet_prefix_list()
+
@property
- def meters(self):
- """A list of the available meters"""
- try:
- return self.client.meters.list()
- except Exception as e:
- logger.error("OpenstackDriver: List meters operation failed. Exception: %s" %(str(e)))
- raise
-
+ def _glance_image_list(self):
+ if 'images' in self.glance_cache:
+ return self.glance_cache['images']
+ else:
+ return self._build_glance_image_list()
+
@property
- def alarms(self):
- """The ceilometer client alarms manager"""
- return self.client.alarms
-
- def query_samples(self, vim_instance_id, counter_name, limit=1):
- """Returns a list of samples
-
- Arguments:
- vim_instance_id - the ID of the VIM that the samples are from
- counter_name - the counter that the samples will come from
- limit - a limit on the number of samples to return
- (default: 1)
-
- Returns:
- A list of samples
-
- """
- try:
- filter = json.dumps({
- "and": [
- {"=": {"resource": vim_instance_id}},
- {"=": {"counter_name": counter_name}}
- ]
- })
- result = self.client.query_samples.query(filter=filter, limit=limit)
- return result[-limit:]
-
- except Exception as e:
- logger.exception(e)
-
- return []
-
-
-class CeilometerDriverV2(CeilometerDriver):
- """
- Driver for openstack ceilometer ceilometer-client
- """
- def __init__(self, ks_drv):
- """
- Constructor for CeilometerDriver
- Arguments: CeilometerDriver class object
- """
- super(CeilometerDriverV2, self).__init__(ks_drv, 'metering', '2')
-
-class OpenstackDriver(object):
- """
- Driver for openstack nova, neutron, glance, keystone, swift, cinder services
- """
- def __init__(self, username, password, auth_url, tenant_name, mgmt_network = None, cert_validate = False, user_domain_name = None, project_domain_name = None):
- """
- OpenstackDriver Driver constructor
- Arguments:
- username (string) : Username for project/tenant.
- password (string) : Password
- auth_url (string) : Keystone Authentication URL.
- tenant_name (string) : Openstack project name
- mgmt_network(string, optional) : Management network name. Each VM created with this cloud-account will
- have a default interface into management network.
- cert_validate (boolean, optional) : In case of SSL/TLS connection if certificate validation is required or not.
-
- """
- insecure = not cert_validate
- if auth_url.find('/v3') != -1:
- self.ks_drv = KeystoneDriverV3(username, password, auth_url, tenant_name, insecure, user_domain_name, project_domain_name)
- self.glance_drv = GlanceDriverV2(self.ks_drv)
- self.nova_drv = NovaDriverV21(self.ks_drv)
- self.neutron_drv = NeutronDriverV2(self.ks_drv)
- self.ceilo_drv = CeilometerDriverV2(self.ks_drv)
- self.cinder_drv = CinderDriverV2(self.ks_drv)
- elif auth_url.find('/v2') != -1:
- self.ks_drv = KeystoneDriverV2(username, password, auth_url, tenant_name, insecure)
- self.glance_drv = GlanceDriverV2(self.ks_drv)
- self.nova_drv = NovaDriverV2(self.ks_drv)
- self.neutron_drv = NeutronDriverV2(self.ks_drv)
- self.ceilo_drv = CeilometerDriverV2(self.ks_drv)
- self.cinder_drv = CinderDriverV2(self.ks_drv)
+ def _cinder_volume_list(self):
+ if 'volumes' in self.cinder_cache:
+ return self.cinder_cache['volumes']
else:
- logger.error("Could not identity the version information for openstack service endpoints. Auth_URL should contain \"/v2\" or \"/v3\" string in it")
- raise NotImplementedError("Auth URL is wrong or invalid. Only Keystone v2 & v3 supported")
-
- self._mgmt_network_id = None
- if mgmt_network != None:
- self._mgmt_network = mgmt_network
-
- networks = []
- try:
- ntconn = self.neutron_drv._get_neutron_connection()
- networks = ntconn.list_networks()
- except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure) as e:
- raise
- except Exception as e:
- logger.error("OpenstackDriver: List Network operation failed. Exception: %s" %(str(e)))
- raise
-
- network_list = [ network for network in networks['networks'] if network['name'] == mgmt_network ]
-
- if not network_list:
- raise NeutronException.NotFound("Could not find network %s" %(mgmt_network))
- self._mgmt_network_id = network_list[0]['id']
+ return self._build_cinder_volume_list()
def validate_account_creds(self):
try:
- ksconn = self.ks_drv._get_keystone_connection()
+ self.sess_drv.invalidate_auth_token()
+ self.sess_drv.auth_token
+ self.build_resource_cache()
+ except KeystoneExceptions.Unauthorized as e:
+ self.log.error("Invalid credentials ")
+ raise ValidationError("Invalid Credentials: "+ str(e))
except KeystoneExceptions.AuthorizationFailure as e:
- logger.error("OpenstackDriver: Unable to authenticate or validate the existing credentials. Exception: %s" %(str(e)))
+ self.log.error("Unable to authenticate or validate the existing credentials. Exception: %s", str(e))
raise ValidationError("Invalid Credentials: "+ str(e))
+ except NeutronException.NotFound as e:
+ self.log.error("Given management network could not be found for Openstack account ")
+ raise ValidationError("Neutron network not found "+ str(e))
except Exception as e:
- logger.error("OpenstackDriver: Could not connect to Openstack. Exception: %s" %(str(e)))
+ self.log.error("Could not connect to Openstack. Exception: %s", str(e))
raise ValidationError("Connection Error: "+ str(e))
- def get_mgmt_network_id(self):
- return self._mgmt_network_id
def glance_image_create(self, **kwargs):
- if not 'disk_format' in kwargs:
+ if 'disk_format' not in kwargs:
kwargs['disk_format'] = 'qcow2'
- if not 'container_format' in kwargs:
+ if 'container_format' not in kwargs:
kwargs['container_format'] = 'bare'
- if not 'min_disk' in kwargs:
+ if 'min_disk' not in kwargs:
kwargs['min_disk'] = 0
- if not 'min_ram' in kwargs:
+ if 'min_ram' not in kwargs:
kwargs['min_ram'] = 0
return self.glance_drv.image_create(**kwargs)
def glance_image_add_location(self, image_id, location):
self.glance_drv.image_add_location(image_id, location)
+ def glance_image_update(self, image_id, remove_props = None, **kwargs):
+ self.glance_drv.image_update(image_id, remove_props=remove_props, **kwargs)
+
def glance_image_delete(self, image_id):
self.glance_drv.image_delete(image_id)
def glance_image_get(self, image_id):
return self.glance_drv.image_get(image_id)
-
def nova_flavor_list(self):
return self.nova_drv.flavor_list()
- def nova_flavor_create(self, name, ram, vcpus, disk, epa_specs):
- extra_specs = epa_specs if epa_specs else {}
+ def nova_flavor_find(self, **kwargs):
+ return self.nova_drv.flavor_find(**kwargs)
+
+ def nova_flavor_create(self, name, ram, vcpus, disk, epa_specs = dict()):
return self.nova_drv.flavor_create(name,
ram = ram,
vcpu = vcpus,
disk = disk,
- extra_specs = extra_specs)
+ extra_specs = epa_specs)
def nova_flavor_delete(self, flavor_id):
self.nova_drv.flavor_delete(flavor_id)
return self.nova_drv.flavor_get(flavor_id)
def nova_server_create(self, **kwargs):
- def _verify_image(image_id):
- image = self.glance_drv.image_get(image_id)
- if image['status'] != 'active':
- raise GlanceException.NotFound("Image with image_id: %s not found in active state. Current State: %s" %(image['id'], image['status']))
-
- assert kwargs['flavor_id'] == self.nova_drv.flavor_get(kwargs['flavor_id'])['id']
-
- if kwargs['block_device_mapping_v2'] is not None:
- for block_map in kwargs['block_device_mapping_v2']:
- if 'uuid' in block_map:
- _verify_image(block_map['uuid'])
- else:
- _verify_image(kwargs['image_id'])
-
- # if 'network_list' in kwargs:
- # kwargs['network_list'].append(self._mgmt_network_id)
- # else:
- # kwargs['network_list'] = [self._mgmt_network_id]
-
if 'security_groups' not in kwargs:
- nvconn = self.nova_drv._get_nova_connection()
- sec_groups = nvconn.security_groups.list()
- if sec_groups:
- ## Should we add VM in all availability security_groups ???
- kwargs['security_groups'] = [x.name for x in sec_groups]
- else:
- kwargs['security_groups'] = None
-
+ security_groups = [s['name'] for s in self._nova_security_groups]
+ #Remove the security group names that are duplicate - RIFT-17035
+ valid_security_groups = list(filter(lambda s: security_groups.count(s) == 1, security_groups))
+ kwargs['security_groups'] = valid_security_groups
return self.nova_drv.server_create(**kwargs)
def nova_server_add_port(self, server_id, port_id):
def nova_volume_list(self, server_id):
return self.nova_drv.volume_list(server_id)
+ def neutron_extensions_list(self):
+ return self.neutron_drv.extensions_list()
+
def neutron_network_list(self):
return self.neutron_drv.network_list()
def neutron_network_get(self, network_id):
- return self.neutron_drv.network_get(network_id)
+ return self.neutron_drv.network_get(network_id=network_id)
+
+ def neutron_network_get_by_name(self, network_name):
+ return self.neutron_drv.network_get(network_name=network_name)
def neutron_network_create(self, **kwargs):
return self.neutron_drv.network_create(**kwargs)
self.neutron_drv.network_delete(network_id)
def neutron_subnet_list(self):
- return self.neutron_drv.subnet_list()
+ return self.neutron_drv.subnet_list(**{})
def neutron_subnet_get(self, subnet_id):
return self.neutron_drv.subnet_get(subnet_id)
return pool_list[0]
else:
return None
-
+
def neutron_port_list(self, **kwargs):
return self.neutron_drv.port_list(**kwargs)
return self.neutron_drv.port_get(port_id)
def neutron_port_create(self, **kwargs):
- subnets = [subnet for subnet in self.neutron_drv.subnet_list() if subnet['network_id'] == kwargs['network_id']]
- assert len(subnets) == 1
- kwargs['subnet_id'] = subnets[0]['id']
- if not 'admin_state_up' in kwargs:
- kwargs['admin_state_up'] = True
- port_id = self.neutron_drv.port_create(**kwargs)
-
+ port_id = self.neutron_drv.port_create([kwargs])[0]
if 'vm_id' in kwargs:
self.nova_server_add_port(kwargs['vm_id'], port_id)
return port_id
+ def neutron_multi_port_create(self, ports):
+ return self.neutron_drv.port_create(ports)
+
def neutron_security_group_list(self):
- return self.neutron_drv.security_group_list()
+ return self.neutron_drv.security_group_list(**{})
def neutron_security_group_by_name(self, group_name):
- group_list = self.neutron_drv.security_group_list()
- groups = [group for group in group_list if group['name'] == group_name]
- if groups:
- return groups[0]
+ group_list = self.neutron_drv.security_group_list(**{'name': group_name})
+ if group_list:
+ return group_list[0]
else:
return None
A dict of NFVI metrics
"""
- def query_latest_sample(counter_name):
- try:
- filter = json.dumps({
- "and": [
- {"=": {"resource": vim_id}},
- {"=": {"counter_name": counter_name}}
- ]
- })
- orderby = json.dumps([{"timestamp": "DESC"}])
- result = self.ceilo_drv.client.query_samples.query(
- filter=filter,
- orderby=orderby,
- limit=1,
- )
- return result[0]
-
- except IndexError:
- pass
-
- except Exception as e:
- logger.error("Got exception while querying ceilometer, exception details:%s " %str(e))
-
- return None
-
- memory_usage = query_latest_sample("memory.usage")
- disk_usage = query_latest_sample("disk.usage")
- cpu_util = query_latest_sample("cpu_util")
-
- metrics = dict()
-
- if memory_usage is not None:
- memory_usage.volume = 1e6 * memory_usage.volume
- metrics["memory_usage"] = memory_usage.to_dict()
-
- if disk_usage is not None:
- metrics["disk_usage"] = disk_usage.to_dict()
-
- if cpu_util is not None:
- metrics["cpu_util"] = cpu_util.to_dict()
-
- return metrics
+ return self.ceilo_drv.nfvi_metrics(vim_id)
def ceilo_alarm_list(self):
"""Returns a list of ceilometer alarms"""
alarm_actions = actions.get('alarm') if actions is not None else None
insufficient_data_actions = actions.get('insufficient_data') if actions is not None else None
- return self.ceilo_drv.client.alarms.create(
- name=name,
- meter_name=meter,
- statistic=statistic,
- comparison_operator=operation,
- threshold=threshold,
- period=period,
- evaluation_periods=evaluations,
- severity=severity,
- repeat_actions=repeat,
- enabled=enabled,
- ok_actions=ok_actions,
- alarm_actions=alarm_actions,
- insufficient_data_actions=insufficient_data_actions,
- **kwargs
- )
+ return self.ceilo_drv.client.alarms.create(name=name,
+ meter_name=meter,
+ statistic=statistic,
+ comparison_operator=operation,
+ threshold=threshold,
+ period=period,
+ evaluation_periods=evaluations,
+ severity=severity,
+ repeat_actions=repeat,
+ enabled=enabled,
+ ok_actions=ok_actions,
+ alarm_actions=alarm_actions,
+ insufficient_data_actions=insufficient_data_actions,
+ **kwargs)
def ceilo_alarm_update(self, alarm_id, **kwargs):
"""Updates an existing alarm
def cinder_volume_list(self):
return self.cinder_drv.volume_list()
- def cinder_volume_get(self,vol_id):
+ def cinder_volume_get(self, vol_id):
return self.cinder_drv.volume_get(vol_id)
def cinder_volume_set_metadata(self, volumeid, metadata):
-class CinderDriver(object):
- """
- Driver for openstack cinder-client
- """
- def __init__(self, ks_drv, service_name, version):
- """
- Constructor for CinderDriver
- Arguments: KeystoneDriver class object
- """
- self.ks_drv = ks_drv
- self._service_name = service_name
- self._version = version
-
- def _get_cinder_credentials(self):
- """
- Returns a dictionary of kwargs required to instantiate python-cinderclient class
-
- Arguments: None
-
- Returns:
- A dictionary object of arguments
- """
- creds = {}
- creds['version'] = self._version
- creds['username'] = self.ks_drv.get_username()
- creds['api_key'] = self.ks_drv.get_password()
- creds['auth_url'] = self.ks_drv.get_service_endpoint("identity", "publicURL")
- creds['project_id'] = self.ks_drv.get_tenant_name()
- creds['insecure'] = self.ks_drv.get_security_mode()
-
- return creds
-
- def _get_cinder_connection(self):
- """
- Returns a object of class python-cinderclient
- """
- if not hasattr(self, '_cinder_connection'):
- self._cinder_connection = cinder_client.Client(**self._get_cinder_credentials())
- else:
- # Reinitialize if auth_token is no longer valid
- if not self.ks_drv.is_auth_token_valid():
- self._cinder_connection = cinder_client.Client(**self._get_cinder_credentials())
- return self._cinder_connection
-
- def volume_list(self):
- """
- Returns list of dictionaries. Each dictionary contains attributes associated with
- volumes
-
- Arguments: None
-
- Returns: List of dictionaries.
- """
- cinderconn = self._get_cinder_connection()
- volumes = []
- try:
- volume_info = cinderconn.volumes.list()
- except Exception as e:
- logger.error("OpenstackDriver: List volumes operation failed. Exception: %s" %(str(e)))
- raise
- volumes = [ volume for volume in volume_info ]
- return volumes
-
- def volume_get(self, volume_id):
- """
- Get details volume
-
- Arguments: None
-
- Returns: List of dictionaries.
- """
- cinderconn = self._get_cinder_connection()
- try:
- vol = cinderconn.volumes.get(volume_id)
- except Exception as e:
- logger.error("OpenstackDriver: Get volume operation failed. Exception: %s" %(str(e)))
- raise
- return vol
-
- def volume_set_metadata(self, volume_id, metadata):
- """
- Set metadata for volume
- Metadata is a dictionary of key-value pairs
-
- Arguments: None
-
- Returns: List of dictionaries.
- """
- cinderconn = self._get_cinder_connection()
- try:
- cinderconn.volumes.set_metadata(volume_id, metadata)
- except Exception as e:
- logger.error("OpenstackDriver: Set metadata operation failed. Exception: %s" %(str(e)))
- raise
-
- def volume_delete_metadata(self, volume_id, metadata):
- """
- Delete metadata for volume
- Metadata is a dictionary of key-value pairs
-
- Arguments: None
-
- Returns: List of dictionaries.
- """
- cinderconn = self._get_cinder_connection()
- try:
- cinderconn.volumes.delete_metadata(volume_id, metadata)
- except Exception as e:
- logger.error("OpenstackDriver: Delete metadata operation failed. Exception: %s" %(str(e)))
- raise
-
-class CinderDriverV2(CinderDriver):
- """
- Driver for openstack cinder-client V2
- """
- def __init__(self, ks_drv):
- super(CinderDriverV2, self).__init__(ks_drv, 'volumev2', 2)
-