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 2014/05/28 23:23:47 UTC

git commit: Fix various bugs and add various improvements:

Repository: libcloud
Updated Branches:
  refs/heads/trunk 91f8df844 -> 21a0d069d


Fix various bugs and add various improvements:

- Fix typos in docstrings and comments
- Add import_key_pair_from_string to dummy compute driver.
- Fix ec2.import_key_pair_from_string for Python 3
- Fix publickey._to_md5_fingerprint for Python 3
- Fix publickey.get_pubkey_ssh2_fingerprint for Python 3
- ec2 driver: Make cidr_ips argument mandatory
- Add "floating IP" functions to the OpenStack provider

Closes #301

Signed-off-by: Tomaz Muraus <to...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/21a0d069
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/21a0d069
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/21a0d069

Branch: refs/heads/trunk
Commit: 21a0d069d0a138ab42ce4403ab553c7fc3e4bbb6
Parents: 91f8df8
Author: Csaba Hoch <cs...@erlang-solutions.com>
Authored: Thu Apr 10 11:33:33 2014 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Wed May 28 23:14:41 2014 +0200

----------------------------------------------------------------------
 CHANGES.rst                           | 18 ++++++++
 libcloud/compute/base.py              |  4 +-
 libcloud/compute/drivers/dummy.py     |  9 ++++
 libcloud/compute/drivers/ec2.py       | 16 +++----
 libcloud/compute/drivers/openstack.py | 74 +++++++++++++++++++++++++++---
 libcloud/test/test_utils.py           | 16 +++++++
 libcloud/utils/publickey.py           |  7 ++-
 libcloud/utils/py3.py                 | 29 +++++++++++-
 8 files changed, 153 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 3d97fee..51cb59f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -19,6 +19,14 @@ General
   (LIBCLOUD-552)
   [Tomaz Muraus]
 
+- Fix Python 3 compatibility bugs in the following functions:
+
+  * import_key_pair_from_string in the EC2 driver
+  * publickey._to_md5_fingerprint
+  * publickey.get_pubkey_ssh2_fingerprint
+  (GITHUB-301)
+  [Csaba Hoch]
+
 Compute
 ~~~~~~~
 
@@ -174,6 +182,16 @@ Compute
 
   Note #2: "timeout" argument is only available in the Paramiko SSH client.
 
+- Make "cidrs_ips" argument in the ex_authorize_security_group_egress method in
+  the EC2 driver mandatory.
+  (GITHUB-301)
+  [Csaba Hoch]
+
+- Add extension methods for manging floating IPs (ex_get_floating_ip,
+  ex_create_floating_ip, ex_delete_floating_ip) to the Openstack 1.1 driver.
+  (GITHUB-301)
+  [Csaba Hoch]
+
 Storage
 ~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/compute/base.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/base.py b/libcloud/compute/base.py
index 06a9249..d971afa 100644
--- a/libcloud/compute/base.py
+++ b/libcloud/compute/base.py
@@ -135,7 +135,7 @@ class Node(UuidMixin):
     >>> node.name
     'dummy-1'
 
-    the node keeps a reference to its own driver which means that we
+    The node keeps a reference to its own driver which means that we
     can work on nodes from different providers without having to know
     which is which.
 
@@ -146,7 +146,7 @@ class Node(UuidMixin):
     >>> node2.driver.creds
     72
 
-    Althrough Node objects can be subclassed, this isn't normally
+    Although Node objects can be subclassed, this isn't normally
     done.  Instead, any driver specific information is stored in the
     "extra" attribute of the node.
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/compute/drivers/dummy.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dummy.py b/libcloud/compute/drivers/dummy.py
index f8e6fe1..9824335 100644
--- a/libcloud/compute/drivers/dummy.py
+++ b/libcloud/compute/drivers/dummy.py
@@ -24,6 +24,7 @@ import struct
 from libcloud.common.base import ConnectionKey
 from libcloud.compute.base import NodeImage, NodeSize, Node
 from libcloud.compute.base import NodeDriver, NodeLocation
+from libcloud.compute.base import KeyPair
 from libcloud.compute.types import Provider, NodeState
 
 
@@ -326,6 +327,14 @@ class DummyNodeDriver(NodeDriver):
         self.nl.append(n)
         return n
 
+    def import_key_pair_from_string(self, name, key_material):
+        key_pair = KeyPair(name=name,
+                           public_key=key_material,
+                           fingerprint='fingerprint',
+                           private_key='private_key',
+                           driver=self)
+        return key_pair
+
 
 def _ip_to_int(ip):
     return socket.htonl(struct.unpack('I', socket.inet_aton(ip))[0])

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/compute/drivers/ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index f50cca6..5f9fb9b 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -28,7 +28,7 @@ try:
 except ImportError:
     from xml.etree import ElementTree as ET
 
-from libcloud.utils.py3 import b, basestring
+from libcloud.utils.py3 import b, basestring, ensure_string
 
 from libcloud.utils.xml import fixxpath, findtext, findattr, findall
 from libcloud.utils.publickey import get_pubkey_ssh2_fingerprint
@@ -1962,8 +1962,8 @@ class BaseEC2NodeDriver(NodeDriver):
 
         if 'auth' in kwargs:
             auth = self._get_and_check_auth(kwargs['auth'])
-            params['KeyName'] = \
-                self.ex_find_or_import_keypair_by_key_material(auth.pubkey)
+            key = self.ex_find_or_import_keypair_by_key_material(auth.pubkey)
+            params['KeyName'] = key['keyName']
 
         if 'ex_keyname' in kwargs:
             params['KeyName'] = kwargs['ex_keyname']
@@ -2173,7 +2173,7 @@ class BaseEC2NodeDriver(NodeDriver):
         return key_pair
 
     def import_key_pair_from_string(self, name, key_material):
-        base64key = base64.b64encode(b(key_material))
+        base64key = ensure_string(base64.b64encode(b(key_material)))
 
         params = {
             'Action': 'ImportKeyPair',
@@ -2600,8 +2600,8 @@ class BaseEC2NodeDriver(NodeDriver):
                                  Group.
         :type       description: ``str``
 
-        :param      description: Optional identifier for VPC networks
-        :type       description: ``str``
+        :param      vpc_id:      Optional identifier for VPC networks
+        :type       vpc_id:      ``str``
 
         :rtype: ``dict``
         """
@@ -2760,7 +2760,7 @@ class BaseEC2NodeDriver(NodeDriver):
         return element == 'true'
 
     def ex_authorize_security_group_egress(self, id, from_port, to_port,
-                                           cidr_ips=None, group_pairs=None,
+                                           cidr_ips, group_pairs=None,
                                            protocol='tcp'):
         """
         Edit a Security Group to allow specific egress traffic using
@@ -4590,7 +4590,7 @@ class BaseEC2NodeDriver(NodeDriver):
 
         :rtype: ``dict``
         """
-        params = {'GroupId': id,
+        params = {'GroupId': group_id,
                   'IpPermissions.1.IpProtocol': protocol,
                   'IpPermissions.1.FromPort': from_port,
                   'IpPermissions.1.ToPort': to_port}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/compute/drivers/openstack.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/openstack.py b/libcloud/compute/drivers/openstack.py
index 27f1ace..5a85201 100644
--- a/libcloud/compute/drivers/openstack.py
+++ b/libcloud/compute/drivers/openstack.py
@@ -1758,7 +1758,7 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
         resp = self.connection.request('/os-security-groups/%s' %
                                        (security_group.id),
                                        method='DELETE')
-        return resp.status == httplib.NO_CONTENT
+        return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
 
     def ex_create_security_group_rule(self, security_group, ip_protocol,
                                       from_port, to_port, cidr=None,
@@ -2168,6 +2168,63 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
         return self._to_floating_ip_pools(
             self.connection.request('/os-floating-ip-pools').object)
 
+    def _to_floating_ips(self, obj):
+        ip_elements = obj['floating_ips']
+        return [self._to_floating_ip(ip) for ip in ip_elements]
+
+    def _to_floating_ip(self, obj):
+        return OpenStack_1_1_FloatingIpAddress(obj['id'], obj['ip'], self,
+                                               obj['instance_id'])
+
+    def ex_list_floating_ips(self):
+        """
+        List floating IPs
+
+        :rtype: ``list`` of :class:`OpenStack_1_1_FloatingIpAddress`
+        """
+        return self._to_floating_ips(
+            self.connection.request('/os-floating-ips').object)
+
+    def ex_get_floating_ip(self, ip):
+        """
+        Get specified floating IP
+
+        :param      ip: floating IP to get
+        :type       ip: ``str``
+
+        :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
+        """
+        floating_ips = self.ex_list_floating_ips()
+        ip_obj, = [x for x in floating_ips if x.ip_address == ip]
+        return ip_obj
+
+    def ex_create_floating_ip(self):
+        """
+        Create new floating IP
+
+        :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
+        """
+        resp = self.connection.request('/os-floating-ips',
+                                       method='POST',
+                                       data={})
+        data = resp.object['floating_ip']
+        id = data['id']
+        ip_address = data['ip']
+        return OpenStack_1_1_FloatingIpAddress(id, ip_address, self)
+
+    def ex_delete_floating_ip(self, ip):
+        """
+        Delete specified floating IP
+
+        :param      ip: floating IP to remove
+        :type       ip::class:`OpenStack_1_1_FloatingIpAddress`
+
+        :rtype: ``bool``
+        """
+        resp = self.connection.request('/os-floating-ips/%s' % ip.id,
+                                       method='DELETE')
+        return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
+
     def ex_attach_floating_ip_to_node(self, node, ip):
         """
         Attach the floating IP to the node
@@ -2276,7 +2333,7 @@ class OpenStack_1_1_FloatingIpPool(object):
         """
         Get specified floating IP from the pool
 
-        :param      ip: floating IP to remove
+        :param      ip: floating IP to get
         :type       ip: ``str``
 
         :rtype: :class:`OpenStack_1_1_FloatingIpAddress`
@@ -2320,11 +2377,12 @@ class OpenStack_1_1_FloatingIpAddress(object):
     Floating IP info.
     """
 
-    def __init__(self, id, ip_address, pool, node_id=None):
+    def __init__(self, id, ip_address, pool, node_id=None, driver=None):
         self.id = str(id)
         self.ip_address = ip_address
         self.pool = pool
         self.node_id = node_id
+        self.driver = driver
 
     def delete(self):
         """
@@ -2332,8 +2390,12 @@ class OpenStack_1_1_FloatingIpAddress(object):
 
         :rtype: ``bool``
         """
-        return self.pool.delete_floating_ip(self)
+        if self.pool is not None:
+            return self.pool.delete_floating_ip(self)
+        elif self.driver is not None:
+            return self.driver.ex_delete_floating_ip(self)
 
     def __repr__(self):
-        return ('<OpenStack_1_1_FloatingIpAddress: id=%s, ip_addr=%s, pool=%s>'
-                % (self.id, self.ip_address, self.pool))
+        return ('<OpenStack_1_1_FloatingIpAddress: id=%s, ip_addr=%s,'
+                ' pool=%s, driver=%s>'
+                % (self.id, self.ip_address, self.pool, self.driver))

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/test/test_utils.py
----------------------------------------------------------------------
diff --git a/libcloud/test/test_utils.py b/libcloud/test/test_utils.py
index 1d900d4..58b3506 100644
--- a/libcloud/test/test_utils.py
+++ b/libcloud/test/test_utils.py
@@ -33,6 +33,8 @@ from libcloud.utils.misc import get_driver, set_driver
 from libcloud.utils.py3 import PY3
 from libcloud.utils.py3 import StringIO
 from libcloud.utils.py3 import b
+from libcloud.utils.py3 import bchr
+from libcloud.utils.py3 import hexadigits
 from libcloud.utils.py3 import urlquote
 from libcloud.compute.types import Provider
 from libcloud.compute.providers import DRIVERS
@@ -262,6 +264,20 @@ class TestUtils(unittest.TestCase):
             value = get_secure_random_string(size=i)
             self.assertEqual(len(value), i)
 
+    def test_hexadigits(self):
+        self.assertEqual(hexadigits(b('')), [])
+        self.assertEqual(hexadigits(b('a')), ['61'])
+        self.assertEqual(hexadigits(b('AZaz09-')),
+                         ['41', '5a', '61', '7a', '30', '39', '2d'])
+
+    def test_bchr(self):
+        if PY3:
+            self.assertEqual(bchr(0), b'\x00')
+            self.assertEqual(bchr(97), b'a')
+        else:
+            self.assertEqual(bchr(0), '\x00')
+            self.assertEqual(bchr(97), 'a')
+
 
 class NetworkingUtilsTestCase(unittest.TestCase):
     def test_is_public_and_is_private_subnet(self):

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/utils/publickey.py
----------------------------------------------------------------------
diff --git a/libcloud/utils/publickey.py b/libcloud/utils/publickey.py
index d9e59b9..86c6ec3 100644
--- a/libcloud/utils/publickey.py
+++ b/libcloud/utils/publickey.py
@@ -16,6 +16,9 @@
 import base64
 import hashlib
 
+from libcloud.utils.py3 import hexadigits
+from libcloud.utils.py3 import bchr
+
 __all__ = [
     'get_pubkey_openssh_fingerprint',
     'get_pubkey_ssh2_fingerprint',
@@ -32,7 +35,7 @@ except ImportError:
 
 def _to_md5_fingerprint(data):
     hashed = hashlib.md5(data).digest()
-    return ":".join(x.encode("hex") for x in hashed)
+    return ":".join(hexadigits(hashed))
 
 
 def get_pubkey_openssh_fingerprint(pubkey):
@@ -53,7 +56,7 @@ def get_pubkey_ssh2_fingerprint(pubkey):
     k = importKey(pubkey)
     derPK = DerSequence([k.n, k.e])
     bitmap = DerObject('BIT STRING')
-    bitmap.payload = chr(0x00) + derPK.encode()
+    bitmap.payload = bchr(0x00) + derPK.encode()
     der = DerSequence([algorithmIdentifier, bitmap.encode()])
     return _to_md5_fingerprint(der.encode())
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/21a0d069/libcloud/utils/py3.py
----------------------------------------------------------------------
diff --git a/libcloud/utils/py3.py b/libcloud/utils/py3.py
index 797d317..1f7d229 100644
--- a/libcloud/utils/py3.py
+++ b/libcloud/utils/py3.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Libcloud Python 2.x and 3.x compatibility layer
-# Some methods bellow are taken from Django PYK3 port which is licensed under 3
+# Some methods below are taken from Django PYK3 port which is licensed under 3
 # clause BSD license
 # https://bitbucket.org/loewis/django-3k
 
@@ -83,16 +83,33 @@ if PY3:
         else:
             raise TypeError("Invalid argument %r for b()" % (s,))
 
+    def ensure_string(s):
+        if isinstance(s, str):
+            return s
+        elif isinstance(s, bytes):
+            return s.decode('utf-8')
+        else:
+            raise TypeError("Invalid argument %r for ensure_string()" % (s,))
+
     def byte(n):
         # assume n is a Latin-1 string of length 1
         return ord(n)
     u = str
 
+    def bchr(s):
+        """Take an integer and make a 1-character byte string."""
+        return bytes([s])
+
     def dictvalues(d):
         return list(d.values())
 
     def tostring(node):
         return ET.tostring(node, encoding='unicode')
+
+    def hexadigits(s):
+        # s needs to be a byte string.
+        return [format(x, "x") for x in s]
+
 else:
     import httplib  # NOQA
     from StringIO import StringIO  # NOQA
@@ -125,13 +142,17 @@ else:
 
     method_type = types.MethodType
 
-    b = bytes = str
+    b = bytes = ensure_string = str
 
     def byte(n):
         return n
 
     u = unicode
 
+    def bchr(s):
+        """Take an integer and make a 1-character byte string."""
+        return chr(s)
+
     def next(i):
         return i.next()
 
@@ -146,6 +167,10 @@ else:
             s = s.encode('utf8')
         return _urlquote(s, safe)
 
+    def hexadigits(s):
+        # s needs to be a string.
+        return [x.encode("hex") for x in s]
+
 if PY25:
     import posixpath