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)