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: