Merge "Add basic tempest run instructions to the quickstart"
diff --git a/.gitignore b/.gitignore
index 5b87cec..e96deb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@
 !.coveragerc
 cover/
 doc/source/_static/tempest.conf.sample
+doc/source/plugin-registry.rst
 
 # Files created by releasenotes build
 releasenotes/build
diff --git a/doc/source/conf.py b/doc/source/conf.py
index eef3620..127613d 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -15,6 +15,17 @@
 import os
 import subprocess
 
+# Build the plugin registry
+def build_plugin_registry(app):
+    root_dir = os.path.dirname(
+        os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+    subprocess.call(['tools/generate-tempest-plugins-list.sh'], cwd=root_dir)
+
+def setup(app):
+    app.connect('builder-inited', build_plugin_registry)
+
+
+
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 60ff46b..f1ede06 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -2,19 +2,14 @@
 Tempest Testing Project
 =======================
 
-Contents:
+--------
+Overview
+--------
 
 .. toctree::
    :maxdepth: 2
 
    overview
-   HACKING
-   REVIEWING
-   plugin
-   plugin-registry
-   library
-   microversion_testing
-   test-removal
 
 ------------
 Field Guides
@@ -32,6 +27,10 @@
    field_guide/stress
    field_guide/unit_tests
 
+=========
+For users
+=========
+
 ---------------------------
 Tempest Configuration Guide
 ---------------------------
@@ -56,6 +55,41 @@
    workspace
    run
 
+==============
+For developers
+==============
+
+-----------
+Development
+-----------
+
+.. toctree::
+   :maxdepth: 2
+
+   HACKING
+   REVIEWING
+   microversion_testing
+   test-removal
+
+-------
+Plugins
+-------
+
+.. toctree::
+   :maxdepth: 2
+
+   plugin
+   plugin-registry
+
+-------
+Library
+-------
+
+.. toctree::
+   :maxdepth: 2
+
+   library
+
 ==================
 Indices and tables
 ==================
diff --git a/doc/source/plugin-registry.rst b/doc/source/plugin-registry.rst
deleted file mode 100644
index 517e5b8..0000000
--- a/doc/source/plugin-registry.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-..
-  Note to patch submitters: this file is covered by a periodic proposal
-  job.  You should edit the files data/tempest-plugins-registry.footer
-  data/tempest-plugins-registry.header instead of this one.
-
-==========================
- Tempest Plugin Registry
-==========================
-
-Since we've created the external plugin mechanism, it's gotten used by
-a lot of projects. The following is a list of plugins that currently
-exist.
-
-Detected Plugins
-================
-
-The following will list plugins that a script has found in the openstack/
-namespace, which includes but is not limited to official OpenStack
-projects.
-
-+----------------------------+-------------------------------------------------------------------------+
-|Plugin Name                 |URL                                                                      |
-+----------------------------+-------------------------------------------------------------------------+
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
new file mode 100644
index 0000000..f38a068
--- /dev/null
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -0,0 +1,44 @@
+# Copyright 2016 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.volume import base
+from tempest import config
+from tempest import test
+
+
+CONF = config.CONF
+
+
+class VolumesCloneTest(base.BaseVolumeTest):
+
+    @test.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e')
+    def test_create_from_volume(self):
+        # Creates a volume from another volume passing a size different from
+        # the source volume.
+        src_size = CONF.volume.volume_size
+
+        src_vol = self.create_volume(size=src_size)
+        # Destination volume bigger than source
+        dst_vol = self.create_volume(source_volid=src_vol['id'],
+                                     size=src_size + 1)
+
+        volume = self.volumes_client.show_volume(dst_vol['id'])['volume']
+        # Should allow
+        self.assertEqual(volume['source_volid'], src_vol['id'])
+        self.assertEqual(int(volume['size']), src_size + 1)
+
+
+class VolumesV1CloneTest(VolumesCloneTest):
+    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_clone_negative.py b/tempest/api/volume/test_volumes_clone_negative.py
new file mode 100644
index 0000000..ee51e00
--- /dev/null
+++ b/tempest/api/volume/test_volumes_clone_negative.py
@@ -0,0 +1,42 @@
+# Copyright 2016 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.volume import base
+from tempest import config
+from tempest.lib import exceptions
+from tempest import test
+
+
+CONF = config.CONF
+
+
+class VolumesCloneTest(base.BaseVolumeTest):
+
+    @test.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e')
+    def test_create_from_volume_decreasing_size(self):
+        # Creates a volume from another volume passing a size different from
+        # the source volume.
+        src_size = CONF.volume.volume_size + 1
+        src_vol = self.create_volume(size=src_size)
+
+        # Destination volume smaller than source
+        self.assertRaises(exceptions.BadRequest,
+                          self.volumes_client.create_volume,
+                          size=src_size - 1,
+                          source_volid=src_vol['id'])
+
+
+class VolumesV1CloneTest(VolumesCloneTest):
+    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 0f7c4f6..c7f1e6e 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -178,16 +178,19 @@
 
     @test.idempotent_id('677863d1-3142-456d-b6ac-9924f667a7f4')
     def test_volume_from_snapshot(self):
-        # Create a temporary snap using wrapper method from base, then
-        # create a snap based volume and deletes it
-        snapshot = self.create_snapshot(self.volume_origin['id'])
-        # NOTE(gfidente): size is required also when passing snapshot_id
-        volume = self.volumes_client.create_volume(
-            snapshot_id=snapshot['id'])['volume']
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
-        self.delete_volume(self.volumes_client, volume['id'])
-        self.cleanup_snapshot(snapshot)
+        # Creates a volume a snapshot passing a size different from the source
+        src_size = CONF.volume.volume_size
+
+        src_vol = self.create_volume(size=src_size)
+        src_snap = self.create_snapshot(src_vol['id'])
+        # Destination volume bigger than source snapshot
+        dst_vol = self.create_volume(snapshot_id=src_snap['id'],
+                                     size=src_size + 1)
+
+        volume = self.volumes_client.show_volume(dst_vol['id'])['volume']
+        # Should allow
+        self.assertEqual(volume['snapshot_id'], src_snap['id'])
+        self.assertEqual(int(volume['size']), src_size + 1)
 
     @test.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896')
     def test_snapshot_list_param_limit(self):
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 374979c..2df9523 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -46,6 +46,20 @@
                           self.snapshots_client.create_snapshot,
                           volume_id=None, display_name=s_name)
 
+    @test.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4')
+    def test_volume_from_snapshot_decreasing_size(self):
+        # Creates a volume a snapshot passing a size different from the source
+        src_size = CONF.volume.volume_size + 1
+
+        src_vol = self.create_volume(size=src_size)
+        src_snap = self.create_snapshot(src_vol['id'])
+
+        # Destination volume smaller than source
+        self.assertRaises(lib_exc.BadRequest,
+                          self.volumes_client.create_volume,
+                          size=src_size - 1,
+                          snapshot_id=src_snap['id'])
+
 
 class VolumesV1SnapshotNegativeTestJSON(VolumesV2SnapshotNegativeTestJSON):
     _api_version = 1
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index c990add..da7f426 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -45,6 +45,7 @@
 
 Ports file JSON structure
 ^^^^^^^^^^^^^^^^^^^^^^^^^
+::
 
   {
       "<port number>": "<name of service>",
@@ -54,6 +55,8 @@
 
 Output file JSON structure
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
   {
       "full_test_name[with_id_and_tags]": [
           {
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 80728dc..446c87a 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import json
+import re
 
 from oslo_log import log as logging
 
@@ -83,9 +84,9 @@
     def verify_metadata_on_config_drive(self):
         if self.run_ssh and CONF.compute_feature_enabled.config_drive:
             # Verify metadata on config_drive
-            cmd_blkid = 'blkid -t LABEL=config-2 -o device'
-            dev_name = self.ssh_client.exec_command(cmd_blkid)
-            dev_name = dev_name.rstrip()
+            cmd_blkid = 'blkid | grep -i config-2'
+            result = self.ssh_client.exec_command(cmd_blkid)
+            dev_name = re.match('([^:]+)', result).group()
             self.ssh_client.exec_command('sudo mount %s /mnt' % dev_name)
             cmd_md = 'sudo cat /mnt/openstack/latest/meta_data.json'
             result = self.ssh_client.exec_command(cmd_md)