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/08/31 18:41:43 UTC

git commit: Adds the following methods for the Softlayer driver: - list_key_pairs() - get_key_pair() - import_key_pair_from_string() - delete_key_pair() - create_key_pair() (only if Pycripto is installed)

Repository: libcloud
Updated Branches:
  refs/heads/trunk 860674ac7 -> f007edaaf


Adds the following methods for the Softlayer driver: - list_key_pairs() - get_key_pair() - import_key_pair_from_string() - delete_key_pair() - create_key_pair() (only if Pycripto is installed)

Adds tests for all new methods.
Modifies the test_create_node() to use an ssh key.
Adds a new property on the Softlayer node "ex_keyname"which is the name of the key to be associated to the new node.

Closes #354

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/f007edaa
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/f007edaa
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/f007edaa

Branch: refs/heads/trunk
Commit: f007edaafcae79afb2890e75cd2ba1f91aa26d7e
Parents: 860674a
Author: Itxaka Serrano <it...@virdata.com>
Authored: Sun Aug 31 18:07:14 2014 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Sun Aug 31 18:34:45 2014 +0200

----------------------------------------------------------------------
 CHANGES.rst                                     |  4 +
 libcloud/compute/drivers/softlayer.py           | 96 +++++++++++++++++++-
 .../v3__SoftLayer_Account_getSshKeys.xml        | 63 +++++++++++++
 ..._SoftLayer_Security_Ssh_Key_createObject.xml | 39 ++++++++
 ..._SoftLayer_Security_Ssh_Key_deleteObject.xml | 15 +++
 ...v3__SoftLayer_Security_Ssh_Key_getObject.xml | 33 +++++++
 libcloud/test/compute/test_softlayer.py         | 64 ++++++++++++-
 7 files changed, 308 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 53345c8..69ab399 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -78,6 +78,10 @@ Compute
   (LIBCLOUD-544, GITHUB-349, GITHUB-353)
   [Raphael Theberge]
 
+- Add SSH key pair management methods to the Softlayer driver.
+  (GITHUB-321, GITHUB-354)
+  [Itxaka Serrano]
+
 Storage
 ~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/libcloud/compute/drivers/softlayer.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/softlayer.py b/libcloud/compute/drivers/softlayer.py
index 4fe8cdd..61a1e1a 100644
--- a/libcloud/compute/drivers/softlayer.py
+++ b/libcloud/compute/drivers/softlayer.py
@@ -17,13 +17,19 @@ Softlayer driver
 """
 
 import time
+try:
+    from Crypto.PublicKey import RSA
+    crypto = True
+except ImportError:
+    crypto = False
 
 from libcloud.common.base import ConnectionUserAndKey
 from libcloud.common.xmlrpc import XMLRPCResponse, XMLRPCConnection
 from libcloud.common.types import InvalidCredsError, LibcloudError
 from libcloud.compute.types import Provider, NodeState
 from libcloud.compute.base import NodeDriver, Node, NodeLocation, NodeSize, \
-    NodeImage
+    NodeImage, KeyPair
+from libcloud.compute.types import KeyPairDoesNotExistError
 
 DEFAULT_DOMAIN = 'example.com'
 DEFAULT_CPU_SIZE = 1
@@ -158,7 +164,6 @@ class SoftLayerConnection(XMLRPCConnection, ConnectionUserAndKey):
 
         args = ({'headers': headers}, ) + args
         endpoint = '%s/%s' % (self.endpoint, service)
-
         return super(SoftLayerConnection, self).request(method, *args,
                                                         **{'endpoint':
                                                             endpoint})
@@ -204,7 +209,7 @@ class SoftLayerNodeDriver(NodeDriver):
     website = 'http://www.softlayer.com/'
     type = Provider.SOFTLAYER
 
-    features = {'create_node': ['generates_password']}
+    features = {'create_node': ['generates_password', 'ssh_key']}
 
     def _to_node(self, host):
         try:
@@ -330,6 +335,8 @@ class SoftLayerNodeDriver(NodeDriver):
         :type       ex_datacenter: ``str``
         :keyword    ex_os: e.g. UBUNTU_LATEST
         :type       ex_os: ``str``
+        :keyword    ex_keyname: The name of the key pair
+        :type       ex_keyname: ``str``
         """
         name = kwargs['name']
         os = 'DEBIAN_LATEST'
@@ -402,6 +409,9 @@ class SoftLayerNodeDriver(NodeDriver):
         if datacenter:
             newCCI['datacenter'] = {'name': datacenter}
 
+        if 'ex_keyname' in kwargs:
+            newCCI['sshKeys'] = [self._key_name_to_id(kwargs['ex_keyname'])]
+
         res = self.connection.request(
             'SoftLayer_Virtual_Guest', 'createObject', newCCI
         ).object
@@ -411,6 +421,59 @@ class SoftLayerNodeDriver(NodeDriver):
 
         return self._to_node(raw_node)
 
+    def list_key_pairs(self):
+        result = self.connection.request(
+            'SoftLayer_Account', 'getSshKeys'
+        ).object
+        elems = [x for x in result]
+        key_pairs = self._to_key_pairs(elems=elems)
+        return key_pairs
+
+    def get_key_pair(self, name):
+        key_id = self._key_name_to_id(name=name)
+        result = self.connection.request(
+            'SoftLayer_Security_Ssh_Key', 'getObject', id=key_id
+        ).object
+        return self._to_key_pair(result)
+
+    # TODO: Check this with the libcloud guys,
+    # can we create new dependencies?
+    def create_key_pair(self, name, ex_size=4096):
+        if crypto is False:
+            raise NotImplementedError('create_key_pair needs'
+                                      'the pycrypto library')
+        key = RSA.generate(ex_size)
+        new_key = {
+            'key': key.publickey().exportKey('OpenSSH'),
+            'label': name,
+            'notes': '',
+        }
+        result = self.connection.request(
+            'SoftLayer_Security_Ssh_Key', 'createObject', new_key
+        ).object
+        result['private'] = key.exportKey('PEM')
+        return self._to_key_pair(result)
+
+    def import_key_pair_from_string(self, name, key_material):
+        new_key = {
+            'key': key_material,
+            'label': name,
+            'notes': '',
+        }
+        result = self.connection.request(
+            'SoftLayer_Security_Ssh_Key', 'createObject', new_key
+        ).object
+
+        key_pair = self._to_key_pair(result)
+        return key_pair
+
+    def delete_key_pair(self, key_pair):
+        key = self._key_name_to_id(key_pair)
+        result = self.connection.request(
+            'SoftLayer_Security_Ssh_Key', 'deleteObject', id=key
+        ).object
+        return result
+
     def _to_image(self, img):
         return NodeImage(
             id=img['template']['operatingSystemReferenceCode'],
@@ -467,8 +530,31 @@ class SoftLayerNodeDriver(NodeDriver):
             },
         }
         res = self.connection.request(
-            "SoftLayer_Account",
-            "getVirtualGuests",
+            'SoftLayer_Account',
+            'getVirtualGuests',
             object_mask=mask
         ).object
         return [self._to_node(h) for h in res]
+
+    def _to_key_pairs(self, elems):
+        key_pairs = [self._to_key_pair(elem=elem) for elem in elems]
+        return key_pairs
+
+    def _to_key_pair(self, elem):
+        key_pair = KeyPair(name=elem['label'],
+                           public_key=elem['key'],
+                           fingerprint=elem['fingerprint'],
+                           private_key=elem.get('private', None),
+                           driver=self,
+                           extra={'id': elem['id']})
+        return key_pair
+
+    def _key_name_to_id(self, name):
+        result = self.connection.request(
+            'SoftLayer_Account', 'getSshKeys'
+        ).object
+        key_id = [x for x in result if x['label'] == name]
+        if len(key_id) == 0:
+            raise KeyPairDoesNotExistError(name, self)
+        else:
+            return int(key_id[0]['id'])

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Account_getSshKeys.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Account_getSshKeys.xml b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Account_getSshKeys.xml
new file mode 100644
index 0000000..a06952c
--- /dev/null
+++ b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Account_getSshKeys.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+    <param>
+        <value>
+            <struct>
+                <member>
+                    <name>id</name>
+                    <value>
+                        <int>1</int>
+                    </value>
+                </member>
+                <member>
+                    <name>key</name>
+                    <value>
+                        <string>ssh-key</string>
+                    </value>
+                </member>
+                <member>
+                    <name>label</name>
+                    <value>
+                        <string>test1</string>
+                    </value>
+                </member>
+                <member>
+                    <name>fingerprint</name>
+                    <value>
+                        <string>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</string>
+                    </value>
+                </member>
+            </struct>
+        </value>
+    </param>
+    <param>
+        <value>
+            <struct>
+                <member>
+                    <name>id</name>
+                    <value>
+                        <int>2</int>
+                    </value>
+                </member>
+                <member>
+                    <name>key</name>
+                    <value>
+                        <string>ssh-key</string>
+                    </value>
+                </member>
+                <member>
+                    <name>label</name>
+                    <value>
+                        <string>test2</string>
+                    </value>
+                </member>
+                <member>
+                    <name>fingerprint</name>
+                    <value>
+                        <string>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</string>
+                    </value>
+                </member>
+            </struct>
+        </value>
+    </param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_createObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_createObject.xml b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_createObject.xml
new file mode 100644
index 0000000..716832e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_createObject.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+    <param>
+        <value>
+            <struct>
+                <member>
+                    <name>id</name>
+                    <value>
+                        <int>1</int>
+                    </value>
+                </member>
+                <member>
+                    <name>key</name>
+                    <value>
+                        <string>ssh-key</string>
+                    </value>
+                </member>
+                <member>
+                    <name>label</name>
+                    <value>
+                        <string>my-key-pair</string>
+                    </value>
+                </member>
+                 <member>
+                    <name>label</name>
+                    <value>
+                        <string>my-key-pair</string>
+                    </value>
+                </member>
+                <member>
+                    <name>fingerprint</name>
+                    <value>
+                        <string>1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f</string>
+                    </value>
+                </member>
+            </struct>
+        </value>
+    </param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_deleteObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_deleteObject.xml b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_deleteObject.xml
new file mode 100644
index 0000000..119680e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_deleteObject.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+    <param>
+        <value>
+            <struct>
+                <member>
+                    <name>status</name>
+                    <value>
+                        <string>success</string>
+                    </value>
+                </member>
+            </struct>
+        </value>
+    </param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_getObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_getObject.xml b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_getObject.xml
new file mode 100644
index 0000000..cf96523
--- /dev/null
+++ b/libcloud/test/compute/fixtures/softlayer/v3__SoftLayer_Security_Ssh_Key_getObject.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+    <param>
+        <value>
+            <struct>
+                <member>
+                    <name>id</name>
+                    <value>
+                        <int>1</int>
+                    </value>
+                </member>
+                <member>
+                    <name>key</name>
+                    <value>
+                        <string>ssh-key</string>
+                    </value>
+                </member>
+                <member>
+                    <name>label</name>
+                    <value>
+                        <string>test1</string>
+                    </value>
+                </member>
+                <member>
+                    <name>fingerprint</name>
+                    <value>
+                        <string>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</string>
+                    </value>
+                </member>
+            </struct>
+        </value>
+    </param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/f007edaa/libcloud/test/compute/test_softlayer.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_softlayer.py b/libcloud/test/compute/test_softlayer.py
index 74f4a32..8f4536b 100644
--- a/libcloud/test/compute/test_softlayer.py
+++ b/libcloud/test/compute/test_softlayer.py
@@ -16,6 +16,13 @@
 import unittest
 import sys
 
+try:
+    import Crypto
+    Crypto
+    crypto = True
+except ImportError:
+    crypto = False
+
 from libcloud.common.types import InvalidCredsError
 
 from libcloud.utils.py3 import httplib
@@ -25,12 +32,15 @@ from libcloud.utils.py3 import next
 from libcloud.compute.drivers.softlayer import SoftLayerNodeDriver as SoftLayer
 from libcloud.compute.drivers.softlayer import SoftLayerException, \
     NODE_STATE_MAP
-from libcloud.compute.types import NodeState
+from libcloud.compute.types import NodeState, KeyPairDoesNotExistError
 
 from libcloud.test import MockHttp               # pylint: disable-msg=E0611
 from libcloud.test.file_fixtures import ComputeFileFixtures
 from libcloud.test.secrets import SOFTLAYER_PARAMS
 
+null_fingerprint = '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:' + \
+                   '00:00:00:00:00'
+
 
 class SoftLayerTests(unittest.TestCase):
 
@@ -119,6 +129,7 @@ class SoftLayerTests(unittest.TestCase):
                                 ex_cpus=2,
                                 ex_ram=2048,
                                 ex_disk=100,
+                                ex_key='test1',
                                 ex_bandwidth=10,
                                 ex_local_disk=False,
                                 ex_datacenter='Dal05',
@@ -132,6 +143,37 @@ class SoftLayerTests(unittest.TestCase):
         node = self.driver.list_nodes()[0]
         self.driver.destroy_node(node)
 
+    def test_list_keypairs(self):
+        keypairs = self.driver.list_key_pairs()
+        self.assertEqual(len(keypairs), 2)
+        self.assertEqual(keypairs[0].name, 'test1')
+        self.assertEqual(keypairs[0].fingerprint, null_fingerprint)
+
+    def test_get_key_pair(self):
+        key_pair = self.driver.get_key_pair(name='test1')
+        self.assertEqual(key_pair.name, 'test1')
+
+    def test_get_key_pair_does_not_exist(self):
+        self.assertRaises(KeyPairDoesNotExistError, self.driver.get_key_pair,
+                          name='test-key-pair')
+
+    def test_create_key_pair(self):
+        if crypto:
+            key_pair = self.driver.create_key_pair(name='my-key-pair')
+            fingerprint = ('1f:51:ae:28:bf:89:e9:d8:1f:25:5d'
+                           ':37:2d:7d:b8:ca:9f:f5:f1:6f')
+
+            self.assertEqual(key_pair.name, 'my-key-pair')
+            self.assertEqual(key_pair.fingerprint, fingerprint)
+            self.assertTrue(key_pair.private_key is not None)
+        else:
+            self.assertRaises(NotImplementedError, self.driver.create_key_pair,
+                              name='my-key-pair')
+
+    def test_delete_key_pair(self):
+        success = self.driver.delete_key_pair('test1')
+        self.assertTrue(success)
+
 
 class SoftLayerMockHttp(MockHttp):
     fixtures = ComputeFileFixtures('softlayer')
@@ -188,6 +230,26 @@ class SoftLayerMockHttp(MockHttp):
         body = self.fixtures.load('empty.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _xmlrpc_v3_SoftLayer_Account_getSshKeys(
+            self, method, url, body, headers):
+        body = self.fixtures.load('v3__SoftLayer_Account_getSshKeys.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Security_Ssh_Key_getObject(
+            self, method, url, body, headers):
+        body = self.fixtures.load('v3__SoftLayer_Security_Ssh_Key_getObject.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Security_Ssh_Key_createObject(
+            self, method, url, body, headers):
+        body = self.fixtures.load('v3__SoftLayer_Security_Ssh_Key_createObject.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Security_Ssh_Key_deleteObject(
+            self, method, url, body, headers):
+        body = self.fixtures.load('v3__SoftLayer_Security_Ssh_Key_deleteObject.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
 
 if __name__ == '__main__':
     sys.exit(unittest.main())