Merge "Addresses lp#940832"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 22d9f7e..b63b077 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -24,6 +24,9 @@
 build_timeout=600
 catalog_type=compute
 create_image_enabled=true
+# For resize to work with libvirt/kvm, one of the following must be true:
+# Single node: allow_resize_to_same_host=True must be set in nova.conf
+# Cluster: the 'nova' user must have scp access between cluster nodes
 resize_available=true
 
 [image]
diff --git a/stress/README.rst b/stress/README.rst
index 00e3b90..bf44f13 100644
--- a/stress/README.rst
+++ b/stress/README.rst
@@ -23,14 +23,15 @@
 ------------

 This particular framework assumes your working Nova cluster understands Nova 

 API 2.0. The stress tests can read the logs from the cluster. To enable this

-you have to

-provide the private key and user name for ssh to the cluster in the

+you have to provide the hostname to call 'nova-manage' and

+the private key and user name for ssh to the cluster in the

 [stress] section of tempest.conf. You also need to provide the

 value of --logdir in nova.conf:

 

   host_private_key_path=<path to private ssh key>

   host_admin_user=<name of user for ssh command>

   nova_logdir=<value of --logdir in nova.conf>

+  controller=<hostname for calling nova-manage>

 

 The stress test needs the top-level tempest directory to be on PYTHONPATH

 if you are not using nosetests to run.

diff --git a/stress/config.py b/stress/config.py
index 3f107af..0dce816 100755
--- a/stress/config.py
+++ b/stress/config.py
@@ -41,3 +41,8 @@
     def nova_logdir(self):

         """Directory containing log files on the compute nodes"""

         return self.get("nova_logdir", None)

+

+    @property

+    def controller(self):

+        """Controller host"""

+        return self.get("controller", None)

diff --git a/stress/test_servers.py b/stress/test_servers.py
index 3f62ac3..47d30b5 100644
--- a/stress/test_servers.py
+++ b/stress/test_servers.py
@@ -57,7 +57,8 @@
             return None
 
         _key_name = kwargs.get('key_name', '')
-        _timeout = int(kwargs.get('timeout', 60))
+        _timeout = int(kwargs.get('timeout',
+                                  manager.config.compute.build_timeout))
         _image_ref = kwargs.get('image_ref', manager.config.compute.image_ref)
         _flavor_ref = kwargs.get('flavor_ref',
                                  manager.config.compute.flavor_ref)
@@ -172,7 +173,7 @@
             self._logger.info('no ACTIVE instances to delete')
             return
 
-        _timeout = kwargs.get('timeout', 600)
+        _timeout = kwargs.get('timeout', manager.config.compute.build_timeout)
 
         target = random.choice(active_vms)
         killtarget = target[0]
@@ -240,7 +241,7 @@
             self._logger.info('no active instances to delete')
             return
 
-        _timeout = kwargs.get('timeout', 60)
+        _timeout = kwargs.get('timeout', manager.config.compute.build_timeout)
 
         target = random.choice(vms)
         killtarget = target[0]
@@ -276,7 +277,7 @@
             self._logger.info('no active instances to update')
             return
 
-        _timeout = kwargs.get('timeout', 600)
+        _timeout = kwargs.get('timeout', manager.config.compute.build_timeout)
 
         target = random.choice(active_vms)
         update_target = target[0]
diff --git a/stress/tests/create_kill.py b/stress/tests/create_kill.py
index 1457279..752f72d 100644
--- a/stress/tests/create_kill.py
+++ b/stress/tests/create_kill.py
@@ -20,13 +20,8 @@
 from tempest import openstack

 

 choice_spec = [

-    BasherAction(TestCreateVM(), 50,

-                 kargs={'timeout': '600',

-                        'image_ref': 2,

-                        'flavor_ref': 1}

-                 ),

-    BasherAction(TestKillActiveVM(), 50,

-                 kargs={'timeout': '600'})

+    BasherAction(TestCreateVM(), 50),

+    BasherAction(TestKillActiveVM(), 50)

 ]

 

 nova = openstack.Manager()

diff --git a/stress/tests/hard_reboots.py b/stress/tests/hard_reboots.py
index 503159e..f38ef6f 100644
--- a/stress/tests/hard_reboots.py
+++ b/stress/tests/hard_reboots.py
@@ -21,10 +21,9 @@
 from tempest import openstack

 

 choice_spec = [

-    BasherAction(TestCreateVM(), 50,

-                 kargs={'timeout': '600'}),

+    BasherAction(TestCreateVM(), 50),

     BasherAction(TestRebootVM(), 50,

-                 kargs={'type': 'HARD'}),

+                 kargs={'type': 'HARD'})

 ]

 

 nova = openstack.Manager()

diff --git a/stress/utils/util.py b/stress/utils/util.py
index aac6c26..ac8f062 100644
--- a/stress/utils/util.py
+++ b/stress/utils/util.py
@@ -32,6 +32,7 @@
 

 

 def ssh(keypath, user, node, command, check=True):

+    command = 'sudo ' + command

     command = "ssh %s %s@%s %s" % (get_ssh_options(keypath), user,

                                    node, command)

     popenargs = shlex.split(command)

diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index d4ad014..ff27384 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -93,7 +93,8 @@
             management_url = service_url + tenant_id
             return token, management_url
         elif resp.status == 401:
-            raise exceptions.AuthenticationFailure(user=user, password=api_key)
+            raise exceptions.AuthenticationFailure(user=user,
+                                                   password=password)
 
     def post(self, url, body, headers):
         return self.request('POST', url, headers, body)
diff --git a/tempest/openstack.py b/tempest/openstack.py
index 68d924c..69b4e3c 100644
--- a/tempest/openstack.py
+++ b/tempest/openstack.py
@@ -10,6 +10,7 @@
 import SecurityGroupsClient
 from tempest.services.nova.json.floating_ips_client import FloatingIPsClient
 from tempest.services.nova.json.keypairs_client import KeyPairsClient
+from tempest.services.nova.json.volumes_client import VolumesClient
 
 
 class Manager(object):
@@ -46,6 +47,7 @@
         self.keypairs_client = KeyPairsClient(*client_args)
         self.security_groups_client = SecurityGroupsClient(*client_args)
         self.floating_ips_client = FloatingIPsClient(*client_args)
+        self.volumes_client = VolumesClient(*client_args)
 
 
 class ServiceManager(object):
diff --git a/tempest/services/nova/json/volumes_client.py b/tempest/services/nova/json/volumes_client.py
new file mode 100644
index 0000000..95131f2
--- /dev/null
+++ b/tempest/services/nova/json/volumes_client.py
@@ -0,0 +1,36 @@
+from tempest.common import rest_client
+import json
+
+
+class VolumesClient(object):
+
+    def __init__(self, config, username, key, auth_url, tenant_name=None):
+        self.config = config
+        catalog_type = self.config.compute.catalog_type
+        self.client = rest_client.RestClient(config, username, key, auth_url,
+                                             catalog_type, tenant_name)
+
+    def list_volumes(self, params=None):
+        """List all the volumes created"""
+        url = 'os-volumes'
+        if params != None:
+            param_list = []
+            for param, value in params.iteritems():
+                param_list.append("%s=%s&" % (param, value))
+
+            url += '?' + ' '.join(param_list)
+
+        resp, body = self.client.get(url)
+        body = json.loads(body)
+        return resp, body['volumes']
+
+    def get_volume(self, volume_id):
+        """Returns the details of a single volume"""
+        url = "os-volumes/%s" % str(volume_id)
+        resp, body = self.client.get(url)
+        body = json.loads(body)
+        return resp, body['volume']
+
+    def delete_volume(self, volume_id):
+        """Deletes the Specified Volume"""
+        return self.client.delete("os-volumes/%s" % str(volume_id))
diff --git a/tempest/tests/image/test_images.py b/tempest/tests/image/test_images.py
index 70dec32..8f75f08 100644
--- a/tempest/tests/image/test_images.py
+++ b/tempest/tests/image/test_images.py
@@ -202,4 +202,4 @@
         Simple test to see all fixture images returned
         """
         images = self.client.get_images()
-        self.assertEqual(10, len(images) - len(cls.original_images))
+        self.assertEqual(10, len(images) - len(self.original_images))
diff --git a/tempest/tests/test_images.py b/tempest/tests/test_images.py
index c422708..8217d2a 100644
--- a/tempest/tests/test_images.py
+++ b/tempest/tests/test_images.py
@@ -7,8 +7,8 @@
 
 
 def _parse_image_id(image_ref):
-    temp = image_ref.rsplit('/')
-    return temp[6]
+    temp = image_ref.rsplit('images/')
+    return temp[1]
 
 
 class ImagesTest(unittest.TestCase):
diff --git a/tempest/tests/test_volumes_negative.py b/tempest/tests/test_volumes_negative.py
new file mode 100644
index 0000000..83eef52
--- /dev/null
+++ b/tempest/tests/test_volumes_negative.py
@@ -0,0 +1,54 @@
+from nose.plugins.attrib import attr
+import unittest2 as unittest
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+
+
+class VolumesTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.os = openstack.Manager()
+        cls.client = cls.os.volumes_client
+
+    @attr(type='negative')
+    def test_volume_get_nonexistant_volume_id(self):
+        """Negative: Should not be able to get details of nonexistant volume"""
+        #Creating a nonexistant volume id
+        volume_id_list = list()
+        resp, body = self.client.list_volumes()
+        for i in range(len(body)):
+            volume_id_list.append(body[i]['id'])
+        while True:
+            non_exist_id = rand_name('999')
+            if non_exist_id not in volume_id_list:
+                break
+        #Trying to GET a non existant volume
+        try:
+            resp, body = self.client.get_volume(non_exist_id)
+        except exceptions.NotFound:
+            pass
+        else:
+            self.fail('Should not be able to GET the details from a '
+                      'nonexistant volume')
+
+    @attr(type='negative')
+    def test_volume_delete_nonexistant_volume_id(self):
+        """Negative: Should not be able to delete nonexistant Volume"""
+        #Creating nonexistant volume id
+        volume_id_list = list()
+        resp, body = self.client.list_volumes()
+        for i in range(len(body)):
+            volume_id_list.append(body[i]['id'])
+        while True:
+            non_exist_id = rand_name('999')
+            if non_exist_id not in volume_id_list:
+                break
+        #Trying to DELETE a non existant volume
+        try:
+            resp, body = self.client.delete_volume(non_exist_id)
+        except exceptions.NotFound:
+            pass
+        else:
+            self.fail('Should not be able to DELETE a nonexistant volume')