Author: tomaz
Date: Mon Jul 16 05:25:58 2012
New Revision: 1361909
URL: http://svn.apache.org/viewvc?rev=1361909&view=rev
Log:
Add Gridspot compute driver. Contributed by Amir Elaguizy, part of LIBCLOUD-223.
Added:
libcloud/trunk/libcloud/compute/drivers/gridspot.py
libcloud/trunk/libcloud/test/compute/test_gridspot.py
Modified:
libcloud/trunk/CHANGES
libcloud/trunk/libcloud/compute/types.py
libcloud/trunk/libcloud/test/secrets.py-dist
Modified: libcloud/trunk/CHANGES
URL:
http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1361909&r1=1361908&r2=1361909&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Mon Jul 16 05:25:58 2012
@@ -73,10 +73,14 @@ Changes with Apache Libcloud in developm
- Add 'auth_user_variable' to the OpenStackAuthConnection class.
[Mark Everett]
- - Fix a bug with repeated URLs in some requests the vCloud driver.
- ; LIBCLOUD-22
+ - Fix a bug with repeated URLs in some requests the vCloud driver.
+ ; LIBCLOUD-222
[Michal Galet]
+ - New Gridspot driver with basic list and destroy functionality. ;
+ LIBCLOUD-223
+ [Amir Elaguizy]
+
*) DNS
- Add support for GEO RecordType to Zerigo driver. ; LIBCLOUD-203
Added: libcloud/trunk/libcloud/compute/drivers/gridspot.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/gridspot.py?rev=1361909&view=auto
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/gridspot.py (added)
+++ libcloud/trunk/libcloud/compute/drivers/gridspot.py Mon Jul 16 05:25:58 2012
@@ -0,0 +1,127 @@
+# 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.
+
+from libcloud.compute.base import NodeDriver, Node
+from libcloud.compute.base import NodeState
+from libcloud.common.base import ConnectionKey, JsonResponse
+from libcloud.compute.types import Provider
+from libcloud.common.types import InvalidCredsError
+
+
+class GridspotAPIException(Exception):
+ def __str__(self):
+ return self.args[0]
+
+ def __repr__(self):
+ return "<GridspotAPIException '%s'>" % (self.args[0])
+
+
+class GridspotResponse(JsonResponse):
+ """
+ Response class for Gridspot
+ """
+ def parse_body(self):
+ body = super(GridspotResponse, self).parse_body()
+
+ if 'exception_name' in body and body['exception_name']:
+ raise GridspotAPIException(body['exception_name'])
+
+ return body
+
+ def parse_error(self):
+ # Gridspot 404s on invalid api key or instance_id
+ raise InvalidCredsError("Invalid api key/instance_id")
+
+
+class GridspotConnection(ConnectionKey):
+ """
+ Connection class to connect to Gridspot's API servers
+ """
+
+ host = 'gridspot.com'
+ responseCls = GridspotResponse
+
+ def add_default_params(self, params):
+ params['api_key'] = self.key
+ return params
+
+
+class GridspotNodeDriver(NodeDriver):
+ """
+ Gridspot (http://www.gridspot.com/) node driver.
+ """
+
+ type = Provider.GRIDSPOT
+ name = 'Gridspot'
+ website = 'http://www.gridspot.com/'
+ connectionCls = GridspotConnection
+ NODE_STATE_MAP = {
+ 'Running': NodeState.RUNNING,
+ 'Starting': NodeState.PENDING
+ }
+
+ def list_nodes(self):
+ data = self.connection.request(
+ '/compute_api/v1/list_instances').object
+ return [self._to_node(n) for n in data['instances']]
+
+ def destroy_node(self, node):
+ data = {'instance_id': node.id}
+ self.connection.request('/compute_api/v1/stop_instance', data).object
+ return True
+
+ def _get_node_state(self, state):
+ result = self.NODE_STATE_MAP.get(state, NodeState.UNKNOWN)
+ return result
+
+ def _add_int_param(self, params, data, field):
+ if data[field]:
+ try:
+ params[field] = int(data[field])
+ except:
+ pass
+
+ def _to_node(self, data):
+ port = None
+ ip = None
+
+ state = self._get_node_state(data['current_state'])
+
+ if data['vm_ssh_wan_ip_endpoint'] != 'null':
+ parts = data['vm_ssh_wan_ip_endpoint'].split(':')
+ ip = parts[0]
+ port = int(parts[1])
+
+ extra_params = {
+ 'winning_bid_id': data['winning_bid_id'],
+ 'port': port
+ }
+
+ # Spec is vague and doesn't indicate if these will always be present
+ self._add_int_param(extra_params, data, 'vm_num_logical_cores')
+ self._add_int_param(extra_params, data, 'vm_num_physical_cores')
+ self._add_int_param(extra_params, data, 'vm_ram')
+ self._add_int_param(extra_params, data, 'start_state_time')
+ self._add_int_param(extra_params, data, 'ended_state_time')
+ self._add_int_param(extra_params, data, 'running_state_time')
+
+ return Node(
+ id=data['instance_id'],
+ name=data['instance_id'],
+ state=state,
+ public_ips=[ip],
+ private_ips=[],
+ driver=self.connection.driver,
+ extra=extra_params)
Modified: libcloud/trunk/libcloud/compute/types.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/types.py?rev=1361909&r1=1361908&r2=1361909&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/types.py (original)
+++ libcloud/trunk/libcloud/compute/types.py Mon Jul 16 05:25:58 2012
@@ -68,6 +68,7 @@ class Provider(object):
@cvar JOYENT: Joyent driver
@cvar VCL: VCL driver
@cvar KTUCLOUD: kt ucloud driver
+ @cvar GRIDSPOT: Gridspot driver
"""
DUMMY = 0
EC2 = 1 # deprecated name
@@ -118,8 +119,9 @@ class Provider(object):
ELASTICHOSTS_CA1 = 44
JOYENT = 45
VCL = 46
- KTUCLOUD=47
+ KTUCLOUD = 47
RACKSPACE_NOVA_LON = 48
+ GRIDSPOT = 49
class NodeState(object):
Added: libcloud/trunk/libcloud/test/compute/test_gridspot.py
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/test_gridspot.py?rev=1361909&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/test_gridspot.py (added)
+++ libcloud/trunk/libcloud/test/compute/test_gridspot.py Mon Jul 16 05:25:58
2012
@@ -0,0 +1,232 @@
+# 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
+from libcloud.utils.py3 import httplib
+
+try:
+ import simplejson as json
+except ImportError:
+ import json
+
+from libcloud.common.types import InvalidCredsError
+from libcloud.compute.drivers.gridspot import GridspotNodeDriver
+from libcloud.compute.types import NodeState
+
+from libcloud.test import MockHttp
+from libcloud.test.compute import TestCaseMixin
+from libcloud.test.secrets import GRIDSPOT_PARAMS
+
+
+class GridspotTest(unittest.TestCase, TestCaseMixin):
+ def setUp(self):
+ GridspotNodeDriver.connectionCls.conn_classes = (
+ None,
+ GridspotMockHttp
+ )
+ GridspotMockHttp.type = None
+ self.driver = GridspotNodeDriver(*GRIDSPOT_PARAMS)
+
+ def test_invalid_creds(self):
+ """
+ Tests the error-handling for passing a bad API Key to the Gridspot API
+ """
+ GridspotMockHttp.type = 'BAD_AUTH'
+ try:
+ self.driver.list_nodes()
+ # Above command should have thrown an InvalidCredsException
+ self.assertTrue(False)
+ except InvalidCredsError:
+ self.assertTrue(True)
+
+ def test_list_nodes(self):
+ nodes = self.driver.list_nodes()
+ self.assertEqual(len(nodes), 2)
+
+ running_node = nodes[0]
+ starting_node = nodes[1]
+
+ self.assertEqual(running_node.id, 'inst_CP2WrQi2WIS4iheyAVkQYw')
+ self.assertEqual(running_node.state, NodeState.RUNNING)
+ self.assertTrue('69.4.239.74' in running_node.public_ips)
+ self.assertEqual(running_node.extra['port'], 62394)
+ self.assertEqual(running_node.extra['vm_ram'], 1429436743)
+ self.assertEqual(running_node.extra['start_state_time'], 1342108905)
+ self.assertEqual(running_node.extra['vm_num_logical_cores'], 8)
+ self.assertEqual(running_node.extra['vm_num_physical_cores'], 4)
+ self.assertEqual(running_node.extra['winning_bid_id'],\
+ 'bid_X5xhotGYiGUk7_RmIqVafA')
+ self.assertFalse('ended_state_time' in running_node.extra)
+ self.assertEqual(running_node.extra['running_state_time'], 1342108989)
+
+ self.assertEqual(starting_node.id, 'inst_CP2WrQi2WIS4iheyAVkQYw2')
+ self.assertEqual(starting_node.state, NodeState.PENDING)
+ self.assertTrue('69.4.239.74' in starting_node.public_ips)
+ self.assertEqual(starting_node.extra['port'], 62395)
+ self.assertEqual(starting_node.extra['vm_ram'], 1429436744)
+ self.assertEqual(starting_node.extra['start_state_time'], 1342108906)
+ self.assertEqual(starting_node.extra['vm_num_logical_cores'], 7)
+ self.assertEqual(starting_node.extra['vm_num_physical_cores'], 5)
+ self.assertEqual(starting_node.extra['winning_bid_id'],\
+ 'bid_X5xhotGYiGUk7_RmIqVafA1')
+ self.assertFalse('ended_state_time' in starting_node.extra)
+ self.assertEqual(starting_node.extra['running_state_time'], 1342108990)
+
+ def test_create_node(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_destroy_node(self):
+ """
+ Test destroy_node for Gridspot driver
+ """
+ node = self.driver.list_nodes()[0]
+ self.assertTrue(self.driver.destroy_node(node))
+
+ def test_destroy_node_failure(self):
+ """
+ Gridspot does not fail a destroy node unless the parameters are bad, in
+ which case it 404s
+ """
+ self.assertTrue(True)
+
+ def test_reboot_node(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_reboot_node_failure(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_resize_node(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_reboot_node_response(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_list_images_response(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_create_node_response(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_destroy_node_response(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_list_sizes_response(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_resize_node_failure(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_list_images(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_list_sizes(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_list_locations(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+ def test_list_locations_response(self):
+ """
+ Gridspot does not implement this functionality
+ """
+ self.assertTrue(True)
+
+
+class GridspotMockHttp(MockHttp):
+ def _compute_api_v1_list_instances_BAD_AUTH(self, method, url, body,
+ headers):
+ return (httplib.NOT_FOUND, "", {},
+ httplib.responses[httplib.NOT_FOUND])
+
+ def _compute_api_v1_list_instances(self, method, url, body, headers):
+ body = json.dumps({
+ "instances": [
+ {
+ "instance_id": "inst_CP2WrQi2WIS4iheyAVkQYw",
+ "vm_num_logical_cores": 8,
+ "vm_num_physical_cores": 4,
+ "winning_bid_id": "bid_X5xhotGYiGUk7_RmIqVafA",
+ "vm_ram": 1429436743,
+ "start_state_time": 1342108905,
+ "vm_ssh_wan_ip_endpoint": "69.4.239.74:62394",
+ "current_state": "Running",
+ "ended_state_time": "null",
+ "running_state_time": 1342108989
+ },
+ {
+ "instance_id": "inst_CP2WrQi2WIS4iheyAVkQYw2",
+ "vm_num_logical_cores": 7,
+ "vm_num_physical_cores": 5,
+ "winning_bid_id": "bid_X5xhotGYiGUk7_RmIqVafA1",
+ "vm_ram": 1429436744,
+ "start_state_time": 1342108906,
+ "vm_ssh_wan_ip_endpoint": "69.4.239.74:62395",
+ "current_state": "Starting",
+ "ended_state_time": "null",
+ "running_state_time": 1342108990
+ }
+ ],
+ "exception_name": ""
+ })
+
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _compute_api_v1_stop_instance(self, method, url, body, headers):
+ body = json.dumps({"exception_name": ""})
+
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+if __name__ == '__main__':
+ sys.exit(unittest.main())
Modified: libcloud/trunk/libcloud/test/secrets.py-dist
URL:
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/secrets.py-dist?rev=1361909&r1=1361908&r2=1361909&view=diff
==============================================================================
--- libcloud/trunk/libcloud/test/secrets.py-dist (original)
+++ libcloud/trunk/libcloud/test/secrets.py-dist Mon Jul 16 05:25:58 2012
@@ -37,6 +37,7 @@ VOXEL_PARAMS = ('key', 'secret')
VPSNET_PARAMS = ('user', 'key')
JOYENT_PARAMS = ('user', 'key')
VCL_PARAMS = ('user', 'pass', True, 'foo.bar.com')
+GRIDSPOT_PARAMS = ('key',)
# Storage
STORAGE_S3_PARAMS = ('key', 'secret')