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