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 2012/11/18 02:23:01 UTC
svn commit: r1410809 [1/4] - in /libcloud/branches/0.11.x: ./ libcloud/
libcloud/common/ libcloud/compute/ libcloud/compute/drivers/ libcloud/data/
libcloud/dns/ libcloud/dns/drivers/ libcloud/loadbalancer/
libcloud/loadbalancer/drivers/ libcloud/stora...
Author: tomaz
Date: Sun Nov 18 01:22:54 2012
New Revision: 1410809
URL: http://svn.apache.org/viewvc?rev=1410809&view=rev
Log:
Merge 0.11.3 into 0.11.x branch.
Added:
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ec2/authorize_security_group_ingress.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ec2/authorize_security_group_ingress.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ec2/describe_key_pairs.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ec2/describe_key_pairs.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ec2/describe_security_groups.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ec2/describe_security_groups.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/allocate_address.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/attach_volume.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/create_volume.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/delete_address.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/destroy_volume.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/detach_volume.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_addresses.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_storage_offerings.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/ibm_sce/list_volumes.xml
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml
- copied unchanged from r1388947, libcloud/trunk/libcloud/test/compute/fixtures/vcloud_1_5/api_vApp_vapp_8c57a5b6_e61b_48ca_8a78_3b70ee65ef6a_power_action_all.xml
Removed:
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/cloudstack/attachVolume_default.json.rej
Modified:
libcloud/branches/0.11.x/ (props changed)
libcloud/branches/0.11.x/CHANGES
libcloud/branches/0.11.x/doap_libcloud.rdf
libcloud/branches/0.11.x/libcloud/__init__.py
libcloud/branches/0.11.x/libcloud/common/base.py
libcloud/branches/0.11.x/libcloud/common/gandi.py
libcloud/branches/0.11.x/libcloud/common/gogrid.py
libcloud/branches/0.11.x/libcloud/compute/base.py
libcloud/branches/0.11.x/libcloud/compute/drivers/brightbox.py
libcloud/branches/0.11.x/libcloud/compute/drivers/cloudstack.py
libcloud/branches/0.11.x/libcloud/compute/drivers/dummy.py
libcloud/branches/0.11.x/libcloud/compute/drivers/ec2.py
libcloud/branches/0.11.x/libcloud/compute/drivers/gandi.py
libcloud/branches/0.11.x/libcloud/compute/drivers/gogrid.py
libcloud/branches/0.11.x/libcloud/compute/drivers/ibm_sce.py
libcloud/branches/0.11.x/libcloud/compute/drivers/joyent.py
libcloud/branches/0.11.x/libcloud/compute/drivers/libvirt_driver.py
libcloud/branches/0.11.x/libcloud/compute/drivers/linode.py
libcloud/branches/0.11.x/libcloud/compute/drivers/openstack.py
libcloud/branches/0.11.x/libcloud/compute/drivers/rackspacenova.py
libcloud/branches/0.11.x/libcloud/compute/drivers/rimuhosting.py
libcloud/branches/0.11.x/libcloud/compute/drivers/slicehost.py
libcloud/branches/0.11.x/libcloud/compute/drivers/softlayer.py
libcloud/branches/0.11.x/libcloud/compute/drivers/vcl.py
libcloud/branches/0.11.x/libcloud/compute/drivers/vcloud.py
libcloud/branches/0.11.x/libcloud/compute/providers.py
libcloud/branches/0.11.x/libcloud/compute/types.py
libcloud/branches/0.11.x/libcloud/data/pricing.json
libcloud/branches/0.11.x/libcloud/dns/base.py
libcloud/branches/0.11.x/libcloud/dns/drivers/dummy.py
libcloud/branches/0.11.x/libcloud/dns/drivers/linode.py
libcloud/branches/0.11.x/libcloud/dns/drivers/rackspace.py
libcloud/branches/0.11.x/libcloud/dns/drivers/route53.py
libcloud/branches/0.11.x/libcloud/dns/drivers/zerigo.py
libcloud/branches/0.11.x/libcloud/httplib_ssl.py
libcloud/branches/0.11.x/libcloud/loadbalancer/base.py
libcloud/branches/0.11.x/libcloud/loadbalancer/drivers/brightbox.py
libcloud/branches/0.11.x/libcloud/loadbalancer/drivers/cloudstack.py
libcloud/branches/0.11.x/libcloud/loadbalancer/drivers/gogrid.py
libcloud/branches/0.11.x/libcloud/loadbalancer/drivers/ninefold.py
libcloud/branches/0.11.x/libcloud/loadbalancer/drivers/rackspace.py
libcloud/branches/0.11.x/libcloud/loadbalancer/providers.py
libcloud/branches/0.11.x/libcloud/loadbalancer/types.py
libcloud/branches/0.11.x/libcloud/security.py
libcloud/branches/0.11.x/libcloud/storage/base.py
libcloud/branches/0.11.x/libcloud/storage/drivers/atmos.py
libcloud/branches/0.11.x/libcloud/storage/drivers/cloudfiles.py
libcloud/branches/0.11.x/libcloud/storage/drivers/dummy.py
libcloud/branches/0.11.x/libcloud/storage/drivers/google_storage.py
libcloud/branches/0.11.x/libcloud/storage/drivers/nimbus.py
libcloud/branches/0.11.x/libcloud/storage/drivers/ninefold.py
libcloud/branches/0.11.x/libcloud/storage/drivers/s3.py
libcloud/branches/0.11.x/libcloud/storage/providers.py
libcloud/branches/0.11.x/libcloud/storage/types.py
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/openstack/_v2_0__auth.json
libcloud/branches/0.11.x/libcloud/test/compute/fixtures/vcloud_1_5/api_vdc_3d9ae28c_1de9_4307_8107_9356ff8ba6d0.xml
libcloud/branches/0.11.x/libcloud/test/compute/test_ec2.py
libcloud/branches/0.11.x/libcloud/test/compute/test_ibm_sce.py
libcloud/branches/0.11.x/libcloud/test/compute/test_openstack.py
libcloud/branches/0.11.x/libcloud/test/compute/test_rackspacenova.py
libcloud/branches/0.11.x/libcloud/test/compute/test_vcloud.py
libcloud/branches/0.11.x/libcloud/test/loadbalancer/test_brightbox.py
libcloud/branches/0.11.x/libcloud/test/loadbalancer/test_cloudstack.py
libcloud/branches/0.11.x/libcloud/test/loadbalancer/test_gogrid.py
libcloud/branches/0.11.x/libcloud/test/loadbalancer/test_rackspace.py
libcloud/branches/0.11.x/libcloud/test/storage/test_cloudfiles.py
libcloud/branches/0.11.x/libcloud/test/storage/test_s3.py
libcloud/branches/0.11.x/libcloud/test/test_httplib_ssl.py
Propchange: libcloud/branches/0.11.x/
------------------------------------------------------------------------------
Merged /libcloud/trunk:r1364889-1388947
Merged /libcloud/tags/0.11.3:r1388949-1410808
Modified: libcloud/branches/0.11.x/CHANGES
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/CHANGES?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/CHANGES (original)
+++ libcloud/branches/0.11.x/CHANGES Sun Nov 18 01:22:54 2012
@@ -1,5 +1,59 @@
-*- coding: utf-8 -*-
+Changes with Apache Libcloud 0.11.3:
+
+ *) Storage
+
+ - Include 'last_modified' and 'content_type' attribute in the Object
+ 'extra' dictionary when retrieving object using get_object in the S3
+ driver. Also modify 'meta_data' dictionary to include all the headers
+ prefixed with 'x-amz-meta-'.
+ [Tomaz Muraus]
+
+Changes with Apache Libcloud 0.11.2:
+
+ *) General
+
+ Fix a bug with the Libcloud SSL verification code. Code was too strict and
+ didn't allow "-" character in the sub-domain when using a wildcard
+ certificate.
+
+ Note: This is NOT a security vulnerability. ; LIBCLOUD-244
+ [Tomaz Muraus]
+
+ *) Compute
+
+ - Add new Rackspace Nova driver for Chicago (ORD) location ; LIBCLOUD-234
+ [Brian McDaniel]
+
+ - Add capacity information to Vdc objects and implement power operations. ;
+ LIBCLOUD-239
+ [Michal Galet]
+
+ - Allow user to pass 'timeout' argument to the 'deploy_node' method.
+ [Tomaz Muraus]
+
+ - Add ex_list_security_groups, ex_authorize_security_group and
+ ex_describe_all_keypairs methods to the EC2 driver. ; LIBCLOUD-241,
+ LIBCLOUD-243
+ [Nick Bailey]
+
+ - Add new methods for managing storage volumes and other extenstion methods
+ to the IBM SCE driver. ; LIBCLOUD-242
+ [Sengor Kusturica]
+
+ *) Storage
+
+ - Add the following new methods to the CloudFiles driver:
+ ex_set_account_metadata_temp_url_key, ex_get_object_temp_url. ; GITHUB-72
+ [Shawn Smith]
+
+ *) Load-balancer
+
+ - Add 'balancer' attribute to the Member instance. This attribute refers to
+ the LoadBalancer instance this member belongs to.
+ [Tomaz Muraus]
+
Changes with Apache Libcloud 0.11.1:
*) General
@@ -35,7 +89,7 @@ Changes with Apache Libcloud 0.11.0:
- Joyent
[Sengor Kusturica, Hutson Betts, Tomaz Muraus]
- - Make CloudStuck driver more robust and make it work if list_images() call
+ - Make CloudStack driver more robust and make it work if list_images() call
returns no images. ; LIBCLOUD-202
[Gabriel Reid]
@@ -52,7 +106,7 @@ Changes with Apache Libcloud 0.11.0:
[Gabriel Reid]
- New driver for KT UCloud (http://home.ucloud.olleh.com/main.kt) based on
- CloudStack driver.
+ the CloudStack driver.
[DaeMyung Kang]
- Add a standard API and methods for managing storage volumes to the
Modified: libcloud/branches/0.11.x/doap_libcloud.rdf
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/doap_libcloud.rdf?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/doap_libcloud.rdf (original)
+++ libcloud/branches/0.11.x/doap_libcloud.rdf Sun Nov 18 01:22:54 2012
@@ -125,6 +125,20 @@
<revision>0.10.1</revision>
</Version>
</release>
+ <release>
+ <Version>
+ <name>0.11.0</name>
+ <created>2012-07-30</created>
+ <revision>0.11.0</revision>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <name>0.11.1</name>
+ <created>2012-08-01</created>
+ <revision>0.11.1</revision>
+ </Version>
+ </release>
<repository>
<SVNRepository>
<location rdf:resource="https://svn.apache.org/repos/asf/libcloud/trunk/"/>
Modified: libcloud/branches/0.11.x/libcloud/__init__.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/__init__.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/__init__.py (original)
+++ libcloud/branches/0.11.x/libcloud/__init__.py Sun Nov 18 01:22:54 2012
@@ -20,7 +20,7 @@ libcloud provides a unified interface to
"""
__all__ = ['__version__', 'enable_debug']
-__version__ = '0.11.1'
+__version__ = '0.11.3'
try:
import paramiko
Modified: libcloud/branches/0.11.x/libcloud/common/base.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/common/base.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/common/base.py (original)
+++ libcloud/branches/0.11.x/libcloud/common/base.py Sun Nov 18 01:22:54 2012
@@ -785,27 +785,27 @@ class BaseDriver(object):
def __init__(self, key, secret=None, secure=True, host=None, port=None,
api_version=None, **kwargs):
"""
- @keyword key: API key or username to used
- @type key: str
+ @param key: API key or username to used (required)
+ @type key: C{str}
- @keyword secret: Secret password to be used
- @type secret: str
+ @param secret: Secret password to be used (required)
+ @type secret: C{str}
- @keyword secure: Weither to use HTTPS or HTTP. Note: Some providers
+ @param secure: Weither to use HTTPS or HTTP. Note: Some providers
only support HTTPS, and it is on by default.
- @type secure: bool
+ @type secure: C{bool}
- @keyword host: Override hostname used for connections.
- @type host: str
+ @param host: Override hostname used for connections.
+ @type host: C{str}
- @keyword port: Override port used for connections.
- @type port: int
+ @param port: Override port used for connections.
+ @type port: C{int}
- @keyword api_version: Optional API version. Only used by drivers
+ @param api_version: Optional API version. Only used by drivers
which support multiple API versions.
- @type api_version: str
+ @type api_version: C{str}
- @requires: key, secret
+ @rtype: C{None}
"""
self.key = key
Modified: libcloud/branches/0.11.x/libcloud/common/gandi.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/common/gandi.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/common/gandi.py (original)
+++ libcloud/branches/0.11.x/libcloud/common/gandi.py Sun Nov 18 01:22:54 2012
@@ -106,7 +106,14 @@ class BaseGandiDriver(object):
def __init__(self, key, secret=None, secure=False):
"""
- @requires: key, secret
+ @param key: API key or username to used (required)
+ @type key: C{str}
+
+ @param secret: Secret password to be used (required)
+ @type secret: C{str}
+
+ @param secure: Weither to use HTTPS or HTTP.
+ @type secure: C{bool}
"""
self.key = key
self.secret = secret
Modified: libcloud/branches/0.11.x/libcloud/common/gogrid.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/common/gogrid.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/common/gogrid.py (original)
+++ libcloud/branches/0.11.x/libcloud/common/gogrid.py Sun Nov 18 01:22:54 2012
@@ -139,14 +139,17 @@ class BaseGoGridDriver(object):
private IPs. Set to None or not specify
at all not to filter by type
@type public: C{bool}
+
@keyword assigned: set to True to list only addresses
assigned to servers, False to list unassigned
addresses and set to None or don't set at all
not no filter by state
@type assigned: C{bool}
+
@keyword location: filter IP addresses by location
@type location: L{NodeLocation}
- @return: C{list} of L{GoGridIpAddress}es
+
+ @rtype: C{list} of L{GoGridIpAddress}
"""
params = {}
Modified: libcloud/branches/0.11.x/libcloud/compute/base.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/base.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/base.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/base.py Sun Nov 18 01:22:54 2012
@@ -446,9 +446,6 @@ class NodeDriver(BaseDriver):
def __init__(self, key, secret=None, secure=True, host=None, port=None,
api_version=None, **kwargs):
- """
- @requires: key, secret
- """
super(NodeDriver, self).__init__(key=key, secret=secret, secure=secure,
host=host, port=port,
api_version=api_version, **kwargs)
@@ -610,6 +607,10 @@ class NodeDriver(BaseDriver):
to attempt to authenticate. (optional)
@type ssh_key: C{str} or C{list} of C{str}
+ @keyword timeout: How many seconds to wait before timing out.
+ (default is 600)
+ @type timeout: C{int}
+
@keyword max_tries: How many times to retry if a deployment fails
before giving up (default is 3)
@type max_tries: C{int}
@@ -661,6 +662,7 @@ class NodeDriver(BaseDriver):
ssh_port = kwargs.get('ssh_port', 22)
ssh_timeout = kwargs.get('ssh_timeout', 10)
ssh_key_file = kwargs.get('ssh_key', None)
+ timeout = kwargs.get('timeout', SSH_CONNECT_TIMEOUT)
ssh_client = SSHClient(hostname=ip_addresses[0],
port=ssh_port, username=ssh_username,
@@ -670,7 +672,7 @@ class NodeDriver(BaseDriver):
# Connect to the SSH server running on the node
ssh_client = self._ssh_client_connect(ssh_client=ssh_client,
- timeout=SSH_CONNECT_TIMEOUT)
+ timeout=timeout)
# Execute the deployment task
self._run_deployment_script(task=kwargs['deploy'],
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/brightbox.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/brightbox.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/brightbox.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/brightbox.py Sun Nov 18 01:22:54 2012
@@ -56,9 +56,6 @@ class BrightboxNodeDriver(NodeDriver):
def __init__(self, key, secret=None, secure=True, host=None, port=None,
api_version=API_VERSION, **kwargs):
- """
- @requires: key, secret
- """
super(BrightboxNodeDriver, self).__init__(key=key, secret=secret,
secure=secure,
host=host, port=port,
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/cloudstack.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/cloudstack.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/cloudstack.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/cloudstack.py Sun Nov 18 01:22:54 2012
@@ -116,7 +116,13 @@ class CloudStackNodeDriver(CloudStackDri
def __init__(self, key, secret=None, secure=True, host=None,
path=None, port=None, *args, **kwargs):
"""
- @requires: key, secret, host or path
+ @inherits: L{NodeDriver.__init__}
+
+ @param host: The host where the API can be reached. (required)
+ @type host: C{str}
+
+ @param path: The host where the API can be reached. (required)
+ @type path: C{str}
"""
host = host if host else self.host
@@ -146,7 +152,7 @@ class CloudStackNodeDriver(CloudStackDri
'hypervisor': img['hypervisor'],
'format': img['format'],
'os': img['ostypename'],
- }))
+ }))
return images
def list_locations(self):
@@ -157,6 +163,10 @@ class CloudStackNodeDriver(CloudStackDri
return locations
def list_nodes(self):
+ """
+ @inherits: L{NodeDriver.list_nodes}
+ @rtype: C{list} of L{CloudStackNode}
+ """
vms = self._sync_request('listVirtualMachines')
addrs = self._sync_request('listPublicIpAddresses')
@@ -216,6 +226,10 @@ class CloudStackNodeDriver(CloudStackDri
return sizes
def create_node(self, name, size, image, location=None, **kwargs):
+ """
+ @inherits: L{NodeDriver.create_node}
+ @rtype: L{CloudStackNode}
+ """
extra_args = {}
if location is None:
location = self.list_locations()[0]
@@ -242,14 +256,22 @@ class CloudStackNodeDriver(CloudStackDri
'zoneid': location.id,
'ip_addresses': [],
'forwarding_rules': [],
- }
+ }
)
def destroy_node(self, node):
+ """
+ @inherits: L{NodeDriver.reboot_node}
+ @type node: L{CloudStackNode}
+ """
self._async_request('destroyVirtualMachine', id=node.id)
return True
def reboot_node(self, node):
+ """
+ @inherits: L{NodeDriver.reboot_node}
+ @type node: L{CloudStackNode}
+ """
self._async_request('rebootVirtualMachine', id=node.id)
return True
@@ -300,6 +322,10 @@ class CloudStackNodeDriver(CloudStackDri
extra=dict(name=volumeResponse['name']))
def attach_volume(self, node, volume, device=None):
+ """
+ @inherits: L{NodeDriver.attach_volume}
+ @type node: L{CloudStackNode}
+ """
# TODO Add handling for device name
self._async_request('attachVolume', id=volume.id,
virtualMachineId=node.id)
@@ -317,8 +343,8 @@ class CloudStackNodeDriver(CloudStackDri
"""
"Allocate a public IP and bind it to a node.
- @param node: Node which should be used
- @type node: L{Node}
+ @param node: Node which should be used
+ @type node: L{CloudStackNode}
@rtype: L{CloudStackAddress}
"""
@@ -341,11 +367,11 @@ class CloudStackNodeDriver(CloudStackDri
"""
Release a public IP.
- @param node: Node which should be used
- @type node: L{Node}
+ @param node: Node which should be used
+ @type node: L{CloudStackNode}
- @param address: CloudStackAddress which should be used
- @type address: L{CloudStackAddress}
+ @param address: CloudStackAddress which should be used
+ @type address: L{CloudStackAddress}
@rtype: C{bool}
"""
@@ -362,8 +388,8 @@ class CloudStackNodeDriver(CloudStackDri
"""
"Add a NAT/firewall forwarding rule.
- @param node: Node which should be used
- @type node: L{Node}
+ @param node: Node which should be used
+ @type node: L{CloudStackNode}
@param address: CloudStackAddress which should be used
@type address: L{CloudStackAddress}
@@ -403,8 +429,8 @@ class CloudStackNodeDriver(CloudStackDri
"""
Remove a NAT/firewall forwarding rule.
- @param node: Node which should be used
- @type node: L{Node}
+ @param node: Node which should be used
+ @type node: L{CloudStackNode}
@param rule: Forwarding rule which should be used
@type rule: L{CloudStackForwardingRule}
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/dummy.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/dummy.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/dummy.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/dummy.py Sun Nov 18 01:22:54 2012
@@ -69,7 +69,10 @@ class DummyNodeDriver(NodeDriver):
def __init__(self, creds):
"""
- @requires: creds
+ @param creds: Credentials
+ @type creds: C{str}
+
+ @rtype: C{None}
"""
self.creds = creds
try:
@@ -110,6 +113,12 @@ class DummyNodeDriver(NodeDriver):
self.connection = DummyConnection(self.creds)
def get_uuid(self, unique_field=None):
+ """
+
+ @param unique_field: Unique field
+ @type unique_field: C{bool}
+ @rtype: L{UUID}
+ """
return str(uuid.uuid4())
def list_nodes(self):
@@ -138,6 +147,8 @@ class DummyNodeDriver(NodeDriver):
'i2'
>>> sorted([node.name for node in driver.list_nodes()])
['dummy-1', 'dummy-2', 'dummy-3']
+
+ @inherits: L{NodeDriver.list_nodes}
"""
return self.nl
@@ -160,6 +171,8 @@ class DummyNodeDriver(NodeDriver):
True
Please note, dummy nodes never recover from the reboot.
+
+ @inherits: L{NodeDriver.reboot_node}
"""
node.state = NodeState.REBOOTING
@@ -181,6 +194,8 @@ class DummyNodeDriver(NodeDriver):
False
>>> [node for node in driver.list_nodes() if node.name == 'dummy-1']
[]
+
+ @inherits: L{NodeDriver.destroy_node}
"""
node.state = NodeState.TERMINATED
@@ -195,6 +210,8 @@ class DummyNodeDriver(NodeDriver):
>>> driver = DummyNodeDriver(0)
>>> sorted([image.name for image in driver.list_images()])
['Slackware 4', 'Ubuntu 9.04', 'Ubuntu 9.10']
+
+ @inherits: L{NodeDriver.list_images}
"""
return [
NodeImage(id=1, name="Ubuntu 9.10", driver=self),
@@ -210,6 +227,8 @@ class DummyNodeDriver(NodeDriver):
>>> driver = DummyNodeDriver(0)
>>> sorted([size.ram for size in driver.list_sizes()])
[128, 512, 4096, 8192]
+
+ @inherits: L{NodeDriver.list_images}
"""
return [
@@ -251,6 +270,8 @@ class DummyNodeDriver(NodeDriver):
>>> driver = DummyNodeDriver(0)
>>> sorted([loc.name + " in " + loc.country for loc in driver.list_locations()])
['Island Datacenter in FJ', 'London Loft in GB', "Paul's Room in US"]
+
+ @inherits: L{NodeDriver.list_locations}
"""
return [
NodeLocation(id=1,
@@ -285,6 +306,8 @@ class DummyNodeDriver(NodeDriver):
True
>>> sorted([node.name for node in driver.list_nodes()])
['dummy-1', 'dummy-2', 'dummy-4']
+
+ @inherits: L{NodeDriver.create_node}
"""
l = len(self.nl) + 1
n = Node(id=l,
@@ -311,4 +334,5 @@ def _int_to_ip(ip):
if __name__ == "__main__":
import doctest
+
doctest.testmod()
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/ec2.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/ec2.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/ec2.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/ec2.py Sun Nov 18 01:22:54 2012
@@ -644,6 +644,28 @@ class EC2NodeDriver(NodeDriver):
'keyFingerprint': key_fingerprint,
}
+ def ex_describe_all_keypairs(self):
+ """
+ Describes all keypairs.
+
+ @note: This is a non-standard extension API, and only works for EC2.
+
+ @rtype: C{list}
+ """
+
+ params = {
+ 'Action': 'DescribeKeyPairs'
+ }
+
+ response = self.connection.request(self.path, params=params).object
+ names = []
+ for elem in findall(element=response, xpath='keySet/item',
+ namespace=NAMESPACE):
+ name = findtext(element=elem, xpath='keyName', namespace=NAMESPACE)
+ names.append(name)
+
+ return names
+
def ex_describe_keypairs(self, name):
"""Describes a keypair by name
@@ -653,7 +675,6 @@ class EC2NodeDriver(NodeDriver):
@type name: C{str}
@rtype: C{dict}
-
"""
params = {
@@ -668,13 +689,34 @@ class EC2NodeDriver(NodeDriver):
'keyName': key_name
}
+ def ex_list_security_groups(self):
+ """
+ List existing Security Groups.
+
+ @note: This is a non-standard extension API, and only works for EC2.
+
+ @rtype: C{list} of C{str}
+ """
+ params = {'Action': 'DescribeSecurityGroups'}
+ response = self.connection.request(self.path, params=params).object
+
+ groups = []
+ for group in findall(element=response, xpath='securityGroupInfo/item',
+ namespace=NAMESPACE):
+ name = findtext(element=group, xpath='groupName',
+ namespace=NAMESPACE)
+ groups.append(name)
+
+ return groups
+
def ex_create_security_group(self, name, description):
- """Creates a new Security Group
+ """
+ Creates a new Security Group
@note: This is a non-standard extension API, and only works for EC2.
@param name: The name of the security group to Create.
- This must be unique.
+ This must be unique.
@type name: C{str}
@param description: Human readable description of a Security
@@ -688,6 +730,46 @@ class EC2NodeDriver(NodeDriver):
'GroupDescription': description}
return self.connection.request(self.path, params=params).object
+ def ex_authorize_security_group(self, name, from_port, to_port, cidr_ip,
+ protocol='tcp'):
+ """
+ Edit a Security Group to allow specific traffic.
+
+ @note: This is a non-standard extension API, and only works for EC2.
+
+ @param name: The name of the security group to edit
+ @type name: C{str}
+
+ @param from_port: The beginning of the port range to open
+ @type from_port: C{str}
+
+ @param end_port: The end of the port range to open
+ @type end_port: C{str}
+
+ @param cidr_ip: The ip to allow traffic for.
+ @type cidr_ip: C{str}
+
+ @param protocol: tcp/udp/icmp
+ @type protocol: C{str}
+
+ @rtype: C{boolean}
+ """
+
+ params = {'Action': 'AuthorizeSecurityGroupIngress',
+ 'GroupName': name,
+ 'IpProtocol': protocol,
+ 'FromPort': str(from_port),
+ 'ToPort': str(to_port),
+ 'CidrIp': cidr_ip}
+ try:
+ resp = self.connection.request(self.path, params=params.copy()).object
+ return bool(findtext(element=resp, xpath='return',
+ namespace=NAMESPACE))
+ except Exception:
+ e = sys.exc_info()[1]
+ if e.args[0].find('InvalidPermission.Duplicate') == -1:
+ raise e
+
def ex_authorize_security_group_permissive(self, name):
"""
Edit a Security Group to allow all traffic.
@@ -1321,7 +1403,10 @@ class EucNodeDriver(EC2NodeDriver):
def __init__(self, key, secret=None, secure=True, host=None,
path=None, port=None):
"""
- @requires: key, secret
+ @inherits: L{EC2NodeDriver.__init__}
+
+ @param path: The host where the API can be reached.
+ @type path: C{str}
"""
super(EucNodeDriver, self).__init__(key, secret, secure, host, port)
if path is None:
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/gandi.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/gandi.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/gandi.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/gandi.py Sun Nov 18 01:22:54 2012
@@ -53,6 +53,12 @@ class GandiNodeDriver(BaseGandiDriver, N
# TODO : which features to enable ?
features = {}
+ def __init__(self, *args, **kwargs):
+ """
+ @inherits: L{NodeDriver.__init__}
+ """
+ super(BaseGandiDriver, self).__init__(*args, **kwargs)
+
def _resource_info(self, type, id):
try:
obj = self.connection.request('%s.info' % type, int(id))
@@ -102,42 +108,6 @@ class GandiNodeDriver(BaseGandiDriver, N
def _to_volumes(self, disks):
return [self._to_volume(d) for d in disks]
- def _to_volume(self, disk):
- extra = {'can_snapshot': disk['can_snapshot']}
- return StorageVolume(
- id=disk['id'],
- name=disk['name'],
- size=int(disk['size']),
- driver=self,
- extra=extra)
-
- def _to_volumes(self, disks):
- return [self._to_volume(d) for d in disks]
-
- def _to_volume(self, disk):
- extra = {'can_snapshot': disk['can_snapshot']}
- return StorageVolume(
- id=disk['id'],
- name=disk['name'],
- size=int(disk['size']),
- driver=self,
- extra=extra)
-
- def _to_volumes(self, disks):
- return [self._to_volume(d) for d in disks]
-
- def _to_volume(self, disk):
- extra = {'can_snapshot': disk['can_snapshot']}
- return StorageVolume(
- id=disk['id'],
- name=disk['name'],
- size=int(disk['size']),
- driver=self,
- extra=extra)
-
- def _to_volumes(self, disks):
- return [self._to_volume(d) for d in disks]
-
def list_nodes(self):
vms = self.connection.request('vm.list')
ips = self.connection.request('ip.list')
@@ -167,7 +137,7 @@ class GandiNodeDriver(BaseGandiDriver, N
op_stop = self.connection.request('vm.stop', int(node.id))
if not self._wait_operation(op_stop['id']):
raise GandiException(1010, 'vm.stop failed')
- # Delete
+ # Delete
op = self.connection.request('vm.delete', int(node.id))
if self._wait_operation(op['id']):
return True
@@ -340,93 +310,10 @@ class GandiNodeDriver(BaseGandiDriver, N
return [self._to_loc(l) for l in res]
def list_volumes(self):
- """List all volumes"""
- res = self.connection.request('disk.list', {})
- return self._to_volumes(res)
-
- def create_volume(self, size, name, location=None, snapshot=None):
- disk_param = {
- 'name': name,
- 'size': int(size),
- 'datacenter_id': int(location.id)
- }
- if snapshot:
- op = self.connection.request('disk.create_from',
- disk_param, int(snapshot.id))
- else:
- op = self.connection.request('disk.create', disk_param)
- if self._wait_operation(op['id']):
- disk = self._volume_info(op['disk_id'])
- return self._to_volume(disk)
- return None
-
- def attach_volume(self, node, volume, device=None):
- """Attach a volume to a node"""
- op = self.connection.request('vm.disk_attach',
- int(node.id), int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def detach_volume(self, node, volume):
- """Detach a volume from a node"""
- op = self.connection.request('vm.disk_detach',
- int(node.id), int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def destroy_volume(self, volume):
- op = self.connection.request('disk.delete', int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def list_volumes(self):
- """List all volumes"""
- res = self.connection.request('disk.list', {})
- return self._to_volumes(res)
-
- def create_volume(self, size, name, location=None, snapshot=None):
- disk_param = {
- 'name': name,
- 'size': int(size),
- 'datacenter_id': int(location.id)
- }
- if snapshot:
- op = self.connection.request('disk.create_from',
- disk_param, int(snapshot.id))
- else:
- op = self.connection.request('disk.create', disk_param)
- if self._wait_operation(op['id']):
- disk = self._volume_info(op['disk_id'])
- return self._to_volume(disk)
- return None
-
- def attach_volume(self, node, volume, device=None):
- """Attach a volume to a node"""
- op = self.connection.request('vm.disk_attach',
- int(node.id), int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def detach_volume(self, node, volume):
- """Detach a volume from a node"""
- op = self.connection.request('vm.disk_detach',
- int(node.id), int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def destroy_volume(self, volume):
- op = self.connection.request('disk.delete', int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
+ """
- def list_volumes(self):
- """List all volumes"""
+ @rtype: C{list} of L{StorageVolume}
+ """
res = self.connection.request('disk.list', {})
return self._to_volumes(res)
@@ -438,7 +325,7 @@ class GandiNodeDriver(BaseGandiDriver, N
}
if snapshot:
op = self.connection.request('disk.create_from',
- disk_param, int(snapshot.id))
+ disk_param, int(snapshot.id))
else:
op = self.connection.request('disk.create', disk_param)
if self._wait_operation(op['id']):
@@ -447,60 +334,26 @@ class GandiNodeDriver(BaseGandiDriver, N
return None
def attach_volume(self, node, volume, device=None):
- """Attach a volume to a node"""
op = self.connection.request('vm.disk_attach',
- int(node.id), int(volume.id))
+ int(node.id), int(volume.id))
if self._wait_operation(op['id']):
return True
return False
def detach_volume(self, node, volume):
- """Detach a volume from a node"""
- op = self.connection.request('vm.disk_detach',
- int(node.id), int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def destroy_volume(self, volume):
- op = self.connection.request('disk.delete', int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
-
- def list_volumes(self):
- """List all volumes"""
- res = self.connection.request('disk.list', {})
- return self._to_volumes(res)
+ """
+ Detaches a volume from a node.
- def create_volume(self, size, name, location=None, snapshot=None):
- disk_param = {
- 'name': name,
- 'size': int(size),
- 'datacenter_id': int(location.id)
- }
- if snapshot:
- op = self.connection.request('disk.create_from',
- disk_param, int(snapshot.id))
- else:
- op = self.connection.request('disk.create', disk_param)
- if self._wait_operation(op['id']):
- disk = self._volume_info(op['disk_id'])
- return self._to_volume(disk)
- return None
+ @param node: Node which should be used
+ @type node: L{Node}
- def attach_volume(self, node, volume, device=None):
- """Attach a volume to a node"""
- op = self.connection.request('vm.disk_attach',
- int(node.id), int(volume.id))
- if self._wait_operation(op['id']):
- return True
- return False
+ @param volume: Volume to be detached
+ @type volume: L{StorageVolume}
- def detach_volume(self, node, volume):
- """Detach a volume from a node"""
+ @rtype: C{bool}
+ """
op = self.connection.request('vm.disk_detach',
- int(node.id), int(volume.id))
+ int(node.id), int(volume.id))
if self._wait_operation(op['id']):
return True
return False
@@ -672,10 +525,11 @@ class GandiNodeDriver(BaseGandiDriver, N
if not name:
suffix = datetime.today().strftime("%Y%m%d")
name = "snap_%s" % (suffix)
- op = self.connection.request('disk.create_from',
- {'name': name, 'type': 'snapshot', },
- int(disk.id),
- )
+ op = self.connection.request(
+ 'disk.create_from',
+ {'name': name, 'type': 'snapshot', },
+ int(disk.id),
+ )
if self._wait_operation(op['id']):
return True
return False
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/gogrid.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/gogrid.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/gogrid.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/gogrid.py Sun Nov 18 01:22:54 2012
@@ -103,6 +103,12 @@ class GoGridNodeDriver(BaseGoGridDriver,
_instance_types = GOGRID_INSTANCE_TYPES
+ def __init__(self, *args, **kwargs):
+ """
+ @inherits: L{NodeDriver.__init__}
+ """
+ super(GoGridNodeDriver, self).__init__(*args, **kwargs)
+
def _get_state(self, element):
try:
return STATE[element['state']['name']]
@@ -163,6 +169,10 @@ class GoGridNodeDriver(BaseGoGridDriver,
return images
def list_nodes(self):
+ """
+ @inherits: L{NodeDriver.list_nodes}
+ @rtype: C{list} of L{GoGridNode}
+ """
passwords_map = {}
res = self._server_list()
@@ -182,6 +192,10 @@ class GoGridNodeDriver(BaseGoGridDriver,
for el in res['list']]
def reboot_node(self, node):
+ """
+ @inherits: L{NodeDriver.reboot_node}
+ @type node: L{GoGridNode}
+ """
id = node.id
power = 'restart'
res = self._server_power(id, power)
@@ -190,6 +204,10 @@ class GoGridNodeDriver(BaseGoGridDriver,
return True
def destroy_node(self, node):
+ """
+ @inherits: L{NodeDriver.reboot_node}
+ @type node: L{GoGridNode}
+ """
id = node.id
res = self._server_delete(id)
if not res.success():
@@ -262,7 +280,7 @@ class GoGridNodeDriver(BaseGoGridDriver,
specified, first available IP address will be picked
@type ex_ip: C{str}
- @rtype: L{Node}
+ @rtype: L{GoGridNode}
"""
name = kwargs['name']
image = kwargs['image']
@@ -295,6 +313,8 @@ class GoGridNodeDriver(BaseGoGridDriver,
@keyword ex_ip: Public IP address to use for a Node. If not
specified, first available IP address will be picked
@type ex_ip: C{str}
+
+ @rtype: L{GoGridNode}
"""
node = self.ex_create_node_nowait(**kwargs)
@@ -328,7 +348,7 @@ class GoGridNodeDriver(BaseGoGridDriver,
http://wiki.gogrid.com/wiki/index.php/MyGSI
@keyword node: node to use as a base for image
- @type node: L{Node}
+ @type node: L{GoGridNode}
@keyword name: name for new image
@type name: C{str}
@@ -345,10 +365,10 @@ class GoGridNodeDriver(BaseGoGridDriver,
def ex_edit_node(self, **kwargs):
"""Change attributes of a node.
- @keyword node: node to be edited
- @type node: L{Node}
+ @keyword node: node to be edited (required)
+ @type node: L{GoGridNode}
- @keyword size: new size of a node
+ @keyword size: new size of a node (required)
@type size: L{NodeSize}
@keyword ex_description: new description of a node
@@ -373,10 +393,10 @@ class GoGridNodeDriver(BaseGoGridDriver,
def ex_edit_image(self, **kwargs):
"""Edit metadata of a server image.
- @keyword image: image to be edited
+ @keyword image: image to be edited (required)
@type image: L{NodeImage}
- @keyword public: should be the image public?
+ @keyword public: should be the image public (required)
@type public: C{bool}
@keyword ex_description: description of the image (optional)
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/ibm_sce.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/ibm_sce.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/ibm_sce.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/ibm_sce.py Sun Nov 18 01:22:54 2012
@@ -17,20 +17,22 @@
Driver for IBM SmartCloud Enterprise
Formerly known as:
-- IBM Developer Cloud.
+- IBM Developer Cloud
+- IBM Smart Business Development and Test on the IBM Cloud
- IBM SmartBusiness Cloud
"""
import base64
+import time
from libcloud.utils.py3 import urlencode
from libcloud.utils.py3 import b
from libcloud.common.base import XmlResponse, ConnectionUserAndKey
-from libcloud.common.types import InvalidCredsError
+from libcloud.common.types import InvalidCredsError, LibcloudError
from libcloud.compute.types import NodeState, Provider
from libcloud.compute.base import NodeDriver, Node, NodeImage, \
- NodeSize, NodeLocation, NodeAuthSSHKey
+ NodeSize, NodeLocation, NodeAuthSSHKey, StorageVolume
HOST = 'www-147.ibm.com'
REST_BASE = '/computecloud/enterprise/api/rest/20100331'
@@ -51,7 +53,7 @@ class IBMResponse(XmlResponse):
class IBMConnection(ConnectionUserAndKey):
"""
- Connection class for the IBM Developer Cloud driver
+ Connection class for the IBM SmartCloud Enterprise driver
"""
host = HOST
@@ -69,6 +71,77 @@ class IBMConnection(ConnectionUserAndKey
return urlencode(data)
+class IBMNodeLocation(NodeLocation):
+ """
+ Extends the base LibCloud NodeLocation to contain additional attributes
+ """
+ def __init__(self, id, name, country, driver, extra=None):
+ self.id = str(id)
+ self.name = name
+ self.country = country
+ self.driver = driver
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return ('<IBMNodeLocation: id=%s, name=%s, country=%s, '
+ 'driver=%s, extra=%s>' % self.id, self.name, self.country,
+ self.driver.name, self.extra)
+
+
+class VolumeState(object):
+ """
+ The SCE specific states for a storage volume
+ """
+ NEW = '0'
+ CREATING = '1'
+ DELETING = '2'
+ DELETED = '3'
+ DETACHED = '4'
+ ATTACHED = '5'
+ FAILED = '6'
+ DELETE_PENDING = '7'
+ BEING_CLONED = '8'
+ CLONING = '9'
+ ATTACHING = '10'
+ DETACHING = '11'
+ ATTACHIED = '12'
+ IMPORTING = '13'
+ TRANSFER_RETRYING = '14'
+
+
+class VolumeOffering(object):
+ """
+ An SCE specific storage volume offering class.
+ The volume offering ID is needed to create a volume.
+ Volume offering IDs are different for each data center.
+ """
+ def __init__(self, id, name, location, extra=None):
+ self.id = id
+ self.location = location
+ self.name = name
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return ('<VolumeOffering: id=%s, location=%s, name=%s, extra=%s>' %
+ self.id, self.location, self.name, self.extra)
+
+
+class Address(object):
+ """
+ A reserved IP address that can be attached to an instance.
+ Properties: id, ip, state, options(location, type, created_time, state, hostname, instance_ids, vlan, owner,
+ mode, offering_id)
+ """
+ def __init__(self, id, ip, state, options):
+ self.id = id
+ self.ip = ip
+ self.state = state
+ self.options = options
+
+ def __repr__(self):
+ return ('<Address: id=%s, ip=%s, state=%s, options=%s>' %
+ self.id, self.ip, self.state, self.options)
+
class IBMNodeDriver(NodeDriver):
"""
Node driver for IBM SmartCloud Enterprise
@@ -94,12 +167,14 @@ class IBMNodeDriver(NodeDriver):
12: NodeState.PENDING, # Deprovision Pending
13: NodeState.PENDING, # Restart Pending
14: NodeState.PENDING, # Attaching
- 15: NodeState.PENDING, # Detaching
+ 15: NodeState.PENDING, # Detaching
}
def create_node(self, **kwargs):
"""
- Creates a node in the IBM Developer Cloud.
+ Creates a node in the IBM SmartCloud Enterprise.
+
+ See L{NodeDriver.create_node} for more keyword args.
@inherits: L{NodeDriver.create_node}
@@ -131,8 +206,9 @@ class IBMNodeDriver(NodeDriver):
data.update({'publicKey': kwargs['auth'].pubkey})
if 'ex_configurationData' in kwargs:
configurationData = kwargs['ex_configurationData']
- for key in configurationData.keys():
- data.update({key: configurationData.get(key)})
+ if configurationData:
+ for key in configurationData.keys():
+ data.update({key: configurationData.get(key)})
# Send request!
resp = self.connection.request(
@@ -142,12 +218,164 @@ class IBMNodeDriver(NodeDriver):
data=data).object
return self._to_nodes(resp)[0]
+ def create_volume(self, size, name, location, **kwargs):
+ """
+ Create a new block storage volume (virtual disk)
+
+ @param size: Size of volume in gigabytes (required).
+ Find out the possible sizes from the
+ offerings/storage REST interface
+ @type size: C{int}
+
+ @keyword name: Name of the volume to be created (required)
+ @type name: C{str}
+
+ @keyword location: Which data center to create a volume in. If
+ empty, it will fail for IBM SmartCloud Enterprise
+ (required)
+ @type location: L{NodeLocation}
+
+ @keyword snapshot: Not supported for IBM SmartCloud Enterprise
+ @type snapshot: C{str}
+
+ @keyword kwargs.format: Either RAW or EXT3 for IBM SmartCloud
+ Enterprise (optional)
+ @type kwargs.format: C{str}
+
+ @keyword kwargs.offering_id: The storage offering ID for IBM
+ SmartCloud Enterprise
+ Find this from the REST interface
+ storage/offerings. (optional)
+ @type kwargs.offering_id: C{str}
+
+ @keyword kwargs.source_disk_id: If cloning a volume, the storage
+ disk to make a copy from (optional)
+ @type kwargs.source_disk_id: C{str}
+
+ @keyword kwargs.storage_area_id: The id of the storage availability
+ area to create the volume in
+ (optional)
+ @type kwargs.storage_area_id: C{str}
+
+ @keyword kwargs.target_location_id: If cloning a volume, the
+ storage disk to make a copy
+ from (optional)
+ @type kwargs.target_location_id: C{str}
+
+ @return: The newly created L{StorageVolume}.
+ """
+ data = {}
+ data.update({'name': name})
+ data.update({'size': size})
+ data.update({'location': location})
+ if (('format' in kwargs) and (kwargs['format'] is not None)):
+ data.update({'format': kwargs['format']})
+ if (('offering_id' in kwargs) and (kwargs['offering_id'] is not None)):
+ data.update({'offeringID': kwargs['offering_id']})
+ if (('storage_area_id' in kwargs) and (kwargs['storage_area_id'] is not None)):
+ data.update({'storageAreaID': kwargs['storage_area_id']})
+ if 'source_disk_id' in kwargs:
+ data.update({'sourceDiskID': kwargs['source_disk_id']})
+ data.update({'type': 'clone'})
+ if 'target_location_id' in kwargs:
+ data.update({'targetLocationID': kwargs['target_location_id']})
+ resp = self.connection.request(action=REST_BASE + '/storage',
+ headers={'Content-Type': 'application/x-www-form-urlencoded'},
+ method='POST',
+ data=data).object
+ return self._to_volumes(resp)[0]
+
+ def create_image(self, name, description=None, **kwargs):
+ """
+ Create a new node image from an existing volume or image.
+
+ @param name: Name of the image to be created (required)
+ @type name: C{str}
+
+ @param description: Description of the image to be created (optional)
+ @type description: L{str}
+
+ @keyword kwarge.image_id: The ID of the source image if cloning the image
+ @type kwargs.image_id: C{str}
+
+ @keyword kwargs.volume_id: The ID of the storage volume if importing the image
+ @type kwargs.volume_id: C{str}
+
+ @return: The newly created L{NodeImage}.
+ """
+ data = {}
+ data.update({'name': name})
+ if description is not None:
+ data.update({'description': description})
+ if (('image_id' in kwargs) and (kwargs['image_id'] is not None)):
+ data.update({'imageId': kwargs['image_id']})
+ if (('volume_id' in kwargs) and (kwargs['volume_id'] is not None)):
+ data.update({'volumeId': kwargs['volume_id']})
+ resp = self.connection.request(action=REST_BASE + '/offerings/image',
+ headers={'Content-Type': 'application/x-www-form-urlencoded'},
+ method='POST',
+ data=data).object
+ return self._to_images(resp)[0]
+
def destroy_node(self, node):
url = REST_BASE + '/instances/%s' % (node.id)
status = int(self.connection.request(action=url,
method='DELETE').status)
return status == 200
+ def destroy_volume(self, volume):
+ """
+ Destroys a storage volume.
+
+ @param volume: Volume to be destroyed
+ @type volume: L{StorageVolume}
+
+ @return: C{bool}
+ """
+ url = REST_BASE + '/storage/%s' % (volume.id)
+ status = int(self.connection.request(action=url,
+ method='DELETE').status)
+ return status == 200
+
+ def attach_volume(self, node, volume):
+ """
+ Attaches volume to node.
+
+ @param node: Node to attach volume to
+ @type node: L{Node}
+
+ @param volume: Volume to attach
+ @type volume: L{StorageVolume}
+
+ @return: C{bool}
+ """
+ url = REST_BASE + '/instances/%s' % (node.id)
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+ data = {'storageID': volume.id, 'type': 'attach'}
+ resp = self.connection.request(action=url,
+ method='PUT',
+ headers=headers,
+ data=data)
+ return int(resp.status) == 200
+
+ def detach_volume(self, node, volume):
+ """
+ Detaches a volume from a node.
+
+ @param volume: Volume to be detached
+ @type volume: L{StorageVolume}
+
+ @returns C{bool}
+ """
+ url = REST_BASE + '/instances/%s' % (node.id)
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+ data = {'storageID': volume.id, 'type': 'detach'}
+ resp = self.connection.request(action=url,
+ method='PUT',
+ headers=headers,
+ data=data)
+ return int(resp.status) == 200
+
def reboot_node(self, node):
url = REST_BASE + '/instances/%s' % (node.id)
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
@@ -167,10 +395,21 @@ class IBMNodeDriver(NodeDriver):
return self._to_images(
self.connection.request(REST_BASE + '/offerings/image').object)
+ def list_volumes(self):
+ """
+ List storage volumes.
+
+ @return: C{list} of L{StorageVolume} objects
+ """
+ return self._to_volumes(
+ self.connection.request(REST_BASE + '/storage').object)
+
def list_sizes(self, location=None):
"""
- Returns a generic list of sizes. See list_images() for a
- list of supported sizes for specific images.
+ Returns a generic list of sizes. See list_images() for a list of supported
+ sizes for specific images. In particular, you need to have a size that
+ matches the architecture (32-bit vs 64-bit) of the virtual machine image
+ operating system.
@inherits: L{NodeDriver.list_sizes}
"""
@@ -195,9 +434,124 @@ class IBMNodeDriver(NodeDriver):
None, None, None, None, self.connection.driver)]
def list_locations(self):
+ """
+ List the data center locations
+ """
return self._to_locations(
self.connection.request(REST_BASE + '/locations').object)
+ def ex_list_storage_offerings(self):
+ """
+ List the storage center offerings
+ """
+ return self._to_volume_offerings(
+ self.connection.request(REST_BASE + '/offerings/storage').object)
+
+ def ex_allocate_address(self, location_id, offering_id, vlan_id=None):
+ """
+ Allocate a new reserved IP address
+
+ @param location_id: Target data center
+ @type location_id: L{str}
+ @param offering_id: Offering ID for address to create
+ @type offering_id: L{str}
+ @param vlan_id: ID of target VLAN
+ @type vlan_id: L{str}
+ @return: L{Address} object
+ """
+ url = REST_BASE + '/addresses'
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+ data = {'location': location_id, 'offeringID': offering_id}
+ if vlan_id is not None:
+ data.update({'vlanID': vlan_id})
+ resp = self.connection.request(action=url,
+ method='POST',
+ headers=headers,
+ data=data).object
+ return self._to_addresses(resp)[0]
+
+ def ex_list_addresses(self, resource_id=None):
+ """
+ List the reserved IP addresses
+
+ @param resource_id: If this is supplied only a single address will be returned (optional)
+ @type resource_id: L{str}
+ """
+ url = REST_BASE + '/addresses'
+ if resource_id:
+ url += '/' + resource_id
+ return self._to_addresses(self.connection.request(url).object)
+
+ def ex_copy_to(self, image, volume):
+ """
+ Copies a node image to a storage volume
+
+ @param image: source image to copy
+ @type image: L{NodeImage}
+
+ @param volume: Target storage volume to copy to
+ @type volume: L{StorageVolume}
+
+ @return: C{bool} The success of the operation
+ """
+ url = REST_BASE + '/storage/%s' % (volume.id)
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+ data = {'imageId': image.id}
+ resp = self.connection.request(action=url,
+ method='PUT',
+ headers=headers,
+ data=data)
+ return int(resp.status) == 200
+
+ def ex_delete_address(self, resource_id):
+ """
+ Delete a reserved IP address
+
+ @param resource_id: The address to delete (required)
+ @type resource_id: L{str}
+ """
+ url = REST_BASE + '/addresses/' + resource_id
+ status = int(self.connection.request(action=url,
+ method='DELETE').status)
+ return status == 200
+
+ def ex_wait_storage_state(self, volume, state=VolumeState.DETACHED,
+ wait_period=60, timeout=1200):
+ """
+ Block until storage volume state changes to the given value
+
+ @param volume: Storage volume.
+ @type node: C{StorageVolume}
+
+ @param state: The target state to wait for
+ @type state: C{int}
+
+ @param wait_period: How many seconds to between each loop
+ iteration (default is 3)
+ @type wait_period: C{int}
+
+ @param timeout: How many seconds to wait before timing out
+ (default is 1200)
+ @type timeout: C{int}
+
+ @return: C{StorageVolume}
+ """
+ start = time.time()
+ end = start + timeout
+
+ while time.time() < end:
+ volumes = self.list_volumes()
+ volumes = list([v for v in volumes if v.uuid == volume.uuid])
+
+ if (len(volumes) == 1 and volumes[0].extra['state'] == state):
+ return volumes[0]
+ else:
+ time.sleep(wait_period)
+ continue
+
+ raise LibcloudError(value='Timed out after %d seconds' % (timeout),
+ driver=self)
+
def _to_nodes(self, object):
return [self._to_node(instance) for instance in
object.findall('Instance')]
@@ -210,16 +564,16 @@ class IBMNodeDriver(NodeDriver):
public_ips.append(ip)
return Node(
- id=instance.findtext('ID'),
- name=instance.findtext('Name'),
- state=self.NODE_STATE_MAP[int(instance.findtext('Status'))],
- public_ips=public_ips,
- private_ips=[],
- driver=self.connection.driver
+ id=instance.findtext('ID'),
+ name=instance.findtext('Name'),
+ state=self.NODE_STATE_MAP[int(instance.findtext('Status'))],
+ public_ips=public_ips,
+ private_ips=[],
+ driver=self.connection.driver
)
def _to_images(self, object):
- #Converts data retrieved from SCE /offerings/image REST call to a NodeImage
+ # Converts data retrieved from SCE /offerings/image REST call to a NodeImage
return [self._to_image(image) for image in object.findall('Image')]
def _to_image(self, image):
@@ -248,7 +602,7 @@ class IBMNodeDriver(NodeDriver):
'platform': platform,
'description': description,
'documentation': documentation,
- 'supportedInstanceTypes': nodeSizes
+ 'node_sizes': nodeSizes
}
)
@@ -259,11 +613,31 @@ class IBMNodeDriver(NodeDriver):
def _to_location(self, location):
# Converts an SCE Location object to a Libcloud NodeLocation object
name_text = location.findtext('Name')
+ description = location.findtext('Description')
+ state = location.findtext('State')
(nameVal, separator, countryVal) = name_text.partition(',')
- return NodeLocation(id=location.findtext('ID'),
- name=nameVal,
- country=countryVal.strip(),
- driver=self.connection.driver)
+ capabiltyElements = location.findall('Capabilities/Capability')
+ capabilities = {}
+ for elem in capabiltyElements:
+ capabilityID = elem.attrib['id']
+ entryElements = elem.findall('Entry')
+ entries = []
+ for entryElem in entryElements:
+ key = entryElem.attrib['key']
+ valueElements = elem.findall('Value')
+ values = []
+ for valueElem in valueElements:
+ values.append(valueElem.text)
+ entry = {'key': key, 'values': values}
+ entries.append(entry)
+ capabilities[capabilityID] = entries
+ extra = {'description': description, 'state': state,
+ 'capabilities': capabilities}
+ return IBMNodeLocation(id=location.findtext('ID'),
+ name=nameVal,
+ country=countryVal.strip(),
+ driver=self.connection.driver,
+ extra=extra)
def _to_node_sizes(self, object):
# Converts SCE SupportedInstanceTypes object to
@@ -280,3 +654,61 @@ class IBMNodeDriver(NodeDriver):
None,
object.findtext('Price/Rate'),
self.connection.driver)
+
+ def _to_volumes(self, object):
+ return [self._to_volume(iType) for iType in
+ object.findall('Volume')]
+
+ def _to_volume(self, object):
+ # Converts an SCE Volume to a Libcloud StorageVolume
+ extra = {'state': object.findtext('State'),
+ 'location': object.findtext('Location'),
+ 'instanceID': object.findtext('instanceID'),
+ 'owner': object.findtext('Owner'),
+ 'format': object.findtext('Format'),
+ 'createdTime': object.findtext('CreatedTime'),
+ 'storageAreaID': object.findtext('StorageArea/ID')}
+ return StorageVolume(object.findtext('ID'),
+ object.findtext('Name'),
+ object.findtext('Size'),
+ self.connection.driver,
+ extra)
+
+ def _to_volume_offerings(self, object):
+ return [self._to_volume_offering(iType) for iType in
+ object.findall('Offerings')]
+
+ def _to_volume_offering(self, object):
+ # Converts an SCE DescribeVolumeOfferingsResponse/Offerings XML object
+ # to an SCE VolumeOffering
+ extra = {'label': object.findtext('Label'),
+ 'supported_sizes': object.findtext('SupportedSizes'),
+ 'formats': object.findall('SupportedFormats/Format/ID'),
+ 'price': object.findall('Price')}
+ return VolumeOffering(object.findtext('ID'),
+ object.findtext('Name'),
+ object.findtext('Location'),
+ extra)
+
+ def _to_addresses(self, object):
+ # Converts an SCE DescribeAddressesResponse XML object to a list of
+ # Address objects
+ return [self._to_address(iType) for iType in
+ object.findall('Address')]
+
+ def _to_address(self, object):
+ # Converts an SCE DescribeAddressesResponse/Address XML object to
+ # an Address object
+ extra = {'location': object.findtext('Location'),
+ 'type': object.findtext('Label'),
+ 'created_time': object.findtext('SupportedSizes'),
+ 'hostname': object.findtext('Hostname'),
+ 'instance_ids': object.findtext('InstanceID'),
+ 'vlan': object.findtext('VLAN'),
+ 'owner': object.findtext('owner'),
+ 'mode': object.findtext('Mode'),
+ 'offering_id': object.findtext('OfferingID')}
+ return Address(object.findtext('ID'),
+ object.findtext('IP'),
+ object.findtext('State'),
+ extra)
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/joyent.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/joyent.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/joyent.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/joyent.py Sun Nov 18 01:22:54 2012
@@ -98,7 +98,10 @@ class JoyentNodeDriver(NodeDriver):
def __init__(self, *args, **kwargs):
"""
- @requires: key, secret
+ @inherits: L{NodeDriver.__init__}
+
+ @keyword location: Location which should be used
+ @type location: C{str}
"""
if 'location' in kwargs:
if kwargs['location'] not in LOCATIONS:
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/libvirt_driver.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/libvirt_driver.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/libvirt_driver.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/libvirt_driver.py Sun Nov 18 01:22:54 2012
@@ -49,7 +49,10 @@ class LibvirtNodeDriver(NodeDriver):
def __init__(self, uri):
"""
- @requires: uri
+ @param uri: URI (required)
+ @type uri: C{str}
+
+ @rtype: C{None}
"""
if not have_libvirt:
raise RuntimeError('Libvirt driver requires \'libvirt\' Python ' +
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/linode.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/linode.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/linode.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/linode.py Sun Nov 18 01:22:54 2012
@@ -78,10 +78,10 @@ class LinodeNodeDriver(NodeDriver):
def __init__(self, key):
"""Instantiate the driver with the given API key
- @keyword key: the API key to use
- @type key: C{str}
+ @param key: the API key to use (required)
+ @type key: C{str}
- @requires: key
+ @rtype: C{None}
"""
self.datacenter = None
NodeDriver.__init__(self, key)
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/openstack.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/openstack.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/openstack.py Sun Nov 18 01:22:54 2012
@@ -175,9 +175,6 @@ class OpenStackNodeDriver(NodeDriver, Op
def __new__(cls, key, secret=None, secure=True, host=None, port=None,
api_version=DEFAULT_API_VERSION, **kwargs):
- """
- @requires: key, secret
- """
if cls is OpenStackNodeDriver:
if api_version == '1.0':
cls = OpenStack_1_0_NodeDriver
@@ -367,6 +364,10 @@ class OpenStack_1_0_NodeDriver(OpenStack
@keyword ex_files: File Path => File contents to create on
the node
@type ex_files: C{dict}
+
+ @keyword ex_shared_ip_group_id: The server is launched into
+ that shared IP group
+ @type ex_shared_ip_group_id: C{str}
"""
name = kwargs['name']
image = kwargs['image']
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/rackspacenova.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/rackspacenova.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/rackspacenova.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/rackspacenova.py Sun Nov 18 01:22:54 2012
@@ -25,7 +25,6 @@ class RackspaceNovaConnection(OpenStack_
get_endpoint_args = {}
def get_endpoint(self):
-
if not self.get_endpoint_args:
raise LibcloudError(
'RackspaceNovaConnection must have get_endpoint_args set')
@@ -71,7 +70,22 @@ class RackspaceNovaDfwNodeDriver(OpenSta
website = 'http://www.rackspace.com/'
connectionCls = RackspaceNovaDfwConnection
type = Provider.RACKSPACE_NOVA_DFW
- api_name = 'rackspacenovadfw'
+ api_name = 'rackspacenovaus'
+
+
+class RackspaceNovaOrdConnection(RackspaceNovaConnection):
+
+ get_endpoint_args = {'service_type': 'compute',
+ 'name': 'cloudServersOpenStack',
+ 'region': 'ORD'}
+
+
+class RackspaceNovaOrdNodeDriver(OpenStack_1_1_NodeDriver):
+ name = 'RackspaceNovaord'
+ website = 'http://www.rackspace.com/'
+ connectionCls = RackspaceNovaOrdConnection
+ type = Provider.RACKSPACE_NOVA_ORD
+ api_name = 'rackspacenovaus'
class RackspaceNovaLonNodeDriver(OpenStack_1_1_NodeDriver):
@@ -79,7 +93,7 @@ class RackspaceNovaLonNodeDriver(OpenSta
website = 'http://www.rackspace.com/'
connectionCls = RackspaceNovaLonConnection
type = Provider.RACKSPACE_NOVA_LON
- api_name = 'rackspacenovalon'
+ api_name = 'rackspacenovauk'
class RackspaceNovaBetaNodeDriver(OpenStack_1_1_NodeDriver):
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/rimuhosting.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/rimuhosting.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/rimuhosting.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/rimuhosting.py Sun Nov 18 01:22:54 2012
@@ -120,7 +120,22 @@ class RimuHostingNodeDriver(NodeDriver):
def __init__(self, key, host=API_HOST, port=443,
api_context=API_CONTEXT, secure=True):
"""
- @requires: key, secret
+ @param key: API key (required)
+ @type key: C{str}
+
+ @param host: hostname for connection
+ @type host: C{str}
+
+ @param port: Override port used for connections.
+ @type port: C{int}
+
+ @param api_context: Optional API context.
+ @type api_context: C{str}
+
+ @param secure: Weither to use HTTPS or HTTP.
+ @type secure: C{bool}
+
+ @rtype: C{None}
"""
# Pass in some extra vars so that
self.key = key
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/slicehost.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/slicehost.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/slicehost.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/slicehost.py Sun Nov 18 01:22:54 2012
@@ -119,8 +119,6 @@ class SlicehostNodeDriver(NodeDriver):
return node
def reboot_node(self, node):
- """Reboot the node by passing in the node object"""
-
# 'hard' could bubble up as kwarg depending on how reboot_node
# turns out. Defaulting to soft reboot.
#hard = False
@@ -142,6 +140,8 @@ class SlicehostNodeDriver(NodeDriver):
<error>You must enable slice deletes in the SliceManager</error>
<error>Permission denied</error>
</errors>
+
+ @inherits: L{NodeDriver.destroy_node}
"""
uri = '/slices/%s/destroy.xml' % (node.id)
self.connection.request(uri, method='PUT')
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/softlayer.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/softlayer.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/softlayer.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/softlayer.py Sun Nov 18 01:22:54 2012
@@ -266,7 +266,16 @@ class SoftLayerNodeDriver(NodeDriver):
def __init__(self, key, secret=None, secure=False):
"""
- @requires: key, secret
+ @param key: API key or username to used (required)
+ @type key: C{str}
+
+ @param secret: Secret password to be used (required)
+ @type secret: C{str}
+
+ @param secure: Weither to use HTTPS or HTTP.
+ @type secure: C{bool}
+
+ @rtype: C{None}
"""
self.key = key
self.secret = secret
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/vcl.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/vcl.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/vcl.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/vcl.py Sun Nov 18 01:22:54 2012
@@ -130,7 +130,22 @@ class VCLNodeDriver(NodeDriver):
def __init__(self, key, secret, secure=True, host=None, port=None, *args,
**kwargs):
"""
- @requires: key, secret, host
+ @param key: API key or username to used (required)
+ @type key: C{str}
+
+ @param secret: Secret password to be used (required)
+ @type secret: C{str}
+
+ @param secure: Weither to use HTTPS or HTTP.
+ @type secure: C{bool}
+
+ @param host: Override hostname used for connections. (required)
+ @type host: C{str}
+
+ @param port: Override port used for connections.
+ @type port: C{int}
+
+ @rtype: C{None}
"""
if not host:
raise Exception('When instantiating VCL driver directly ' +
Modified: libcloud/branches/0.11.x/libcloud/compute/drivers/vcloud.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/drivers/vcloud.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/drivers/vcloud.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/drivers/vcloud.py Sun Nov 18 01:22:54 2012
@@ -74,16 +74,32 @@ def get_url_path(url):
class Vdc:
"""Virtual datacenter (vDC) representation"""
- def __init__(self, id, name, driver):
+ def __init__(self, id, name, driver, allocation_model=None, cpu=None, memory=None, storage=None):
self.id = id
self.name = name
self.driver = driver
+ self.allocation_model = allocation_model
+ self.cpu = cpu
+ self.memory = memory
+ self.storage = storage
def __repr__(self):
return (('<Vdc: id=%s, name=%s, driver=%s ...>')
% (self.id, self.name, self.driver.name))
+class Capacity:
+ """Represents CPU, Memory or Storage capacity of vDC."""
+ def __init__(self, limit, used, units):
+ self.limit = limit
+ self.used = used
+ self.units = units
+
+ def __repr__(self):
+ return (('<Capacity: limit=%s, used=%s, units=%s>')
+ % (self.limit, self.used, self.units))
+
+
class InstantiateVAppXML(object):
def __init__(self, name, template, net_href, cpus, memory,
password=None, row=None, group=None):
@@ -338,12 +354,17 @@ class VCloudNodeDriver(NodeDriver):
self.connection.check_org() # make sure the org is set. # pylint: disable-msg=E1101
res = self.connection.request(self.org)
self._vdcs = [
- Vdc(i.get('href'), i.get('name'), self)
+ self._to_vdc(
+ self.connection.request(get_url_path(i.get('href'))).object
+ )
for i in res.object.findall(fixxpath(res.object, "Link"))
if i.get('type') == 'application/vnd.vmware.vcloud.vdc+xml'
]
return self._vdcs
+ def _to_vdc(self, vdc_elm):
+ return Vdc(vdc_elm.get('href'), vdc_elm.get('name'), self)
+
def _get_vdc(self, vdc_name):
vdc = None
if not vdc_name:
@@ -442,8 +463,8 @@ class VCloudNodeDriver(NodeDriver):
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)
+ raise Exception("Timeout (%s sec) while waiting for task %s."
+ % (timeout, task_href))
time.sleep(5)
res = self.connection.request(get_url_path(task_href))
status = res.object.get('status')
@@ -482,8 +503,25 @@ class VCloudNodeDriver(NodeDriver):
return res.status in [httplib.ACCEPTED, httplib.NO_CONTENT]
def list_nodes(self):
+ return self.ex_list_nodes()
+
+ def ex_list_nodes(self, vdcs=None):
+ """
+ List all nodes across all vDCs. Using 'vdcs' you can specify which vDCs
+ should be queried.
+
+ @param vdcs: None, vDC or a list of vDCs to query. If None all vDCs
+ will be queried.
+ @type vdcs: L{Vdc}
+
+ @rtype: C{list} of L{Node} objects
+ """
+ if not vdcs:
+ vdcs = self.vdcs
+ if not isinstance(vdcs, (list, tuple)):
+ vdcs = [vdcs]
nodes = []
- for vdc in self.vdcs:
+ for vdc in vdcs:
res = self.connection.request(get_url_path(vdc.id))
elms = res.object.findall(fixxpath(
res.object, "ResourceEntities/ResourceEntity")
@@ -577,10 +615,10 @@ class VCloudNodeDriver(NodeDriver):
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'
+ self._to_image(i)
+ for i in res_ents
+ if i.get('type') ==
+ 'application/vnd.vmware.vcloud.vAppTemplate+xml'
]
def idfun(image):
@@ -953,6 +991,62 @@ class VCloud_1_5_NodeDriver(VCloudNodeDr
res = self.connection.request(get_url_path(node.id))
return self._to_node(res.object)
+ def ex_power_off_node(self, node):
+ """
+ Powers on all VMs under specified node. VMs need to be This operation
+ is allowed only when the vApp/VM is powered on.
+
+ @param node: The node to be powered off
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'powerOff')
+
+ def ex_power_on_node(self, node):
+ """
+ Powers on all VMs under specified node. This operation is allowed
+ only when the vApp/VM is powered off or suspended.
+
+ @param node: The node to be powered on
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'powerOn')
+
+ def ex_shutdown_node(self, node):
+ """
+ Shutdowns all VMs under specified node. This operation is allowed only
+ when the vApp/VM is powered on.
+
+ @param node: The node to be shut down
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'shutdown')
+
+ def ex_suspend_node(self, node):
+ """
+ Suspends all VMs under specified node. This operation is allowed only
+ when the vApp/VM is powered on.
+
+ @param node: The node to be suspended
+ @type node: L{Node}
+
+ @rtype: L{Node}
+ """
+ return self._perform_power_operation(node, 'suspend')
+
+ def _perform_power_operation(self, node, operation):
+ res = self.connection.request(
+ '%s/power/action/%s' % (get_url_path(node.id), operation),
+ method='POST')
+ self._wait_for_task_completion(res.object.get('href'))
+ res = self.connection.request(get_url_path(node.id))
+ return self._to_node(res.object)
+
def create_node(self, **kwargs):
"""Creates and returns node. If the source image is:
- vApp template - a new vApp is instantiated from template
@@ -1529,11 +1623,38 @@ class VCloud_1_5_NodeDriver(VCloudNodeDr
public_ips.extend(vm['public_ips'])
private_ips.extend(vm['private_ips'])
+ # Find vDC
+ vdc_id = next(link.get('href') for link in node_elm.findall(fixxpath(node_elm, 'Link'))
+ if link.get('type') == 'application/vnd.vmware.vcloud.vdc+xml')
+ vdc = next(vdc for vdc in self.vdcs if vdc.id == vdc_id)
+
node = Node(id=node_elm.get('href'),
name=node_elm.get('name'),
state=self.NODE_STATE_MAP[node_elm.get('status')],
public_ips=public_ips,
private_ips=private_ips,
driver=self.connection.driver,
- extra={'vms': vms})
+ extra={'vdc': vdc.name, 'vms': vms})
return node
+
+ def _to_vdc(self, vdc_elm):
+
+ def get_capacity_values(capacity_elm):
+ if capacity_elm is None:
+ return None
+ limit = int(capacity_elm.findtext(fixxpath(capacity_elm, 'Limit')))
+ used = int(capacity_elm.findtext(fixxpath(capacity_elm, 'Used')))
+ units = capacity_elm.findtext(fixxpath(capacity_elm, 'Units'))
+ return Capacity(limit, used, units)
+
+ cpu = get_capacity_values(vdc_elm.find(fixxpath(vdc_elm, 'ComputeCapacity/Cpu')))
+ memory = get_capacity_values(vdc_elm.find(fixxpath(vdc_elm, 'ComputeCapacity/Memory')))
+ storage = get_capacity_values(vdc_elm.find(fixxpath(vdc_elm, 'StorageCapacity')))
+
+ return Vdc(id=vdc_elm.get('href'),
+ name=vdc_elm.get('name'),
+ driver=self,
+ allocation_model=vdc_elm.findtext(fixxpath(vdc_elm, 'AllocationModel')),
+ cpu=cpu,
+ memory=memory,
+ storage=storage)
Modified: libcloud/branches/0.11.x/libcloud/compute/providers.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.11.x/libcloud/compute/providers.py?rev=1410809&r1=1410808&r2=1410809&view=diff
==============================================================================
--- libcloud/branches/0.11.x/libcloud/compute/providers.py (original)
+++ libcloud/branches/0.11.x/libcloud/compute/providers.py Sun Nov 18 01:22:54 2012
@@ -111,6 +111,8 @@ DRIVERS = {
('libcloud.compute.drivers.rackspacenova', 'RackspaceNovaBetaNodeDriver'),
Provider.RACKSPACE_NOVA_DFW:
('libcloud.compute.drivers.rackspacenova', 'RackspaceNovaDfwNodeDriver'),
+ Provider.RACKSPACE_NOVA_ORD:
+ ('libcloud.compute.drivers.rackspacenova', 'RackspaceNovaOrdNodeDriver'),
Provider.RACKSPACE_NOVA_LON:
('libcloud.compute.drivers.rackspacenova', 'RackspaceNovaLonNodeDriver'),
Provider.LIBVIRT: