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__)