libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject [3/7] libcloud git commit: Add Onapp IaaS platform support
Date Sat, 01 Aug 2015 10:16:13 GMT
Add Onapp IaaS platform support

Implement missing support for Virtual Server in OnApp node driver,
as described in the OnApp API documentation:
https://docs.onapp.com/display/34API/Virtual+Servers

Closes #502

Signed-off-by: Tomaz Muraus <tomaz@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/592c934c
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/592c934c
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/592c934c

Branch: refs/heads/trunk
Commit: 592c934cd02c5b464fdcd286982732c931796137
Parents: b6d0c57
Author: Matthias Wiesner <mw@cloudcontrol.de>
Authored: Tue Mar 3 16:55:43 2015 +0100
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Sat Aug 1 11:37:37 2015 +0200

----------------------------------------------------------------------
 CHANGES.rst                                     |   4 +
 docs/_static/images/provider_logos/onapp.png    | Bin 0 -> 6134 bytes
 docs/compute/drivers/onapp.rst                  |  51 +++
 docs/examples/compute/onapp/functionality.py    |  61 +++
 libcloud/common/onapp.py                        |  48 +++
 libcloud/compute/drivers/__init__.py            |   1 +
 libcloud/compute/drivers/onapp.py               | 405 +++++++++++++++++++
 libcloud/compute/providers.py                   |   2 +
 libcloud/compute/types.py                       |   1 +
 .../compute/fixtures/onapp/create_node.json     |  87 ++++
 .../test/compute/fixtures/onapp/list_nodes.json |  89 ++++
 libcloud/test/compute/test_onapp.py             | 111 +++++
 libcloud/test/secrets.py-dist                   |   1 +
 13 files changed, 861 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 67aaf1a..d6f887c 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -235,6 +235,10 @@ Compute
   returned by the OpenStack driver.
   (LIBCLOUD-730, GITHUB-557)
 
+- Add new driver for Onapp IaaS platform.
+  (LIBCLOUD-691, GITHUB-502)
+  [Matthias Wiesner]
+
 Storage
 ~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/docs/_static/images/provider_logos/onapp.png
----------------------------------------------------------------------
diff --git a/docs/_static/images/provider_logos/onapp.png b/docs/_static/images/provider_logos/onapp.png
new file mode 100644
index 0000000..048f7cf
Binary files /dev/null and b/docs/_static/images/provider_logos/onapp.png differ

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/docs/compute/drivers/onapp.rst
----------------------------------------------------------------------
diff --git a/docs/compute/drivers/onapp.rst b/docs/compute/drivers/onapp.rst
new file mode 100644
index 0000000..1f8a2d9
--- /dev/null
+++ b/docs/compute/drivers/onapp.rst
@@ -0,0 +1,51 @@
+OnApp Compute Driver Documentation
+===========================================
+
+`OnApp`_ software enables Infrastructure-as-a-Service for hosts, telcos and
+other service providers. It's a turnkey platform for selling cloud, VPS,
+dedicated servers, CDN and more through a "single pane of glass" control panel,
+and now supports Xen, KVM, VMware and Amazon EC2.
+
+.. figure:: /_static/images/provider_logos/onapp.png
+    :align: center
+    :width: 382
+    :target: http://onapp.com/
+
+`OnApp`_ has its own non-standard `API`_ , `libcloud` provides a Python
+wrapper on top of this `API`_ with common methods with other IaaS solutions and
+Public cloud providers. Therefore, you can use the `OnApp` libcloud
+driver to communicate with OnApp public clouds.
+
+Instantiating a driver
+----------------------
+
+When you instantiate a driver you need to pass the following arguments to the
+driver constructor:
+
+* ``key`` - Your OnApp username
+* ``secret`` - Your OnApp password
+* ``host`` - The host of your OnApp endpoint
+* ``path`` - The path to your OnApp endpoint
+  (e.g ``/client/api`` for ``http://onapp.test/client/api``)
+* ``url`` - The url to your OnApp endpoint, mutually exclusive with
+  ``host`` and ``path``
+* ``secure`` - True or False. True by default
+
+To authenticate using API key, put your account email as ``key`` and the API key
+to the server as ``secret``.
+
+Example
+--------
+
+.. literalinclude:: /examples/compute/onapp/functionality.py
+   :language: python
+
+API Docs
+--------
+
+.. autoclass:: libcloud.compute.drivers.onapp.OnAppNodeDriver
+    :members:
+    :inherited-members:
+
+.. _`OnApp`: http://onapp.com/
+.. _`API`: https://docs.onapp.com/display/31API/OnApp+3.1+API+Guide

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/docs/examples/compute/onapp/functionality.py
----------------------------------------------------------------------
diff --git a/docs/examples/compute/onapp/functionality.py b/docs/examples/compute/onapp/functionality.py
new file mode 100644
index 0000000..eb28fae
--- /dev/null
+++ b/docs/examples/compute/onapp/functionality.py
@@ -0,0 +1,61 @@
+from libcloud.compute.types import Provider
+from libcloud.compute.providers import get_driver
+
+#
+# Instantiate driver
+#
+username = 'your account username'
+password = 'your account password'
+host = 'onapp.test'
+
+cls = get_driver(Provider.ONAPP)
+driver = cls(
+    key=username,
+    secret=password,
+    host=host
+)
+
+#
+# Create node
+#
+name = 'virtual_servers_name'  # user-friendly VS description
+memory = 2 * 1024  # amount of RAM assigned to the VS in MB
+cpus = 2  # number of CPUs assigned to the VS
+cpu_shares = 100
+# For KVM hypervisor the CPU priority value is always 100. For XEN, set a
+# custom value. The default value for XEN is 1
+hostname = 'vshostname'  # set the host name for this VS
+template_id = 8  # the ID of a template from which a VS should be built
+primary_disk_size = 100  # set the disk space for this VS
+swap_disk_size = None  # set swap space
+
+# optional parameter, but recommended
+rate_limit = None
+# set max port speed. If none set, the system sets port speed to unlimited
+
+node = driver.create_node(
+    ex_label=name,
+    ex_memory=memory,
+    ex_cpus=cpus,
+    ex_cpu_shares=cpu_shares,
+    ex_hostname=hostname,
+    ex_template_id=template_id,
+    ex_primary_disk_size=primary_disk_size,
+    ex_swap_disk_size=swap_disk_size,
+    ex_rate_limit=rate_limit
+)
+
+#
+# List nodes
+#
+for node in driver.list_nodes():
+    print node
+
+#
+# Destroy node
+#
+identifier = 'nodesidentifier'
+
+node, = [n for n in driver.list_nodes() if n.id == identifier]
+
+driver.destroy_node(node)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/common/onapp.py
----------------------------------------------------------------------
diff --git a/libcloud/common/onapp.py b/libcloud/common/onapp.py
new file mode 100644
index 0000000..990ce53
--- /dev/null
+++ b/libcloud/common/onapp.py
@@ -0,0 +1,48 @@
+from base64 import b64encode
+
+from libcloud.utils.py3 import b
+from libcloud.utils.py3 import httplib
+from libcloud.common.base import ConnectionUserAndKey, JsonResponse
+
+
+class OnAppResponse(JsonResponse):
+    """
+    OnApp response class
+    """
+
+    def success(self):
+        """
+        Determine if our request was successful.
+
+        The meaning of this can be arbitrary; did we receive OK status? Did
+        the node get created? Were we authenticated?
+
+        :rtype: ``bool``
+        :return: ``True`` or ``False``
+        """
+        return self.status in [httplib.OK, httplib.CREATED, httplib.NO_CONTENT]
+
+
+class OnAppConnection(ConnectionUserAndKey):
+    """
+    OnApp connection class
+    """
+
+    responseCls = OnAppResponse
+
+    def add_default_headers(self, headers):
+        """
+        Add Basic Authentication header to all the requests.
+        It injects the "Authorization: Basic Base64String===" header
+        in each request
+        :type  headers: ``dict``
+        :param headers: Default input headers
+        :rtype:         ``dict``
+        :return:        Default input headers with the "Authorization"
+                        header
+        """
+        b64string = b("%s:%s" % (self.user_id, self.key))
+        encoded = b64encode(b64string).decode("utf-8")
+
+        headers["Authorization"] = "Basic " + encoded
+        return headers

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/compute/drivers/__init__.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/__init__.py b/libcloud/compute/drivers/__init__.py
index fd534e8..d7c26ed 100644
--- a/libcloud/compute/drivers/__init__.py
+++ b/libcloud/compute/drivers/__init__.py
@@ -40,4 +40,5 @@ __all__ = [
     'vcloud',
     'voxel',
     'vpsnet',
+    'onapp',
 ]

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/compute/drivers/onapp.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/onapp.py b/libcloud/compute/drivers/onapp.py
new file mode 100644
index 0000000..8fb164c
--- /dev/null
+++ b/libcloud/compute/drivers/onapp.py
@@ -0,0 +1,405 @@
+import json
+
+from libcloud.compute.base import Node, NodeDriver
+from libcloud.common.onapp import OnAppConnection
+from libcloud.utils.networking import is_private_subnet
+from libcloud.compute.providers import Provider
+
+
+__all__ = [
+    "OnAppNodeDriver"
+]
+
+"""
+Define the extra dictionary for specific resources
+"""
+RESOURCE_EXTRA_ATTRIBUTES_MAP = {
+    "node": {
+        "add_to_marketplace": {
+            "key_name": "add_to_marketplace",
+            "transform_func": bool
+        },
+        "admin_note": {
+            "key_name": "admin_note",
+            "transform_func": str
+        },
+        "allow_resize_without_reboot": {
+            "key_name": "allow_resize_without_reboot",
+            "transform_func": bool
+        },
+        "allowed_hot_migrate": {
+            "key_name": "allowed_hot_migrate",
+            "transform_func": bool
+        },
+        "allowed_swap": {
+            "key_name": "allowed_swap",
+            "transform_func": bool
+        },
+        "booted": {
+            "key_name": "booted",
+            "transform_func": bool
+        },
+        "built": {
+            "key_name": "built",
+            "transform_func": bool
+        },
+        "cpu_priority": {
+            "key_name": "cpu_priority",
+            "transform_func": int
+        },
+        "cpu_shares": {
+            "key_name": "cpu_shares",
+            "transform_func": int
+        },
+        "cpu_sockets": {
+            "key_name": "cpu_sockets",
+            "transform_func": int
+        },
+        "cpu_threads": {
+            "key_name": "cpu_threads",
+            "transform_func": int
+        },
+        "cpu_units": {
+            "key_name": "cpu_units",
+            "transform_func": int
+        },
+        "cpus": {
+            "key_name": "cpus",
+            "transform_func": int
+        },
+        "created_at": {
+            "key_name": "created_at",
+            "transform_func": str
+        },
+        "customer_network_id": {
+            "key_name": "customer_network_id",
+            "transform_func": str
+        },
+        "deleted_at": {
+            "key_name": "deleted_at",
+            "transform_func": str
+        },
+        "edge_server_type": {
+            "key_name": "edge_server_type",
+            "transform_func": str
+        },
+        "enable_autoscale": {
+            "key_name": "enable_autoscale",
+            "transform_func": bool
+        },
+        "enable_monitis": {
+            "key_name": "enable_monitis",
+            "transform_func": bool
+        },
+        "firewall_notrack": {
+            "key_name": "firewall_notrack",
+            "transform_func": bool
+        },
+        "hostname": {
+            "key_name": "hostname",
+            "transform_func": str
+        },
+        "hypervisor_id": {
+            "key_name": "hypervisor_id",
+            "transform_func": int
+        },
+        "id": {
+            "key_name": "id",
+            "transform_func": int
+        },
+        "initial_root_password": {
+            "key_name": "initial_root_password",
+            "transform_func": str
+        },
+        "initial_root_password_encrypted": {
+            "key_name": "initial_root_password_encrypted",
+            "transform_func": bool
+        },
+        "local_remote_access_ip_address": {
+            "key_name": "local_remote_access_ip_address",
+            "transform_func": str
+        },
+        "local_remote_access_port": {
+            "key_name": "local_remote_access_port",
+            "transform_func": int
+        },
+        "locked": {
+            "key_name": "locked",
+            "transform_func": bool
+        },
+        "memory": {
+            "key_name": "memory",
+            "transform_func": int
+        },
+        "min_disk_size": {
+            "key_name": "min_disk_size",
+            "transform_func": int
+        },
+        "monthly_bandwidth_used": {
+            "key_name": "monthly_bandwidth_used",
+            "transform_func": int
+        },
+        "note": {
+            "key_name": "note",
+            "transform_func": str
+        },
+        "operating_system": {
+            "key_name": "operating_system",
+            "transform_func": str
+        },
+        "operating_system_distro": {
+            "key_name": "operating_system_distro",
+            "transform_func": str
+        },
+        "preferred_hvs": {
+            "key_name": "preferred_hvs",
+            "transform_func": list
+        },
+        "price_per_hour": {
+            "key_name": "price_per_hour",
+            "transform_func": float
+        },
+        "price_per_hour_powered_off": {
+            "key_name": "price_per_hour_powered_off",
+            "transform_func": float
+        },
+        "recovery_mode": {
+            "key_name": "recovery_mode",
+            "transform_func": bool
+        },
+        "remote_access_password": {
+            "key_name": "remote_access_password",
+            "transform_func": str
+        },
+        "service_password": {
+            "key_name": "service_password",
+            "transform_func": str
+        },
+        "state": {
+            "key_name": "state",
+            "transform_func": str
+        },
+        "storage_server_type": {
+            "key_name": "storage_server_type",
+            "transform_func": str
+        },
+        "strict_virtual_machine_id": {
+            "key_name": "strict_virtual_machine_id",
+            "transform_func": str
+        },
+        "support_incremental_backups": {
+            "key_name": "support_incremental_backups",
+            "transform_func": bool
+        },
+        "suspended": {
+            "key_name": "suspended",
+            "transform_func": bool
+        },
+        "template_id": {
+            "key_name": "template_id",
+            "transform_func": int
+        },
+        "template_label": {
+            "key_name": "template_label",
+            "transform_func": str
+        },
+        "total_disk_size": {
+            "key_name": "total_disk_size",
+            "transform_func": int
+        },
+        "updated_at": {
+            "key_name": "updated_at",
+            "transform_func": str
+        },
+        "user_id": {
+            "key_name": "user_id",
+            "transform_func": int
+        },
+        "vip": {
+            "key_name": "vip",
+            "transform_func": bool
+        },
+        "xen_id": {
+            "key_name": "xen_id",
+            "transform_func": int
+        }
+    }
+}
+
+
+class OnAppNodeDriver(NodeDriver):
+    """
+    Base OnApp node driver.
+    """
+
+    connectionCls = OnAppConnection
+    type = Provider.ONAPP
+    name = 'OnApp'
+    website = 'http://onapp.com/'
+
+    def create_node(self, name, ex_memory, ex_cpus, ex_cpu_shares,
+                    ex_hostname, ex_template_id, ex_primary_disk_size,
+                    ex_swap_disk_size, ex_required_virtual_machine_build=1,
+                    ex_required_ip_address_assignment=1, **kwargs):
+        """
+        Add a VS
+
+        :param  kwargs: All keyword arguments to create a VS
+        :type   kwargs: ``dict``
+
+        :rtype: :class:`OnAppNode`
+        """
+        server_params = dict(
+            label=name,
+            memory=ex_memory,
+            cpus=ex_cpus,
+            cpu_shares=ex_cpu_shares,
+            hostname=ex_hostname,
+            template_id=ex_template_id,
+            primary_disk_size=ex_primary_disk_size,
+            swap_disk_size=ex_swap_disk_size,
+            required_virtual_machine_build=ex_required_virtual_machine_build,
+            required_ip_address_assignment=ex_required_ip_address_assignment,
+            rate_limit=kwargs.get("rate_limit")
+        )
+
+        server_params.update(OnAppNodeDriver._create_args_to_params(**kwargs))
+        data = json.dumps({"virtual_machine": server_params})
+
+        response = self.connection.request(
+            "/virtual_machines.json",
+            data=data,
+            headers={
+                "Content-type": "application/json"},
+            method="POST")
+
+        return self._to_node(response.object["virtual_machine"])
+
+    def destroy_node(self,
+                     node,
+                     ex_convert_last_backup=0,
+                     ex_destroy_all_backups=0):
+        """
+        Delete a VS
+
+        :param node: OnApp node
+        :type  node: :class: `OnAppNode`
+
+        :param convert_last_backup: set 1 to convert the last VS's backup to
+                                    template, otherwise set 0
+        :type  convert_last_backup: ``int``
+
+        :param destroy_all_backups: set 1 to destroy all existing backups of
+                                    this VS, otherwise set 0
+        :type  destroy_all_backups: ``int``
+        """
+        server_params = {
+            "convert_last_backup": ex_convert_last_backup,
+            "destroy_all_backups": ex_destroy_all_backups
+        }
+        action = "/virtual_machines/{identifier}.json".format(
+            identifier=node.id)
+
+        self.connection.request(action, params=server_params, method="DELETE")
+
+    def list_nodes(self):
+        """
+        List all VS
+
+        :rtype: ``list`` of :class:`OnAppNode`
+        """
+        response = self.connection.request("/virtual_machines.json")
+        nodes = []
+        for vm in response.object:
+            nodes.append(self._to_node(vm["virtual_machine"]))
+        return nodes
+
+    #
+    # Helper methods
+    #
+
+    def _to_node(self, data):
+        identifier = data["identifier"]
+        name = data["label"]
+        private_ips = []
+        public_ips = []
+        for ip in data["ip_addresses"]:
+            address = ip["ip_address"]['address']
+            if is_private_subnet(address):
+                private_ips.append(address)
+            else:
+                public_ips.append(address)
+
+        extra = OnAppNodeDriver._get_extra_dict(
+            data, RESOURCE_EXTRA_ATTRIBUTES_MAP["node"]
+        )
+        return Node(identifier,
+                    name,
+                    extra['state'],
+                    public_ips,
+                    private_ips,
+                    self,
+                    extra=extra)
+
+    @staticmethod
+    def _get_extra_dict(response, mapping):
+        """
+        Extract attributes from the element based on rules provided in the
+        mapping dictionary.
+
+        :param   response: The JSON response to parse the values from.
+        :type    response: ``dict``
+
+        :param   mapping: Dictionary with the extra layout
+        :type    mapping: ``dict``
+
+        :rtype:  ``dict``
+        """
+        extra = {}
+        for attribute, values in mapping.items():
+            transform_func = values["transform_func"]
+            value = response.get(values["key_name"])
+
+            extra[attribute] = transform_func(value) if value else None
+        return extra
+
+    @staticmethod
+    def _create_args_to_params(**kwargs):
+        """
+        Extract server params from keyword args to create a VS
+
+        :param   kwargs: keyword args
+        :return: ``dict``
+        """
+        params = [
+            "ex_cpu_sockets",
+            "ex_cpu_threads",
+            "ex_enable_autoscale",
+            "ex_data_store_group_primary_id",
+            "ex_data_store_group_swap_id",
+            "ex_hypervisor_group_id",
+            "ex_hypervisor_id",
+            "ex_initial_root_password",
+            "ex_note",
+            "ex_primary_disk_min_iops",
+            "ex_primary_network_id",
+            "ex_primary_network_group_id",
+            "ex_recipe_ids",
+            "ex_required_automatic_backup",
+            "ex_required_virtual_machine_startup",
+            "ex_required_virtual_machine_startup",
+            "ex_selected_ip_address_id",
+            "ex_swap_disk_min_iops",
+            "ex_type_of_format",
+            "ex_custom_recipe_variables",
+            "ex_licensing_key",
+            "ex_licensing_server_id",
+            "ex_licensing_type",
+        ]
+        server_params = {}
+
+        for p in params:
+            value = kwargs.get(p)
+            if value:
+                server_params[p[3:]] = value
+        return server_params

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/compute/providers.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/providers.py b/libcloud/compute/providers.py
index 25687c3..f2df4d5 100644
--- a/libcloud/compute/providers.py
+++ b/libcloud/compute/providers.py
@@ -163,6 +163,8 @@ DRIVERS = {
     ('libcloud.compute.drivers.cloudwatt', 'CloudwattNodeDriver'),
     Provider.PACKET:
     ('libcloud.compute.drivers.packet', 'PacketNodeDriver'),
+    Provider.ONAPP:
+    ('libcloud.compute.drivers.onapp', 'OnAppNodeDriver'),
 
     # Deprecated
     Provider.CLOUDSIGMA_US:

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/compute/types.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py
index f045546..64785ef 100644
--- a/libcloud/compute/types.py
+++ b/libcloud/compute/types.py
@@ -139,6 +139,7 @@ class Provider(object):
     HPCLOUD = 'hpcloud'
     CLOUDWATT = 'cloudwatt'
     KILI = 'kili'
+    ONAPP = 'onapp'
 
     # Deprecated constants which are still supported
     EC2_US_EAST = 'ec2_us_east'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/test/compute/fixtures/onapp/create_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/onapp/create_node.json b/libcloud/test/compute/fixtures/onapp/create_node.json
new file mode 100644
index 0000000..435d92e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/onapp/create_node.json
@@ -0,0 +1,87 @@
+{
+  "virtual_machine": {
+    "add_to_marketplace": false,
+    "admin_note": "",
+    "allow_resize_without_reboot": true,
+    "allowed_hot_migrate": true,
+    "allowed_swap": true,
+    "booted": true,
+    "built": true,
+    "cpu_priority": 100,
+    "cpu_shares": 100,
+    "cpu_sockets": 1,
+    "cpu_threads": 1,
+    "cpu_units": 1000,
+    "cpus": 2,
+    "created_at": "2015-01-16T02:06:19+07:00",
+    "customer_network_id": "",
+    "deleted_at": "",
+    "edge_server_type": "",
+    "enable_autoscale": false,
+    "enable_monitis": false,
+    "firewall_notrack": false,
+    "hostname": "onapp-new-fred",
+    "hypervisor_id": 24,
+    "id": 652,
+    "identifier": "456789",
+    "initial_root_password": "passwd",
+    "initial_root_password_encrypted": false,
+    "ip_addresses": [
+      {
+        "ip_address": {
+          "address": "192.168.15.73",
+          "broadcast": "192.168.15.255",
+          "created_at": "2015-01-16T02:49:58+07:00",
+          "customer_network_id": "",
+          "disallowed_primary": false,
+          "free": false,
+          "gateway": "192.168.15.51",
+          "hypervisor_id": "",
+          "id": 2947,
+          "ip_address_pool_id": "",
+          "netmask": "255.255.255.0",
+          "network_address": "192.168.15.0",
+          "network_id": 39,
+          "pxe": false,
+          "updated_at": "2015-01-20T22:42:14+07:00",
+          "user_id": ""
+        }
+      }
+    ],
+    "label": "onapp-new-fred",
+    "local_remote_access_ip_address": "8.8.8.8",
+    "local_remote_access_port": 5967,
+    "locked": false,
+    "memory": 8192,
+    "min_disk_size": 5,
+    "monthly_bandwidth_used": 1887,
+    "note": "",
+    "operating_system": "linux",
+    "operating_system_distro": "ubunt",
+    "preferred_hvs": [
+      5,
+      4,
+      2,
+      3,
+      1,
+      6
+    ],
+    "price_per_hour": 0.0,
+    "price_per_hour_powered_off": 0.0,
+    "recovery_mode": "",
+    "remote_access_password": "passwd",
+    "service_password": "",
+    "state": "delivered",
+    "storage_server_type": "",
+    "strict_virtual_machine_id": "",
+    "support_incremental_backups": false,
+    "suspended": false,
+    "template_id": 93,
+    "template_label": "Ubuntu 12.04 x64",
+    "total_disk_size": 410,
+    "updated_at": "2015-02-28T07:54:47+07:00",
+    "user_id": 136,
+    "vip": "",
+    "xen_id": 161
+  }
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/test/compute/fixtures/onapp/list_nodes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/onapp/list_nodes.json b/libcloud/test/compute/fixtures/onapp/list_nodes.json
new file mode 100644
index 0000000..2b3b8f2
--- /dev/null
+++ b/libcloud/test/compute/fixtures/onapp/list_nodes.json
@@ -0,0 +1,89 @@
+[
+  {
+    "virtual_machine": {
+      "add_to_marketplace": false,
+      "admin_note": "",
+      "allow_resize_without_reboot": true,
+      "allowed_hot_migrate": true,
+      "allowed_swap": true,
+      "booted": true,
+      "built": true,
+      "cpu_priority": 100,
+      "cpu_shares": 100,
+      "cpu_sockets": 1,
+      "cpu_threads": 1,
+      "cpu_units": 1000,
+      "cpus": 2,
+      "created_at": "2015-01-16T02:06:19+07:00",
+      "customer_network_id": "",
+      "deleted_at": "",
+      "edge_server_type": "",
+      "enable_autoscale": false,
+      "enable_monitis": false,
+      "firewall_notrack": false,
+      "hostname": "onapp-fred",
+      "hypervisor_id": 24,
+      "id": 652,
+      "identifier": "123456",
+      "initial_root_password": "passwd",
+      "initial_root_password_encrypted": false,
+      "ip_addresses": [
+        {
+          "ip_address": {
+            "address": "192.168.15.72",
+            "broadcast": "192.168.15.255",
+            "created_at": "2015-01-16T02:49:58+07:00",
+            "customer_network_id": "",
+            "disallowed_primary": false,
+            "free": false,
+            "gateway": "192.168.15.51",
+            "hypervisor_id": "",
+            "id": 2947,
+            "ip_address_pool_id": "",
+            "netmask": "255.255.255.0",
+            "network_address": "192.168.15.0",
+            "network_id": 39,
+            "pxe": false,
+            "updated_at": "2015-01-20T22:42:14+07:00",
+            "user_id": ""
+          }
+        }
+      ],
+      "label": "onapp-fred",
+      "local_remote_access_ip_address": "9.9.9.9",
+      "local_remote_access_port": 5967,
+      "locked": false,
+      "memory": 8192,
+      "min_disk_size": 5,
+      "monthly_bandwidth_used": 1887,
+      "note": "",
+      "operating_system": "linux",
+      "operating_system_distro": "ubunt",
+      "preferred_hvs": [
+        5,
+        4,
+        2,
+        3,
+        1,
+        6
+      ],
+      "price_per_hour": 0.0,
+      "price_per_hour_powered_off": 0.0,
+      "recovery_mode": "",
+      "remote_access_password": "passwd",
+      "service_password": "",
+      "state": "delivered",
+      "storage_server_type": "",
+      "strict_virtual_machine_id": "",
+      "support_incremental_backups": false,
+      "suspended": false,
+      "template_id": 93,
+      "template_label": "Ubuntu 12.04 x64",
+      "total_disk_size": 410,
+      "updated_at": "2015-02-28T07:54:47+07:00",
+      "user_id": 136,
+      "vip": "",
+      "xen_id": 161
+    }
+  }
+]

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/test/compute/test_onapp.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_onapp.py b/libcloud/test/compute/test_onapp.py
new file mode 100644
index 0000000..324ae43
--- /dev/null
+++ b/libcloud/test/compute/test_onapp.py
@@ -0,0 +1,111 @@
+import unittest
+import sys
+import json
+
+from mock import call, MagicMock
+
+from libcloud.test.file_fixtures import ComputeFileFixtures
+from libcloud.compute.drivers.onapp import OnAppNodeDriver
+from libcloud.test import LibcloudTestCase
+from libcloud.test.secrets import ONAPP_PARAMS
+from libcloud.compute.base import Node
+
+
+class OnAppNodeTestCase(LibcloudTestCase):
+    def setUp(self):
+        def _request(*args, **kwargs):
+            fixtures = ComputeFileFixtures('onapp')
+            response = MagicMock()
+            method = kwargs.get('method', "GET")
+
+            if method is 'GET' and args[0] == '/virtual_machines.json':
+                response.object = json.loads(fixtures.load(
+                    'list_nodes.json'))
+            if method is 'POST' and args[0] == '/virtual_machines.json':
+                response.object = json.loads(fixtures.load('create_node.json'))
+            if method is 'DELETE' and args[0] == '/virtual_machines.json':
+                response.status = 204
+
+            return response
+
+        self.connection_mock = MagicMock()
+        self.connection_mock.return_value.request.side_effect = _request
+        OnAppNodeDriver.connectionCls = self.connection_mock
+        self.driver = OnAppNodeDriver(*ONAPP_PARAMS)
+
+    def test_create_node(self):
+        node = self.driver.create_node(
+            name='onapp-new-fred',
+            ex_memory=512,
+            ex_cpus=4,
+            ex_cpu_shares=4,
+            ex_hostname='onapp-new-fred',
+            ex_template_id='template_id',
+            ex_primary_disk_size=100,
+            ex_swap_disk_size=1,
+            ex_required_virtual_machine_build=0,
+            ex_required_ip_address_assignment=0
+        )
+
+        req_mock = self.connection_mock.return_value.request
+        self.assertEqual('/virtual_machines.json', req_mock.call_args[0][0])
+        self.assertEqual({'Content-type': 'application/json'},
+                         req_mock.call_args[1]['headers'])
+        self.assertEqual(json.loads(
+            '{"virtual_machine": {'
+            '"swap_disk_size": 1, "required_ip_address_assignment": 0, '
+            '"hostname": "onapp-new-fred", "cpus": 4, "label": '
+            '"onapp-new-fred", "primary_disk_size": 100, "memory": 512, '
+            '"required_virtual_machine_build": 0, "template_id": '
+            '"template_id", "cpu_shares": 4, "rate_limit": null}}'),
+            json.loads(req_mock.call_args[1]['data']))
+        self.assertEqual('POST', req_mock.call_args[1]['method'])
+
+        extra = node.extra
+
+        self.assertEqual('onapp-new-fred', node.name)
+        self.assertEqual('456789', node.id)
+        self.assertEqual('456789', node.id)
+
+        self.assertEqual('delivered', node.state)
+
+        self.assertEqual(True, extra['booted'])
+        self.assertEqual('passwd', extra['initial_root_password'])
+        self.assertEqual('8.8.8.8', extra['local_remote_access_ip_address'])
+
+        self.assertEqual(['192.168.15.73'], node.private_ips)
+        self.assertEqual([], node.public_ips)
+
+    def test_destroy_node(self):
+        node = Node('identABC', 'testnode',
+                    ['123.123.123.123'], [],
+                    {'state': 'test', 'template_id': 88}, None)
+        self.driver.destroy_node(node=node)
+        self.assertEqual(call(
+            '/virtual_machines/identABC.json',
+            params={'destroy_all_backups': 0, 'convert_last_backup': 0},
+            method='DELETE'),
+            self.connection_mock.return_value.request.call_args)
+
+    def test_list_nodes(self):
+        nodes = self.driver.list_nodes()
+        extra = nodes[0].extra
+        private_ips = nodes[0].private_ips
+
+        self.assertEqual(1, len(nodes))
+        self.assertEqual('onapp-fred', nodes[0].name)
+        self.assertEqual('123456', nodes[0].id)
+
+        self.assertEqual(True, extra['booted'])
+        self.assertEqual('passwd', extra['initial_root_password'])
+        self.assertEqual('9.9.9.9', extra['local_remote_access_ip_address'])
+
+        self.assertEqual(1, len(private_ips))
+        self.assertEqual('192.168.15.72', private_ips[0])
+
+        self.assertEqual(call('/virtual_machines.json'),
+                         self.connection_mock.return_value.request.call_args)
+
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())

http://git-wip-us.apache.org/repos/asf/libcloud/blob/592c934c/libcloud/test/secrets.py-dist
----------------------------------------------------------------------
diff --git a/libcloud/test/secrets.py-dist b/libcloud/test/secrets.py-dist
index 83e28d1..fbadf81 100644
--- a/libcloud/test/secrets.py-dist
+++ b/libcloud/test/secrets.py-dist
@@ -27,6 +27,7 @@ GCE_PARAMS = ('email@developer.gserviceaccount.com', 'key')  # Service Account
A
 GCE_KEYWORD_PARAMS = {'project': 'project_name'}
 HOSTINGCOM_PARAMS = ('user', 'secret')
 IBM_PARAMS = ('user', 'secret')
+ONAPP_PARAMS = ('key',)
 # OPENSTACK_PARAMS = ('user_name', 'api_key', secure_bool, 'host', port_int)
 OPENSTACK_PARAMS = ('user_name', 'api_key', False, 'host', 8774)
 OPENNEBULA_PARAMS = ('user', 'key')


Mime
View raw message