CAL refactoring
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rift / rwcal / openstack / nova / nova_drv.py
diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/nova/nova_drv.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/nova/nova_drv.py
new file mode 100644 (file)
index 0000000..4dc8c65
--- /dev/null
@@ -0,0 +1,717 @@
+#!/usr/bin/python
+
+# 
+#   Copyright 2017 RIFT.IO Inc
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+import logging
+from novaclient import client as nvclient
+
+
+class NovaDrvAPIVersionException(Exception):
+    def __init__(self, errors):
+        self.errors = errors
+        super(NovaDrvAPIVersionException, self).__init__("Multiple Exception Received")
+        
+    def __str__(self):
+        return self.__repr__()
+        
+    def __repr__(self):
+        msg = "{} : Following Exception(s) have occured during Nova API discovery".format(self.__class__)
+        for n,e in enumerate(self.errors):
+            msg += "\n"
+            msg += " {}:  {}".format(n, str(e))
+        return msg
+
+
+class NovaDriver(object):
+    """
+    NovaDriver Class for compute orchestration
+    """
+    ### List of supported API versions in prioritized order 
+    supported_versions = ["2.1", "2.0"]
+    
+    def __init__(self,
+                 sess_handle,
+                 region_name    = 'RegionOne',
+                 service_type   = 'compute',
+                 logger = None):
+        """
+        Constructor for NovaDriver class
+        Arguments:
+        sess_handle (instance of class SessionDriver)
+        region_name (string): Region Name
+        service_type(string): Type of service in service catalog
+        logger (instance of logging.Logger)
+        """
+
+        if logger is None:
+            self.log = logging.getLogger('rwcal.openstack.nova')
+            self.log.setLevel(logging.DEBUG)
+        else:
+            self.log = logger
+        
+        self._sess_handle = sess_handle
+
+        #### Attempt to use API versions in prioritized order defined in
+        #### NovaDriver.supported_versions
+        def select_version(version):
+            try:
+                self.log.info("Attempting to use Nova v%s APIs", version)
+                nvdrv = nvclient.Client(version=version,
+                                        region_name = region_name,
+                                        service_type = service_type,
+                                        session = self._sess_handle.session,
+                                        logger = self.log)
+            except Exception as e:
+                self.log.info(str(e))
+                raise
+            else:
+                self.log.info("Nova API v%s selected", version)
+                return (version, nvdrv)
+
+        errors = []
+        for v in NovaDriver.supported_versions:
+            try:
+                (self._version, self._nv_drv) = select_version(v)
+            except Exception as e:
+                errors.append(e)
+            else:
+                break
+        else:
+            raise NovaDrvAPIVersionException(errors)
+
+    @property
+    def project_id(self):
+        return self._sess_handle.project_id
+
+    @property
+    def nova_endpoint(self):
+        return self._nv_drv.client.get_endpoint()
+
+    @property
+    def nova_quota(self):
+        """
+        Returns Nova Quota (a dictionary) for project
+        """
+        try:
+            quota = self._nv_drv.quotas.get(self.project_id)
+        except Exception as e:
+            self.log.exception("Get Nova quota operation failed. Exception: %s", str(e))
+            raise
+        return quota.to_dict()
+    
+    def extensions_list(self):
+        """
+        Returns a list of available nova extensions.
+        Arguments:
+           None
+        Returns:
+           A list of dictionaries. Each dictionary contains attributes for a single NOVA extension
+        """
+        try:
+            extensions = self._nv_drv.list_extensions.show_all()
+        except Exception as e:
+            self.log.exception("List extension operation failed. Exception: %s", str(e))
+            raise
+        return [ ext.to_dict() for ext in extensions ]
+            
+    
+    def _get_nova_connection(self):
+        """
+        Returns instance of object novaclient.client.Client
+        Use for DEBUG ONLY
+        """
+        return self._nv_drv
+
+    def _flavor_extra_spec_get(self, flavor):
+        """
+        Get extra_specs associated with a flavor
+        Arguments:
+           flavor: Object of novaclient.v2.flavors.Flavor
+
+        Returns:
+           A dictionary of extra_specs (key-value pairs)
+        """
+        try:
+            extra_specs = flavor.get_keys()
+        except Exception as e:
+            self.log.exception("Could not get the EPA attributes for flavor with flavor_id : %s. Exception: %s",
+                               flavor.id, str(e))
+            raise
+        return extra_specs
+    
+    def _flavor_get(self, flavor_id):
+        """
+        Get flavor by flavor_id
+        Arguments:
+           flavor_id(string): UUID of flavor_id
+
+        Returns:
+        dictionary of flavor parameters
+        """
+        try:
+            flavor = self._nv_drv.flavors.get(flavor_id)
+        except Exception as e:
+            self.log.exception("Did not find flavor with flavor_id : %s. Exception: %s",flavor_id, str(e))
+            raise
+        response = flavor.to_dict()
+        response['extra_specs'] = self._flavor_extra_spec_get(flavor)
+        return response
+        
+        try:
+            extra_specs = flavor.get_keys()
+        except Exception as e:
+            self.log.exception("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_find(self, **kwargs):
+        """
+        Returns list of all flavors (dictionary) matching the filters provided in kwargs 
+
+        Arguments:
+          A dictionary in following keys
+             {
+                "vcpus": Number of vcpus required
+                "ram"  : Memory in MB
+                "disk" : Secondary storage in GB
+             }
+        Returns:
+           A list of dictionaries. Each dictionary contains attributes for a single flavor instance
+        """
+        try:
+            flavor_list = self._nv_drv.flavors.findall(**kwargs)
+        except Exception as e:
+            self.log.exception("Find Flavor operation failed. Exception: %s",str(e))
+            raise
+        
+        flavor_info = list()
+        for f in flavor_list:
+            flavor = f.to_dict()
+            flavor['extra_specs'] = self._flavor_extra_spec_get(f)
+            flavor_info.append(flavor)
+            
+        return flavor_info
+    
+    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 = []
+        
+        try:
+            flavors = self._nv_drv.flavors.list()
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            flavor = self._nv_drv.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:
+            self.log.exception("Create Flavor operation failed. Exception: %s",str(e))
+            raise
+
+        if extra_specs:
+            try:
+                flavor.set_keys(extra_specs)
+            except Exception as e:
+                self.log.exception("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']
+        try:
+            self._nv_drv.flavors.delete(flavor_id)
+        except Exception as e:
+            self.log.exception("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 = []
+        try:
+            servers     = self._nv_drv.servers.list()
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            server = self._nv_drv.servers.get(server = server_id)
+        except Exception as e:
+            self.log.exception("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})
+
+        try:
+            server = self._nv_drv.servers.create(
+                kwargs['name'],
+                kwargs['image_id'],
+                kwargs['flavor_id'],
+                meta                 = kwargs['metadata'] if 'metadata' in kwargs else None,
+                files                = kwargs['files'] if 'files' in kwargs else None,
+                reservation_id       = None,
+                min_count            = None,
+                max_count            = None,
+                userdata             = kwargs['userdata'] if 'userdata' in kwargs else None,
+                security_groups      = kwargs['security_groups'] if 'security_groups' in kwargs else None,
+                availability_zone    = kwargs['availability_zone'] if 'availability_zone' in kwargs else None,
+                block_device_mapping_v2 = kwargs['block_device_mapping_v2'] if 'block_device_mapping_v2' in kwargs else None,
+                nics                 = nics,
+                scheduler_hints      = kwargs['scheduler_hints'] if 'scheduler_hints' in kwargs else None,
+                config_drive         = kwargs['config_drive'] if 'config_drive' in kwargs else None
+            )
+            
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.delete(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.start(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.stop(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.pause(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.unpause(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.suspend(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.resume(server_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.reboot(server_id, reboot_type)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            console_info = self._nv_drv.servers.get_vnc_console(server_id, console_type)
+        except Exception as e:
+            self.log.exception("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
+        """
+
+        try:
+            self._nv_drv.servers.rebuild(server_id, image_id)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.interface_attach(server_id,
+                                            port_id,
+                                            net_id = None,
+                                            fixed_ip = None)
+        except Exception as e:
+            self.log.exception("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
+
+        """
+        try:
+            self._nv_drv.servers.interface_detach(server_id, port_id)
+        except Exception as e:
+            self.log.exception("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)
+        """
+        try:
+            ip_list = self._nv_drv.floating_ips.list()
+        except Exception as e:
+            self.log.exception("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)
+        """
+        try:
+            floating_ip = self._nv_drv.floating_ips.create(pool)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            floating_ip = self._nv_drv.floating_ips.delete(floating_ip)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.add_floating_ip(server_id, floating_ip, fixed_ip)
+        except Exception as e:
+            self.log.exception("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
+        """
+        try:
+            self._nv_drv.servers.remove_floating_ip(server_id, floating_ip)
+        except Exception as e:
+            self.log.exception("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)
+        """
+        try:
+            volumes = self._nv_drv.volumes.get_server_volumes(server_id=server_id)
+        except Exception as e:
+            self.log.exception("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)
+        """
+        try:
+            group_list = self._nv_drv.server_groups.list()
+        except Exception as e:
+            self.log.exception("Server Group List operation failed. Exception: %s", str(e))
+            raise
+
+        group_info = [ group.to_dict() for group in group_list ]
+        return group_info
+
+        
+    def security_group_list(self):
+        """
+        List of Security Group
+        Arguments:
+        None
+        Returns:
+        List of dictionary objects representating novaclient.v2.security_groups.SecurityGroup class
+        """
+        try:
+            sec_groups = self._nv_drv.security_groups.list()
+        except Exception as e:
+            self.log.exception("Security Group List operation failed. Exception: %s", str(e))
+            raise
+        sec_info = [ sec_group.to_dict() for sec_group in sec_groups]
+        return sec_info
+