You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2011/03/08 00:44:12 UTC

svn commit: r1079029 [5/13] - in /incubator/libcloud/trunk: ./ demos/ dist/ libcloud/ libcloud/common/ libcloud/compute/ libcloud/compute/drivers/ libcloud/drivers/ libcloud/storage/ libcloud/storage/drivers/ test/ test/compute/ test/compute/fixtures/ ...

Added: incubator/libcloud/trunk/libcloud/compute/drivers/softlayer.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/drivers/softlayer.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/drivers/softlayer.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/drivers/softlayer.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,442 @@
+# 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.
+"""
+Softlayer driver
+"""
+
+import time
+import xmlrpclib
+
+import libcloud
+
+from libcloud.common.types import InvalidCredsError, LibcloudError
+from libcloud.compute.types import Provider, NodeState
+from libcloud.compute.base import NodeDriver, Node, NodeLocation, NodeSize, NodeImage
+
+DATACENTERS = {
+    'sea01': {'country': 'US'},
+    'wdc01': {'country': 'US'},
+    'dal01': {'country': 'US'}
+}
+
+NODE_STATE_MAP = {
+    'RUNNING': NodeState.RUNNING,
+    'HALTED': NodeState.TERMINATED,
+    'PAUSED': NodeState.TERMINATED,
+}
+
+DEFAULT_PACKAGE = 46
+
+SL_IMAGES = [
+    {'id': 1684, 'name': 'CentOS 5 - Minimal Install (32 bit)'},
+    {'id': 1685, 'name': 'CentOS 5 - Minimal Install (64 bit)'},
+    {'id': 1686, 'name': 'CentOS 5 - LAMP Install (32 bit)'},
+    {'id': 1687, 'name': 'CentOS 5 - LAMP Install (64 bit)'},
+    {'id': 1688, 'name': 'Red Hat Enterprise Linux 5 - Minimal Install (32 bit)'},
+    {'id': 1689, 'name': 'Red Hat Enterprise Linux 5 - Minimal Install (64 bit)'},
+    {'id': 1690, 'name': 'Red Hat Enterprise Linux 5 - LAMP Install (32 bit)'},
+    {'id': 1691, 'name': 'Red Hat Enterprise Linux 5 - LAMP Install (64 bit)'},
+    {'id': 1692, 'name': 'Ubuntu Linux 8 LTS Hardy Heron - Minimal Install (32 bit)'},
+    {'id': 1693, 'name': 'Ubuntu Linux 8 LTS Hardy Heron - Minimal Install (64 bit)'},
+    {'id': 1694, 'name': 'Ubuntu Linux 8 LTS Hardy Heron - LAMP Install (32 bit)'},
+    {'id': 1695, 'name': 'Ubuntu Linux 8 LTS Hardy Heron - LAMP Install (64 bit)'},
+    {'id': 1696, 'name': 'Debian GNU/Linux 5.0 Lenny/Stable - Minimal Install (32 bit)'},
+    {'id': 1697, 'name': 'Debian GNU/Linux 5.0 Lenny/Stable - Minimal Install (64 bit)'},
+    {'id': 1698, 'name': 'Debian GNU/Linux 5.0 Lenny/Stable - LAMP Install (32 bit)'},
+    {'id': 1699, 'name': 'Debian GNU/Linux 5.0 Lenny/Stable - LAMP Install (64 bit)'},
+    {'id': 1700, 'name': 'Windows Server 2003 Standard SP2 with R2 (32 bit)'},
+    {'id': 1701, 'name': 'Windows Server 2003 Standard SP2 with R2 (64 bit)'},
+    {'id': 1703, 'name': 'Windows Server 2003 Enterprise SP2 with R2 (64 bit)'},
+    {'id': 1705, 'name': 'Windows Server 2008 Standard Edition (64bit)'},
+    {'id': 1715, 'name': 'Windows Server 2003 Datacenter SP2 (64 bit)'},
+    {'id': 1716, 'name': 'Windows Server 2003 Datacenter SP2 (32 bit)'},
+    {'id': 1742, 'name': 'Windows Server 2008 Standard Edition SP2 (32bit)'},
+    {'id': 1752, 'name': 'Windows Server 2008 Standard Edition SP2 (64bit)'},
+    {'id': 1756, 'name': 'Windows Server 2008 Enterprise Edition SP2 (32bit)'},
+    {'id': 1761, 'name': 'Windows Server 2008 Enterprise Edition SP2 (64bit)'},
+    {'id': 1766, 'name': 'Windows Server 2008 Datacenter Edition SP2 (32bit)'},
+    {'id': 1770, 'name': 'Windows Server 2008 Datacenter Edition SP2 (64bit)'},
+    {'id': 1857, 'name': 'Windows Server 2008 R2 Standard Edition (64bit)'},
+    {'id': 1860, 'name': 'Windows Server 2008 R2 Enterprise Edition (64bit)'},
+    {'id': 1863, 'name': 'Windows Server 2008 R2 Datacenter Edition (64bit)'},
+]
+
+"""
+The following code snippet will print out all available "prices"
+    mask = { 'items': '' }
+    res = self.connection.request(
+        "SoftLayer_Product_Package",
+        "getObject",
+        res,
+        id=46,
+        object_mask=mask
+    )
+
+    from pprint import pprint; pprint(res)
+"""
+SL_TEMPLATES = {
+    'sl1': {
+        'imagedata': {
+            'name': '2 x 2.0 GHz, 1GB ram, 100GB',
+            'ram': 1024,
+            'disk': 100,
+            'bandwidth': None
+        },
+        'prices': [
+            {'id': 1644}, # 1 GB
+            {'id': 1639}, # 100 GB (SAN)
+            {'id': 1963}, # Private 2 x 2.0 GHz Cores
+            {'id': 21}, # 1 IP Address
+            {'id': 55}, # Host Ping
+            {'id': 58}, # Automated Notification
+            {'id': 1800}, # 0 GB Bandwidth
+            {'id': 57}, # Email and Ticket
+            {'id': 274}, # 1000 Mbps Public & Private Networks
+            {'id': 905}, # Reboot / Remote Console
+            {'id': 418}, # Nessus Vulnerability Assessment & Reporting
+            {'id': 420}, # Unlimited SSL VPN Users & 1 PPTP VPN User per account
+        ],
+    },
+    'sl2': {
+        'imagedata': {
+            'name': '2 x 2.0 GHz, 4GB ram, 350GB',
+            'ram': 4096,
+            'disk': 350,
+            'bandwidth': None
+        },
+        'prices': [
+            {'id': 1646}, # 4 GB
+            {'id': 1639}, # 100 GB (SAN) - This is the only available "First Disk"
+            {'id': 1638}, # 250 GB (SAN)
+            {'id': 1963}, # Private 2 x 2.0 GHz Cores
+            {'id': 21}, # 1 IP Address
+            {'id': 55}, # Host Ping
+            {'id': 58}, # Automated Notification
+            {'id': 1800}, # 0 GB Bandwidth
+            {'id': 57}, # Email and Ticket
+            {'id': 274}, # 1000 Mbps Public & Private Networks
+            {'id': 905}, # Reboot / Remote Console
+            {'id': 418}, # Nessus Vulnerability Assessment & Reporting
+            {'id': 420}, # Unlimited SSL VPN Users & 1 PPTP VPN User per account
+        ],
+    }
+}
+
+class SoftLayerException(LibcloudError):
+    """
+    Exception class for SoftLayer driver
+    """
+    pass
+
+class SoftLayerSafeTransport(xmlrpclib.SafeTransport):
+    pass
+
+class SoftLayerTransport(xmlrpclib.Transport):
+    pass
+
+class SoftLayerProxy(xmlrpclib.ServerProxy):
+    transportCls = (SoftLayerTransport, SoftLayerSafeTransport)
+    API_PREFIX = "http://api.service.softlayer.com/xmlrpc/v3"
+
+    def __init__(self, service, user_agent, verbose=0):
+        cls = self.transportCls[0]
+        if SoftLayerProxy.API_PREFIX[:8] == "https://":
+            cls = self.transportCls[1]
+        t = cls(use_datetime=0)
+        t.user_agent = user_agent
+        xmlrpclib.ServerProxy.__init__(
+            self,
+            uri="%s/%s" % (SoftLayerProxy.API_PREFIX, service),
+            transport=t,
+            verbose=verbose
+        )
+
+class SoftLayerConnection(object):
+    """
+    Connection class for the SoftLayer driver
+    """
+
+    proxyCls = SoftLayerProxy
+    driver = None
+
+    def __init__(self, user, key):
+        self.user = user
+        self.key = key
+        self.ua = []
+
+    def request(self, service, method, *args, **kwargs):
+        sl = self.proxyCls(service, self._user_agent())
+
+        headers = {}
+        headers.update(self._get_auth_headers())
+        headers.update(self._get_init_params(service, kwargs.get('id')))
+        headers.update(self._get_object_mask(service, kwargs.get('object_mask')))
+        params = [{'headers': headers}] + list(args)
+
+        try:
+            return getattr(sl, method)(*params)
+        except xmlrpclib.Fault, e:
+            if e.faultCode == "SoftLayer_Account":
+                raise InvalidCredsError(e.faultString)
+            raise SoftLayerException(e)
+
+    def _user_agent(self):
+        return 'libcloud/%s (%s)%s' % (
+                libcloud.__version__,
+                self.driver.name,
+                "".join([" (%s)" % x for x in self.ua]))
+
+    def user_agent_append(self, s):
+        self.ua.append(s)
+
+    def _get_auth_headers(self):
+        return {
+            'authenticate': {
+                'username': self.user,
+                'apiKey': self.key
+            }
+        }
+
+    def _get_init_params(self, service, id):
+        if id is not None:
+            return {
+                '%sInitParameters' % service: {'id': id}
+            }
+        else:
+            return {}
+
+    def _get_object_mask(self, service, mask):
+        if mask is not None:
+            return {
+                '%sObjectMask' % service: {'mask': mask}
+            }
+        else:
+            return {}
+
+class SoftLayerNodeDriver(NodeDriver):
+    """
+    SoftLayer node driver
+
+    Extra node attributes:
+        - password: root password
+        - hourlyRecurringFee: hourly price (if applicable)
+        - recurringFee      : flat rate    (if applicable)
+        - recurringMonths   : The number of months in which the recurringFee will be incurred.
+    """
+    connectionCls = SoftLayerConnection
+    name = 'SoftLayer'
+    type = Provider.SOFTLAYER
+
+    features = {"create_node": ["generates_password"]}
+
+    def __init__(self, key, secret=None, secure=False):
+        self.key = key
+        self.secret = secret
+        self.connection = self.connectionCls(key, secret)
+        self.connection.driver = self
+
+    def _to_node(self, host):
+        try:
+            password = host['softwareComponents'][0]['passwords'][0]['password']
+        except (IndexError, KeyError):
+            password = None
+
+        hourlyRecurringFee = host.get('billingItem', {}).get('hourlyRecurringFee', 0)
+        recurringFee       = host.get('billingItem', {}).get('recurringFee', 0)
+        recurringMonths    = host.get('billingItem', {}).get('recurringMonths', 0)
+
+        return Node(
+            id=host['id'],
+            name=host['hostname'],
+            state=NODE_STATE_MAP.get(
+                host['powerState']['keyName'],
+                NodeState.UNKNOWN
+            ),
+            public_ip=[host['primaryIpAddress']],
+            private_ip=[host['primaryBackendIpAddress']],
+            driver=self,
+            extra={
+                'password': password,
+                'hourlyRecurringFee': hourlyRecurringFee,
+                'recurringFee': recurringFee,
+                'recurringMonths': recurringMonths,
+            }
+        )
+
+    def _to_nodes(self, hosts):
+        return [self._to_node(h) for h in hosts]
+
+    def destroy_node(self, node):
+        billing_item = self.connection.request(
+            "SoftLayer_Virtual_Guest",
+            "getBillingItem",
+            id=node.id
+        )
+
+        if billing_item:
+            res = self.connection.request(
+                "SoftLayer_Billing_Item",
+                "cancelService",
+                id=billing_item['id']
+            )
+            return res
+        else:
+            return False
+
+    def _get_order_information(self, order_id, timeout=1200, check_interval=5):
+        mask = {
+            'orderTopLevelItems': {
+                'billingItem':  {
+                    'resource': {
+                        'softwareComponents': {
+                            'passwords': ''
+                        },
+                        'powerState': '',
+                    }
+                },
+            }
+         }
+
+        for i in range(0, timeout, check_interval):
+            try:
+                res = self.connection.request(
+                    "SoftLayer_Billing_Order",
+                    "getObject",
+                    id=order_id,
+                    object_mask=mask
+                )
+                item = res['orderTopLevelItems'][0]['billingItem']['resource']
+                if item['softwareComponents'][0]['passwords']:
+                    return item
+
+            except (KeyError, IndexError):
+                pass
+
+            time.sleep(check_interval)
+
+        return None
+
+    def create_node(self, **kwargs):
+        """Create a new SoftLayer node
+
+        See L{NodeDriver.create_node} for more keyword args.
+        @keyword    ex_domain: e.g. libcloud.org
+        @type       ex_domain: C{string}
+        """
+        name = kwargs['name']
+        image = kwargs['image']
+        size = kwargs['size']
+        domain = kwargs.get('ex_domain')
+        location = kwargs['location']
+        if domain == None:
+            if name.find(".") != -1:
+                domain = name[name.find('.')+1:]
+
+        if domain == None:
+            # TODO: domain is a required argument for the Sofylayer API, but it
+            # it shouldn't be.
+            domain = "exmaple.com"
+
+        res = {'prices': SL_TEMPLATES[size.id]['prices']}
+        res['packageId'] = DEFAULT_PACKAGE
+        res['prices'].append({'id': image.id})  # Add OS to order
+        res['location'] = location.id
+        res['complexType'] = 'SoftLayer_Container_Product_Order_Virtual_Guest'
+        res['quantity'] = 1
+        res['useHourlyPricing'] = True
+        res['virtualGuests'] = [
+            {
+                'hostname': name,
+                'domain': domain
+            }
+        ]
+
+        res = self.connection.request(
+            "SoftLayer_Product_Order",
+            "placeOrder",
+            res
+        )
+
+        order_id = res['orderId']
+        raw_node = self._get_order_information(order_id)
+
+        return self._to_node(raw_node)
+
+    def _to_image(self, img):
+        return NodeImage(
+            id=img['id'],
+            name=img['name'],
+            driver=self.connection.driver
+        )
+
+    def list_images(self, location=None):
+        return [self._to_image(i) for i in SL_IMAGES]
+
+    def _to_size(self, id, size):
+        return NodeSize(
+            id=id,
+            name=size['name'],
+            ram=size['ram'],
+            disk=size['disk'],
+            bandwidth=size['bandwidth'],
+            price=None,
+            driver=self.connection.driver,
+        )
+
+    def list_sizes(self, location=None):
+        return [self._to_size(id, s['imagedata']) for id, s in SL_TEMPLATES.iteritems()]
+
+    def _to_loc(self, loc):
+        return NodeLocation(
+            id=loc['id'],
+            name=loc['name'],
+            country=DATACENTERS[loc['name']]['country'],
+            driver=self
+        )
+
+    def list_locations(self):
+        res = self.connection.request(
+            "SoftLayer_Location_Datacenter",
+            "getDatacenters"
+        )
+
+        # checking "in DATACENTERS", because some of the locations returned by getDatacenters are not useable.
+        return [self._to_loc(l) for l in res if l['name'] in DATACENTERS]
+
+    def list_nodes(self):
+        mask = {
+            'virtualGuests': {
+                'powerState': '',
+                'softwareComponents': {
+                    'passwords': ''
+                },
+                'billingItem': '',
+            },
+        }
+        res = self.connection.request(
+            "SoftLayer_Account",
+            "getVirtualGuests",
+            object_mask=mask
+        )
+        nodes = self._to_nodes(res)
+        return nodes
+
+    def reboot_node(self, node):
+        res = self.connection.request(
+            "SoftLayer_Virtual_Guest",
+            "rebootHard",
+            id=node.id
+        )
+        return res

Added: incubator/libcloud/trunk/libcloud/compute/drivers/vcloud.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/drivers/vcloud.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/drivers/vcloud.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/drivers/vcloud.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,624 @@
+# 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.
+"""
+VMware vCloud driver.
+"""
+import base64
+import httplib
+import time
+
+from urlparse import urlparse
+from xml.etree import ElementTree as ET
+from xml.parsers.expat import ExpatError
+
+from libcloud.common.base import Response, ConnectionUserAndKey
+from libcloud.common.types import InvalidCredsError
+from libcloud.compute.providers import Provider
+from libcloud.compute.types import NodeState
+from libcloud.compute.base import Node, NodeDriver, NodeLocation
+from libcloud.compute.base import NodeSize, NodeImage, NodeAuthPassword
+
+"""
+From vcloud api "The VirtualQuantity element defines the number of MB
+of memory. This should be either 512 or a multiple of 1024 (1 GB)."
+"""
+VIRTUAL_MEMORY_VALS = [512] + [1024 * i for i in range(1,9)]
+
+DEFAULT_TASK_COMPLETION_TIMEOUT = 600
+
+def get_url_path(url):
+    return urlparse(url.strip()).path
+
+def fixxpath(root, xpath):
+    """ElementTree wants namespaces in its xpaths, so here we add them."""
+    namespace, root_tag = root.tag[1:].split("}", 1)
+    fixed_xpath = "/".join(["{%s}%s" % (namespace, e)
+                            for e in xpath.split("/")])
+    return fixed_xpath
+
+class InstantiateVAppXML(object):
+
+    def __init__(self, name, template, net_href, cpus, memory,
+                 password=None, row=None, group=None):
+        self.name = name
+        self.template = template
+        self.net_href = net_href
+        self.cpus = cpus
+        self.memory = memory
+        self.password = password
+        self.row = row
+        self.group = group
+
+        self._build_xmltree()
+
+    def tostring(self):
+        return ET.tostring(self.root)
+
+    def _build_xmltree(self):
+        self.root = self._make_instantiation_root()
+
+        self._add_vapp_template(self.root)
+        instantionation_params = ET.SubElement(self.root,
+                                               "InstantiationParams")
+
+        # product and virtual hardware
+        self._make_product_section(instantionation_params)
+        self._make_virtual_hardware(instantionation_params)
+
+        network_config_section = ET.SubElement(instantionation_params,
+                                               "NetworkConfigSection")
+
+        network_config = ET.SubElement(network_config_section,
+                                       "NetworkConfig")
+        self._add_network_association(network_config)
+
+    def _make_instantiation_root(self):
+        return ET.Element(
+            "InstantiateVAppTemplateParams",
+            {'name': self.name,
+             'xml:lang': 'en',
+             'xmlns': "http://www.vmware.com/vcloud/v0.8",
+             'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance"}
+        )
+
+    def _add_vapp_template(self, parent):
+        return ET.SubElement(
+            parent,
+            "VAppTemplate",
+            {'href': self.template}
+        )
+
+    def _make_product_section(self, parent):
+        prod_section = ET.SubElement(
+            parent,
+            "ProductSection",
+            {'xmlns:q1': "http://www.vmware.com/vcloud/v0.8",
+             'xmlns:ovf': "http://schemas.dmtf.org/ovf/envelope/1"}
+        )
+
+        if self.password:
+            self._add_property(prod_section, 'password', self.password)
+
+        if self.row:
+            self._add_property(prod_section, 'row', self.row)
+
+        if self.group:
+            self._add_property(prod_section, 'group', self.group)
+
+        return prod_section
+
+    def _add_property(self, parent, ovfkey, ovfvalue):
+        return ET.SubElement(
+            parent,
+            "Property",
+            {'xmlns': 'http://schemas.dmtf.org/ovf/envelope/1',
+             'ovf:key': ovfkey,
+             'ovf:value': ovfvalue}
+        )
+
+    def _make_virtual_hardware(self, parent):
+        vh = ET.SubElement(
+            parent,
+            "VirtualHardwareSection",
+            {'xmlns:q1': "http://www.vmware.com/vcloud/v0.8"}
+        )
+
+        self._add_cpu(vh)
+        self._add_memory(vh)
+
+        return vh
+
+    def _add_cpu(self, parent):
+        cpu_item = ET.SubElement(
+            parent,
+            "Item",
+            {'xmlns': "http://schemas.dmtf.org/ovf/envelope/1"}
+        )
+        self._add_instance_id(cpu_item, '1')
+        self._add_resource_type(cpu_item, '3')
+        self._add_virtual_quantity(cpu_item, self.cpus)
+
+        return cpu_item
+
+    def _add_memory(self, parent):
+        mem_item = ET.SubElement(
+            parent,
+            "Item",
+            {'xmlns': "http://schemas.dmtf.org/ovf/envelope/1"}
+        )
+        self._add_instance_id(mem_item, '2')
+        self._add_resource_type(mem_item, '4')
+        self._add_virtual_quantity(mem_item, self.memory)
+
+        return mem_item
+
+    def _add_instance_id(self, parent, id):
+        elm = ET.SubElement(
+            parent,
+            "InstanceID",
+            {'xmlns': 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData'}
+        )
+        elm.text = id
+        return elm
+
+    def _add_resource_type(self, parent, type):
+        elm = ET.SubElement(
+            parent,
+            "ResourceType",
+            {'xmlns': 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData'}
+        )
+        elm.text = type
+        return elm
+
+    def _add_virtual_quantity(self, parent, amount):
+        elm = ET.SubElement(
+             parent,
+             "VirtualQuantity",
+             {'xmlns': 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData'}
+         )
+        elm.text = amount
+        return elm
+
+    def _add_network_association(self, parent):
+        return ET.SubElement(
+            parent,
+            "NetworkAssociation",
+            {'href': self.net_href}
+        )
+
+class VCloudResponse(Response):
+
+    def parse_body(self):
+        if not self.body:
+            return None
+        try:
+            return ET.XML(self.body)
+        except ExpatError, e:
+            raise Exception("%s: %s" % (e, self.parse_error()))
+
+    def parse_error(self):
+        return self.error
+
+    def success(self):
+        return self.status in (httplib.OK, httplib.CREATED,
+                               httplib.NO_CONTENT, httplib.ACCEPTED)
+
+class VCloudConnection(ConnectionUserAndKey):
+    """
+    Connection class for the vCloud driver
+    """
+
+    responseCls = VCloudResponse
+    token = None
+    host = None
+
+    def request(self, *args, **kwargs):
+        self._get_auth_token()
+        return super(VCloudConnection, self).request(*args, **kwargs)
+
+    def check_org(self):
+        # the only way to get our org is by logging in.
+        self._get_auth_token()
+
+    def _get_auth_headers(self):
+        """Some providers need different headers than others"""
+        return {
+            'Authorization':
+                "Basic %s"
+                % base64.b64encode('%s:%s' % (self.user_id, self.key)),
+            'Content-Length': 0
+        }
+
+    def _get_auth_token(self):
+        if not self.token:
+            conn = self.conn_classes[self.secure](self.host,
+                                                  self.port[self.secure])
+            conn.request(method='POST', url='/api/v0.8/login',
+                         headers=self._get_auth_headers())
+
+            resp = conn.getresponse()
+            headers = dict(resp.getheaders())
+            body = ET.XML(resp.read())
+
+            try:
+                self.token = headers['set-cookie']
+            except KeyError:
+                raise InvalidCredsError()
+
+            self.driver.org = get_url_path(
+                body.find(fixxpath(body, 'Org')).get('href')
+            )
+
+    def add_default_headers(self, headers):
+        headers['Cookie'] = self.token
+        return headers
+
+class VCloudNodeDriver(NodeDriver):
+    """
+    vCloud node driver
+    """
+
+    type = Provider.VCLOUD
+    name = "vCloud"
+    connectionCls = VCloudConnection
+    org = None
+    _vdcs = None
+
+    NODE_STATE_MAP = {'0': NodeState.PENDING,
+                      '1': NodeState.PENDING,
+                      '2': NodeState.PENDING,
+                      '3': NodeState.PENDING,
+                      '4': NodeState.RUNNING}
+
+    @property
+    def vdcs(self):
+        if not self._vdcs:
+            self.connection.check_org() # make sure the org is set.
+            res = self.connection.request(self.org)
+            self._vdcs = [
+                get_url_path(i.get('href'))
+                for i
+                in res.object.findall(fixxpath(res.object, "Link"))
+                if i.get('type') == 'application/vnd.vmware.vcloud.vdc+xml'
+            ]
+
+        return self._vdcs
+
+    @property
+    def networks(self):
+        networks = []
+        for vdc in self.vdcs:
+            res = self.connection.request(vdc).object
+            networks.extend(
+                [network
+                 for network in res.findall(
+                     fixxpath(res, "AvailableNetworks/Network")
+                 )]
+            )
+
+        return networks
+
+    def _to_image(self, image):
+        image = NodeImage(id=image.get('href'),
+                          name=image.get('name'),
+                          driver=self.connection.driver)
+        return image
+
+    def _to_node(self, name, elm):
+        state = self.NODE_STATE_MAP[elm.get('status')]
+        public_ips = []
+        private_ips = []
+
+        # Following code to find private IPs works for Terremark
+        connections = elm.findall('{http://schemas.dmtf.org/ovf/envelope/1}NetworkConnectionSection/{http://www.vmware.com/vcloud/v0.8}NetworkConnection')
+        for connection in connections:
+            ips = [ip.text
+                   for ip
+                   in connection.findall(fixxpath(elm, "IpAddress"))]
+            if connection.get('Network') == 'Internal':
+                private_ips.extend(ips)
+            else:
+                public_ips.extend(ips)
+
+        node = Node(id=elm.get('href'),
+                    name=name,
+                    state=state,
+                    public_ip=public_ips,
+                    private_ip=private_ips,
+                    driver=self.connection.driver)
+
+        return node
+
+    def _get_catalog_hrefs(self):
+        res = self.connection.request(self.org)
+        catalogs = [
+            get_url_path(i.get('href'))
+            for i in res.object.findall(fixxpath(res.object, "Link"))
+            if i.get('type') == 'application/vnd.vmware.vcloud.catalog+xml'
+        ]
+
+        return catalogs
+
+    def _wait_for_task_completion(self, task_href,
+                                  timeout=DEFAULT_TASK_COMPLETION_TIMEOUT):
+        start_time = time.time()
+        res = self.connection.request(task_href)
+        status = res.object.get('status')
+        while status != 'success':
+            if status == 'error':
+                raise Exception("Error status returned by task %s."
+                                % task_href)
+            if status == 'canceled':
+                raise Exception("Canceled status returned by task %s."
+                                % task_href)
+            if (time.time() - start_time >= timeout):
+                raise Exception("Timeout while waiting for task %s."
+                                % task_href)
+            time.sleep(5)
+            res = self.connection.request(task_href)
+            status = res.object.get('status')
+
+    def destroy_node(self, node):
+        node_path = get_url_path(node.id)
+        # blindly poweroff node, it will throw an exception if already off
+        try:
+            res = self.connection.request('%s/power/action/poweroff'
+                                          % node_path,
+                                          method='POST')
+            self._wait_for_task_completion(res.object.get('href'))
+        except Exception:
+            pass
+
+        try:
+            res = self.connection.request('%s/action/undeploy' % node_path,
+                                          method='POST')
+            self._wait_for_task_completion(res.object.get('href'))
+        except ExpatError:
+            # The undeploy response is malformed XML atm.
+            # We can remove this whent he providers fix the problem.
+            pass
+        except Exception:
+            # Some vendors don't implement undeploy at all yet,
+            # so catch this and move on.
+            pass
+
+        res = self.connection.request(node_path, method='DELETE')
+        return res.status == 202
+
+    def reboot_node(self, node):
+        res = self.connection.request('%s/power/action/reset'
+                                      % get_url_path(node.id),
+                                      method='POST')
+        return res.status == 202 or res.status == 204
+
+    def list_nodes(self):
+        nodes = []
+        for vdc in self.vdcs:
+            res = self.connection.request(vdc)
+            elms = res.object.findall(fixxpath(
+                res.object, "ResourceEntities/ResourceEntity")
+            )
+            vapps = [
+                (i.get('name'), get_url_path(i.get('href')))
+                for i in elms
+                if i.get('type')
+                    == 'application/vnd.vmware.vcloud.vApp+xml'
+                    and i.get('name')
+            ]
+
+            for vapp_name, vapp_href in vapps:
+                res = self.connection.request(
+                    vapp_href,
+                    headers={
+                        'Content-Type':
+                            'application/vnd.vmware.vcloud.vApp+xml'
+                    }
+                )
+                nodes.append(self._to_node(vapp_name, res.object))
+
+        return nodes
+
+    def _to_size(self, ram):
+        ns = NodeSize(
+            id=None,
+            name="%s Ram" % ram,
+            ram=ram,
+            disk=None,
+            bandwidth=None,
+            price=None,
+            driver=self.connection.driver
+        )
+        return ns
+
+    def list_sizes(self, location=None):
+        sizes = [self._to_size(i) for i in VIRTUAL_MEMORY_VALS]
+        return sizes
+
+    def _get_catalogitems_hrefs(self, catalog):
+        """Given a catalog href returns contained catalog item hrefs"""
+        res = self.connection.request(
+            catalog,
+            headers={
+                'Content-Type':
+                    'application/vnd.vmware.vcloud.catalog+xml'
+            }
+        ).object
+
+        cat_items = res.findall(fixxpath(res, "CatalogItems/CatalogItem"))
+        cat_item_hrefs = [i.get('href')
+                          for i in cat_items
+                          if i.get('type') ==
+                              'application/vnd.vmware.vcloud.catalogItem+xml']
+
+        return cat_item_hrefs
+
+    def _get_catalogitem(self, catalog_item):
+        """Given a catalog item href returns elementree"""
+        res = self.connection.request(
+            catalog_item,
+            headers={
+                'Content-Type':
+                    'application/vnd.vmware.vcloud.catalogItem+xml'
+            }
+        ).object
+
+        return res
+
+    def list_images(self, location=None):
+        images = []
+        for vdc in self.vdcs:
+            res = self.connection.request(vdc).object
+            res_ents = res.findall(fixxpath(
+                res, "ResourceEntities/ResourceEntity")
+            )
+            images += [
+                self._to_image(i)
+                for i in res_ents
+                if i.get('type') ==
+                    'application/vnd.vmware.vcloud.vAppTemplate+xml'
+            ]
+
+        for catalog in self._get_catalog_hrefs():
+            for cat_item in self._get_catalogitems_hrefs(catalog):
+                res = self._get_catalogitem(cat_item)
+                res_ents = res.findall(fixxpath(res, 'Entity'))
+                images += [
+                    self._to_image(i)
+                    for i in res_ents
+                    if i.get('type') ==
+                        'application/vnd.vmware.vcloud.vAppTemplate+xml'
+                ]
+
+        return images
+
+    def create_node(self, **kwargs):
+        """Creates and returns node.
+
+
+        See L{NodeDriver.create_node} for more keyword args.
+
+        Non-standard optional keyword arguments:
+        @keyword    ex_network: link to a "Network" e.g., "https://services.vcloudexpress.terremark.com/api/v0.8/network/7"
+        @type       ex_network: C{string}
+
+        @keyword    ex_vdc: link to a "VDC" e.g., "https://services.vcloudexpress.terremark.com/api/v0.8/vdc/1"
+        @type       ex_vdc: C{string}
+
+        @keyword    ex_cpus: number of virtual cpus (limit depends on provider)
+        @type       ex_cpus: C{int}
+
+        @keyword    row: ????
+        @type       row: C{????}
+
+        @keyword    group: ????
+        @type       group: C{????}
+        """
+        name = kwargs['name']
+        image = kwargs['image']
+        size = kwargs['size']
+
+        # Some providers don't require a network link
+        try:
+            network = kwargs.get('ex_network', self.networks[0].get('href'))
+        except IndexError:
+            network = ''
+
+        password = None
+        if kwargs.has_key('auth'):
+            auth = kwargs['auth']
+            if isinstance(auth, NodeAuthPassword):
+                password = auth.password
+            else:
+                raise ValueError('auth must be of NodeAuthPassword type')
+
+        instantiate_xml = InstantiateVAppXML(
+            name=name,
+            template=image.id,
+            net_href=network,
+            cpus=str(kwargs.get('ex_cpus', 1)),
+            memory=str(size.ram),
+            password=password,
+            row=kwargs.get('ex_row', None),
+            group=kwargs.get('ex_group', None)
+        )
+
+        # Instantiate VM and get identifier.
+        res = self.connection.request(
+            '%s/action/instantiateVAppTemplate'
+                % kwargs.get('vdc', self.vdcs[0]),
+            data=instantiate_xml.tostring(),
+            method='POST',
+            headers={
+                'Content-Type':
+                    'application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml'
+            }
+        )
+        vapp_name = res.object.get('name')
+        vapp_href = get_url_path(res.object.get('href'))
+
+        # Deploy the VM from the identifier.
+        res = self.connection.request('%s/action/deploy' % vapp_href,
+                                      method='POST')
+
+        self._wait_for_task_completion(res.object.get('href'))
+
+        # Power on the VM.
+        res = self.connection.request('%s/power/action/powerOn' % vapp_href,
+                                      method='POST')
+
+        res = self.connection.request(vapp_href)
+        node = self._to_node(vapp_name, res.object)
+
+        return node
+
+    features = {"create_node": ["password"]}
+
+class HostingComConnection(VCloudConnection):
+    """
+    vCloud connection subclass for Hosting.com
+    """
+
+    host = "vcloud.safesecureweb.com"
+
+    def _get_auth_headers(self):
+        """hosting.com doesn't follow the standard vCloud authentication API"""
+        return {
+            'Authentication':
+                base64.b64encode('%s:%s' % (self.user_id, self.key)),
+            'Content-Length': 0
+        }
+
+class HostingComDriver(VCloudNodeDriver):
+    """
+    vCloud node driver for Hosting.com
+    """
+    connectionCls = HostingComConnection
+
+class TerremarkConnection(VCloudConnection):
+    """
+    vCloud connection subclass for Terremark
+    """
+
+    host = "services.vcloudexpress.terremark.com"
+
+class TerremarkDriver(VCloudNodeDriver):
+    """
+    vCloud node driver for Terremark
+    """
+
+    connectionCls = TerremarkConnection
+
+    def list_locations(self):
+        return [NodeLocation(0, "Terremark Texas", 'US', self)]

Added: incubator/libcloud/trunk/libcloud/compute/drivers/voxel.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/drivers/voxel.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/drivers/voxel.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/drivers/voxel.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,308 @@
+# 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.
+
+"""
+Voxel VoxCloud driver
+"""
+import datetime
+import hashlib
+
+from xml.etree import ElementTree as ET
+
+from libcloud.common.base import Response, ConnectionUserAndKey
+from libcloud.common.types import InvalidCredsError
+from libcloud.compute.providers import Provider
+from libcloud.compute.types import NodeState
+from libcloud.compute.base import Node, NodeDriver
+from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
+
+VOXEL_API_HOST = "api.voxel.net"
+
+class VoxelResponse(Response):
+
+    def __init__(self, response):
+        self.parsed = None
+        super(VoxelResponse, self).__init__(response)
+
+    def parse_body(self):
+        if not self.body:
+            return None
+        if not self.parsed:
+            self.parsed = ET.XML(self.body)
+        return self.parsed
+
+    def parse_error(self):
+        err_list = []
+        if not self.body:
+            return None
+        if not self.parsed:
+            self.parsed = ET.XML(self.body)
+        for err in self.parsed.findall('err'):
+            code = err.get('code')
+            err_list.append("(%s) %s" % (code, err.get('msg')))
+            # From voxel docs:
+            # 1: Invalid login or password
+            # 9: Permission denied: user lacks access rights for this method
+            if code == "1" or code == "9":
+                # sucks, but only way to detect
+                # bad authentication tokens so far
+                raise InvalidCredsError(err_list[-1])
+        return "\n".join(err_list)
+
+    def success(self):
+        if not self.parsed:
+            self.parsed = ET.XML(self.body)
+        stat = self.parsed.get('stat')
+        if stat != "ok":
+            return False
+        return True
+
+class VoxelConnection(ConnectionUserAndKey):
+    """
+    Connection class for the Voxel driver
+    """
+
+    host = VOXEL_API_HOST
+    responseCls = VoxelResponse
+
+    def add_default_params(self, params):
+        params["key"] = self.user_id
+        params["timestamp"] = datetime.datetime.utcnow().isoformat()+"+0000"
+
+        for param in params.keys():
+            if params[param] is None:
+                del params[param]
+
+        keys = params.keys()
+        keys.sort()
+
+        md5 = hashlib.md5()
+        md5.update(self.key)
+        for key in keys:
+            if params[key]:
+                if not params[key] is None:
+                    md5.update("%s%s"% (key, params[key]))
+                else:
+                    md5.update(key)
+        params['api_sig'] = md5.hexdigest()
+        return params
+
+VOXEL_INSTANCE_TYPES = {}
+RAM_PER_CPU = 2048
+
+NODE_STATE_MAP = {
+    'IN_PROGRESS': NodeState.PENDING,
+    'QUEUED': NodeState.PENDING,
+    'SUCCEEDED': NodeState.RUNNING,
+    'shutting-down': NodeState.TERMINATED,
+    'terminated': NodeState.TERMINATED,
+    'unknown': NodeState.UNKNOWN,
+}
+
+class VoxelNodeDriver(NodeDriver):
+    """
+    Voxel VoxCLOUD node driver
+    """
+
+    connectionCls = VoxelConnection
+    type = Provider.VOXEL
+    name = 'Voxel VoxCLOUD'
+
+    def _initialize_instance_types():
+        for cpus in range(1,14):
+            if cpus == 1:
+                name = "Single CPU"
+            else:
+                name = "%d CPUs" % cpus
+            id = "%dcpu" % cpus
+            ram = cpus * RAM_PER_CPU
+
+            VOXEL_INSTANCE_TYPES[id]= {
+                         'id': id,
+                         'name': name,
+                         'ram': ram,
+                         'disk': None,
+                         'bandwidth': None,
+                         'price': None}
+
+    features = {"create_node": [],
+                "list_sizes":  ["variable_disk"]}
+
+    _initialize_instance_types()
+
+    def list_nodes(self):
+        params = {"method": "voxel.devices.list"}
+        result = self.connection.request('/', params=params).object
+        return self._to_nodes(result)
+
+    def list_sizes(self, location=None):
+        return [ NodeSize(driver=self.connection.driver, **i)
+                 for i in VOXEL_INSTANCE_TYPES.values() ]
+
+    def list_images(self, location=None):
+        params = {"method": "voxel.images.list"}
+        result = self.connection.request('/', params=params).object
+        return self._to_images(result)
+
+    def create_node(self, **kwargs):
+        """Create Voxel Node
+
+        @keyword name: the name to assign the node (mandatory)
+        @type    name: C{str}
+
+        @keyword image: distribution to deploy
+        @type    image: L{NodeImage}
+
+        @keyword size: the plan size to create (mandatory)
+                       Requires size.disk (GB) to be set manually
+        @type    size: L{NodeSize}
+
+        @keyword location: which datacenter to create the node in
+        @type    location: L{NodeLocation}
+
+        @keyword ex_privateip: Backend IP address to assign to node;
+                               must be chosen from the customer's
+                               private VLAN assignment.
+        @type    ex_privateip: C{str}
+
+        @keyword ex_publicip: Public-facing IP address to assign to node;
+                              must be chosen from the customer's
+                              public VLAN assignment.
+        @type    ex_publicip: C{str}
+
+        @keyword ex_rootpass: Password for root access; generated if unset.
+        @type    ex_rootpass: C{str}
+
+        @keyword ex_consolepass: Password for remote console;
+                                 generated if unset.
+        @type    ex_consolepass: C{str}
+
+        @keyword ex_sshuser: Username for SSH access
+        @type    ex_sshuser: C{str}
+
+        @keyword ex_sshpass: Password for SSH access; generated if unset.
+        @type    ex_sshpass: C{str}
+
+        @keyword ex_voxel_access: Allow access Voxel administrative access.
+                                  Defaults to False.
+        @type    ex_voxel_access: C{bool}
+        """
+
+        # assert that disk > 0
+        if not kwargs["size"].disk:
+            raise ValueError("size.disk must be non-zero")
+
+        # convert voxel_access to string boolean if needed
+        voxel_access = kwargs.get("ex_voxel_access", None)
+        if voxel_access is not None:
+            voxel_access = "true" if voxel_access else "false"
+
+        params = {
+            'method':           'voxel.voxcloud.create',
+            'hostname':         kwargs["name"],
+            'disk_size':        int(kwargs["size"].disk),
+            'facility':         kwargs["location"].id,
+            'image_id':         kwargs["image"].id,
+            'processing_cores': kwargs["size"].ram / RAM_PER_CPU,
+            'backend_ip':       kwargs.get("ex_privateip", None),
+            'frontend_ip':      kwargs.get("ex_publicip", None),
+            'admin_password':   kwargs.get("ex_rootpass", None),
+            'console_password': kwargs.get("ex_consolepass", None),
+            'ssh_username':     kwargs.get("ex_sshuser", None),
+            'ssh_password':     kwargs.get("ex_sshpass", None),
+            'voxel_access':     voxel_access,
+        }
+
+        object = self.connection.request('/', params=params).object
+
+        if self._getstatus(object):
+            return Node(
+                id = object.findtext("device/id"),
+                name = kwargs["name"],
+                state = NODE_STATE_MAP[object.findtext("device/status")],
+                public_ip = kwargs.get("publicip", None),
+                private_ip = kwargs.get("privateip", None),
+                driver = self.connection.driver
+            )
+        else:
+            return None
+
+    def reboot_node(self, node):
+        """
+        Reboot the node by passing in the node object
+        """
+        params = {'method': 'voxel.devices.power',
+                  'device_id': node.id,
+                  'power_action': 'reboot'}
+        return self._getstatus(self.connection.request('/', params=params).object)
+
+    def destroy_node(self, node):
+        """
+        Destroy node by passing in the node object
+        """
+        params = {'method': 'voxel.voxcloud.delete',
+                  'device_id': node.id}
+        return self._getstatus(self.connection.request('/', params=params).object)
+
+    def list_locations(self):
+        params = {"method": "voxel.voxcloud.facilities.list"}
+        result = self.connection.request('/', params=params).object
+        nodes = self._to_locations(result)
+        return nodes
+
+    def _getstatus(self, element):
+        status = element.attrib["stat"]
+        return status == "ok"
+
+
+    def _to_locations(self, object):
+        return [NodeLocation(element.attrib["label"],
+                             element.findtext("description"),
+                             element.findtext("description"),
+                             self)
+                for element in object.findall('facilities/facility')]
+
+    def _to_nodes(self, object):
+        nodes = []
+        for element in object.findall('devices/device'):
+            if element.findtext("type") == "Virtual Server":
+                try:
+                    state = self.NODE_STATE_MAP[element.attrib['status']]
+                except KeyError:
+                    state = NodeState.UNKNOWN
+
+                public_ip = private_ip = None
+                ipassignments = element.findall("ipassignments/ipassignment")
+                for ip in ipassignments:
+                    if ip.attrib["type"] =="frontend":
+                        public_ip = ip.text
+                    elif ip.attrib["type"] == "backend":
+                        private_ip = ip.text
+
+                nodes.append(Node(id= element.attrib['id'],
+                                 name=element.attrib['label'],
+                                 state=state,
+                                 public_ip= public_ip,
+                                 private_ip= private_ip,
+                                 driver=self.connection.driver))
+        return nodes
+
+    def _to_images(self, object):
+        images = []
+        for element in object.findall("images/image"):
+            images.append(NodeImage(id = element.attrib["id"],
+                                    name = element.attrib["summary"],
+                                    driver = self.connection.driver))
+        return images

Added: incubator/libcloud/trunk/libcloud/compute/drivers/vpsnet.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/drivers/vpsnet.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/drivers/vpsnet.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/drivers/vpsnet.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,199 @@
+# 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.
+"""
+VPS.net driver
+"""
+import base64
+
+try:
+    import json
+except:
+    import simplejson as json
+
+from libcloud.common.base import ConnectionUserAndKey, Response
+from libcloud.common.types import InvalidCredsError
+from libcloud.compute.providers import Provider
+from libcloud.compute.types import NodeState
+from libcloud.compute.base import Node, NodeDriver
+from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
+
+API_HOST = 'api.vps.net'
+API_VERSION = 'api10json'
+
+RAM_PER_NODE = 256
+DISK_PER_NODE = 10
+BANDWIDTH_PER_NODE = 250
+PRICE_PER_NODE = {1: 20,
+                  2: 19,
+                  3: 18,
+                  4: 17,
+                  5: 16,
+                  6: 15,
+                  7: 14,
+                  15: 13,
+                  30: 12,
+                  60: 11,
+                  100: 10}
+
+class VPSNetResponse(Response):
+
+    def parse_body(self):
+        try:
+            js = json.loads(self.body)
+            return js
+        except ValueError:
+            return self.body
+
+    def success(self):
+        # vps.net wrongly uses 406 for invalid auth creds
+        if self.status == 406 or self.status == 403:
+            raise InvalidCredsError()
+        return True
+
+    def parse_error(self):
+        try:
+            errors = json.loads(self.body)['errors'][0]
+        except ValueError:
+            return self.body
+        else:
+            return "\n".join(errors)
+
+class VPSNetConnection(ConnectionUserAndKey):
+    """
+    Connection class for the VPS.net driver
+    """
+
+    host = API_HOST
+    responseCls = VPSNetResponse
+
+    def add_default_headers(self, headers):
+        user_b64 = base64.b64encode('%s:%s' % (self.user_id, self.key))
+        headers['Authorization'] = 'Basic %s' % (user_b64)
+        return headers
+
+class VPSNetNodeDriver(NodeDriver):
+    """
+    VPS.net node driver
+    """
+
+    type = Provider.VPSNET
+    name = "vps.net"
+    connectionCls = VPSNetConnection
+
+    def _to_node(self, vm):
+        if vm['running']:
+            state = NodeState.RUNNING
+        else:
+            state = NodeState.PENDING
+
+        n = Node(id=vm['id'],
+                 name=vm['label'],
+                 state=state,
+                 public_ip=[vm.get('primary_ip_address', None)],
+                 private_ip=[],
+                 extra={'slices_count':vm['slices_count']}, # Number of nodes consumed by VM
+                 driver=self.connection.driver)
+        return n
+
+    def _to_image(self, image, cloud):
+        image = NodeImage(id=image['id'],
+                          name="%s: %s" % (cloud, image['label']),
+                          driver=self.connection.driver)
+
+        return image
+
+    def _to_size(self, num):
+        size = NodeSize(id=num,
+                        name="%d Node" % (num,),
+                        ram=RAM_PER_NODE * num,
+                        disk=DISK_PER_NODE,
+                        bandwidth=BANDWIDTH_PER_NODE * num,
+                        price=self._get_price_per_node(num) * num,
+                        driver=self.connection.driver)
+        return size
+
+    def _get_price_per_node(self, num):
+        keys = sorted(PRICE_PER_NODE.keys())
+
+        if num >= max(keys):
+            return PRICE_PER_NODE[keys[-1]]
+
+        for i in range(0,len(keys)):
+            if keys[i] <= num < keys[i+1]:
+                return PRICE_PER_NODE[keys[i]]
+
+    def create_node(self, name, image, size, **kwargs):
+        """Create a new VPS.net node
+
+        See L{NodeDriver.create_node} for more keyword args.
+        @keyword    ex_backups_enabled: Enable automatic backups
+        @type       ex_backups_enabled: C{bool}
+
+        @keyword    ex_fqdn:   Fully Qualified domain of the node
+        @type       ex_fqdn:   C{string}
+        """
+        headers = {'Content-Type': 'application/json'}
+        request = {'virtual_machine':
+                        {'label': name,
+                         'fqdn': kwargs.get('ex_fqdn', ''),
+                         'system_template_id': image.id,
+                         'backups_enabled': kwargs.get('ex_backups_enabled', 0),
+                         'slices_required': size.id}}
+
+        res = self.connection.request('/virtual_machines.%s' % (API_VERSION,),
+                                    data=json.dumps(request),
+                                    headers=headers,
+                                    method='POST')
+        node = self._to_node(res.object['virtual_machine'])
+        return node
+
+    def reboot_node(self, node):
+        res = self.connection.request('/virtual_machines/%s/%s.%s' %
+                                        (node.id, 'reboot', API_VERSION),
+                                        method="POST")
+        node = self._to_node(res.object['virtual_machine'])
+        return True
+
+    def list_sizes(self, location=None):
+        res = self.connection.request('/nodes.%s' % (API_VERSION,))
+        available_nodes = len([size for size in res.object
+                            if size['slice']['virtual_machine_id']])
+        sizes = [self._to_size(i) for i in range(1, available_nodes + 1)]
+        return sizes
+
+    def destroy_node(self, node):
+        res = self.connection.request('/virtual_machines/%s.%s'
+                                      % (node.id, API_VERSION),
+                                      method='DELETE')
+        return res.status == 200
+
+    def list_nodes(self):
+        res = self.connection.request('/virtual_machines.%s' % (API_VERSION,))
+        return [self._to_node(i['virtual_machine']) for i in res.object]
+
+    def list_images(self, location=None):
+        res = self.connection.request('/available_clouds.%s' % (API_VERSION,))
+
+        images = []
+        for cloud in res.object:
+            label = cloud['cloud']['label']
+            templates = cloud['cloud']['system_templates']
+            images.extend([self._to_image(image, label)
+                           for image in templates])
+
+        return images
+
+    def list_locations(self):
+        return [NodeLocation(0, "VPS.net Western US", 'US', self)]

Added: incubator/libcloud/trunk/libcloud/compute/providers.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/providers.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/providers.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/providers.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,76 @@
+# 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.
+"""
+Provider related utilities
+"""
+
+from libcloud.utils import get_driver as get_provider_driver
+from libcloud.compute.types import Provider
+
+DRIVERS = {
+    Provider.DUMMY:
+        ('libcloud.drivers.dummy', 'DummyNodeDriver'),
+    Provider.EC2_US_EAST:
+        ('libcloud.drivers.ec2', 'EC2NodeDriver'),
+    Provider.EC2_EU_WEST:
+        ('libcloud.drivers.ec2', 'EC2EUNodeDriver'),
+    Provider.EC2_US_WEST:
+        ('libcloud.drivers.ec2', 'EC2USWestNodeDriver'),
+    Provider.EC2_AP_SOUTHEAST:
+        ('libcloud.drivers.ec2', 'EC2APSENodeDriver'),
+    Provider.EC2_AP_NORTHEAST:
+        ('libcloud.drivers.ec2', 'EC2APNENodeDriver'),
+    Provider.ECP:
+        ('libcloud.drivers.ecp', 'ECPNodeDriver'),
+    Provider.ELASTICHOSTS_UK1:
+        ('libcloud.drivers.elastichosts', 'ElasticHostsUK1NodeDriver'),
+    Provider.ELASTICHOSTS_UK2:
+        ('libcloud.drivers.elastichosts', 'ElasticHostsUK2NodeDriver'),
+    Provider.ELASTICHOSTS_US1:
+        ('libcloud.drivers.elastichosts', 'ElasticHostsUS1NodeDriver'),
+    Provider.CLOUDSIGMA:
+        ('libcloud.drivers.cloudsigma', 'CloudSigmaZrhNodeDriver'),
+    Provider.GOGRID:
+        ('libcloud.drivers.gogrid', 'GoGridNodeDriver'),
+    Provider.RACKSPACE:
+        ('libcloud.drivers.rackspace', 'RackspaceNodeDriver'),
+    Provider.RACKSPACE_UK:
+        ('libcloud.drivers.rackspace', 'RackspaceUKNodeDriver'),
+    Provider.SLICEHOST:
+        ('libcloud.drivers.slicehost', 'SlicehostNodeDriver'),
+    Provider.VPSNET:
+        ('libcloud.drivers.vpsnet', 'VPSNetNodeDriver'),
+    Provider.LINODE:
+        ('libcloud.drivers.linode', 'LinodeNodeDriver'),
+    Provider.RIMUHOSTING:
+        ('libcloud.drivers.rimuhosting', 'RimuHostingNodeDriver'),
+    Provider.VOXEL:
+        ('libcloud.drivers.voxel', 'VoxelNodeDriver'),
+    Provider.SOFTLAYER:
+        ('libcloud.drivers.softlayer', 'SoftLayerNodeDriver'),
+    Provider.EUCALYPTUS:
+        ('libcloud.drivers.ec2', 'EucNodeDriver'),
+    Provider.IBM:
+        ('libcloud.drivers.ibm_sbc', 'IBMNodeDriver'),
+    Provider.OPENNEBULA:
+        ('libcloud.drivers.opennebula', 'OpenNebulaNodeDriver'),
+    Provider.DREAMHOST:
+        ('libcloud.drivers.dreamhost', 'DreamhostNodeDriver'),
+    Provider.BRIGHTBOX:
+        ('libcloud.drivers.brightbox', 'BrightboxNodeDriver'),
+}
+
+def get_driver(provider):
+    return get_provider_driver(DRIVERS, provider)

Added: incubator/libcloud/trunk/libcloud/compute/ssh.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/ssh.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/ssh.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/ssh.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,186 @@
+# 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.
+
+"""
+Wraps multiple ways to communicate over SSH
+"""
+have_paramiko = False
+
+try:
+    import paramiko
+    have_paramiko = True
+except ImportError:
+    pass
+
+# Depending on your version of Paramiko, it may cause a deprecation
+# warning on Python 2.6.
+# Ref: https://bugs.launchpad.net/paramiko/+bug/392973
+
+from os.path import split as psplit
+
+class BaseSSHClient(object):
+    """
+    Base class representing a connection over SSH/SCP to a remote node.
+    """
+
+    def __init__(self, hostname, port=22, username='root', password=None, key=None):
+        """
+        @type hostname: C{str}
+        @keyword hostname: Hostname or IP address to connect to.
+
+        @type port: C{int}
+        @keyword port: TCP port to communicate on, defaults to 22.
+
+        @type username: C{str}
+        @keyword username: Username to use, defaults to root.
+
+        @type password: C{str}
+        @keyword password: Password to authenticate with.
+
+        @type key: C{list}
+        @keyword key: Private SSH keys to authenticate with.
+        """
+        self.hostname = hostname
+        self.port = port
+        self.username = username
+        self.password = password
+        self.key = key
+
+    def connect(self):
+        """
+        Connect to the remote node over SSH.
+
+        @return: C{bool}
+        """
+        raise NotImplementedError, \
+            'connect not implemented for this ssh client'
+
+    def put(self, path, contents=None, chmod=None):
+        """
+        Upload a file to the remote node.
+
+        @type path: C{str}
+        @keyword path: File path on the remote node.
+
+        @type contents: C{str}
+        @keyword contents: File Contents.
+
+        @type chmod: C{int}
+        @keyword chmod: chmod file to this after creation.
+        """
+        raise NotImplementedError, \
+            'put not implemented for this ssh client'
+
+    def delete(self, path):
+        """
+        Delete/Unlink a file on the remote node.
+
+        @type path: C{str}
+        @keyword path: File path on the remote node.
+        """
+        raise NotImplementedError, \
+            'delete not implemented for this ssh client'
+
+    def run(self, cmd):
+        """
+        Run a command on a remote node.
+
+        @type cmd: C{str}
+        @keyword cmd: Command to run.
+        
+        @return C{list} of [stdout, stderr, exit_status]
+        """
+        raise NotImplementedError, \
+            'run not implemented for this ssh client'
+
+    def close(self):
+        """
+        Shutdown connection to the remote node.
+        """
+        raise NotImplementedError, \
+            'close not implemented for this ssh client'
+
+class ParamikoSSHClient(BaseSSHClient):
+    """
+    A SSH Client powered by Paramiko.
+    """
+    def __init__(self, hostname, port=22, username='root', password=None, key=None):
+        super(ParamikoSSHClient, self).__init__(hostname, port, username, password, key)
+        self.client = paramiko.SSHClient()
+        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+
+    def connect(self):
+        conninfo = {'hostname': self.hostname,
+                    'port': self.port,
+                    'username': self.username,
+                    'password': self.password,
+                    'allow_agent': False,
+                    'look_for_keys': False}
+        self.client.connect(**conninfo)
+        return True
+
+    def put(self, path, contents=None, chmod=None):
+        sftp = self.client.open_sftp()
+        # less than ideal, but we need to mkdir stuff otherwise file() fails
+        head, tail = psplit(path)
+        if path[0] == "/":
+            sftp.chdir("/")
+        for part in head.split("/"):
+            if part != "":
+                try:
+                    sftp.mkdir(part)
+                except IOError:
+                    # so, there doesn't seem to be a way to
+                    # catch EEXIST consistently *sigh*
+                    pass
+                sftp.chdir(part)
+        ak = sftp.file(tail,  mode='w')
+        ak.write(contents)
+        if chmod is not None:
+            ak.chmod(chmod)
+        ak.close()
+        sftp.close()
+
+    def delete(self, path):
+        sftp = self.client.open_sftp()
+        sftp.unlink(path)
+        sftp.close()
+
+    def run(self, cmd):
+        # based on exec_command()
+        bufsize = -1
+        t =  self.client.get_transport()
+        chan = t.open_session()
+        chan.exec_command(cmd)
+        stdin = chan.makefile('wb', bufsize)
+        stdout = chan.makefile('rb', bufsize)
+        stderr = chan.makefile_stderr('rb', bufsize)
+        #stdin, stdout, stderr = self.client.exec_command(cmd)
+        stdin.close()
+        status = chan.recv_exit_status()
+        so = stdout.read()
+        se = stderr.read()
+        return [so, se, status]
+
+    def close(self):
+        self.client.close()
+
+class ShellOutSSHClient(BaseSSHClient):
+    # TODO: write this one
+    pass
+
+SSHClient = ParamikoSSHClient
+if not have_paramiko:
+    SSHClient = ShellOutSSHClient

Added: incubator/libcloud/trunk/libcloud/compute/types.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/compute/types.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/compute/types.py (added)
+++ incubator/libcloud/trunk/libcloud/compute/types.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,103 @@
+# 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.
+"""
+Base types used by other parts of libcloud
+"""
+
+from libcloud.common.types import LibcloudError, MalformedResponseError
+from libcloud.common.types import InvalidCredsError, InvalidCredsException
+
+class Provider(object):
+    """
+    Defines for each of the supported providers
+
+    @cvar DUMMY: Example provider
+    @cvar EC2_US_EAST: Amazon AWS US N. Virgina
+    @cvar EC2_US_WEST: Amazon AWS US N. California
+    @cvar EC2_EU_WEST: Amazon AWS EU Ireland
+    @cvar RACKSPACE: Rackspace Cloud Servers
+    @cvar RACKSPACE_UK: Rackspace UK Cloud Servers
+    @cvar SLICEHOST: Slicehost.com
+    @cvar GOGRID: GoGrid
+    @cvar VPSNET: VPS.net
+    @cvar LINODE: Linode.com
+    @cvar VCLOUD: vmware vCloud
+    @cvar RIMUHOSTING: RimuHosting.com
+    @cvar ECP: Enomaly
+    @cvar IBM: IBM Developer Cloud
+    @cvar OPENNEBULA: OpenNebula.org
+    @cvar DREAMHOST: DreamHost Private Server
+    @cvar CLOUDSIGMA: CloudSigma
+    """
+    DUMMY = 0
+    EC2 = 1  # deprecated name
+    EC2_US_EAST = 1
+    EC2_EU = 2 # deprecated name
+    EC2_EU_WEST = 2
+    RACKSPACE = 3
+    SLICEHOST = 4
+    GOGRID = 5
+    VPSNET = 6
+    LINODE = 7
+    VCLOUD = 8
+    RIMUHOSTING = 9
+    EC2_US_WEST = 10
+    VOXEL = 11
+    SOFTLAYER = 12
+    EUCALYPTUS = 13
+    ECP = 14
+    IBM = 15
+    OPENNEBULA = 16
+    DREAMHOST = 17
+    ELASTICHOSTS = 18
+    ELASTICHOSTS_UK1 = 19
+    ELASTICHOSTS_UK2 = 20
+    ELASTICHOSTS_US1 = 21
+    EC2_AP_SOUTHEAST = 22
+    RACKSPACE_UK = 23
+    BRIGHTBOX = 24
+    CLOUDSIGMA = 25
+    EC2_AP_NORTHEAST = 26
+
+class NodeState(object):
+    """
+    Standard states for a node
+
+    @cvar RUNNING: Node is running
+    @cvar REBOOTING: Node is rebooting
+    @cvar TERMINATED: Node is terminated
+    @cvar PENDING: Node is pending
+    @cvar UNKNOWN: Node state is unknown
+    """
+    RUNNING = 0
+    REBOOTING = 1
+    TERMINATED = 2
+    PENDING = 3
+    UNKNOWN = 4
+
+class DeploymentError(LibcloudError):
+    """
+    Exception used when a Deployment Task failed.
+
+    @ivar node: L{Node} on which this exception happened, you might want to call L{Node.destroy}
+    """
+    def __init__(self, node, original_exception=None):
+        self.node = node
+        self.value = original_exception
+    def __str__(self):
+        return repr(self.value)
+
+"""Deprecated alias of L{DeploymentException}"""
+DeploymentException = DeploymentError

Added: incubator/libcloud/trunk/libcloud/deployment.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/deployment.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/deployment.py (added)
+++ incubator/libcloud/trunk/libcloud/deployment.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.deployment import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/__init__.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/__init__.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/__init__.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/__init__.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,38 @@
+# 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.
+
+"""
+Drivers for working with different providers
+"""
+
+__all__ = [
+    'brightbox',
+    'dummy',
+    'ec2',
+    'ecp',
+    'elastichosts',
+    'cloudsigma',
+    'gogrid',
+    'ibm_sbc',
+    'linode',
+    'opennebula',
+    'rackspace',
+    'rimuhosting',
+    'slicehost',
+    'softlayer',
+    'vcloud',
+    'voxel',
+    'vpsnet',
+]

Added: incubator/libcloud/trunk/libcloud/drivers/brightbox.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/brightbox.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/brightbox.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/brightbox.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.brightbox import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/cloudsigma.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/cloudsigma.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/cloudsigma.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/cloudsigma.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.cloudsigma import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/dreamhost.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/dreamhost.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/dreamhost.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/dreamhost.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.dreamhost import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/dummy.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/dummy.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/dummy.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/dummy.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.dummy import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/ec2.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/ec2.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/ec2.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/ec2.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.ec2 import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/ecp.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/ecp.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/ecp.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/ecp.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.ecp import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/elastichosts.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/elastichosts.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/elastichosts.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/elastichosts.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.elastichosts import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/gogrid.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/gogrid.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/gogrid.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/gogrid.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.gogrid import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/ibm_sbc.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/ibm_sbc.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/ibm_sbc.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/ibm_sbc.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.ibm_sbc import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/linode.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/linode.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/linode.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/linode.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.linode import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/opennebula.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/opennebula.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/opennebula.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/opennebula.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,22 @@
+# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
+# Complutense de Madrid (dsa-research.org)
+#
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.opennebula import *
+
+deprecated_warning(__name__)

Added: incubator/libcloud/trunk/libcloud/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/rackspace.py?rev=1079029&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/rackspace.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/rackspace.py Mon Mar  7 23:44:06 2011
@@ -0,0 +1,19 @@
+# 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.utils import deprecated_warning
+from libcloud.compute.drivers.rackspace import *
+
+deprecated_warning(__name__)