Repository: libcloud
Updated Branches:
  refs/heads/trunk 526d06b86 -> 9c0ef27f0


Add Vultr compute driver

Closes #384

Signed-off-by: Tomaz Muraus <[email protected]>


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

Branch: refs/heads/trunk
Commit: 9defdb5e2f6e51161eb5c9f78e6b750a512f05c8
Parents: 526d06b
Author: clark.kang <[email protected]>
Authored: Sun Nov 9 11:57:14 2014 +0900
Committer: Tomaz Muraus <[email protected]>
Committed: Tue Nov 11 18:20:09 2014 +0800

----------------------------------------------------------------------
 docs/compute/drivers/vultr.rst                  |  30 +++
 .../compute/vultr/vultr_compute_simple.py       |   5 +
 libcloud/compute/drivers/vultr.py               | 184 +++++++++++++++++++
 libcloud/compute/providers.py                   |   2 +
 libcloud/compute/types.py                       |   2 +
 .../compute/fixtures/vultr/list_images.json     |   1 +
 .../compute/fixtures/vultr/list_locations.json  |   1 +
 .../test/compute/fixtures/vultr/list_nodes.json |   1 +
 .../test/compute/fixtures/vultr/list_sizes.json |   1 +
 libcloud/test/compute/test_vultr.py             | 114 ++++++++++++
 libcloud/test/secrets.py-dist                   |   1 +
 11 files changed, 342 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/docs/compute/drivers/vultr.rst
----------------------------------------------------------------------
diff --git a/docs/compute/drivers/vultr.rst b/docs/compute/drivers/vultr.rst
new file mode 100644
index 0000000..f062afd
--- /dev/null
+++ b/docs/compute/drivers/vultr.rst
@@ -0,0 +1,30 @@
+Vultr Compute Driver Documentation
+========================================
+
+`Vultr`_ is a public cloud provider based in mulitiple counties.
+
+How to get API Key
+------------------
+
+Visit https://my.vultr.com/settings/#API
+
+You can see Your API Key in API Information Section in the middle of page.
+If you want to change your API Key, press the Regenerate Button.
+
+Examples
+--------
+
+1. Create vultr driver - how to create vultr driver with api key
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. literalinclude:: /examples/compute/vultr/vultr_compute_simple.py
+   :language: python
+
+API Docs
+--------
+
+.. autoclass:: libcloud.compute.drivers.vultr.VultrNodeDriver
+    :members:
+    :inherited-members:
+
+.. _`vultr`: http://www.vultr.com

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/docs/examples/compute/vultr/vultr_compute_simple.py
----------------------------------------------------------------------
diff --git a/docs/examples/compute/vultr/vultr_compute_simple.py 
b/docs/examples/compute/vultr/vultr_compute_simple.py
new file mode 100644
index 0000000..5db958b
--- /dev/null
+++ b/docs/examples/compute/vultr/vultr_compute_simple.py
@@ -0,0 +1,5 @@
+from libcloud.compute.types import Provider
+from libcloud.compute.providers import get_driver
+
+cls = get_driver(Provider.VULTR)
+driver = cls('your api key')

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/compute/drivers/vultr.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/vultr.py 
b/libcloud/compute/drivers/vultr.py
new file mode 100644
index 0000000..ab47aa0
--- /dev/null
+++ b/libcloud/compute/drivers/vultr.py
@@ -0,0 +1,184 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+"""
+Vultr Driver
+"""
+
+import time
+
+from libcloud.utils.py3 import httplib
+from libcloud.utils.py3 import urlencode
+
+from libcloud.common.base import ConnectionKey, JsonResponse
+from libcloud.compute.types import Provider, NodeState
+from libcloud.common.types import LibcloudError, InvalidCredsError
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.base import Node, NodeImage, NodeSize, NodeLocation
+
+
+class VultrResponse(JsonResponse):
+    def parse_error(self):
+        if self.status == httplib.OK:
+            body = self.parse_body()
+            return body
+        elif self.status == httplib.FORBIDDEN:
+            raise InvalidCredsError(self.body)
+        else:
+            raise LibcloudError(self.body)
+
+
+class VultrConnection(ConnectionKey):
+    """
+    Connection class for the Vultr driver.
+    """
+
+    host = 'api.vultr.com'
+    responseCls = VultrResponse
+
+    def add_default_params(self, params):
+        """
+        Add parameters that are necessary for every request
+
+        This method add ``api_key`` to
+        the request.
+        """
+        params['api_key'] = self.key
+        return params
+
+    def encode_data(self, data):
+        return urlencode(data)
+
+    def get(self, url):
+        return self.request(url)
+
+    def post(self, url, data):
+        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        return self.request(url, data=data, headers=headers, method='POST')
+
+
+class VultrNodeDriver(NodeDriver):
+    """
+    VultrNode node driver.
+    """
+
+    connectionCls = VultrConnection
+
+    type = Provider.VULTR
+    name = 'Vultr'
+    website = 'https://www.vultr.com'
+
+    NODE_STATE_MAP = {'pending': NodeState.PENDING,
+                      'active': NodeState.RUNNING}
+
+    def list_nodes(self):
+        return self._list_resources('/v1/server/list', self._to_node)
+
+    def list_locations(self):
+        return self._list_resources('/v1/regions/list', self._to_location)
+
+    def list_sizes(self):
+        return self._list_resources('/v1/plans/list', self._to_size)
+
+    def list_images(self):
+        return self._list_resources('/v1/os/list', self._to_image)
+
+    def create_node(self, name, size, image, location):
+        params = {'DCID': location.id, 'VPSPLANID': size.id,
+                  'OSID': image.id, 'label': name}
+
+        result = self.connection.post('/v1/server/create', params)
+        if result.status != httplib.OK:
+            return False
+
+        subid = result.object['SUBID']
+
+        retry_count = 3
+        created_node = None
+
+        for i in range(retry_count):
+            try:
+                nodes = self.list_nodes()
+                created_node = [n for n in nodes if n.id == subid][0]
+            except IndexError:
+                time.sleep(1)
+                pass
+            else:
+                break
+
+        return created_node
+
+    def reboot_node(self, node):
+        params = {'SUBID': node.id}
+        res = self.connection.post('/v1/server/reboot', params)
+
+        return res.status == httplib.OK
+
+    def destroy_node(self, node):
+        params = {'SUBID': node.id}
+        res = self.connection.post('/v1/server/destroy', params)
+
+        return res.status == httplib.OK
+
+    def _list_resources(self, url, tranform_func):
+        data = self.connection.get(url).object
+        sorted_key = sorted(data)
+        return [tranform_func(data[key]) for key in sorted_key]
+
+    def _to_node(self, data):
+        if 'status' in data:
+            state = self.NODE_STATE_MAP.get(data['status'], NodeState.UNKNOWN)
+            if state == NodeState.RUNNING and \
+               data['power_status'] != 'running':
+                state = NodeState.STOPPED
+        else:
+            state = NodeState.UNKNOWN
+
+        if 'main_ip' in data and data['main_ip'] is not None:
+            public_ips = [data['main_ip']]
+        else:
+            public_ips = []
+
+        extra_keys = []
+        extra = {}
+        for key in extra_keys:
+            if key in data:
+                extra[key] = data[key]
+
+        node = Node(id=data['SUBID'], name=data['label'], state=state,
+                    public_ips=public_ips, private_ips=None, extra=extra,
+                    driver=self)
+
+        return node
+
+    def _to_location(self, data):
+        return NodeLocation(id=data['DCID'], name=data['name'],
+                            country=data['country'], driver=self)
+
+    def _to_size(self, data):
+        extra = {'vcpu_count': int(data['vcpu_count'])}
+        ram = int(data['ram'])
+        disk = int(data['disk'])
+        bandwidth = float(data['bandwidth'])
+        price = float(data['price_per_month'])
+
+        return NodeSize(id=data['VPSPLANID'], name=data['name'],
+                        ram=ram, disk=disk,
+                        bandwidth=bandwidth, price=price,
+                        extra=extra, driver=self)
+
+    def _to_image(self, data):
+        extra = {'arch': data['arch'], 'family': data['family']}
+        return NodeImage(id=data['OSID'], name=data['name'], extra=extra,
+                         driver=self)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/compute/providers.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/providers.py b/libcloud/compute/providers.py
index b449e78..bdceafc 100644
--- a/libcloud/compute/providers.py
+++ b/libcloud/compute/providers.py
@@ -151,6 +151,8 @@ DRIVERS = {
     ('libcloud.compute.drivers.vsphere', 'VSphereNodeDriver'),
     Provider.PROFIT_BRICKS:
     ('libcloud.compute.drivers.profitbricks', 'ProfitBricksNodeDriver'),
+    Provider.VULTR:
+    ('libcloud.compute.drivers.vultr', 'VultrNodeDriver'),
 
     # Deprecated
     Provider.CLOUDSIGMA_US:

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/compute/types.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py
index f07bc48..c21a4d1 100644
--- a/libcloud/compute/types.py
+++ b/libcloud/compute/types.py
@@ -77,6 +77,7 @@ class Provider(object):
     :cvar OUTSCALE_SAS: Outscale SAS driver.
     :cvar OUTSCALE_INC: Outscale INC driver.
     :cvar PROFIT_BRICKS: ProfitBricks driver.
+    :cvar VULTR: vultr driver.
     """
     DUMMY = 'dummy'
     EC2 = 'ec2_us_east'
@@ -124,6 +125,7 @@ class Provider(object):
     OUTSCALE_INC = 'outscale_inc'
     VSPHERE = 'vsphere'
     PROFIT_BRICKS = 'profitbricks'
+    VULTR = 'vultr'
 
     # OpenStack based providers
     HPCLOUD = 'hpcloud'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/test/compute/fixtures/vultr/list_images.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/vultr/list_images.json 
b/libcloud/test/compute/fixtures/vultr/list_images.json
new file mode 100644
index 0000000..139f2af
--- /dev/null
+++ b/libcloud/test/compute/fixtures/vultr/list_images.json
@@ -0,0 +1 @@
+{"127":{"OSID":127,"name":"CentOS 6 
x64","arch":"x64","family":"centos","windows":false},"147":{"OSID":147,"name":"CentOS
 6 
i386","arch":"i386","family":"centos","windows":false},"162":{"OSID":162,"name":"CentOS
 5 
x64","arch":"x64","family":"centos","windows":false},"163":{"OSID":163,"name":"CentOS
 5 
i386","arch":"i386","family":"centos","windows":false},"167":{"OSID":167,"name":"CentOS
 7 
x64","arch":"x64","family":"centos","windows":false},"160":{"OSID":160,"name":"Ubuntu
 14.04 
x64","arch":"x64","family":"ubuntu","windows":false},"161":{"OSID":161,"name":"Ubuntu
 14.04 
i386","arch":"i386","family":"ubuntu","windows":false},"128":{"OSID":128,"name":"Ubuntu
 12.04 
x64","arch":"x64","family":"ubuntu","windows":false},"148":{"OSID":148,"name":"Ubuntu
 12.04 
i386","arch":"i386","family":"ubuntu","windows":false},"181":{"OSID":181,"name":"Ubuntu
 14.10 
x64","arch":"x64","family":"ubuntu","windows":false},"182":{"OSID":182,"name":"Ubuntu
 14.10 i386","arch":"i386","family":"ubuntu","windows":f
 alse},"139":{"OSID":139,"name":"Debian 7 x64 
(wheezy)","arch":"x64","family":"debian","windows":false},"152":{"OSID":152,"name":"Debian
 7 i386 
(wheezy)","arch":"i386","family":"debian","windows":false},"140":{"OSID":140,"name":"FreeBSD
 10 
x64","arch":"x64","family":"freebsd","windows":false},"124":{"OSID":124,"name":"Windows
 2012 R2 
x64","arch":"x64","family":"windows","windows":true},"159":{"OSID":159,"name":"Custom","arch":"x64","family":"iso","windows":false},"164":{"OSID":164,"name":"Snapshot","arch":"x64","family":"snapshot","windows":false},"180":{"OSID":180,"name":"Backup","arch":"x64","family":"backup","windows":false}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/test/compute/fixtures/vultr/list_locations.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/vultr/list_locations.json 
b/libcloud/test/compute/fixtures/vultr/list_locations.json
new file mode 100644
index 0000000..6cf6d0b
--- /dev/null
+++ b/libcloud/test/compute/fixtures/vultr/list_locations.json
@@ -0,0 +1 @@
+{"6":{"DCID":"6","name":"Atlanta","country":"US","continent":"North 
America","state":"GA"},"2":{"DCID":"2","name":"Chicago","country":"US","continent":"North
 
America","state":"IL"},"3":{"DCID":"3","name":"Dallas","country":"US","continent":"North
 America","state":"TX"},"5":{"DCID":"5","name":"Los 
Angeles","country":"US","continent":"North 
America","state":"CA"},"39":{"DCID":"39","name":"Miami","country":"US","continent":"","state":"FL"},"1":{"DCID":"1","name":"New
 Jersey","country":"US","continent":"North 
America","state":"NJ"},"4":{"DCID":"4","name":"Seattle","country":"US","continent":"North
 America","state":"WA"},"12":{"DCID":"12","name":"Silicon 
Valley","country":"US","continent":"North 
America","state":"CA"},"7":{"DCID":"7","name":"Amsterdam","country":"NL","continent":"Europe","state":""},"25":{"DCID":"25","name":"Tokyo","country":"JP","continent":"Asia","state":""},"8":{"DCID":"8","name":"London","country":"GB","continent":"Europe","state":""},"24":{"DCID":"24","name":"France
 
","country":"FR","continent":"Europe","state":""},"9":{"DCID":"9","name":"Frankfurt","country":"DE","continent":"Europe","state":""},"19":{"DCID":"19","name":"Australia","country":"AU","continent":"Australia","state":""}}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/test/compute/fixtures/vultr/list_nodes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/vultr/list_nodes.json 
b/libcloud/test/compute/fixtures/vultr/list_nodes.json
new file mode 100644
index 0000000..e12ba4a
--- /dev/null
+++ b/libcloud/test/compute/fixtures/vultr/list_nodes.json
@@ -0,0 +1 @@
+{"1":{"SUBID":"1","os":"Ubuntu 12.04 x64","ram":"1024 MB","disk":"Virtual 20 
GB","main_ip":"108.61.206.153","vcpu_count":"1","location":"Los 
Angeles","DCID":"5","default_password":"twizewnatpom!7","date_created":"2014-03-21
 
12:46:35","pending_charges":"1.92","status":"active","cost_per_month":"7.00","current_bandwidth_gb":0.929,"allowed_bandwidth_gb":"2000","netmask_v4":"255.255.254.0","gateway_v4":"108.61.206.1","power_status":"running","VPSPLANID":"30","v6_network":"::","v6_main_ip":"","v6_network_size":"0","label":"","internal_ip":"","kvm_url":"https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=IF3C6VCEN5NFOZ3VMM3FOV3JJVXUQV3OHBWDG6TUKI3VST3JMFDXOOCMIE3HCTBWKVJXOZZYF5BVMZ3IM5XXGWRZIVZW4S2WKAVTSMTQHFCG4QTCNFUEKOCXKY3CW3LGNF4HIVTVJ5GXM4CJORTU6SKYOBDE6WJVMZ3E4ZSVOB2FQ4KYF5DXC5CTJI4FETDIGBITQQZPGFLXKTSRKRJS6ODOMFKDSNLLNVETONSNKA2XQ6CWLJMW6L2EGI2U6SDNN5FGUTJYNB3UC5DXN46Q","auto_backups":"no"},"2":{"SUBID":"2","os":"Ubuntu
 14.04 x64","ram":"768 MB","disk":"Virtual 15 GB","main_ip":
 "104.207.153.143","vcpu_count":"1","location":"Los 
Angeles","DCID":"5","default_password":"cewxoaezap!0","date_created":"2014-11-08
 
14:12:13","pending_charges":"0.01","status":"active","cost_per_month":"5.00","current_bandwidth_gb":0,"allowed_bandwidth_gb":"1000","netmask_v4":"255.255.254.0","gateway_v4":"104.207.152.1","power_status":"running","VPSPLANID":"29","v6_network":"::","v6_main_ip":"","v6_network_size":"0","label":"vultr-test1","internal_ip":"","kvm_url":"https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=NBUUYMTDI4VXGVZXOFBE6UBWKFLWE43MI5EFOR3MJNZW4NRXLFBHA33BHF3C63LSOJRXAU2PO5GHM5LPOFAW2MSDMFZWUMCNNJRG6TRWJREWYNBLG5VTG2DEGIYWITKIGV2FA3JTNJVEETLOGBHFG42XLEZHG22VFNWHE5RUKFIWU3DSOJCS6WDQGJRDIZRPIU2HILZTKB4E4MZSNZIFEQ3SOFSDANCBHBBEWRLVGZEUEVDSJVQVKOKZNQ4GKSRSIJEG62TWMREG6USNIE6Q","auto_backups":"no"}}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/test/compute/fixtures/vultr/list_sizes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/vultr/list_sizes.json 
b/libcloud/test/compute/fixtures/vultr/list_sizes.json
new file mode 100644
index 0000000..ded841d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/vultr/list_sizes.json
@@ -0,0 +1 @@
+{"31":{"VPSPLANID":"31","name":"768 MB RAM,15 GB SSD,0.20 TB 
BW","vcpu_count":"1","ram":"768","disk":"15","bandwidth":"0.20","bandwidth_gb":"204.8","price_per_month":"5.00","windows":false},"29":{"VPSPLANID":"29","name":"768
 MB RAM,15 GB SSD,1.00 TB 
BW","vcpu_count":"1","ram":"768","disk":"15","bandwidth":"1.00","bandwidth_gb":"1024","price_per_month":"5.00","windows":false},"32":{"VPSPLANID":"32","name":"1024
 MB RAM,20 GB SSD,0.40 TB 
BW","vcpu_count":"1","ram":"1024","disk":"20","bandwidth":"0.40","bandwidth_gb":"409.6","price_per_month":"7.00","windows":false},"30":{"VPSPLANID":"30","name":"1024
 MB RAM,20 GB SSD,2.00 TB 
BW","vcpu_count":"1","ram":"1024","disk":"20","bandwidth":"2.00","bandwidth_gb":"2048","price_per_month":"7.00","windows":false},"3":{"VPSPLANID":"3","name":"2048
 MB RAM,40 GB SSD,3.00 TB 
BW","vcpu_count":"2","ram":"2048","disk":"40","bandwidth":"3.00","bandwidth_gb":"3072","price_per_month":"15.00","windows":false},"8":{"VPSPLANID":"8","name":"2048
 MB RAM,40 GB SS
 D,0.60 TB 
BW","vcpu_count":"2","ram":"2048","disk":"40","bandwidth":"0.60","bandwidth_gb":"614.4","price_per_month":"15.00","windows":false},"33":{"VPSPLANID":"33","name":"4096
 MB RAM,65 GB SSD,0.80 TB 
BW","vcpu_count":"2","ram":"4096","disk":"65","bandwidth":"0.80","bandwidth_gb":"819.2","price_per_month":"35.00","windows":false},"27":{"VPSPLANID":"27","name":"4096
 MB RAM,65 GB SSD,4.00 TB 
BW","vcpu_count":"2","ram":"4096","disk":"65","bandwidth":"4.00","bandwidth_gb":"4096","price_per_month":"35.00","windows":false},"28":{"VPSPLANID":"28","name":"8192
 MB RAM,120 GB SSD,5.00 TB 
BW","vcpu_count":"4","ram":"8192","disk":"120","bandwidth":"5.00","bandwidth_gb":"5120","price_per_month":"70.00","windows":false},"34":{"VPSPLANID":"34","name":"8192
 MB RAM,120 GB SSD,1.00 TB 
BW","vcpu_count":"4","ram":"8192","disk":"120","bandwidth":"1.00","bandwidth_gb":"1024","price_per_month":"70.00","windows":false},"11":{"VPSPLANID":"11","name":"512
 MB RAM,160 GB SATA,1.00 TB BW","vcpu_count":"1","ram
 
":"512","disk":"160","bandwidth":"1.00","bandwidth_gb":"1024","price_per_month":"5.00","windows":false},"78":{"VPSPLANID":"78","name":"16384
 MB RAM,250 GB SSD,6.00 TB 
BW","vcpu_count":"8","ram":"16384","disk":"250","bandwidth":"6.00","bandwidth_gb":"6144","price_per_month":"149.95","windows":false},"71":{"VPSPLANID":"71","name":"16384
 MB RAM,250 GB SSD,8.00 TB 
BW","vcpu_count":"4","ram":"16384","disk":"250","bandwidth":"8.00","bandwidth_gb":"8192","price_per_month":"125.00","windows":false},"68":{"VPSPLANID":"68","name":"16384
 MB RAM,250 GB SSD,1.60 TB 
BW","vcpu_count":"4","ram":"16384","disk":"250","bandwidth":"1.60","bandwidth_gb":"1638.4","price_per_month":"125.00","windows":false},"12":{"VPSPLANID":"12","name":"1024
 MB RAM,320 GB SATA,2.00 TB 
BW","vcpu_count":"1","ram":"1024","disk":"320","bandwidth":"2.00","bandwidth_gb":"2048","price_per_month":"8.00","windows":false},"62":{"VPSPLANID":"62","name":"1024
 MB RAM,320 GB SATAPERF,1.00 TB BW, 10GigE","vcpu_count":"1","ram":"1024","
 
disk":"320","bandwidth":"1.00","bandwidth_gb":"1024","price_per_month":"15.00","windows":false},"79":{"VPSPLANID":"79","name":"32768
 MB RAM,400 GB SSD,7.00 TB 
BW","vcpu_count":"12","ram":"32768","disk":"400","bandwidth":"7.00","bandwidth_gb":"7168","price_per_month":"299.95","windows":false},"80":{"VPSPLANID":"80","name":"49152
 MB RAM,600 GB SSD,8.00 TB 
BW","vcpu_count":"16","ram":"49152","disk":"600","bandwidth":"8.00","bandwidth_gb":"8192","price_per_month":"429.95","windows":false},"13":{"VPSPLANID":"13","name":"2048
 MB RAM,640 GB SATA,3.00 TB 
BW","vcpu_count":"1","ram":"2048","disk":"640","bandwidth":"3.00","bandwidth_gb":"3072","price_per_month":"15.00","windows":false},"63":{"VPSPLANID":"63","name":"2048
 MB RAM,640 GB SATAPERF,2.00 TB BW, 
10GigE","vcpu_count":"1","ram":"2048","disk":"640","bandwidth":"2.00","bandwidth_gb":"2048","price_per_month":"25.00","windows":false},"81":{"VPSPLANID":"81","name":"65536
 MB RAM,800 GB SSD,9.00 TB BW","vcpu_count":"24","ram":"65536","disk":"
 
800","bandwidth":"9.00","bandwidth_gb":"9216","price_per_month":"599.95","windows":false},"64":{"VPSPLANID":"64","name":"4096
 MB RAM,1280 GB SATAPERF,3.00 TB BW, 
10GigE","vcpu_count":"2","ram":"4096","disk":"1280","bandwidth":"3.00","bandwidth_gb":"3072","price_per_month":"50.00","windows":false}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/test/compute/test_vultr.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_vultr.py 
b/libcloud/test/compute/test_vultr.py
new file mode 100644
index 0000000..066cc86
--- /dev/null
+++ b/libcloud/test/compute/test_vultr.py
@@ -0,0 +1,114 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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 sys
+import unittest
+
+try:
+    import simplejson as json
+except ImportError:
+    import json  # NOQA
+
+from libcloud.utils.py3 import httplib
+
+from libcloud.compute.drivers.vultr import VultrNodeDriver
+
+from libcloud.test import LibcloudTestCase, MockHttpTestCase
+from libcloud.test.file_fixtures import ComputeFileFixtures
+from libcloud.test.secrets import VULTR_PARAMS
+
+
+# class VultrTests(unittest.TestCase, TestCaseMixin):
+class VultrTests(LibcloudTestCase):
+
+    def setUp(self):
+        VultrNodeDriver.connectionCls.conn_classes = \
+            (VultrMockHttp, VultrMockHttp)
+        VultrMockHttp.type = None
+        self.driver = VultrNodeDriver(*VULTR_PARAMS)
+
+    def test_list_images_success(self):
+        images = self.driver.list_images()
+        self.assertTrue(len(images) >= 1)
+
+        image = images[0]
+        self.assertTrue(image.id is not None)
+        self.assertTrue(image.name is not None)
+
+    def test_list_sizes_success(self):
+        sizes = self.driver.list_sizes()
+        self.assertTrue(len(sizes) == 22)
+
+        size = sizes[0]
+        self.assertTrue(size.id is not None)
+        self.assertEqual(size.name, '512 MB RAM,160 GB SATA,1.00 TB BW')
+        self.assertEqual(size.ram, 512)
+
+        size = sizes[21]
+        self.assertTrue(size.id is not None)
+        self.assertEqual(size.name, '65536 MB RAM,800 GB SSD,9.00 TB BW')
+        self.assertEqual(size.ram, 65536)
+
+    def test_list_locations_success(self):
+        locations = self.driver.list_locations()
+        self.assertTrue(len(locations) >= 1)
+
+        location = locations[0]
+        self.assertEqual(location.id, '1')
+        self.assertEqual(location.name, 'New Jersey')
+
+    def test_list_nodes_success(self):
+        nodes = self.driver.list_nodes()
+        self.assertEqual(len(nodes), 2)
+        self.assertEqual(nodes[0].id, '1')
+        self.assertEqual(nodes[0].public_ips, ['108.61.206.153'])
+
+    def test_reboot_node_success(self):
+        node = self.driver.list_nodes()[0]
+        result = self.driver.reboot_node(node)
+        self.assertTrue(result)
+
+    def test_destroy_node_success(self):
+        node = self.driver.list_nodes()[0]
+        result = self.driver.destroy_node(node)
+        self.assertTrue(result)
+
+
+class VultrMockHttp(MockHttpTestCase):
+    fixtures = ComputeFileFixtures('vultr')
+
+    def _v1_regions_list(self, method, url, body, headers):
+        body = self.fixtures.load('list_locations.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _v1_os_list(self, method, url, body, headers):
+        body = self.fixtures.load('list_images.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _v1_plans_list(self, method, url, body, headers):
+        body = self.fixtures.load('list_sizes.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _v1_server_list(self, method, url, body, headers):
+        body = self.fixtures.load('list_nodes.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _v1_server_destroy(self, method, url, body, headers):
+        return (httplib.OK, "", {}, httplib.responses[httplib.OK])
+
+    def _v1_server_reboot(self, method, url, body, headers):
+        return (httplib.OK, "", {}, httplib.responses[httplib.OK])
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())

http://git-wip-us.apache.org/repos/asf/libcloud/blob/9defdb5e/libcloud/test/secrets.py-dist
----------------------------------------------------------------------
diff --git a/libcloud/test/secrets.py-dist b/libcloud/test/secrets.py-dist
index 940f455..3bac5ae 100644
--- a/libcloud/test/secrets.py-dist
+++ b/libcloud/test/secrets.py-dist
@@ -45,6 +45,7 @@ HOSTVIRTUAL_PARAMS = ('key',)
 DIGITAL_OCEAN_PARAMS = ('user', 'key')
 CLOUDFRAMES_PARAMS = ('key', 'secret', False, 'host', 8888)
 PROFIT_BRICKS_PARAMS = ('user', 'key')
+VULTR_PARAMS = ('key')
 
 # Storage
 STORAGE_S3_PARAMS = ('key', 'secret')

Reply via email to