RIFT OSM R1 Initial Submission
[osm/SO.git] / rwcal / plugins / vala / rwcal_cloudsimproxy / rwcal_cloudsimproxy.py
diff --git a/rwcal/plugins/vala/rwcal_cloudsimproxy/rwcal_cloudsimproxy.py b/rwcal/plugins/vala/rwcal_cloudsimproxy/rwcal_cloudsimproxy.py
new file mode 100644 (file)
index 0000000..addb4d3
--- /dev/null
@@ -0,0 +1,709 @@
+
+# 
+#   Copyright 2016 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
+import os
+import shutil
+import tempfile
+
+import requests
+
+from gi import require_version
+require_version('RwCal', '1.0')
+
+from gi.repository import (
+    GObject,
+    RwCal,
+    RwTypes,
+    RwcalYang,
+    )
+
+import rw_status
+import rift.cal.rwcal_status as rwcal_status
+import rwlogger
+
+logger = logging.getLogger('rwcal.cloudsimproxy')
+
+
+rwstatus_exception_map = { IndexError: RwTypes.RwStatus.NOTFOUND,
+                           KeyError: RwTypes.RwStatus.NOTFOUND,
+                           NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED,}
+
+rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
+rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
+
+
+class CloudsimProxyError(Exception):
+    pass
+
+
+class CloudSimProxyPlugin(GObject.Object, RwCal.Cloud):
+    DEFAULT_PROXY_HOST = "localhost"
+    DEFAULT_PROXY_PORT = 9002
+
+    def __init__(self):
+        self._session = None
+        self._host = None
+        self._port = CloudSimProxyPlugin.DEFAULT_PROXY_PORT
+
+    @property
+    def session(self):
+        if self._session is None:
+            self._session = requests.Session()
+
+        return self._session
+
+    @property
+    def host(self):
+        return self._host
+
+    @host.setter
+    def host(self, host):
+        if self._host is not None:
+            if host != self._host:
+                raise CloudsimProxyError("Cloudsim host changed during execution")
+
+        self._host = host
+
+    def _set_host_from_account(self, account):
+        self.host = account.cloudsim_proxy.host
+
+    def _proxy_rpc_call(self, api, **kwargs):
+        url = "http://{host}:{port}/api/{api}".format(
+                host=self._host,
+                port=self._port,
+                api=api,
+                )
+
+        post_dict = {}
+        for key, val in kwargs.items():
+            post_dict[key] = val
+
+        logger.debug("Sending post to url %s with json data: %s", url, post_dict)
+        r = self.session.post(url, json=post_dict)
+        r.raise_for_status()
+
+        response_dict = r.json()
+        logger.debug("Got json response: %s", response_dict)
+
+        return_vals = []
+        for return_val in response_dict["return_vals"]:
+            value = return_val["value"]
+            proto_type = return_val["proto_type"]
+            if proto_type is not None:
+                gi_cls = getattr(RwcalYang, proto_type)
+                logger.debug("Deserializing into %s", proto_type)
+                gi_obj = gi_cls.from_dict(value)
+                value = gi_obj
+
+            return_vals.append(value)
+
+        logger.debug("Returning RPC return values: %s", return_vals)
+
+        if len(return_vals) == 0:
+            return None
+
+        elif len(return_vals) == 1:
+            return return_vals[0]
+
+        else:
+            return tuple(return_vals[1:])
+
+    @rwstatus
+    def do_init(self, rwlog_ctx):
+        logger.addHandler(
+            rwlogger.RwLogger(
+                category="rw-cal-log",
+                subcategory="cloudsimproxy",
+                log_hdl=rwlog_ctx,
+            )
+        )
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_management_network(self, account):
+        """Returns the management network
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            a NetworkInfo object
+
+        """
+
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_management_network")
+
+    @rwstatus
+    def do_create_tenant(self, account, name):
+        """
+        Create a new tenant.
+
+        @param name     - name to assign to the tenant.
+        """
+        raise NotImplementedError()
+
+    @rwstatus
+    def do_delete_tenant(self, account, tenant_id):
+        """
+        delete a tenant.
+
+        @param tenant_id     - id of tenant to be deleted.
+        """
+        raise NotImplementedError()
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_tenant_list(self, account):
+        """
+        List tenants.
+
+        """
+        raise NotImplementedError()
+
+    @rwstatus
+    def do_create_role(self, account, name):
+        """
+        Create a new role.
+
+        @param name         - name to assign to the role.
+        """
+        raise NotImplementedError()
+
+    @rwstatus
+    def do_delete_role(self, account, role_id):
+        """
+        delete a role.
+
+        @param role_id     - id of role to be deleted.
+        """
+        raise NotImplementedError()
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_role_list(self, account):
+        """
+        List roles.
+
+        """
+        raise NotImplementedError()
+
+    @rwstatus(ret_on_failure=[None])
+    def do_create_image(self, account, image):
+        """Create a new image
+
+        Creates a new container based upon the template and tarfile specified.
+        Only one image is currently supported for a given instance of the CAL.
+
+        Arguments:
+            account - a cloud account
+            image   - an ImageInfo object
+
+        Raises:
+            An RWErrorDuplicate is raised if create_image is called and there
+            is already an image.
+
+        Returns:
+            The UUID of the new image
+
+        """
+        self._set_host_from_account(account)
+
+        if image.has_field("fileno"):
+            logger.debug("Got fileno for cloudsim image create")
+            new_fileno = os.dup(image.fileno)
+            read_hdl = os.fdopen(new_fileno, 'rb')
+            write_hdl = tempfile.NamedTemporaryFile()
+            image.location = write_hdl.name
+            logger.debug("Created temporary file to store the cloudsim image: %s", image.location)
+            shutil.copyfileobj(read_hdl, write_hdl)
+
+            image_dict = image.as_dict()
+            del image_dict["fileno"]
+        else:
+            image_dict = image.as_dict()
+
+        return self._proxy_rpc_call("create_image", image=image_dict)
+
+    @rwstatus
+    def do_delete_image(self, account, image_id):
+        """Deletes an image
+
+        This function will remove the record of the image from the CAL and
+        destroy the associated container.
+
+        Arguments:
+            account  - a cloud account
+            image_id - the UUID of the image to delete
+
+        Raises:
+            An RWErrorNotEmpty exception is raised if there are VMs based on
+            this image (the VMs need to be deleted first). An RWErrorNotFound
+            is raised if the image_id does not match any of the known images.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_image")
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_image(self, account, image_id):
+        """Returns the specified image
+
+        Arguments:
+            account  - a cloud account
+            image_id - the UUID of the image to retrieve
+
+        Raises:
+            An RWErrorNotFound exception is raised if the image_id does not
+            match any of the known images.
+
+        Returns:
+            An image object
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_image", image_id=image_id)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_image_list(self, account):
+        """Returns a list of images"""
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_image_list")
+
+    @rwstatus
+    def do_create_vm(self, account, vm):
+        """Create a VM
+
+        Arguments:
+            vm - the VM info used to define the desire VM
+
+        Raises:
+            An RWErrorFailure is raised if there is not
+
+        Returns:
+            a string containing the unique id of the created VM
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_vm", vm=vm.as_dict())
+
+    @rwstatus
+    def do_start_vm(self, account, vm_id):
+        """Starts the specified VM
+
+        Arguments:
+            vm_id - the id of the vm to start
+
+        Raises:
+            An RWErrorNotFound is raised if the specified vm id is not known to
+            this driver.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("start_vm", vm_id=vm_id)
+
+    @rwstatus
+    def do_stop_vm(self, account, vm_id):
+        """Stops the specified VM
+
+        Arguments:
+            vm_id - the id of the vm to stop
+
+        Raises:
+            An RWErrorNotFound is raised if the specified vm id is not known to
+            this driver.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("stop_vm", vm_id=vm_id)
+
+    @rwstatus
+    def do_delete_vm(self, account, vm_id):
+        """Deletes the specified VM
+
+        Arguments:
+            vm_id - the id of the vm to delete
+
+        Raises:
+            An RWErrorNotFound is raised if the specified vm id is not known to
+            this driver.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_vm", vm_id=vm_id)
+
+    @rwstatus
+    def do_reboot_vm(self, account, vm_id):
+        """
+        reboot a virtual machine.
+
+        @param vm_id     - Instance id of VM to be deleted.
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("reboot_vm", vm_id=vm_id)
+
+    @rwstatus
+    def do_get_vm(self, account, vm_id):
+        """Returns the specified VM
+
+        Arguments:
+            vm_id - the id of the vm to return
+
+        Raises:
+            An RWErrorNotFound is raised if the specified vm id is not known to
+            this driver.
+
+        Returns:
+            a VMInfoItem object
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_vm", vm_id=vm_id)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_vm_list(self, account):
+        """Returns the a list of the VMs known to the driver
+
+        Returns:
+            a list of VMInfoItem objects
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_vm_list")
+
+    @rwstatus
+    def do_create_flavor(self, account, flavor):
+        """
+        create new flavor.
+
+        @param flavor   - Flavor object
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_flavor", flavor=flavor.as_dict())
+
+    @rwstatus
+    def do_delete_flavor(self, account, flavor_id):
+        """
+        Delete flavor.
+
+        @param flavor_id     - Flavor id to be deleted.
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_flavor", flavor_id=flavor_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_flavor(self, account, flavor_id):
+        """
+        Return the specified flavor
+
+        @param flavor_id - the id of the flavor to return
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_flavor", flavor_id=flavor_id)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_flavor_list(self, account):
+        """
+        Return a list of flavors
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_flavor_list")
+
+    @rwstatus
+    def do_add_host(self, account, host):
+        raise NotImplementedError()
+
+    @rwstatus
+    def do_remove_host(self, account, host_id):
+        raise NotImplementedError()
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_host(self, account, host_id):
+        raise NotImplementedError()
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_host_list(self, account):
+        raise NotImplementedError()
+
+    @rwstatus
+    def do_create_port(self, account, port):
+        """Create a port between a network and a virtual machine
+
+        Arguments:
+            account - a cloud account
+            port    - a description of port to create
+
+        Raises:
+            Raises an RWErrorNotFound exception if either the network or the VM
+            associated with the port cannot be found.
+
+        Returns:
+            the ID of the newly created port.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_port", port=port.as_dict())
+
+    @rwstatus
+    def do_delete_port(self, account, port_id):
+        """Delete the specified port
+
+        Arguments:
+            account - a cloud account
+            port_id - the ID of the port to delete
+
+        Raises:
+            A RWErrorNotFound exception is raised if the specified port cannot
+            be found.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_port", port_id=port_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_port(self, account, port_id):
+        """Return the specified port
+
+        Arguments:
+            account - a cloud account
+            port_id - the ID of the port to return
+
+        Raises:
+            A RWErrorNotFound exception is raised if the specified port cannot
+            be found.
+
+        Returns:
+            The specified port.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_port", port_id=port_id)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_port_list(self, account):
+        """Returns a list of ports"""
+
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_port_list")
+
+    @rwstatus
+    def do_create_network(self, account, network):
+        """Create a network
+
+        Arguments:
+            account - a cloud account
+            network - a description of the network to create
+
+        Returns:
+            The ID of the newly created network
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_network", network=network.as_dict())
+
+    @rwstatus
+    def do_delete_network(self, account, network_id):
+        """
+        Arguments:
+            account    - a cloud account
+            network_id - the UUID of the network to delete
+
+        Raises:
+            An RWErrorNotFound is raised if the specified network cannot be
+            found.
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_network", network_id=network_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_network(self, account, network_id):
+        """Returns the specified network
+
+        Arguments:
+            account    - a cloud account
+            network_id - the UUID of the network to delete
+
+        Raises:
+            An RWErrorNotFound is raised if the specified network cannot be
+            found.
+
+        Returns:
+            The specified network
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_network", network_id=network_id)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_network_list(self, account):
+        """Returns a list of network objects"""
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_network_list")
+
+    @rwstatus(ret_on_failure=[None])
+    def do_validate_cloud_creds(self, account):
+        """
+        Validates the cloud account credentials for the specified account.
+        If creds are not valid, returns an error code & reason string
+        Arguments:
+            account - a cloud account to validate
+
+        Returns:
+            Validation Code and Details String
+        """
+        self._set_host_from_account(account)
+
+        status = RwcalYang.CloudConnectionStatus()
+        try:
+            self._proxy_rpc_call("get_vm_list")
+        except Exception as e:
+            status.status = "failure"
+            status.details = "connection to cloudsim server failed: %s" % str(e)
+        else:
+            status.status = "success"
+            status.details = "Connection was successful"
+
+        return status
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_virtual_link(self, account, link_params):
+        """Create a new virtual link
+
+        Arguments:
+            account     - a cloud account
+            link_params - information that defines the type of VDU to create
+
+        Returns:
+            The vdu_id
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_virtual_link", link_params=link_params.as_dict())
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_virtual_link(self, account, link_id):
+        """Get information about virtual link.
+
+        Arguments:
+            account  - a cloud account
+            link_id  - id for the virtual-link
+
+        Returns:
+            Object of type RwcalYang.VirtualLinkInfoParams
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_virtual_link", link_id=link_id)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_virtual_link_list(self, account):
+        """Returns the a list of the Virtual links
+
+        Returns:
+            a list of RwcalYang.VirtualLinkInfoParams objects
+
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_virtual_link_list")
+
+    @rwstatus(ret_on_failure=[None])
+    def do_delete_virtual_link(self, account, link_id):
+        """Delete the virtual link
+
+        Arguments:
+            account  - a cloud account
+            link_id  - id for the virtual-link
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_virtual_link", link_id=link_id)
+
+    @rwcalstatus(ret_on_failure=[""])
+    def do_create_virtual_link(self, account, link_params):
+        """Create a new virtual link
+
+        Arguments:
+            account     - a cloud account
+            link_params - information that defines the type of VDU to create
+
+        Returns:
+            The vdu_id
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_virtual_link", link_params=link_params.as_dict())
+
+    @rwcalstatus(ret_on_failure=[""])
+    def do_create_vdu(self, account, vdu_init):
+        """Create a new virtual deployment unit
+
+        Arguments:
+            account     - a cloud account
+            vdu_init  - information about VDU to create (RwcalYang.VDUInitParams)
+
+        Returns:
+            The vdu_id
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("create_vdu", vdu_params=vdu_init.as_dict())
+
+    @rwstatus
+    def do_modify_vdu(self, account, vdu_modify):
+        """Modify Properties of existing virtual deployment unit
+
+        Arguments:
+            account     -  a cloud account
+            vdu_modify  -  Information about VDU Modification (RwcalYang.VDUModifyParams)
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("modify_vdu", vdu_params=vdu_modify.as_dict())
+
+    @rwstatus
+    def do_delete_vdu(self, account, vdu_id):
+        """Delete a virtual deployment unit
+
+        Arguments:
+            account - a cloud account
+            vdu_id  - id for the vdu to be deleted
+
+        Returns:
+            None
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("delete_vdu", vdu_id=vdu_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_vdu(self, account, vdu_id):
+        """Get information about a virtual deployment unit.
+
+        Arguments:
+            account - a cloud account
+            vdu_id  - id for the vdu
+
+        Returns:
+            Object of type RwcalYang.VDUInfoParams
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_vdu", vdu_id=vdu_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_vdu_list(self, account):
+        """Get information about all the virtual deployment units
+
+        Arguments:
+            account     - a cloud account
+
+        Returns:
+            A list of objects of type RwcalYang.VDUInfoParams
+        """
+        self._set_host_from_account(account)
+        return self._proxy_rpc_call("get_vdu_list")