Added Keypair extension (os-keypairs) client and tests LP#900139
Change-Id: I34c7e9aa6a1796b8d4c3ac9b3b69438796752866
diff --git a/tempest/openstack.py b/tempest/openstack.py
index ba32487..a3fe71d 100644
--- a/tempest/openstack.py
+++ b/tempest/openstack.py
@@ -8,7 +8,7 @@
from tempest.services.nova.json.security_groups_client \
import SecurityGroupsClient
-import tempest.config
+from tempest.services.nova.json.keypairs_client import KeyPairsClient
class Manager(object):
@@ -45,6 +45,11 @@
self.config.nova.api_key,
self.config.nova.auth_url,
self.config.nova.tenant_name)
+ self.keypairs_client = KeyPairsClient(self.config,
+ self.config.nova.username,
+ self.config.nova.api_key,
+ self.config.nova.auth_url,
+ self.config.nova.tenant_name)
self.security_groups_client = SecurityGroupsClient(self.config,
self.config.nova.username,
self.config.nova.api_key,
@@ -76,6 +81,10 @@
self.config.nova.username,
self.config.nova.api_key,
self.config.nova.auth_url)
+ self.keypairs_client = KeyPairsClient(self.config,
+ self.config.nova.username,
+ self.config.nova.api_key,
+ self.config.nova.auth_url)
class ServiceManager(object):
diff --git a/tempest/services/nova/json/keypairs_client.py b/tempest/services/nova/json/keypairs_client.py
new file mode 100644
index 0000000..7c29215
--- /dev/null
+++ b/tempest/services/nova/json/keypairs_client.py
@@ -0,0 +1,40 @@
+from tempest.common import rest_client
+import json
+
+
+class KeyPairsClient(object):
+
+ def __init__(self, config, username, key, auth_url, tenant_name=None):
+ self.config = config
+ self.client = rest_client.RestClient(config, username, key,
+ auth_url, tenant_name)
+ self.headers = {'Content-Type': 'application/json',
+ 'Accept': 'application/json'}
+
+ def list_keypairs(self):
+ resp, body = self.client.get("/os-keypairs")
+ body = json.loads(body)
+ #Each returned keypair is embedded within an unnecessary 'keypair'
+ #element which is a deviation from other resources like floating-ips,
+ #servers, etc. A bug?
+ #For now we shall adhere to the spec, but the spec for keypairs
+ #is yet to be found
+ return resp, body['keypairs']
+
+ def get_keypair(self, key_name):
+ resp, body = self.client.get("/os-keypairs/%s" % str(key_name))
+ body = json.loads(body)
+ return resp, body['keypair']
+
+ def create_keypair(self, name, pub_key=None):
+ post_body = {'keypair': {'name': name}}
+ if pub_key:
+ post_body['keypair']['public_key'] = pub_key
+ post_body = json.dumps(post_body)
+ resp, body = self.client.post("/os-keypairs",
+ headers=self.headers, body=post_body)
+ body = json.loads(body)
+ return resp, body['keypair']
+
+ def delete_keypair(self, key_name):
+ return self.client.delete("/os-keypairs/%s" % str(key_name))
diff --git a/tempest/tests/test_keypairs.py b/tempest/tests/test_keypairs.py
new file mode 100644
index 0000000..4b75524
--- /dev/null
+++ b/tempest/tests/test_keypairs.py
@@ -0,0 +1,152 @@
+from nose.plugins.attrib import attr
+import unittest2 as unittest
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
+
+
+class KeyPairsTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.os = openstack.Manager()
+ cls.client = cls.os.keypairs_client
+ cls.config = cls.os.config
+
+ @attr(type='smoke')
+ def test_keypairs_create_list_delete(self):
+ """Keypairs created should be available in the response list"""
+ #Create 3 keypairs
+ key_list = list()
+ for i in range(3):
+ k_name = rand_name('keypair-')
+ resp, keypair = self.client.create_keypair(k_name)
+ #Need to pop these keys so that our compare doesn't fail later,
+ #as the keypair dicts from list API doesn't have them.
+ keypair.pop('private_key')
+ keypair.pop('user_id')
+ self.assertEqual(200, resp.status)
+ key_list.append(keypair)
+ #Fetch all keypairs and verify the list
+ #has all created keypairs
+ resp, fetched_list = self.client.list_keypairs()
+ self.assertEqual(200, resp.status)
+ #We need to remove the extra 'keypair' element in the
+ #returned dict. See comment in keypairs_client.list_keypairs()
+ new_list = list()
+ for keypair in fetched_list:
+ new_list.append(keypair['keypair'])
+ fetched_list = new_list
+ #Now check if all the created keypairs are in the fetched list
+ missing_kps = [kp for kp in key_list if kp not in fetched_list]
+ self.assertFalse(missing_kps,
+ "Failed to find keypairs %s in fetched list"
+ % ', '.join(m_key['name'] for m_key in missing_kps))
+ #Delete all the keypairs created
+ for keypair in key_list:
+ resp, _ = self.client.delete_keypair(keypair['name'])
+ self.assertEqual(202, resp.status)
+
+ @attr(type='smoke')
+ def test_keypair_create_delete(self):
+ """Keypair should be created, verified and deleted"""
+ k_name = rand_name('keypair-')
+ resp, keypair = self.client.create_keypair(k_name)
+ self.assertEqual(200, resp.status)
+ private_key = keypair['private_key']
+ key_name = keypair['name']
+ self.assertEqual(key_name, k_name,
+ "The created keypair name is not equal to the requested name")
+ self.assertTrue(private_key is not None,
+ "Field private_key is empty or not found.")
+ resp, _ = self.client.delete_keypair(k_name)
+ self.assertEqual(202, resp.status)
+
+ @attr(type='smoke')
+ def test_keypair_create_get_delete(self):
+ """Keypair should be created, fetched and deleted"""
+ k_name = rand_name('keypair-')
+ resp, keypair = self.client.create_keypair(k_name)
+ self.assertEqual(200, resp.status)
+ #Need to pop these keys so that our compare doesn't fail later,
+ #as the keypair dicts from get API doesn't have them.
+ keypair.pop('private_key')
+ keypair.pop('user_id')
+ #Now fetch the created keypair by its name
+ resp, fetched_key = self.client.get_keypair(k_name)
+ self.assertEqual(200, resp.status)
+
+ self.assertEqual(keypair, fetched_key,
+ "The fetched keypair is different from the created key")
+ #Delete the keypair
+ resp, _ = self.client.delete_keypair(k_name)
+ self.assertEqual(202, resp.status)
+
+ @attr(type='smoke')
+ def test_keypair_create_with_pub_key(self):
+ """Keypair should be created with a given public key"""
+ k_name = rand_name('keypair-')
+ pub_key = ("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs"
+ "Ne3/1ILNCqFyfYWDeTKLD6jEXC2OQHLmietMWW+/vd"
+ "aZq7KZEwO0jhglaFjU1mpqq4Gz5RX156sCTNM9vRbw"
+ "KAxfsdF9laBYVsex3m3Wmui3uYrKyumsoJn2g9GNnG1P"
+ "I1mrVjZ61i0GY3khna+wzlTpCCmy5HNlrmbj3XLqBUpip"
+ "TOXmsnr4sChzC53KCd8LXuwc1i/CZPvF+3XipvAgFSE53pCt"
+ "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
+ "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
+ "snSA8wzBx3A/8y9Pp1B nova@ubuntu")
+ resp, keypair = self.client.create_keypair(k_name, pub_key)
+ self.assertEqual(200, resp.status)
+ self.assertFalse('private_key' in keypair,
+ "Field private_key is not empty!")
+ key_name = keypair['name']
+ self.assertEqual(key_name, k_name,
+ "The created keypair name is not equal to the requested name!")
+ resp, _ = self.client.delete_keypair(k_name)
+ self.assertEqual(202, resp.status)
+
+ @attr(type='negative')
+ def test_keypair_create_with_invalid_pub_key(self):
+ """Keypair should not be created with a non RSA public key"""
+ k_name = rand_name('keypair-')
+ pub_key = "ssh-rsa JUNK nova@ubuntu"
+ resp, _ = self.client.create_keypair(k_name, pub_key)
+ self.assertEqual(400, resp.status)
+
+ @attr(type='negative')
+ def test_keypair_create_with_empty_pub_key(self):
+ """Keypair should not be created with an empty public key"""
+ k_name = rand_name('keypair-')
+ pub_key = ""
+ resp, _ = self.client.create_keypair(k_name, pub_key)
+ self.assertEqual(400, resp.status)
+
+ @attr(type='negative')
+ def test_keypair_delete_nonexistant_key(self):
+ """Non-existant key deletion should throw a proper error"""
+ k_name = rand_name("keypair-non-existant-")
+ resp, _ = self.client.delete_keypair(k_name)
+ self.assertEqual(400, resp.status)
+
+ @attr(type='negative')
+ def test_create_keypair_with_duplicate_name(self):
+ """Keypairs with duplicate names should not be created"""
+ k_name = rand_name('keypair-')
+ resp, _ = self.client.create_keypair(k_name)
+ self.assertEqual(200, resp.status)
+ #Now try the same keyname to ceate another key
+ resp, _ = self.client.create_keypair(k_name)
+ #Expect a HTTP 409 Conflict Error
+ self.assertEqual(409, resp.status)
+
+ @attr(type='negative')
+ def test_create_keypair_with_empty_name_string(self):
+ """Keypairs with name being an empty string should not be created"""
+ resp, _ = self.client.create_keypair('')
+ self.assertEqual(400, resp.status)
+
+ @attr(type='negative')
+ def test_create_keypair_with_long_keynames(self):
+ """Keypairs with name longer than 255 chars should not be created"""
+ k_name = 'keypair-'.ljust(260, '0')
+ resp, _ = self.client.create_keypair(k_name)
+ self.assertEqual(400, resp.status)