Hi,

Here is a patch that includes the framework for the new IBM Developer Cloud
adapter.  For proof of concept, I've implemented list_nodes, list_images,
list_sizes, and list_locations.  I've included the patch as an attachment,
so I may need to follow up with the patch directly embedded.

Thanks,
Eric Woods
[email protected]
Index: .project
===================================================================
--- .project    (revision 0)
+++ .project    (revision 0)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>libcloud</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.python.pydev.PyDevBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       
<name>org.eclipse.wst.common.project.facet.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+               <nature>org.python.pydev.pythonNature</nature>
+       </natures>
+</projectDescription>
Index: .pydevproject
===================================================================
--- .pydevproject       (revision 0)
+++ .pydevproject       (revision 0)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property 
name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 
2.6</pydev_property>
+</pydev_project>
Index: libcloud/providers.py
===================================================================
--- libcloud/providers.py       (revision 929707)
+++ libcloud/providers.py       (working copy)
@@ -43,6 +43,8 @@
         ('libcloud.drivers.voxel', 'VoxelNodeDriver'),
     Provider.SOFTLAYER:
         ('libcloud.drivers.softlayer', 'SoftLayerNodeDriver'),
+    Provider.IBM:
+        ('libcloud.drivers.ibm', 'IBMNodeDriver')
 }
 
 def get_driver(provider):
Index: libcloud/types.py
===================================================================
--- libcloud/types.py   (revision 929707)
+++ libcloud/types.py   (working copy)
@@ -47,6 +47,7 @@
     EC2_US_WEST = 10
     VOXEL = 11
     SOFTLAYER = 12
+    IBM = 13
 
 class NodeState(object):
     """
Index: libcloud/drivers/ibm.py
===================================================================
--- libcloud/drivers/ibm.py     (revision 0)
+++ libcloud/drivers/ibm.py     (revision 0)
@@ -0,0 +1,131 @@
+# 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.
+# libcloud.org 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.
+# Copyright 2009 RedRata Ltd
+"""
+Driver for the IBM Developer Cloud.
+"""
+from libcloud.types import NodeState, InvalidCredsException, Provider
+from libcloud.base import Response, ConnectionUserAndKey, NodeDriver, Node, 
NodeImage, NodeSize, NodeLocation
+import base64
+
+from xml.etree import ElementTree as ET
+
+HOST = 'www-180.ibm.com'
+REST_BASE = '/cloud/developer/api/rest/20090403'
+
+class IBMResponse(Response):
+    def success(self):
+        return int(self.status) == 200
+    
+    def parse_body(self):
+        if not self.body:
+            return None
+        return ET.XML(self.body)
+    
+    def parse_error(self):
+        return "Oh noes!  We encountered an error!"
+
+class IBMConnection(ConnectionUserAndKey):
+    """
+    Handles the connection to the IBM Developer Cloud.
+    """
+    host = HOST
+    responseCls = IBMResponse
+    
+    def add_default_headers(self, headers):
+        headers['Accept'] = 'text/xml'
+        headers['Authorization'] = ('Basic %s'
+                      % (base64.b64encode('%s:%s' % (self.user_id, self.key))))
+        return headers
+
+class IBMNodeDriver(NodeDriver):    
+    """
+    IBM Developer Cloud node driver.
+    """
+    connectionCls = IBMConnection
+    type = Provider.IBM
+    name = "IBM Developer Cloud"
+    
+    NODE_STATE_MAP = { 0: NodeState.PENDING,
+                       1: NodeState.PENDING,
+                       2: NodeState.TERMINATED,
+                       3: NodeState.TERMINATED,
+                       4: NodeState.TERMINATED,
+                       5: NodeState.RUNNING,
+                       6: NodeState.UNKNOWN,
+                       7: NodeState.PENDING,
+                       8: NodeState.REBOOTING,
+                       9: NodeState.PENDING,
+                       10: NodeState.PENDING,
+                       11: NodeState.TERMINATED }
+    
+    def create_node(self, **kwargs):
+        pass
+    
+    def destroy_node(self, node):
+        pass
+    
+    def reboot_node(self, node):
+        pass
+        
+    def deploy_node(self, **kwargs):
+        pass
+    
+    def list_nodes(self):
+        return self._to_nodes(self.connection.request(REST_BASE + 
'/instances').object)
+    
+    def list_images(self, location = None):
+        return self._to_images(self.connection.request(REST_BASE + 
'/images').object)
+    
+    def list_sizes(self, location = None):
+        # IBM Developer Cloud instances currently support SMALL, MEDIUM, and
+        # LARGE.  Storage also supports SMALL, MEDIUM, and LARGE.
+        # Can retrieve these dynamically from GET /locations.
+        return [ NodeSize(0, 'SMALL', None, None, None, None, 
self.connection.driver),
+                 NodeSize(1, 'MEDIUM', None, None, None, None, 
self.connection.driver),
+                 NodeSize(2, 'LARGE', None, None, None, None, 
self.connection.driver) ]
+    
+    def list_locations(self):
+        return self._to_locations(self.connection.request(REST_BASE + 
'/locations').object)
+    
+    def _to_nodes(self, object):
+        return [ self._to_node(instance) for instance in 
object.findall('Instance') ]
+            
+            
+    def _to_node(self, instance):
+        return Node(id = instance.findtext('ID'),
+                    name = instance.findtext('Name'),
+                    state = 
self.NODE_STATE_MAP[int(instance.findtext('Status'))],
+                    public_ip = instance.findtext('IP'),
+                    private_ip = instance.findtext('IP'),
+                    driver = self.connection.driver)
+        
+    def _to_images(self, object):
+        return [ self._to_image(image) for image in object.findall('Image') ]
+    
+    def _to_image(self, image):
+        return NodeImage(id = image.findtext('ID'),
+                         name = image.findtext('Name'),
+                         driver = self.connection.driver)
+        
+    def _to_locations(self, object):
+        return [ self._to_location(location) for location in 
object.findall('Location') ]
+    
+    def _to_location(self, location):
+        # NOTE: country currently hardcoded
+        return NodeLocation(id = location.findtext('ID'),
+                            name = location.findtext('Name'),
+                            country = 'USA',
+                            driver = self.connection.driver)

Reply via email to