You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by pq...@apache.org on 2010/01/05 02:27:25 UTC

svn commit: r895841 - in /incubator/libcloud/trunk/libcloud: drivers/gogrid.py providers.py

Author: pquerna
Date: Tue Jan  5 01:27:24 2010
New Revision: 895841

URL: http://svn.apache.org/viewvc?rev=895841&view=rev
Log:
Update GoGrid driver to modern libcloudisms.

Submitted by: Jereme Monteau <me jmoe.com>

Modified:
    incubator/libcloud/trunk/libcloud/drivers/gogrid.py
    incubator/libcloud/trunk/libcloud/providers.py

Modified: incubator/libcloud/trunk/libcloud/drivers/gogrid.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/gogrid.py?rev=895841&r1=895840&r2=895841&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/gogrid.py (original)
+++ incubator/libcloud/trunk/libcloud/drivers/gogrid.py Tue Jan  5 01:27:24 2010
@@ -12,192 +12,211 @@
 # 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.types import NodeState, Node, InvalidCredsException
+from libcloud.providers import Provider
+from libcloud.types import NodeState, InvalidCredsException
+from libcloud.base import Node, ConnectionUserAndKey, Response, NodeDriver, NodeSize, NodeImage
 from libcloud.interface import INodeDriver
 from zope.interface import implements
 import httplib
 import time
 import urllib
-import hashlib
-from xml.etree import ElementTree as ET
+import md5, hashlib
+try:
+    import simplejson as json
+except:
+    import json
 
 HOST = 'api.gogrid.com'
 PORTS_BY_SECURITY = { True: 443, False: 80 }
-API_VERSION = '1.1'
+API_VERSION = '1.3'
 
-class GoGridAuthConnection(object):
-    def __init__(self, api_key, secret,
-                 is_secure=True, server=HOST, port=None):
-
-        if not port:
-            port = PORTS_BY_SECURITY[is_secure]
-
-        self.verbose = False
-        self.api_key = api_key
-        self.secret = secret
-        conn_str = "%s:%d" % (server, port)
-        if (is_secure):
-            self.connection = httplib.HTTPSConnection(conn_str)
-        else:
-            self.connection = httplib.HTTPConnection(conn_str)
-
-
-    def make_request(self, action, params={}, data=''):
-        if self.verbose:
-            print params
+STATE = {
+    "Starting": NodeState.PENDING,
+    "On": NodeState.RUNNING,
+    "Off": NodeState.PENDING,
+    "Restarting": NodeState.REBOOTING,
+    "Saving": NodeState.PENDING,
+    "Restoring": NodeState.PENDING,
+}
 
-        params["api_key"] = self.api_key 
-        params["v"] = API_VERSION
-        params["format"] = 'xml'
-        params["sig"] = self.get_signature(self.api_key, self.secret)
+GOGRID_INSTANCE_TYPES = {'512MB': {'id': '512MB',
+                       'name': '512MB',
+                       'ram': 512,
+                       'disk': 30,
+                       'bandwidth': None,
+                       'price':0.095},
+        '1GB': {'id': '1GB',
+                       'name': '1GB',
+                       'ram': 1024,
+                       'disk': 60,
+                       'bandwidth': None,
+                       'price':0.19},
+        '2GB': {'id': '2GB',
+                       'name': '2GB',
+                       'ram': 2048,
+                       'disk': 120,
+                       'bandwidth': None,
+                       'price':0.38},
+        '4GB': {'id': '4GB',
+                       'name': '4GB',
+                       'ram': 4096,
+                       'disk': 240,
+                       'bandwidth': None,
+                       'price':0.76},
+        '8GB': {'id': '8GB',
+                       'name': '8GB',
+                       'ram': 8192,
+                       'disk': 480,
+                       'bandwidth': None,
+                       'price':1.52}}
+
+
+class GoGridResponse(Response):
+    def success(self):
+        if not self.body:
+            return None
+        return json.loads(self.body)['status'] == 'success'
+
+    def parse_body(self):
+        if not self.body:
+            return None
+        return json.loads(self.body)
+
+    def parse_error(self):
+        if not self.object:
+            return None
+        return self.object['message']
 
-        params = zip(params.keys(), params.values())
-        params.sort(key=lambda x: str.lower(x[0]))
+class GoGridConnection(ConnectionUserAndKey):
 
-        path = "&".join([ "=".join((param[0], urllib.quote_plus(param[1])))
-                          for param in params ])
-        
-        self.connection.request("GET", "/api/%s?%s" % (action, path), data)
-        return self.connection.getresponse()
+    host = HOST
+    responseCls = GoGridResponse
 
+    def add_default_params(self, params):
+        params["api_key"] = self.user_id
+        params["v"] = API_VERSION
+        params["format"] = 'json'
+        params["sig"] = self.get_signature(self.user_id, self.key)
+
+        return params
+        
     def get_signature(self, key, secret):
         """ create sig from md5 of key + secret + time """
-        return hashlib.md5(key + secret + str(int(time.time()))).hexdigest()
+        m = md5.new(key+secret+str(int(time.time())))
+        return m.hexdigest()
 
-    def server_list(self):
-        return Response(self.make_request("/grid/server/list"))
+class GoGridNode(Node):
+    # Generating uuid based on public ip to get around missing id on create_node in gogrid api
+    # Used public ip since it is not mutable and specified at create time, so uuid of node should not change after add is completed
+    def get_uuid(self):
+        return hashlib.sha1("%s:%d" % (self.public_ip,self.driver.type)).hexdigest()
+
+class GoGridNodeDriver(NodeDriver):
+
+    connectionCls = GoGridConnection
+    type = Provider.GOGRID
+    name = 'GoGrid API'
 
-    def server_power(self, id, power):
-        # power in ['start', 'stop', 'restart']
-        params = {'id': id, 'power': power}
-        return Response(self.make_request("/grid/server/power", params))
-
-    def server_delete(self, id):
-        params = {'id': id}
-        return Response(self.make_request("/grid/server/delete", params))
-
-class Response(object):
-    def __init__(self, http_response):
-        if int(http_response.status) == 403:
-            raise InvalidCredsException()
-        self.http_response = http_response
-        self.http_xml = http_response.read()
-
-    def is_error(self):
-        root = ET.XML(self.http_xml)
-        return root.find('response').get('status') != 'success'
-
-    def get_error(self):
-        attrs = ET.XML(self.http_xml).findall('.//attribute')
-        return ': '.join([attr.text for attr in attrs])
-
-STATE = {
-    "Started": NodeState.RUNNING,
-}
-
-class GoGridNodeDriver(object):
-
-    implements(INodeDriver)
-
-    def __init__(self, creds):
-        self.creds = creds
-        self.api = GoGridAuthConnection(creds.key, creds.secret)
-
-    def _findtext(self, element, xpath):
-        return element.findtext(xpath)
-
-    def _findattr(self, element, xpath):
-        return element.findtext(xpath)
+    _instance_types = GOGRID_INSTANCE_TYPES
 
     def get_state(self, element):
         try:
-            for stanza in element.findall("object/attribute"):
-                if stanza.get('name') == "name":
-                    return STATE[stanza.get('name')]
+            return STATE[element['state']['name']]
         except:
             pass
         return NodeState.UNKNOWN
 
-    def section(self, element, name):
-        return element.get('name') == name
-
-    def section_in(self, element, names):
-        return element.get('name') in names
-
     def get_ip(self, element):
-        for stanza in element.getchildren():
-            for ips in stanza.getchildren():
-                if ips.get('name') == "ip":
-                    return ips.text
-        raise Exception("No ipaddress found!")
-
-    def get_deepattr(self, element, node_attrs):
-        if len(element.getchildren()) > 1:
-            i = 0
-            for obj in element.getchildren():
-                name = "%s_%d" %(element.get('name'), i)
-                for attr in obj.getchildren():
-                    node_attrs[name+"_"+attr.get("name")] = attr.text
-                i += 1
-        else:
-            for obj in element.getchildren():
-                name = element.get('name')
-                for attr in obj.getchildren():
-                    node_attrs[name+"_"+attr.get("name")] = attr.text
-            
+        return element['ip']['ip']
 
+    def get_id(self,element):
+        return element.get('id',None)
 
     def _to_node(self, element):
-        attrs = ['id', 'name', 'description', ]
-        deepattrs = ['ram', 'image', 'type', 'os']
-        node_attrs = {}
-        for shard in element.findall('attribute'):
-
-            if self.section(shard, 'state'):
-                state = self.get_state(shard)
-
-            elif self.section(shard, 'ip'):
-                node_attrs['ip'] = self.get_ip(shard)
-
-            elif self.section_in(shard, attrs):
-                node_attrs[shard.get('name')] = shard.text
-
-            elif self.section_in(shard, deepattrs):
-                self.get_deepattr(shard, node_attrs)
-
-        n = Node(uuid=self.get_uuid(node_attrs['id']),
-                 name=node_attrs['name'],
+        state = self.get_state(element)
+        ip = self.get_ip(element)
+        id = self.get_id(element)
+        n = GoGridNode(id=id,
+                 name=element['name'],
                  state=state,
-                 ipaddress=node_attrs['ip'],
-                 creds=self.creds,
-                 attrs=node_attrs)
+                 public_ip=ip,
+                 private_ip=ip,
+                 driver=self.connection.driver)
+        return n
+
+    def _to_image(self, element):
+        n = NodeImage(id=element['id'],
+                      name=element['friendlyName'],
+                      driver=self.connection.driver)
         return n
 
+    def _to_images(self, object):
+        return [ self._to_image(el)
+                 for el in object['list'] ]
+
+    def list_images(self):
+        images = self._to_images(
+                    self.connection.request('/api/grid/image/list').object)
+        return images
+
     def get_uuid(self, field):
-        uuid_str = "%s:%d" % (field,self.creds.provider)
+        uuid_str = "%s:%s" % (field,self.connection.user_id)
         return hashlib.sha1(uuid_str).hexdigest()
-    
+
     def list_nodes(self):
-        res = self.api.server_list()
+        res = self.server_list()
         return [ self._to_node(el)
                  for el
-                 in ET.XML(res.http_xml).findall('response/list/object') ]
+                 in res['list'] ]
 
     def reboot_node(self, node):
-        id = node.attrs['id']
+        id = node.id
         power = 'restart'
-
-        res = self.api.server_power(id, power)
-        if res.is_error():
-            raise Exception(res.get_error())
-
+        res = self.server_power(id, power)
+        if not res.success():
+            raise Exception(res.parse_error())
         return True
 
     def destroy_node(self, node):
         id = node.attrs['id']
+        res = self.server_delete(id)
+        if not res.success():
+            raise Exception(res.parse_error())
+        return True
 
-        res = self.api.server_delete(id)
-        if res.is_error():
-            raise Exception(res.get_error())
+    def server_list(self):
+        return self.connection.request('/api/grid/server/list').object
 
-        return True
+    def server_power(self, id, power):
+        # power in ['start', 'stop', 'restart']
+        params = {'id': id, 'power': power}
+        return self.connection.request("/api/grid/server/power", params)
+
+    def server_delete(self, id):
+        params = {'id': id}
+        return self.connection.request("/api/grid/server/delete", params).object
+
+    def get_first_ip(self):
+        params = {'ip.state': 'Unassigned', 'ip.type':'public'}
+        object = self.connection.request("/api/grid/ip/list", params).object
+        return object['list'][0]['ip']
+
+    def list_sizes(self):
+        return [ NodeSize(driver=self.connection.driver, **i) 
+                    for i in self._instance_types.values() ]
+
+    def create_node(self, **kwargs):
+        name = kwargs['name']
+        image = kwargs['iamge']
+        size = kwargs['size']
+        first_ip = self.get_first_ip()
+        params = {'name': name,
+                  'image': image.id,
+                  'description': kwargs.get('description',''),
+                  'server.ram': size.id,
+                  'ip':first_ip}
+
+        object = self.connection.request('/api/grid/server/add', params=params).object
+        node = self._to_node(object['list'][0])
+
+        return node

Modified: incubator/libcloud/trunk/libcloud/providers.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/providers.py?rev=895841&r1=895840&r2=895841&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/providers.py (original)
+++ incubator/libcloud/trunk/libcloud/providers.py Tue Jan  5 01:27:24 2010
@@ -24,8 +24,8 @@
         ('libcloud.drivers.ec2', 'EC2NodeDriver'),
     Provider.EC2_EU:
         ('libcloud.drivers.ec2', 'EC2EUNodeDriver'),
-#    Provider.GOGRID:
-#        ('libcloud.drivers.gogrid', 'GoGridNodeDriver'),
+    Provider.GOGRID:
+        ('libcloud.drivers.gogrid', 'GoGridNodeDriver'),
     Provider.RACKSPACE:
         ('libcloud.drivers.rackspace', 'RackspaceNodeDriver'),
     Provider.SLICEHOST: