X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwcal%2Fplugins%2Fvala%2Frwcal_openstack%2Frift%2Frwcal%2Fopenstack%2Fopenstack_drv.py;h=500f10cb7fbdf7a2f595a7e3ffbd945da7d8ca53;hb=894c4682150a22e7b560622af0ad0a7b3ddd84cb;hp=191a06f42011d308814ded0e2c449ca5b0075969;hpb=01b0e3fb29fd78e6c5f4ecc11149b9b7ea560add;p=osm%2FSO.git diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py index 191a06f4..500f10cb 100644 --- a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py +++ b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py @@ -16,1764 +16,300 @@ # 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 portchain as port_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, region): - """ - Constructor for KeystoneDriverV3 class - Arguments: - username (string) : Username - password (string) : Password - auth_url (string) : Authentication URL - tenant_name(string): Tenant Name - region (string) : Region name - Returns: None - """ - self._username = username - self._password = password - self._auth_url = auth_url - self._tenant_name = tenant_name - self._insecure = insecure - self._region = region - 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() - creds['region_name'] = self._region - 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, - region = None): - """ - Constructor for KeystoneDriverV3 class - Arguments: - username (string) : Username - password (string) : Password - auth_url (string) : Authentication URL - tenant_name(string): Tenant Name - user_domain_name (string) : User domain name - project_domain_name (string): Project domain name - region (string) : Region 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 - self._region = region - 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 - creds['region_name'] = self._region - 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 - - 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 - - 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 - """ - 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': ''} - 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']}} - if 'port_security_enabled' in kwargs: - params["port"]["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) - - def port_delete(self, port_id): - """ - Deletes a port identified by port_id - - Arguments: - port_id (string) : UUID of the port + @property + def flavor(self): + return self.flavor_utils - Returns: None - """ - assert port_id == self._port_get(port_id)['id'] - ntconn = self._get_neutron_connection() - 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))) - raise + @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 security_group_list(self): + +class OpenstackDriver(object): + """ + Driver for openstack nova, neutron, glance, keystone, swift, cinder services + """ + def __init__(self, logger = None, **kwargs): """ - Returns a list of dictionaries. Each dictionary contains attributes describing the security group - + OpenstackDriver Driver constructor Arguments: - None - - Returns: - A dictionary of the objects of security group attributes - """ - ntconn = self._get_neutron_connection() - try: - group_list = ntconn.list_security_groups(tenant_id=self.ks_drv.get_tenant_id()) - 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'] + 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 [] - - def subnetpool_list(self, **kwargs): - """ - Returns a list of dictionaries. Each dictionary contains attributes describing a subnet prefix pool + 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'], 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) + + self.cinder_drv = ci_drv.CinderDriver(self.sess_drv, + region_name = region, + logger = self.log) + + self.ceilo_drv = ce_drv.CeilometerDriver(self.sess_drv, + region_name = region, + logger = self.log) + + self.portchain_drv = port_drv.L2PortChainDriver(self.sess_drv, + self.neutron_drv, + 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() - Arguments: - None + @property + def nova_cache(self): + return self._cache['nova'] - Returns: - A dictionary of the objects of subnet prefix pool - """ - ntconn = self._get_neutron_connection() - try: - pool_list = ntconn.list_subnetpools(**kwargs) - except Exception as e: - logger.error("List SubnetPool operation, Exception: %s" %(str(e))) - raise + @property + def neutron_cache(self): + return self._cache['neutron'] + + @property + def glance_cache(self): + return self._cache['glance'] - if 'subnetpools' in pool_list: - return pool_list['subnetpools'] + @property + def cinder_cache(self): + return self._cache['cinder'] + + def build_resource_cache(self): + self.build_network_resource_cache() + self.build_nova_resource_cache() + self.build_cinder_resource_cache() + self.build_glance_resource_cache() + + def _cache_populate(self, method, datatype, *args, **kwargs): + try: + rsp = method(*args, **kwargs) + except Exception as e: + self.log.exception("Exception %s occured during execution of %s", + str(e), method) + return datatype else: - return [] + return rsp -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_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: + raise KeyError("Error") + + 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_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") + self._get_neutron_mgmt_network() + self._build_neutron_security_group_list() + self._build_neutron_subnet_prefix_list() -class CeilometerDriver(object): - """ - Driver for openstack ceilometer client - """ + def build_cinder_resource_cache(self): + pass - 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 - @property - def version(self): - """The version of the ceilometer client used by the driver""" - return self._version + def build_glance_resource_cache(self): + self.log.info("Building glance resource cache") + self._build_glance_image_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_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 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 _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 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(self): + return self._mgmt_network + @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 _mgmt_network_id(self): + if 'mgmt_net' in self.neutron_cache: + return self.neutron_cache['mgmt_net'] + else: + return 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_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 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 _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 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, - region = 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. - user_domain_name : Domain name for user - project_domain_name : Domain name for project - region : Region name - """ - 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, - region) - 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, - region) - 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 _glance_image_list(self): + if 'images' in self.glance_cache: + return self.glance_cache['images'] 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_glance_image_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.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 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: kwargs['disk_format'] = 'qcow2' @@ -1791,6 +327,9 @@ class OpenstackDriver(object): 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) @@ -1800,17 +339,18 @@ class OpenstackDriver(object): 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) @@ -1819,34 +359,8 @@ class OpenstackDriver(object): 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 - + kwargs['security_groups'] = [ s['name'] for s in self._nova_security_groups ] return self.nova_drv.server_create(**kwargs) def nova_server_add_port(self, server_id, port_id): @@ -1904,7 +418,7 @@ class OpenstackDriver(object): 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_create(self, **kwargs): return self.neutron_drv.network_create(**kwargs) @@ -1913,7 +427,7 @@ class OpenstackDriver(object): 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) @@ -1933,7 +447,7 @@ class OpenstackDriver(object): return pool_list[0] else: return None - + def neutron_port_list(self, **kwargs): return self.neutron_drv.port_list(**kwargs) @@ -1941,25 +455,21 @@ class OpenstackDriver(object): 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 @@ -1982,47 +492,7 @@ class OpenstackDriver(object): 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""" @@ -2077,22 +547,20 @@ class OpenstackDriver(object): 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 @@ -2107,6 +575,83 @@ class OpenstackDriver(object): def ceilo_alarm_delete(self, alarm_id): self.ceilo_drv.client.alarms.delete(alarm_id) + def create_port_chain(self,name,port_lists): + "Create port chain" + #Create port pair + ppgrp_list = list() + for index,port_pair in enumerate(port_lists): + ppair_list = list() + ingress_port,egress_port = port_pair + #Disable security group and port security for the port + self.neutron_drv.port_update(ingress_port,no_security_groups=True,port_security_enabled=False) + if ingress_port != egress_port: + self.neutron_drv.port_update(egress_port,no_security_groups=True,port_security_enabled=False) + + ppair_id = self.portchain_drv.create_port_pair(name+'ppair'+str(index),ingress_port,egress_port) + ppair_list.append(ppair_id) + # Create port pair group + ppgrp_id = self.portchain_drv.create_port_pair_group(name+'_ppgrp_'+str(index),ppair_list) + ppgrp_list.append(ppgrp_id) + #Create port chain + port_chain_id = self.portchain_drv.create_port_chain(name,ppgrp_list) + return port_chain_id + + def delete_port_chain(self,port_chain_id): + "Delete port chain" + try: + result = self.portchain_drv.get_port_chain(port_chain_id) + port_chain = result.json() + self.log.debug("Port chain result is %s", port_chain) + port_pair_groups = port_chain["port_chain"]["port_pair_groups"] + self.portchain_drv.delete_port_chain(port_chain_id) + + # Get port pairs and delete port pair groups + port_pairs = list() + self.log.debug("Port pair groups during delete is %s", port_pair_groups) + for port_pair_group_id in port_pair_groups: + result = self.portchain_drv.get_port_pair_group(port_pair_group_id) + port_pair_group = result.json() + self.log.debug("Port pair group result is %s", port_pair_group) + port_pairs.extend(port_pair_group["port_pair_group"]["port_pairs"]) + self.portchain_drv.delete_port_pair_group(port_pair_group_id) + + self.log.debug("Port pairs during delete is %s",port_pairs) + + for port_pair_id in port_pairs: + self.portchain_drv.delete_port_pair(port_pair_id) + pass + except Exception as e: + self.log.error("Error while delete port chain with id %s, exception %s", port_chain_id,str(e)) + + def update_port_chain(self,port_chain_id,flow_classifier_list): + result = self.portchain_drv.get_port_chain(port_chain_id) + result.raise_for_status() + port_chain = result.json()['port_chain'] + new_flow_classifier_list = list() + if port_chain and port_chain['flow_classifiers']: + new_flow_classifier_list.extend(port_chain['flow_classifiers']) + new_flow_classifier_list.extend(flow_classifier_list) + port_chain_id = self.portchain_drv.update_port_chain(port_chain['id'],flow_classifiers=new_flow_classifier_list) + return port_chain_id + + def create_flow_classifer(self,classifier_name,classifier_dict): + "Create flow classifier" + flow_classifier_id = self.portchain_drv.create_flow_classifier(classifier_name,classifier_dict) + return flow_classifier_id + + def delete_flow_classifier(self,classifier_id): + "Create flow classifier" + try: + self.portchain_drv.delete_flow_classifier(classifier_id) + except Exception as e: + self.log.error("Error while deleting flow classifier with id %s, exception %s", classifier_id,str(e)) + + def get_port_chain_list(self): + result = self.portchain_drv.get_port_chain_list() + port_chain_list = result.json() + if 'port_chains' in port_chain_list: + return port_chain_list['port_chains'] + def cinder_volume_list(self): return self.cinder_drv.volume_list() @@ -2121,121 +666,3 @@ class OpenstackDriver(object): -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) -