Merge "Remove special_fields definition"
diff --git a/HACKING.rst b/HACKING.rst
index 910a977..f97f97a 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -170,7 +170,7 @@
 All negative tests should be based on `API-WG guideline`_ . Such negative
 tests can block any changes from accurate failure code to invalid one.
 
-.. _API-WG guideline: https://github.com/openstack/api-wg/blob/master/guidelines/http.rst#failure-code-clarifications
+.. _API-WG guideline: http://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications
 
 If facing some gray area which is not clarified on the above guideline, propose
 a new guideline to the API-WG. With a proposal to the API-WG we will be able to
diff --git a/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml b/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
new file mode 100644
index 0000000..233cc28
--- /dev/null
+++ b/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add versions_client module for volume service.
+    This new module provides list_versions() method which shows API versions
+    from Volume service.
diff --git a/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml b/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml
new file mode 100644
index 0000000..69c6bb6
--- /dev/null
+++ b/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+  - |
+    The ``deactivate_image`` configuration switch from the ``config`` module
+    is deprecated. It was added to support the older-than-kilo releases
+    which we don't support anymore.
diff --git a/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml b/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
new file mode 100644
index 0000000..0660d9c
--- /dev/null
+++ b/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
@@ -0,0 +1,12 @@
+---
+deprecations:
+  - |
+    Volume v1 API is deprecated and the v3 are CURRENT.
+    Tempest doesn't need to test the v1 API as the default.
+    The volume config option 'api_v1' has been marked as
+    deprecated.
+upgrade:
+  - |
+    The volume config option 'api_v1' default is changed to
+    ``False`` because the volume v1 API has been deprecated
+    since Juno release.
diff --git a/tempest/api/volume/v3/base.py b/tempest/api/volume/v3/base.py
index 31fc1eb..7f76e6f 100644
--- a/tempest/api/volume/v3/base.py
+++ b/tempest/api/volume/v3/base.py
@@ -45,6 +45,7 @@
     def setup_clients(cls):
         super(VolumesV3Test, cls).setup_clients()
         cls.messages_client = cls.os.volume_v3_messages_client
+        cls.versions_client = cls.os.volume_v3_versions_client
 
     def setUp(self):
         super(VolumesV3Test, self).setUp()
diff --git a/tempest/api/volume/v3/test_versions.py b/tempest/api/volume/v3/test_versions.py
new file mode 100644
index 0000000..20f1657
--- /dev/null
+++ b/tempest/api/volume/v3/test_versions.py
@@ -0,0 +1,28 @@
+# Copyright 2017 NEC Corporation.  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.v3 import base
+from tempest.lib import decorators
+from tempest import test
+
+
+class VersionsTest(base.VolumesV3Test):
+
+    @decorators.idempotent_id('77838fc4-b49b-4c64-9533-166762517369')
+    @test.attr(type='smoke')
+    def test_list_versions(self):
+        # NOTE: The version data is checked on service client side
+        #       with JSON-Schema validation. It is enough to just call
+        #       the API here.
+        self.versions_client.list_versions()['versions']
diff --git a/tempest/clients.py b/tempest/clients.py
index e75fa79..0654110 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -265,6 +265,7 @@
         self.volumes_client = self.volume_v1.VolumesClient()
         self.volumes_v2_client = self.volume_v2.VolumesClient()
         self.volume_v3_messages_client = self.volume_v3.MessagesClient()
+        self.volume_v3_versions_client = self.volume_v3.VersionsClient()
         self.volume_types_client = self.volume_v1.TypesClient()
         self.volume_types_v2_client = self.volume_v2.TypesClient()
         self.volume_hosts_client = self.volume_v1.HostsClient()
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 9a483bb..b2667e5 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -13,6 +13,9 @@
 #    See the License for the specific language governing permissions and
 #    limitations under the License.
 
+import base64
+import textwrap
+
 from oslo_log import log as logging
 from oslo_utils import excutils
 
@@ -113,6 +116,19 @@
             if wait_until is None:
                 wait_until = 'ACTIVE'
 
+        if 'user_data' not in kwargs:
+            # If nothing overrides the default user data script then run
+            # a simple script on the host to print networking info. This is
+            # to aid in debugging ssh failures.
+            script = '''
+                     #!/bin/sh
+                     echo "Printing {user} user authorized keys"
+                     cat ~{user}/.ssh/authorized_keys || true
+                     '''.format(user=CONF.validation.image_ssh_user)
+            script_clean = textwrap.dedent(script).lstrip().encode('utf8')
+            script_b64 = base64.b64encode(script_clean)
+            kwargs['user_data'] = script_b64
+
     if volume_backed:
         volume_name = data_utils.rand_name(__name__ + '-volume')
         volumes_client = clients.volumes_v2_client
diff --git a/tempest/config.py b/tempest/config.py
index d5c8ea9..93b8ab2 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -223,8 +223,8 @@
                 default=True,
                 help='Does the environment support reseller?',
                 deprecated_for_removal=True,
-                deprecated_reason="All supported version of OpenStack now "
-                                  "supports the 'reseller' feature"),
+                deprecated_reason="All supported versions of OpenStack now "
+                                  "support the 'reseller' feature"),
     # TODO(rodrigods): This is a feature flag for bug 1590578 which is fixed
     # in Newton and Ocata. This option can be removed after Mitaka is end of
     # life.
@@ -531,7 +531,10 @@
     cfg.BoolOpt('deactivate_image',
                 default=False,
                 help="Is the deactivate-image feature enabled."
-                     " The feature has been integrated since Kilo."),
+                     " The feature has been integrated since Kilo.",
+                deprecated_for_removal=True,
+                deprecated_reason="All supported versions of OpenStack now "
+                                  "support the 'deactivate_image' feature"),
 ]
 
 network_group = cfg.OptGroup(name='network',
@@ -812,8 +815,12 @@
                      'entry all which indicates every extension is enabled. '
                      'Empty list indicates all extensions are disabled'),
     cfg.BoolOpt('api_v1',
-                default=True,
-                help="Is the v1 volume API enabled"),
+                default=False,
+                help="Is the v1 volume API enabled",
+                deprecated_for_removal=True,
+                deprecated_reason="The v1 volume API has been deprecated "
+                                  "since Juno release, and the API will be "
+                                  "removed."),
     cfg.BoolOpt('api_v2',
                 default=True,
                 help="Is the v2 volume API enabled"),
diff --git a/tempest/lib/api_schema/response/volume/__init__.py b/tempest/lib/api_schema/response/volume/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/versions.py b/tempest/lib/api_schema/response/volume/versions.py
new file mode 100644
index 0000000..2391a8c
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/versions.py
@@ -0,0 +1,60 @@
+# Copyright 2015 NEC Corporation.  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.
+
+
+list_versions = {
+    'status_code': [300],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'versions': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'status': {'type': 'string'},
+                        'updated': {'type': 'string'},
+                        'id': {'type': 'string'},
+                        'links': {
+                            'type': 'array',
+                            'items': {
+                                'type': 'object',
+                                'properties': {
+                                    'href': {'type': 'string',
+                                             'format': 'uri'},
+                                    'rel': {'type': 'string'},
+                                    'type': {'type': 'string'},
+                                },
+                                'required': ['href', 'rel']
+                            }
+                        },
+                        'min_version': {'type': 'string'},
+                        'version': {'type': 'string'},
+                        'media-types': {
+                            'type': 'array',
+                            'properties': {
+                                'base': {'type': 'string'},
+                                'type': {'type': 'string'}
+                            },
+                            'required': ['base', 'type']
+                        }
+                    },
+                    'required': ['status', 'updated', 'id', 'links',
+                                 'min_version', 'version', 'media-types']
+                }
+            }
+        },
+        'required': ['versions'],
+    }
+}
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index a4600a8..72ab785 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -14,5 +14,6 @@
 
 from tempest.lib.services.volume.v3.base_client import BaseClient
 from tempest.lib.services.volume.v3.messages_client import MessagesClient
+from tempest.lib.services.volume.v3.versions_client import VersionsClient
 
-__all__ = ['MessagesClient', 'BaseClient']
+__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient']
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
new file mode 100644
index 0000000..e2941c4
--- /dev/null
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -0,0 +1,47 @@
+# Copyright 2017 NEC Corporation.  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.
+
+import time
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.volume import versions as schema
+from tempest.lib.common import rest_client
+from tempest.lib.services.volume.v3 import base_client
+
+
+class VersionsClient(base_client.BaseClient):
+
+    def list_versions(self):
+        """List API versions
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v3/#list-all-api-versions
+        """
+        version_url = self._get_base_version_url()
+
+        start = time.time()
+        resp, body = self.raw_request(version_url, 'GET')
+        end = time.time()
+        # NOTE: We need a raw_request() here instead of request() call because
+        # "list API versions" API doesn't require an authentication and we can
+        # skip it with raw_request() call.
+        self._log_request('GET', version_url, resp, secs=(end - start),
+                          resp_body=body)
+        self._error_checker(resp, body)
+
+        body = json.loads(body)
+        self.validate_response(schema.list_versions, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 1af0d95..98bf145 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -192,7 +192,7 @@
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
-        fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]}
+        fake_resp = {'versions': [{'id': 'v2.0'}]}
         fake_resp = json.dumps(fake_resp)
         mock_request.return_value = (None, fake_resp)
         fake_os = mock.MagicMock()
@@ -206,7 +206,7 @@
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
-        fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v3.0'}]}
+        fake_resp = {'versions': [{'id': 'v3.0'}]}
         fake_resp = json.dumps(fake_resp)
         mock_request.return_value = (None, fake_resp)
         fake_os = mock.MagicMock()
@@ -231,11 +231,9 @@
         with mock.patch.object(verify_tempest_config,
                                'print_and_or_update') as print_mock:
             verify_tempest_config.verify_cinder_api_versions(fake_os, True)
-        print_mock.assert_any_call('api_v1', 'volume-feature-enabled',
-                                   False, True)
         print_mock.assert_any_call('api_v3', 'volume-feature-enabled',
                                    True, True)
-        self.assertEqual(2, print_mock.call_count)
+        self.assertEqual(1, print_mock.call_count)
 
     def test_verify_glance_version_no_v2_with_v1_1(self):
         def fake_get_versions():
diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py
new file mode 100644
index 0000000..9627b9a
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_versions_client.py
@@ -0,0 +1,91 @@
+# Copyright 2017 NEC Corporation.  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.lib.services.volume.v3 import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVersionsClient(base.BaseServiceTest):
+
+    FAKE_VERSIONS_INFO = {
+        "versions": [
+            {
+                "status": "DEPRECATED", "updated": "2016-05-02T20:25:19Z",
+                "links": [
+                    {"href": "http://docs.openstack.org/", "type": "text/html",
+                     "rel": "describedby"},
+                    {"href": "https://10.30.197.39:8776/v1/", "rel": "self"}
+                ],
+                "min_version": "",
+                "version": "",
+                "media-types": [
+                    {"base": "application/json",
+                     "type": "application/vnd.openstack.volume+json;version=1"}
+                ],
+                "id": "v1.0"
+            },
+            {
+                "status": "DEPRECATED", "updated": "2017-02-25T12:00:00Z",
+                "links": [
+                    {"href": "http://docs.openstack.org/", "type": "text/html",
+                     "rel": "describedby"},
+                    {"href": "https://10.30.197.39:8776/v2/", "rel": "self"}
+                ],
+                "min_version": "",
+                "version": "",
+                "media-types": [
+                    {"base": "application/json",
+                     "type": "application/vnd.openstack.volume+json;version=1"}
+                ],
+                "id": "v2.0"
+            },
+            {
+                "status": "CURRENT", "updated": "2016-02-08T12:20:21Z",
+                "links": [
+                    {"href": "http://docs.openstack.org/", "type": "text/html",
+                     "rel": "describedby"},
+                    {"href": "https://10.30.197.39:8776/v3/", "rel": "self"}
+                ],
+                "min_version": "3.0",
+                "version": "3.28",
+                "media-types": [
+                    {"base": "application/json",
+                     "type": "application/vnd.openstack.volume+json;version=1"}
+                ],
+                "id": "v3.0"
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestVersionsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = versions_client.VersionsClient(fake_auth,
+                                                     'volume',
+                                                     'regionOne')
+
+    def _test_list_versions(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_versions,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSIONS_INFO,
+            bytes_body,
+            300)
+
+    def test_list_versions_with_str_body(self):
+        self._test_list_versions()
+
+    def test_list_versions_with_bytes_body(self):
+        self._test_list_versions(bytes_body=True)