Merge "Scenario: object_storage_basic_ops: move and update test description"
diff --git a/.coveragerc b/.coveragerc
index 51482d3..449e62c 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,4 +1,4 @@
[run]
branch = True
source = tempest
-omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api_schema/*,tempest/api/*
+omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api/*
diff --git a/HACKING.rst b/HACKING.rst
index 432db7d..a209b3f 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -166,8 +166,33 @@
suite, Tempest is not suitable for handling all negative test cases, as
the wide variety and complexity of negative tests can lead to long test
runs and knowledge of internal implementation details. The bulk of
-negative testing should be handled with project function tests. The
-exception to this rule is API tests used for interoperability testing.
+negative testing should be handled with project function tests.
+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
+
+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
+build a consensus across all OpenStack projects and improve the quality and
+consistency of all the APIs.
+
+In addition, we have some guidelines for additional negative tests.
+
+- About BadRequest(HTTP400) case: We can add a single negative tests of
+ BadRequest for each resource and method(POST, PUT).
+ Please don't implement more negative tests on the same combination of
+ resource and method even if API request parameters are different from
+ the existing test.
+- About NotFound(HTTP404) case: We can add a single negative tests of
+ NotFound for each resource and method(GET, PUT, DELETE, HEAD).
+ Please don't implement more negative tests on the same combination
+ of resource and method.
+
+The above guidelines don't cover all cases and we will grow these guidelines
+organically over time. Patches outside of the above guidelines are left up to
+the reviewers' discretion and if we face some conflicts between reviewers, we
+will expand the guideline based on our discussion and experience.
Test skips because of Known Bugs
--------------------------------
@@ -215,29 +240,6 @@
can be used to perform this. See AggregatesAdminTest in
tempest.api.compute.admin for an example of using locking.
-Stress Tests in Tempest
------------------------
-Any tempest test case can be flagged as a stress test. With this flag it will
-be automatically discovery and used in the stress test runs. The stress test
-framework itself is a facility to spawn and control worker processes in order
-to find race conditions (see ``tempest/stress/`` for more information). Please
-note that these stress tests can't be used for benchmarking purposes since they
-don't measure any performance characteristics.
-
-Example::
-
- @stresstest(class_setup_per='process')
- def test_this_and_that(self):
- ...
-
-This will flag the test ``test_this_and_that`` as a stress test. The parameter
-``class_setup_per`` gives control when the setUpClass function should be called.
-
-Good candidates for stress tests are:
-
-- Scenario tests
-- API tests that have a wide focus
-
Sample Configuration File
-------------------------
The sample config file is autogenerated using a script. If any changes are made
diff --git a/README.rst b/README.rst
index 3c0463b..fc4de5e 100644
--- a/README.rst
+++ b/README.rst
@@ -92,18 +92,18 @@
be done using the :ref:`tempest_run` command. This can be done by either
running::
- $ tempest run
+ $ tempest run
from the Tempest workspace directory. Or you can use the ``--workspace``
argument to run in the workspace you created regarless of your current
working directory. For example::
- $ tempest run --workspace cloud-01
+ $ tempest run --workspace cloud-01
There is also the option to use testr directly, or any `testr`_ based test
runner, like `ostestr`_. For example, from the workspace dir run::
- $ ostestr --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))'
+ $ ostestr --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))'
will run the same set of tests as the default gate jobs.
@@ -161,9 +161,9 @@
of the configuration.
You can generate a new sample tempest.conf file, run the following
-command from the top level of the Tempest directory:
+command from the top level of the Tempest directory::
- tox -egenconfig
+ $ tox -egenconfig
The most important pieces that are needed are the user ids, openstack
endpoint, and basic flavors and images needed to run tests.
@@ -196,18 +196,18 @@
from a remote system running python 2.7. (or deploy a cloud guest in your cloud
that has python 2.7)
-Python 3.4
+Python 3.x
----------
Starting during the Liberty release development cycle work began on enabling
Tempest to run under both Python 2.7 and Python 3.4. Tempest strives to fully
-support running with Python 3.4. A gating unit test job was added to also run
-Tempest's unit tests under Python 3.4. This means that the Tempest code at
-least imports under Python 3.4 and things that have unit test coverage will
-work on Python 3.4. However, because large parts of Tempest are self-verifying
-there might be uncaught issues running on Python 3.4. So until there is a gating
-job which does a full Tempest run using Python 3.4 there isn't any guarantee
-that running Tempest under Python 3.4 is bug free.
+support running with Python 3.4 and newer. A gating unit test job was added to
+also run Tempest's unit tests under Python 3. This means that the Tempest
+code at least imports under Python 3.4 and things that have unit test coverage
+will work on Python 3.4. However, because large parts of Tempest are
+self-verifying there might be uncaught issues running on Python 3. So until
+there is a gating job which does a full Tempest run using Python 3 there
+isn't any guarantee that running Tempest under Python 3 is bug free.
Legacy run method
-----------------
@@ -257,11 +257,11 @@
and run the tests or use tox to do the same. Tox also contains several existing
job configurations. For example::
- $ tox -efull
+ $ tox -efull
which will run the same set of tests as the OpenStack gate. (it's exactly how
the gate invokes Tempest) Or::
- $ tox -esmoke
+ $ tox -esmoke
to run the tests tagged as smoke.
diff --git a/REVIEWING.rst b/REVIEWING.rst
index 676a217..9b272bb 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -13,6 +13,13 @@
it. Tests which aren't executed either because of configuration or skips should
not be accepted.
+If a new test is added that depends on a new config option (like a feature
+flag), the commit message must reference a change in DevStack or DevStack-Gate
+that enables the execution of this newly introduced test. This reference could
+either be a `Cross-Repository Dependency <http://docs.openstack.org/infra/
+manual/developers.html#cross-repository-dependencies>`_ or a simple link
+to a Gerrit review.
+
Unit Tests
----------
@@ -86,6 +93,12 @@
.. _reno: http://docs.openstack.org/developer/reno/
+Deprecated Code
+---------------
+Sometimes we have some bugs in deprecated code. Basically, we leave it. Because
+we don't need to maintain it. However, if the bug is critical, we might need to
+fix it. When it will happen, we will deal with it on a case-by-case basis.
+
When to approve
---------------
* Every patch needs two +2s before being approved.
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index fd9ad05..18269bf 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -95,7 +95,7 @@
accounts will be assigned a role on domain configured in
``default_credentials_domain_name``. This will make the accounts provisioned
usable in a cloud where domain scoped tokens are required by keystone for
-admin operations. Note that the the initial pre-provision admin accounts,
+admin operations. Note that the initial pre-provision admin accounts,
configured in tempest.conf, must have a role on the same domain as well, for
Dynamic Credentials to work.
@@ -151,7 +151,7 @@
``admin_domain_scope`` as ``default_credentials_domain_name`` are configured
properly in tempest.conf.
-Pre-Provisioned Credentials are also know as accounts.yaml or accounts file.
+Pre-Provisioned Credentials are also known as accounts.yaml or accounts file.
Compute
-------
diff --git a/doc/source/field_guide/stress.rst b/doc/source/field_guide/stress.rst
deleted file mode 120000
index d39d0f8..0000000
--- a/doc/source/field_guide/stress.rst
+++ /dev/null
@@ -1 +0,0 @@
-../../../tempest/stress/README.rst
\ No newline at end of file
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 6abe9dc..896cd98 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -24,7 +24,6 @@
field_guide/index
field_guide/api
field_guide/scenario
- field_guide/stress
field_guide/unit_tests
=========
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index bff18f8..dc73ef2 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -24,7 +24,9 @@
* max_microversion
Those should be defined under respective section of each service.
- For example::
+ For example:
+
+ .. code-block:: ini
[compute]
min_microversion = None
@@ -42,7 +44,9 @@
api_version_utils.check_skip_with_microversion function can be used
to automatically skip the tests which do not fall under configured
Microversion range.
-For example::
+For example:
+
+.. code-block:: python
class BaseTestCase1(api_version_utils.BaseMicroversionTest):
@@ -65,7 +69,9 @@
to send with API request.
api_version_utils.select_request_microversion function can be used
to select the appropriate Microversion which will be used for API request.
-For example::
+For example:
+
+.. code-block:: python
@classmethod
def resource_setup(cls):
@@ -87,7 +93,9 @@
Also Microversion header name needs to be defined on service clients which
should be constant because it is not supposed to be changed by project
as per API contract.
-For example::
+For example:
+
+.. code-block:: python
COMPUTE_MICROVERSION = None
@@ -96,7 +104,9 @@
Now test class can set the selected Microversion on required service clients
using fixture which can take care of resetting the same once tests is completed.
-For example::
+For example:
+
+.. code-block:: python
def setUp(self):
super(BaseTestCase1, self).setUp()
@@ -105,7 +115,9 @@
Service clients needs to add set Microversion in API request header which
can be done by overriding the get_headers() method of rest_client.
-For example::
+For example:
+
+.. code-block:: python
COMPUTE_MICROVERSION = None
@@ -136,7 +148,9 @@
For example:
-Below test is applicable for Microversion from 2.2 till 2.9::
+Below test is applicable for Microversion from 2.2 till 2.9:
+
+.. code-block:: python
class BaseTestCase1(api_version_utils.BaseMicroversionTest,
tempest.test.BaseTestCase):
@@ -150,7 +164,9 @@
[..]
-Below test is applicable for Microversion from 2.10 till latest::
+Below test is applicable for Microversion from 2.10 till latest:
+
+.. code-block:: python
class Test2(BaseTestCase1):
min_microversion = '2.10'
@@ -159,8 +175,6 @@
[..]
-
-
Notes about Compute Microversion Tests
""""""""""""""""""""""""""""""""""""""
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index d34023f..6b30825 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -61,7 +61,9 @@
to the "tempest.test_plugins" namespace.
If you are using pbr this is fairly straightforward, in the setup.cfg just add
-something like the following::
+something like the following:
+
+.. code-block:: ini
[entry_points]
tempest.test_plugins =
@@ -105,7 +107,9 @@
your plugin you need to create a plugin class which tempest will load and call
to get information when it needs. To simplify creating this tempest provides an
abstract class that should be used as the parent for your plugin. To use this
-you would do something like the following::
+you would do something like the following:
+
+.. code-block:: python
from tempest.test_discover import plugins
@@ -177,7 +181,9 @@
easy to write tests which rely on multiple APIs whose service clients are in
different plugins.
-Example implementation of ``get_service_clients``::
+Example implementation of ``get_service_clients``:
+
+.. code-block:: python
def get_service_clients(self):
# Example implementation with two service clients
@@ -213,7 +219,9 @@
* **client_names**: Name of the classes that implement service clients in the
service clients module.
-Example usage of the the service clients in tests::
+Example usage of the service clients in tests:
+
+.. code-block:: python
# my_creds is instance of tempest.lib.auth.Credentials
# identity_uri is v2 or v3 depending on the configuration
@@ -249,7 +257,9 @@
Third the service client classes should inherit from ``RestClient``, should
accept generic keyword arguments, and should pass those arguments to the
``__init__`` method of ``RestClient``. Extra arguments can be added. For
-instance::
+instance:
+
+.. code-block:: python
class MyAPIClient(rest_client.RestClient):
@@ -273,7 +283,9 @@
client_api_1.py
client_api_2.py
-The content of __init__.py module should be::
+The content of __init__.py module should be:
+
+.. code-block:: python
from client_api_1.py import API1Client
from client_api_2.py import API2Client
@@ -294,7 +306,9 @@
client_api_1.py
client_api_2.py
-The content each of __init__.py module under vN should be::
+The content each of __init__.py module under vN should be:
+
+.. code-block:: python
from client_api_1.py import API1Client
from client_api_2.py import API2Client
diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample
index 36cd324..c131b07 100644
--- a/etc/logging.conf.sample
+++ b/etc/logging.conf.sample
@@ -1,5 +1,5 @@
[loggers]
-keys=root,tempest_stress
+keys=root
[handlers]
keys=file,devel,syslog
@@ -11,11 +11,6 @@
level=DEBUG
handlers=file
-[logger_tempest_stress]
-level=DEBUG
-handlers=file,devel
-qualname=tempest.stress
-
[handler_file]
class=FileHandler
level=DEBUG
diff --git a/releasenotes/notes/Tempest-library-interface-0eb680b810139a50.yaml b/releasenotes/notes/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
similarity index 100%
rename from releasenotes/notes/Tempest-library-interface-0eb680b810139a50.yaml
rename to releasenotes/notes/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
diff --git a/releasenotes/notes/start-using-reno-ed9518126fd0e1a3.yaml b/releasenotes/notes/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml
similarity index 100%
rename from releasenotes/notes/start-using-reno-ed9518126fd0e1a3.yaml
rename to releasenotes/notes/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml
diff --git a/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml b/releasenotes/notes/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml
similarity index 100%
rename from releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml
rename to releasenotes/notes/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml
diff --git a/releasenotes/notes/compute-microversion-support-e0b23f960f894b9b.yaml b/releasenotes/notes/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml
similarity index 100%
rename from releasenotes/notes/compute-microversion-support-e0b23f960f894b9b.yaml
rename to releasenotes/notes/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml
diff --git a/releasenotes/notes/add-network-versions-client-d90e8334e1443f5c.yaml b/releasenotes/notes/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml
similarity index 100%
rename from releasenotes/notes/add-network-versions-client-d90e8334e1443f5c.yaml
rename to releasenotes/notes/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml
diff --git a/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml b/releasenotes/notes/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml
similarity index 100%
rename from releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml
rename to releasenotes/notes/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml
diff --git a/releasenotes/notes/add-tempest-run-3d0aaf69c2ca4115.yaml b/releasenotes/notes/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml
similarity index 100%
rename from releasenotes/notes/add-tempest-run-3d0aaf69c2ca4115.yaml
rename to releasenotes/notes/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml
diff --git a/releasenotes/notes/add-tempest-workspaces-228a2ba4690b5589.yaml b/releasenotes/notes/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml
similarity index 100%
rename from releasenotes/notes/add-tempest-workspaces-228a2ba4690b5589.yaml
rename to releasenotes/notes/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml
diff --git a/releasenotes/notes/add_subunit_describe_calls-5498a37e6cd66c4b.yaml b/releasenotes/notes/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml
similarity index 100%
rename from releasenotes/notes/add_subunit_describe_calls-5498a37e6cd66c4b.yaml
rename to releasenotes/notes/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml
diff --git a/releasenotes/notes/bug-1486834-7ebca15836ae27a9.yaml b/releasenotes/notes/12.1.0-bug-1486834-7ebca15836ae27a9.yaml
similarity index 100%
rename from releasenotes/notes/bug-1486834-7ebca15836ae27a9.yaml
rename to releasenotes/notes/12.1.0-bug-1486834-7ebca15836ae27a9.yaml
diff --git a/releasenotes/notes/identity-clients-as-library-e663c6132fcac6c2.yaml b/releasenotes/notes/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml
similarity index 100%
rename from releasenotes/notes/identity-clients-as-library-e663c6132fcac6c2.yaml
rename to releasenotes/notes/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml
diff --git a/releasenotes/notes/image-clients-as-library-86d17caa26ce3961.yaml b/releasenotes/notes/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml
similarity index 100%
rename from releasenotes/notes/image-clients-as-library-86d17caa26ce3961.yaml
rename to releasenotes/notes/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml
diff --git a/releasenotes/notes/new-test-utils-module-adf34468c4d52719.yaml b/releasenotes/notes/12.1.0-new-test-utils-module-adf34468c4d52719.yaml
similarity index 100%
rename from releasenotes/notes/new-test-utils-module-adf34468c4d52719.yaml
rename to releasenotes/notes/12.1.0-new-test-utils-module-adf34468c4d52719.yaml
diff --git a/releasenotes/notes/remove-input-scenarios-functionality-01308e6d4307f580.yaml b/releasenotes/notes/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml
similarity index 100%
rename from releasenotes/notes/remove-input-scenarios-functionality-01308e6d4307f580.yaml
rename to releasenotes/notes/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml
diff --git a/releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml b/releasenotes/notes/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml
similarity index 100%
rename from releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml
rename to releasenotes/notes/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml
diff --git a/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml b/releasenotes/notes/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
similarity index 100%
rename from releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
rename to releasenotes/notes/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
diff --git a/releasenotes/notes/remove-trove-tests-666522e9113549f9.yaml b/releasenotes/notes/12.1.0-remove-trove-tests-666522e9113549f9.yaml
similarity index 62%
rename from releasenotes/notes/remove-trove-tests-666522e9113549f9.yaml
rename to releasenotes/notes/12.1.0-remove-trove-tests-666522e9113549f9.yaml
index 1157a4f..7a1fc36 100644
--- a/releasenotes/notes/remove-trove-tests-666522e9113549f9.yaml
+++ b/releasenotes/notes/12.1.0-remove-trove-tests-666522e9113549f9.yaml
@@ -1,4 +1,4 @@
---
upgrade:
- All tests for the Trove project have been removed from tempest. They now
- live as a tempest plugin in the the trove project.
+ live as a tempest plugin in the trove project.
diff --git a/releasenotes/notes/routers-client-as-library-25a363379da351f6.yaml b/releasenotes/notes/12.1.0-routers-client-as-library-25a363379da351f6.yaml
similarity index 100%
rename from releasenotes/notes/routers-client-as-library-25a363379da351f6.yaml
rename to releasenotes/notes/12.1.0-routers-client-as-library-25a363379da351f6.yaml
diff --git a/releasenotes/notes/support-chunked-encoding-d71f53225f68edf3.yaml b/releasenotes/notes/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml
similarity index 100%
rename from releasenotes/notes/support-chunked-encoding-d71f53225f68edf3.yaml
rename to releasenotes/notes/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml
diff --git a/releasenotes/notes/tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml b/releasenotes/notes/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
similarity index 100%
rename from releasenotes/notes/tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
rename to releasenotes/notes/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
diff --git a/releasenotes/notes/add-httptimeout-in-restclient-ax78061900e3f3d7.yaml b/releasenotes/notes/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml
similarity index 100%
rename from releasenotes/notes/add-httptimeout-in-restclient-ax78061900e3f3d7.yaml
rename to releasenotes/notes/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml
diff --git a/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml b/releasenotes/notes/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml
similarity index 100%
rename from releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml
rename to releasenotes/notes/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml
diff --git a/releasenotes/notes/clients_module-16f3025f515bf9ec.yaml b/releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml
similarity index 100%
rename from releasenotes/notes/clients_module-16f3025f515bf9ec.yaml
rename to releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml
diff --git a/releasenotes/notes/nova_cert_default-90eb7c1e3cde624a.yaml b/releasenotes/notes/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml
similarity index 100%
rename from releasenotes/notes/nova_cert_default-90eb7c1e3cde624a.yaml
rename to releasenotes/notes/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml
diff --git a/releasenotes/notes/plugin-service-client-registration-00b19a2dd4935ba0.yaml b/releasenotes/notes/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml
similarity index 100%
rename from releasenotes/notes/plugin-service-client-registration-00b19a2dd4935ba0.yaml
rename to releasenotes/notes/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml
diff --git a/releasenotes/notes/remove-javelin-276f62d04f7e4a1d.yaml b/releasenotes/notes/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml
similarity index 100%
rename from releasenotes/notes/remove-javelin-276f62d04f7e4a1d.yaml
rename to releasenotes/notes/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml
diff --git a/releasenotes/notes/service_client_config-8a1d7b4de769c633.yaml b/releasenotes/notes/12.2.0-service_client_config-8a1d7b4de769c633.yaml
similarity index 100%
rename from releasenotes/notes/service_client_config-8a1d7b4de769c633.yaml
rename to releasenotes/notes/12.2.0-service_client_config-8a1d7b4de769c633.yaml
diff --git a/releasenotes/notes/volume-clients-as-library-9a3444dd63c134b3.yaml b/releasenotes/notes/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml
similarity index 100%
rename from releasenotes/notes/volume-clients-as-library-9a3444dd63c134b3.yaml
rename to releasenotes/notes/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml
diff --git a/releasenotes/notes/add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml b/releasenotes/notes/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
similarity index 100%
rename from releasenotes/notes/add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
rename to releasenotes/notes/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
diff --git a/releasenotes/notes/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml b/releasenotes/notes/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml
new file mode 100644
index 0000000..9cfce0d
--- /dev/null
+++ b/releasenotes/notes/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml
@@ -0,0 +1,16 @@
+---
+features:
+ - |
+ Define volume service clients as libraries.
+ The following volume service clients are defined as library interface,
+ so the other projects can use these modules as stable libraries without
+ any maintenance changes.
+
+ * backups_client
+ * encryption_types_client (v1)
+ * encryption_types_client (v2)
+ * qos_clients (v1)
+ * qos_clients (v2)
+ * snapshots_client (v1)
+ * snapshots_client (v2)
+
diff --git a/releasenotes/notes/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml b/releasenotes/notes/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml
new file mode 100644
index 0000000..0884cfa
--- /dev/null
+++ b/releasenotes/notes/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml
@@ -0,0 +1,4 @@
+---
+deprecations:
+ - Oslo.utils provides same method get_ipv6_addr_by_EUI64,
+ so deprecate it in Newton and remove it in Ocata.
diff --git a/releasenotes/notes/move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml b/releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
similarity index 100%
rename from releasenotes/notes/move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
rename to releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
diff --git a/releasenotes/notes/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml b/releasenotes/notes/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml
new file mode 100644
index 0000000..b9b6fb5
--- /dev/null
+++ b/releasenotes/notes/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml
@@ -0,0 +1,13 @@
+---
+prelude: >
+ This release is marking the start of Newton release support in Tempest
+other:
+ - |
+ OpenStack releases supported at this time are **Liberty**, **Mitaka**,
+ and **Newton**.
+
+ The release under current development as of this tag is Ocata,
+ meaning that every Tempest commit is also tested against master during
+ the Ocata cycle. However, this does not necessarily mean that using
+ Tempest as of this tag will work against a Ocata (or future releases)
+ cloud.
diff --git a/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml b/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
new file mode 100644
index 0000000..20f310d
--- /dev/null
+++ b/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+ - the already depreacted tempest-cleanup standalone command has been
+ removed. The corresponding functionalities can be accessed through
+ the unified `tempest` command (`tempest cleanup`).
diff --git a/releasenotes/notes/13.0.0-volume-clients-as-library-660811011be29d1a.yaml b/releasenotes/notes/13.0.0-volume-clients-as-library-660811011be29d1a.yaml
new file mode 100644
index 0000000..9e9eff6
--- /dev/null
+++ b/releasenotes/notes/13.0.0-volume-clients-as-library-660811011be29d1a.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Define the v1 and v2 types_client clients for the volume service as
+ library interfaces, allowing other projects to use these modules as
+ stable libraries without maintenance changes.
diff --git a/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
new file mode 100644
index 0000000..056e199
--- /dev/null
+++ b/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Define volume service clients as libraries.
+ The following volume service clients are defined as library interface,
+ so the other projects can use these modules as stable libraries without
+ any maintenance changes.
+
+ * volumes_client(v1)
+ * volumes_client(v2)
diff --git a/releasenotes/notes/add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml b/releasenotes/notes/add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
new file mode 100644
index 0000000..6f7a411
--- /dev/null
+++ b/releasenotes/notes/add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - The cred_provider abstract class which serves as the basis for both
+ of tempest's cred providers, pre-provisioned credentials and dynamic
+ credentials, is now a library interface. This provides the common signature
+ required for building a credential provider.
diff --git a/releasenotes/notes/add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml b/releasenotes/notes/add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
new file mode 100644
index 0000000..432a6b1
--- /dev/null
+++ b/releasenotes/notes/add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - The cred_client module was added to tempest.lib. This module provides a
+ wrapper to the keystone services client which provides a uniform
+ interface that abstracts out the differences between keystone api versions.
diff --git a/releasenotes/notes/add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml b/releasenotes/notes/add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
new file mode 100644
index 0000000..57bf47c
--- /dev/null
+++ b/releasenotes/notes/add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+ - Add an error translation to list_versions() of versions_client of both
+ compute and network. This can affect users who are expecting that these
+ clients return error status code instead of the exception. It is needed
+ to change the code for handling the exception like the other clients code.
diff --git a/releasenotes/notes/add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml b/releasenotes/notes/add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
new file mode 100644
index 0000000..b2ad199
--- /dev/null
+++ b/releasenotes/notes/add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - A new optional parameter `port` for ssh client (`tempest.lib.common.ssh.Client`)
+ to specify destination port for a host. The default value is 22.
diff --git a/releasenotes/notes/deprecate-nova-api-extensions-df16b02485dae203.yaml b/releasenotes/notes/deprecate-nova-api-extensions-df16b02485dae203.yaml
new file mode 100644
index 0000000..c2d9a9b
--- /dev/null
+++ b/releasenotes/notes/deprecate-nova-api-extensions-df16b02485dae203.yaml
@@ -0,0 +1,7 @@
+---
+deprecations:
+ - The *api_extensions* config option in the *compute-feature-enabled* group is
+ now deprecated. This option will be removed from tempest when all the
+ OpenStack releases supported by tempest no longer support the API extensions
+ mechanism. This was removed from Nova during the Newton cycle, so this will
+ be removed at the Mitaka EOL.
diff --git a/releasenotes/notes/remo-stress-tests-81052b211ad95d2e.yaml b/releasenotes/notes/remo-stress-tests-81052b211ad95d2e.yaml
new file mode 100644
index 0000000..aa3a78e
--- /dev/null
+++ b/releasenotes/notes/remo-stress-tests-81052b211ad95d2e.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - The Stress tests framework and all the stress tests have been removed.
+
diff --git a/releasenotes/notes/remove-sahara-tests-1532c47c7df80e3a.yaml b/releasenotes/notes/remove-sahara-tests-1532c47c7df80e3a.yaml
new file mode 100644
index 0000000..b541cf9
--- /dev/null
+++ b/releasenotes/notes/remove-sahara-tests-1532c47c7df80e3a.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - All tests for the Sahara project have been removed from Tempest. They now
+ live as a Tempest plugin in the ``openstack/sahara-tests`` repository.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 4522a17..140263c 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -275,3 +275,6 @@
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
+
+# -- Options for Internationalization output ------------------------------
+locale_dirs = ['locale/']
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 2c22408..8eac1d0 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -5,10 +5,11 @@
.. toctree::
:maxdepth: 1
+ unreleased
+ v13.0.0
v12.0.0
v11.0.0
v10.0.0
- unreleased
Indices and tables
==================
diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst
index 5860a46..875030f 100644
--- a/releasenotes/source/unreleased.rst
+++ b/releasenotes/source/unreleased.rst
@@ -1,5 +1,5 @@
-==========================
- Unreleased Release Notes
-==========================
+============================
+Current Series Release Notes
+============================
.. release-notes::
diff --git a/releasenotes/source/v13.0.0.rst b/releasenotes/source/v13.0.0.rst
new file mode 100644
index 0000000..39816e4
--- /dev/null
+++ b/releasenotes/source/v13.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v13.0.0 Release Notes
+=====================
+
+.. release-notes:: 13.0.0 Release Notes
+ :version: 13.0.0
diff --git a/requirements.txt b/requirements.txt
index a773d16..07dd1c1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,24 +2,24 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=1.6 # Apache-2.0
-cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
+cliff>=2.2.0 # Apache-2.0
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
testtools>=1.4.0 # MIT
paramiko>=2.0 # LGPLv2.1+
-netaddr!=0.7.16,>=0.7.12 # BSD
+netaddr!=0.7.16,>=0.7.13 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.14.0 # Apache-2.0
-oslo.i18n>=2.1.0 # Apache-2.0
-oslo.log>=1.14.0 # Apache-2.0
+oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
+oslo.log>=3.11.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.16.0 # Apache-2.0
+oslo.utils>=3.18.0 # Apache-2.0
six>=1.9.0 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD
-testscenarios>=0.4 # Apache-2.0/BSD
-PyYAML>=3.1.0 # MIT
-stevedore>=1.16.0 # Apache-2.0
-PrettyTable<0.8,>=0.7 # BSD
-os-testr>=0.7.0 # Apache-2.0
+PyYAML>=3.10.0 # MIT
+python-subunit>=0.0.18 # Apache-2.0/BSD
+stevedore>=1.17.1 # Apache-2.0
+PrettyTable<0.8,>=0.7.1 # BSD
+os-testr>=0.8.0 # Apache-2.0
urllib3>=1.15.1 # MIT
debtcollector>=1.2.0 # Apache-2.0
+unittest2 # BSD
diff --git a/run_tempest.sh b/run_tempest.sh
index af01734..414146b 100755
--- a/run_tempest.sh
+++ b/run_tempest.sh
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
+echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
+
function usage {
echo "Usage: $0 [OPTION]..."
echo "Run Tempest test suite"
diff --git a/setup.cfg b/setup.cfg
index 50bf891..96313fd 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -28,8 +28,6 @@
[entry_points]
console_scripts =
verify-tempest-config = tempest.cmd.verify_tempest_config:main
- run-tempest-stress = tempest.cmd.run_stress:main
- tempest-cleanup = tempest.cmd.cleanup:main
tempest-account-generator = tempest.cmd.account_generator:main
tempest = tempest.cmd.main:main
skip-tracker = tempest.lib.cmd.skip_tracker:main
@@ -39,7 +37,6 @@
account-generator = tempest.cmd.account_generator:TempestAccountGenerator
init = tempest.cmd.init:TempestInit
cleanup = tempest.cmd.cleanup:TempestCleanup
- run-stress = tempest.cmd.run_stress:TempestRunStress
list-plugins = tempest.cmd.list_plugins:TempestListPlugins
verify-config = tempest.cmd.verify_tempest_config:TempestVerifyConfig
workspace = tempest.cmd.workspace:TempestWorkspace
diff --git a/tempest/README.rst b/tempest/README.rst
index c9a0491..0feec41 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -15,7 +15,6 @@
| tempest/
| api/ - API tests
| scenario/ - complex scenario tests
-| stress/ - stress tests
Each of these directories contains different types of tests. What
belongs in each directory, the rules and examples for good tests, are
@@ -46,14 +45,6 @@
but should instead use the tempest implementations of clients.
-:ref:`stress_field_guide`
--------------------------
-
-Stress tests are designed to stress an OpenStack environment by running a high
-workload against it and seeing what breaks. The stress test framework runs
-several test jobs in parallel and can run any existing test in Tempest as a
-stress job.
-
:ref:`unit_tests_field_guide`
-----------------------------
diff --git a/tempest/api/baremetal/admin/test_nodestates.py b/tempest/api/baremetal/admin/test_nodestates.py
index 1ffea25..e74dd04 100644
--- a/tempest/api/baremetal/admin/test_nodestates.py
+++ b/tempest/api/baremetal/admin/test_nodestates.py
@@ -15,7 +15,7 @@
from oslo_utils import timeutils
from tempest.api.baremetal.admin import base
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 4f48ad0..61359f1 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -16,7 +16,6 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
from tempest import test
LOG = log.getLogger(__name__)
@@ -30,24 +29,16 @@
super(AgentsAdminTestJSON, cls).setup_clients()
cls.client = cls.os_adm.agents_client
- def setUp(self):
- super(AgentsAdminTestJSON, self).setUp()
- params = self._param_helper(
+ @classmethod
+ def resource_setup(cls):
+ super(AgentsAdminTestJSON, cls).resource_setup()
+ cls.params_agent = cls._param_helper(
hypervisor='common', os='linux', architecture='x86_64',
version='7.0', url='xxx://xxxx/xxx/xxx',
md5hash='add6bb58e139be103324d04d82d8f545')
- body = self.client.create_agent(**params)['agent']
- self.agent_id = body['agent_id']
- def tearDown(self):
- try:
- test_utils.call_and_ignore_notfound_exc(
- self.client.delete_agent, self.agent_id)
- except Exception:
- LOG.exception('Exception raised deleting agent %s', self.agent_id)
- super(AgentsAdminTestJSON, self).tearDown()
-
- def _param_helper(self, **kwargs):
+ @staticmethod
+ def _param_helper(**kwargs):
rand_key = 'architecture'
if rand_key in kwargs:
# NOTE: The rand_name is for avoiding agent conflicts.
@@ -71,33 +62,42 @@
@test.idempotent_id('dc9ffd51-1c50-4f0e-a820-ae6d2a568a9e')
def test_update_agent(self):
- # Update an agent.
+ # Create and update an agent.
+ body = self.client.create_agent(**self.params_agent)['agent']
+ self.addCleanup(self.client.delete_agent, body['agent_id'])
+ agent_id = body['agent_id']
params = self._param_helper(
version='8.0', url='xxx://xxxx/xxx/xxx2',
md5hash='add6bb58e139be103324d04d82d8f547')
- body = self.client.update_agent(self.agent_id, **params)['agent']
+ body = self.client.update_agent(agent_id, **params)['agent']
for expected_item, value in params.items():
self.assertEqual(value, body[expected_item])
@test.idempotent_id('470e0b89-386f-407b-91fd-819737d0b335')
def test_delete_agent(self):
- # Delete an agent.
- self.client.delete_agent(self.agent_id)
+ # Create an agent and delete it.
+ body = self.client.create_agent(**self.params_agent)['agent']
+ self.client.delete_agent(body['agent_id'])
# Verify the list doesn't contain the deleted agent.
agents = self.client.list_agents()['agents']
- self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
+ self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
+ agents))
@test.idempotent_id('6a326c69-654b-438a-80a3-34bcc454e138')
def test_list_agents(self):
- # List all agents.
+ # Create an agent and list all agents.
+ body = self.client.create_agent(**self.params_agent)['agent']
+ self.addCleanup(self.client.delete_agent, body['agent_id'])
agents = self.client.list_agents()['agents']
self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
- self.assertIn(self.agent_id, map(lambda x: x['agent_id'], agents))
+ self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents))
@test.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
def test_list_agents_with_filter(self):
- # List the agent builds by the filter.
+ # Create agents and list the agent builds by the filter.
+ body = self.client.create_agent(**self.params_agent)['agent']
+ self.addCleanup(self.client.delete_agent, body['agent_id'])
params = self._param_helper(
hypervisor='xen', os='linux', architecture='x86',
version='7.0', url='xxx://xxxx/xxx/xxx1',
@@ -110,4 +110,5 @@
['agents'])
self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
- self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
+ self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
+ agents))
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index fbcc1d1..667d30b 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -215,10 +215,8 @@
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
- server_name = data_utils.rand_name('test_server')
admin_servers_client = self.os_adm.servers_client
- server = self.create_test_server(name=server_name,
- availability_zone=az_name,
+ server = self.create_test_server(availability_zone=az_name,
wait_until='ACTIVE')
body = admin_servers_client.show_server(server['id'])['server']
self.assertEqual(self.host, body['OS-EXT-SRV-ATTR:host'])
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 5befa53..3470602 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -29,10 +29,10 @@
def test_get_availability_zone_list(self):
# List of availability zone
availability_zone = self.client.list_availability_zones()
- self.assertTrue(len(availability_zone['availabilityZoneInfo']) > 0)
+ self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
@test.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c')
def test_get_availability_zone_list_detail(self):
# List of availability zones and available services
availability_zone = self.client.list_availability_zones(detail=True)
- self.assertTrue(len(availability_zone['availabilityZoneInfo']) > 0)
+ self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 95e7ef1..fde5622 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -161,6 +161,7 @@
verify_flavor_response_extension(flavor)
# Check if flavor is present in list
+ flag = False
flavors = self.user_client.list_flavors(detail=True)['flavors']
for flavor in flavors:
if flavor['name'] == flavor_name:
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 456363c..e207aed 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -17,7 +17,7 @@
from tempest.api.compute import base
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index a9e9644..29e1eb8 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -36,7 +36,7 @@
hosts = self.client.list_hosts()['hosts']
host = hosts[0]
hosts = self.client.list_hosts(zone=host['zone'])['hosts']
- self.assertTrue(len(hosts) >= 1)
+ self.assertGreaterEqual(len(hosts), 1)
self.assertIn(host, hosts)
@test.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6')
@@ -58,12 +58,12 @@
hosts = self.client.list_hosts()['hosts']
hosts = [host for host in hosts if host['service'] == 'compute']
- self.assertTrue(len(hosts) >= 1)
+ self.assertGreaterEqual(len(hosts), 1)
for host in hosts:
hostname = host['host_name']
resources = self.client.show_host(hostname)['host']
- self.assertTrue(len(resources) >= 1)
+ self.assertGreaterEqual(len(resources), 1)
host_resource = resources[0]['resource']
self.assertIsNotNone(host_resource)
self.assertIsNotNone(host_resource['cpu'])
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 8366945..c270829 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -29,7 +29,7 @@
def _get_host_name(self):
hosts = self.client.list_hosts()['hosts']
- self.assertTrue(len(hosts) >= 1)
+ self.assertGreaterEqual(len(hosts), 1)
hostname = hosts[0]['host_name']
return hostname
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 113ec40..92a9135 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -52,7 +52,7 @@
self.assertHypervisors(hypers)
details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor']
- self.assertTrue(len(details) > 0)
+ self.assertGreater(len(details), 0)
self.assertEqual(details['hypervisor_hostname'],
hypers[0]['hypervisor_hostname'])
@@ -65,14 +65,14 @@
hostname = hypers[0]['hypervisor_hostname']
hypervisors = (self.client.list_servers_on_hypervisor(hostname)
['hypervisors'])
- self.assertTrue(len(hypervisors) > 0)
+ self.assertGreater(len(hypervisors), 0)
@test.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
def test_get_hypervisor_stats(self):
# Verify the stats of the all hypervisor
stats = (self.client.show_hypervisor_statistics()
['hypervisor_statistics'])
- self.assertTrue(len(stats) > 0)
+ self.assertGreater(len(stats), 0)
@test.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70')
def test_get_hypervisor_uptime(self):
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 9c6df7f..220ea39 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -47,7 +47,7 @@
@test.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03')
def test_show_hypervisor_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertTrue(len(hypers) > 0)
+ self.assertGreater(len(hypers), 0)
self.assertRaises(
lib_exc.Forbidden,
@@ -58,7 +58,7 @@
@test.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
def test_show_servers_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertTrue(len(hypers) > 0)
+ self.assertGreater(len(hypers), 0)
self.assertRaises(
lib_exc.Forbidden,
@@ -96,7 +96,7 @@
@test.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2')
def test_get_hypervisor_uptime_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertTrue(len(hypers) > 0)
+ self.assertGreater(len(hypers), 0)
self.assertRaises(
lib_exc.Forbidden,
@@ -133,7 +133,7 @@
@test.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
def test_search_hypervisor_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertTrue(len(hypers) > 0)
+ self.assertGreater(len(hypers), 0)
self.assertRaises(
lib_exc.Forbidden,
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 18a6afc..72d5b18 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -82,14 +82,6 @@
if host != target_host:
return target_host
- def _volume_clean_up(self, server_id, volume_id):
- body = self.volumes_client.show_volume(volume_id)['volume']
- if body['status'] == 'in-use':
- self.servers_client.detach_volume(server_id, volume_id)
- waiters.wait_for_volume_status(self.volumes_client,
- volume_id, 'available')
- self.volumes_client.delete_volume(volume_id)
-
def _test_live_migration(self, state='ACTIVE', volume_backed=False):
"""Tests live migration between two hosts.
@@ -136,8 +128,7 @@
def test_live_block_migration_paused(self):
self._test_live_migration(state='PAUSED')
- @decorators.skip_because(bug="1549511",
- condition=CONF.service_available.neutron)
+ @decorators.skip_because(bug="1524898")
@test.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
@test.services('volume')
def test_volume_backed_live_migration(self):
@@ -151,22 +142,15 @@
block_migrate_cinder_iscsi,
'Block Live migration not configured for iSCSI')
def test_iscsi_volume(self):
- server_id = self.create_test_server(wait_until="ACTIVE")['id']
+ server = self.create_test_server(wait_until="ACTIVE")
+ server_id = server['id']
actual_host = self._get_host_for_server(server_id)
target_host = self._get_host_other_than(actual_host)
- volume = self.volumes_client.create_volume(
- size=CONF.volume.volume_size, display_name='test')['volume']
-
- waiters.wait_for_volume_status(self.volumes_client,
- volume['id'], 'available')
- self.addCleanup(self._volume_clean_up, server_id, volume['id'])
+ volume = self.create_volume()
# Attach the volume to the server
- self.servers_client.attach_volume(server_id, volumeId=volume['id'],
- device='/dev/xvdb')
- waiters.wait_for_volume_status(self.volumes_client,
- volume['id'], 'in-use')
+ self.attach_volume(server, volume, device='/dev/xvdb')
self._migrate_server_to(server_id, target_host)
waiters.wait_for_server_status(self.servers_client,
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index 6113c04..4f075eb 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -31,6 +31,8 @@
super(MigrationsAdminTest, cls).setup_clients()
cls.client = cls.os_adm.migrations_client
cls.flavors_admin_client = cls.os_adm.flavors_client
+ cls.admin_hosts_client = cls.os_adm.hosts_client
+ cls.admin_servers_client = cls.os_adm.servers_client
@test.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
def test_list_migrations(self):
@@ -103,3 +105,42 @@
server = self.servers_client.show_server(server['id'])['server']
self.assertEqual(flavor['id'], server['flavor']['id'])
+
+ def _test_cold_migrate_server(self, revert=False):
+ if CONF.compute.min_compute_nodes < 2:
+ msg = "Less than 2 compute nodes, skipping multinode tests."
+ raise self.skipException(msg)
+
+ server = self.create_test_server(wait_until="ACTIVE")
+ src_host = self.admin_servers_client.show_server(
+ server['id'])['server']['OS-EXT-SRV-ATTR:host']
+
+ self.admin_servers_client.migrate_server(server['id'])
+
+ waiters.wait_for_server_status(self.servers_client,
+ server['id'], 'VERIFY_RESIZE')
+
+ if revert:
+ self.servers_client.revert_resize_server(server['id'])
+ assert_func = self.assertEqual
+ else:
+ self.servers_client.confirm_resize_server(server['id'])
+ assert_func = self.assertNotEqual
+
+ waiters.wait_for_server_status(self.servers_client,
+ server['id'], 'ACTIVE')
+ dst_host = self.admin_servers_client.show_server(
+ server['id'])['server']['OS-EXT-SRV-ATTR:host']
+ assert_func(src_host, dst_host)
+
+ @test.idempotent_id('4bf0be52-3b6f-4746-9a27-3143636fe30d')
+ @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+ 'Cold migration not available.')
+ def test_cold_migration(self):
+ self._test_cold_migrate_server(revert=False)
+
+ @test.idempotent_id('caa1aa8b-f4ef-4374-be0d-95f001c2ac2d')
+ @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+ 'Cold migration not available.')
+ def test_revert_cold_migration(self):
+ self._test_cold_migrate_server(revert=True)
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index e5c8790..8504840 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -42,8 +42,12 @@
"{0} networks with label {1}".format(
len(configured_network),
CONF.compute.fixed_network_name))
+ elif CONF.network.public_network_id:
+ configured_network = [x for x in networks if x['id'] ==
+ CONF.network.public_network_id]
else:
- configured_network = networks
+ raise self.skipException(
+ "Environment has no known-for-sure existing network.")
configured_network = configured_network[0]
network = (self.client.show_network(configured_network['id'])
['network'])
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
old mode 100755
new mode 100644
index aabb40c..efa55d5
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -102,14 +102,26 @@
params = {'tenant_id': tenant_id}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- self.assertEqual([], servers)
+ servers_name = map(lambda x: x['name'], servers)
+ self.assertNotIn(self.s1_name, servers_name)
+ self.assertNotIn(self.s2_name, servers_name)
- # List the admin tenant which has no servers
+ # List the primary tenant with all_tenants is specified
+ params = {'all_tenants': '', 'tenant_id': tenant_id}
+ body = self.client.list_servers(detail=True, **params)
+ servers = body['servers']
+ servers_name = map(lambda x: x['name'], servers)
+ self.assertIn(self.s1_name, servers_name)
+ self.assertIn(self.s2_name, servers_name)
+
+ # List the admin tenant shouldn't get servers created by other tenants
admin_tenant_id = self.client.tenant_id
params = {'all_tenants': '', 'tenant_id': admin_tenant_id}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- self.assertEqual([], servers)
+ servers_name = map(lambda x: x['name'], servers)
+ self.assertNotIn(self.s1_name, servers_name)
+ self.assertNotIn(self.s2_name, servers_name)
@test.idempotent_id('86c7a8f7-50cf-43a9-9bac-5b985317134f')
def test_list_servers_filter_by_exist_host(self):
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
old mode 100755
new mode 100644
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
new file mode 100644
index 0000000..f603abd
--- /dev/null
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -0,0 +1,75 @@
+# 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.compute import base
+from tempest.common import waiters
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class TestVolumeSwap(base.BaseV2ComputeAdminTest):
+ """The test suite for swapping of volume with admin user.
+
+ The following is the scenario outline:
+ 1. Create a volume "volume1" with non-admin.
+ 2. Create a volume "volume2" with non-admin.
+ 3. Boot an instance "instance1" with non-admin.
+ 4. Attach "volume1" to "instance1" with non-admin.
+ 5. Swap volume from "volume1" to "volume2" as admin.
+ 6. Check the swap volume is successful and "volume2"
+ is attached to "instance1" and "volume1" is in available state.
+ """
+
+ @classmethod
+ def skip_checks(cls):
+ super(TestVolumeSwap, cls).skip_checks()
+ if not CONF.compute_feature_enabled.swap_volume:
+ raise cls.skipException("Swapping volumes is not supported.")
+
+ @classmethod
+ def setup_clients(cls):
+ super(TestVolumeSwap, cls).setup_clients()
+ # We need the admin client for performing the update (swap) volume call
+ cls.servers_admin_client = cls.os_adm.servers_client
+
+ @test.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
+ @test.services('volume')
+ def test_volume_swap(self):
+ # Create two volumes.
+ # NOTE(gmann): Volumes are created before server creation so that
+ # volumes cleanup can happen successfully irrespective of which volume
+ # is attached to server.
+ volume1 = self.create_volume()
+ volume2 = self.create_volume()
+ # Boot server
+ server = self.create_test_server(wait_until='ACTIVE')
+ # Attach "volume1" to server
+ self.attach_volume(server, volume1)
+ # Swap volume from "volume1" to "volume2"
+ self.servers_admin_client.update_attached_volume(
+ server['id'], volume1['id'], volumeId=volume2['id'])
+ waiters.wait_for_volume_status(self.volumes_client,
+ volume1['id'], 'available')
+ waiters.wait_for_volume_status(self.volumes_client,
+ volume2['id'], 'in-use')
+ self.addCleanup(self.servers_client.detach_volume,
+ server['id'], volume2['id'])
+ # Verify "volume2" is attached to the server
+ vol_attachments = self.servers_client.list_volume_attachments(
+ server['id'])['volumeAttachments']
+ self.assertEqual(1, len(vol_attachments))
+ self.assertIn(volume2['id'], vol_attachments[0]['volumeId'])
+
+ # TODO(mriedem): Test swapping back from volume2 to volume1 after
+ # nova bug 1490236 is fixed.
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 5e75493..b738e82 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -120,6 +120,7 @@
cls.images = []
cls.security_groups = []
cls.server_groups = []
+ cls.volumes = []
@classmethod
def resource_cleanup(cls):
@@ -127,6 +128,7 @@
cls.clear_servers()
cls.clear_security_groups()
cls.clear_server_groups()
+ cls.clear_volumes()
super(BaseV2ComputeTest, cls).resource_cleanup()
@classmethod
@@ -219,6 +221,8 @@
:param validatable: Whether the server will be pingable or sshable.
:param volume_backed: Whether the instance is volume backed or not.
"""
+ if 'name' not in kwargs:
+ kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server")
tenant_network = cls.get_tenant_network()
body, servers = compute.create_test_server(
cls.os,
@@ -368,6 +372,66 @@
self.useFixture(api_microversion_fixture.APIMicroversionFixture(
self.request_microversion))
+ @classmethod
+ def create_volume(cls):
+ """Create a volume and wait for it to become 'available'.
+
+ :returns: The available volume.
+ """
+ vol_name = data_utils.rand_name(cls.__name__ + '-volume')
+ volume = cls.volumes_client.create_volume(
+ size=CONF.volume.volume_size, display_name=vol_name)['volume']
+ cls.volumes.append(volume)
+ waiters.wait_for_volume_status(cls.volumes_client,
+ volume['id'], 'available')
+ return volume
+
+ @classmethod
+ def clear_volumes(cls):
+ LOG.debug('Clearing volumes: %s', ','.join(
+ volume['id'] for volume in cls.volumes))
+ for volume in cls.volumes:
+ try:
+ test_utils.call_and_ignore_notfound_exc(
+ cls.volumes_client.delete_volume, volume['id'])
+ except Exception:
+ LOG.exception('Deleting volume %s failed', volume['id'])
+
+ for volume in cls.volumes:
+ try:
+ cls.volumes_client.wait_for_resource_deletion(volume['id'])
+ except Exception:
+ LOG.exception('Waiting for deletion of volume %s failed',
+ volume['id'])
+
+ def attach_volume(self, server, volume, device=None):
+ """Attaches volume to server and waits for 'in-use' volume status.
+
+ The volume will be detached when the test tears down.
+
+ :param server: The server to which the volume will be attached.
+ :param volume: The volume to attach.
+ :param device: Optional mountpoint for the attached volume. Note that
+ this is not guaranteed for all hypervisors and is not recommended.
+ """
+ attach_kwargs = dict(volumeId=volume['id'])
+ if device:
+ attach_kwargs['device'] = device
+ self.servers_client.attach_volume(
+ server['id'], **attach_kwargs)
+ # On teardown detach the volume and wait for it to be available. This
+ # is so we don't error out when trying to delete the volume during
+ # teardown.
+ self.addCleanup(waiters.wait_for_volume_status,
+ self.volumes_client, volume['id'], 'available')
+ # Ignore 404s on detach in case the server is deleted or the volume
+ # is already detached.
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.servers_client.detach_volume,
+ server['id'], volume['id'])
+ waiters.wait_for_volume_status(self.volumes_client,
+ volume['id'], 'in-use')
+
class BaseV2ComputeAdminTest(BaseV2ComputeTest):
"""Base test case class for Compute Admin API tests."""
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
deleted file mode 100644
index 83f8e19..0000000
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2013 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.compute import base
-from tempest.api_schema.request.compute.v2 import flavors
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
-
-load_tests = test.NegativeAutoTest.load_tests
-
-
-@test.SimpleNegativeAutoTest
-class FlavorsListWithDetailsNegativeTestJSON(base.BaseV2ComputeTest,
- test.NegativeAutoTest):
- _service = CONF.compute.catalog_type
- _schema = flavors.flavor_list
-
-
-@test.SimpleNegativeAutoTest
-class FlavorDetailsNegativeTestJSON(base.BaseV2ComputeTest,
- test.NegativeAutoTest):
- _service = CONF.compute.catalog_type
- _schema = flavors.flavors_details
-
- @classmethod
- def resource_setup(cls):
- super(FlavorDetailsNegativeTestJSON, cls).resource_setup()
- cls.set_resource("flavor", cls.flavor_ref)
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index 3508ba9..fdf1e93 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -14,7 +14,6 @@
# under the License.
from tempest.api.compute.floating_ips import base
-from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import test_utils
@@ -112,8 +111,7 @@
# positive test:Association of an already associated floating IP
# to specific server should change the association of the Floating IP
# Create server so as to use for Multiple association
- new_name = data_utils.rand_name('floating_server')
- body = self.create_test_server(name=new_name)
+ body = self.create_test_server()
waiters.wait_for_server_status(self.servers_client,
body['id'], 'ACTIVE')
self.new_server_id = body['id']
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 5738293..222bf18 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -41,8 +41,8 @@
@classmethod
def resource_cleanup(cls):
- for i in range(3):
- cls.client.delete_floating_ip(cls.floating_ip_id[i])
+ for f_id in cls.floating_ip_id:
+ cls.client.delete_floating_ip(f_id)
super(FloatingIPDetailsTestJSON, cls).resource_cleanup()
@test.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f')
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 3754637..154d717 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -42,11 +42,9 @@
@test.idempotent_id('aa06b52b-2db5-4807-b218-9441f75d74e3')
def test_delete_saving_image(self):
- snapshot_name = data_utils.rand_name('test-snap')
server = self.create_test_server(wait_until='ACTIVE')
self.addCleanup(self.servers_client.delete_server, server['id'])
image = self.create_image_from_server(server['id'],
- name=snapshot_name,
wait_until='SAVING')
self.client.delete_image(image['id'])
msg = ('The image with ID {image_id} failed to be deleted'
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index e91944f..8db094d 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -64,8 +64,6 @@
# Create a new image with invalid server id
name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
- resp = {}
- resp['status'] = None
self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
'!@$^&*()', name=name, meta=meta)
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 7b978ab..6c417f1 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -19,6 +19,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest.lib.common.utils import test_utils
from tempest import test
CONF = config.CONF
@@ -27,26 +28,6 @@
class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
- def tearDown(self):
- """Terminate test instances created after a test is executed."""
- self.server_check_teardown()
- super(ImagesOneServerTestJSON, self).tearDown()
-
- def setUp(self):
- # NOTE(afazekas): Normally we use the same server with all test cases,
- # but if it has an issue, we build a new one
- super(ImagesOneServerTestJSON, self).setUp()
- # Check if the server is in a clean state after test
- try:
- waiters.wait_for_server_status(self.servers_client,
- self.server_id, 'ACTIVE')
- except Exception:
- LOG.exception('server %s timed out to become ACTIVE. rebuilding'
- % self.server_id)
- # Rebuild server if cannot reach the ACTIVE state
- # Usually it means the server had a serious accident
- self.__class__.server_id = self.rebuild_server(self.server_id)
-
@classmethod
def skip_checks(cls):
super(ImagesOneServerTestJSON, cls).skip_checks()
@@ -74,6 +55,18 @@
flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
return flavor['disk']
+ @classmethod
+ def _rebuild_server_when_fails(cls, server_id):
+ try:
+ waiters.wait_for_server_status(cls.servers_client,
+ server_id, 'ACTIVE')
+ except Exception:
+ LOG.exception('server %s timed out to become ACTIVE. rebuilding'
+ % server_id)
+ # Rebuild server if cannot reach the ACTIVE state
+ # Usually it means the server had a serious accident
+ cls.server_id = cls.rebuild_server(server_id)
+
@test.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
def test_create_delete_image(self):
@@ -83,6 +76,8 @@
body = self.client.create_image(self.server_id, name=name,
metadata=meta)
image_id = data_utils.parse_image_id(body.response['location'])
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.client.delete_image, image_id)
waiters.wait_for_image_status(self.client, image_id, 'ACTIVE')
# Verify the image was created correctly
@@ -103,6 +98,7 @@
# Verify the image was deleted correctly
self.client.delete_image(image_id)
self.client.wait_for_resource_deletion(image_id)
+ self.addCleanup(self._rebuild_server_when_fails, self.server_id)
@test.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
def test_create_image_specify_multibyte_character_image_name(self):
@@ -116,3 +112,4 @@
body = self.client.create_image(self.server_id, name=utf8_name)
image_id = data_utils.parse_image_id(body.response['location'])
self.addCleanup(self.client.delete_image, image_id)
+ self.addCleanup(self._rebuild_server_when_fails, self.server_id)
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
old mode 100755
new mode 100644
index f340658..a9c2f7a
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -23,7 +23,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index f6353c8..755336f 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -94,8 +94,7 @@
# Create server and add the security group created
# above to the server we just created
- server_name = data_utils.rand_name('server')
- server = self.create_test_server(name=server_name)
+ server = self.create_test_server()
server_id = server['id']
waiters.wait_for_server_status(self.servers_client, server_id,
'ACTIVE')
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 7c12bf9..fc6a20f 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -20,7 +20,6 @@
from tempest.common.utils import net_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -47,22 +46,20 @@
@classmethod
def setup_clients(cls):
super(AttachInterfacesTestJSON, cls).setup_clients()
- cls.client = cls.os.interfaces_client
cls.networks_client = cls.os.networks_client
cls.subnets_client = cls.os.subnets_client
cls.ports_client = cls.os.ports_client
- cls.servers_client = cls.servers_client
def wait_for_interface_status(self, server, port_id, status):
"""Waits for an interface to reach a given status."""
- body = (self.client.show_interface(server, port_id)
+ body = (self.interfaces_client.show_interface(server, port_id)
['interfaceAttachment'])
interface_status = body['port_state']
start = int(time.time())
while(interface_status != status):
time.sleep(self.build_interval)
- body = (self.client.show_interface(server, port_id)
+ body = (self.interfaces_client.show_interface(server, port_id)
['interfaceAttachment'])
interface_status = body['port_state']
@@ -73,7 +70,7 @@
'(current %s) within the required time (%s s).' %
(port_id, status, interface_status,
self.build_timeout))
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
return body
@@ -101,7 +98,7 @@
message = ('Port %s failed to detach (device_id %s) within '
'the required time (%s s).' %
(port_id, device_id, self.build_timeout))
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
return port
@@ -119,7 +116,7 @@
def _create_server_get_interfaces(self):
server = self.create_test_server(wait_until='ACTIVE')
- ifs = (self.client.list_interfaces(server['id'])
+ ifs = (self.interfaces_client.list_interfaces(server['id'])
['interfaceAttachments'])
body = self.wait_for_interface_status(
server['id'], ifs[0]['port_id'], 'ACTIVE')
@@ -127,7 +124,7 @@
return server, ifs
def _test_create_interface(self, server):
- iface = (self.client.create_interface(server['id'])
+ iface = (self.interfaces_client.create_interface(server['id'])
['interfaceAttachment'])
iface = self.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
@@ -136,7 +133,7 @@
def _test_create_interface_by_network_id(self, server, ifs):
network_id = ifs[0]['net_id']
- iface = self.client.create_interface(
+ iface = self.interfaces_client.create_interface(
server['id'], net_id=network_id)['interfaceAttachment']
iface = self.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
@@ -148,7 +145,7 @@
port = self.ports_client.create_port(network_id=network_id)
port_id = port['port']['id']
self.addCleanup(self.ports_client.delete_port, port_id)
- iface = self.client.create_interface(
+ iface = self.interfaces_client.create_interface(
server['id'], port_id=port_id)['interfaceAttachment']
iface = self.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
@@ -165,7 +162,7 @@
1)
fixed_ips = [{'ip_address': ip_list[0]}]
- iface = self.client.create_interface(
+ iface = self.interfaces_client.create_interface(
server['id'], net_id=network_id,
fixed_ips=fixed_ips)['interfaceAttachment']
self.addCleanup(self.ports_client.delete_port, iface['port_id'])
@@ -176,7 +173,7 @@
def _test_show_interface(self, server, ifs):
iface = ifs[0]
- _iface = self.client.show_interface(
+ _iface = self.interfaces_client.show_interface(
server['id'], iface['port_id'])['interfaceAttachment']
self._check_interface(iface, port_id=_iface['port_id'],
network_id=_iface['net_id'],
@@ -186,20 +183,20 @@
def _test_delete_interface(self, server, ifs):
# NOTE(danms): delete not the first or last, but one in the middle
iface = ifs[1]
- self.client.delete_interface(server['id'], iface['port_id'])
- _ifs = (self.client.list_interfaces(server['id'])
+ self.interfaces_client.delete_interface(server['id'], iface['port_id'])
+ _ifs = (self.interfaces_client.list_interfaces(server['id'])
['interfaceAttachments'])
start = int(time.time())
while len(ifs) == len(_ifs):
time.sleep(self.build_interval)
- _ifs = (self.client.list_interfaces(server['id'])
+ _ifs = (self.interfaces_client.list_interfaces(server['id'])
['interfaceAttachments'])
timed_out = int(time.time()) - start >= self.build_timeout
if len(ifs) == len(_ifs) and timed_out:
message = ('Failed to delete interface within '
'the required time: %s sec.' % self.build_timeout)
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
self.assertNotIn(iface['port_id'], [i['port_id'] for i in _ifs])
return _ifs
@@ -217,7 +214,7 @@
def test_create_list_show_delete_interfaces(self):
server, ifs = self._create_server_get_interfaces()
interface_count = len(ifs)
- self.assertTrue(interface_count > 0)
+ self.assertGreater(interface_count, 0)
self._check_interface(ifs[0])
try:
@@ -239,7 +236,7 @@
iface = self._test_create_interface_by_fixed_ips(server, ifs)
ifs.append(iface)
- _ifs = (self.client.list_interfaces(server['id'])
+ _ifs = (self.interfaces_client.list_interfaces(server['id'])
['interfaceAttachments'])
self._compare_iface_list(ifs, _ifs)
@@ -255,7 +252,7 @@
# Add and Remove the fixed IP to server.
server, ifs = self._create_server_get_interfaces()
interface_count = len(ifs)
- self.assertTrue(interface_count > 0)
+ self.assertGreater(interface_count, 0)
self._check_interface(ifs[0])
network_id = ifs[0]['net_id']
self.servers_client.add_fixed_ip(server['id'], networkId=network_id)
@@ -302,11 +299,11 @@
for server in servers:
# attach the port to the server
- iface = self.client.create_interface(
+ iface = self.interfaces_client.create_interface(
server['id'], port_id=port_id)['interfaceAttachment']
self._check_interface(iface, port_id=port_id)
# detach the port from the server; this is a cast in the compute
# API so we have to poll the port until the device_id is unset.
- self.client.delete_interface(server['id'], port_id)
+ self.interfaces_client.delete_interface(server['id'], port_id)
self.wait_for_port_detach(port_id)
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 76da317..00df86b 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -29,4 +29,4 @@
def test_get_availability_zone_list_with_non_admin_user(self):
# List of availability zone with non-administrator user
availability_zone = self.client.list_availability_zones()
- self.assertTrue(len(availability_zone['availabilityZoneInfo']) > 0)
+ self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
old mode 100755
new mode 100644
index 78f0db4..2f43157
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -142,16 +142,12 @@
self.assertEqual(self.name.lower(), hostname, msg)
@test.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
+ @testtools.skipUnless(
+ test.is_scheduler_filter_enabled("ServerGroupAffinityFilter"),
+ 'ServerGroupAffinityFilter is not available.')
def test_create_server_with_scheduler_hint_group(self):
# Create a server with the scheduler hint "group".
- name = data_utils.rand_name('server_group')
- policies = ['affinity']
- body = self.server_groups_client.create_server_group(
- name=name, policies=policies)['server_group']
- group_id = body['id']
- self.addCleanup(self.server_groups_client.delete_server_group,
- group_id)
-
+ group_id = self.create_test_server_group()['id']
hints = {'group': group_id}
server = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')
@@ -268,37 +264,25 @@
flavor_base = self.flavors_client.show_flavor(
self.flavor_ref)['flavor']
- def create_flavor_with_extra_specs():
- flavor_with_eph_disk_name = data_utils.rand_name('eph_flavor')
+ def create_flavor_with_ephemeral(ephem_disk):
flavor_with_eph_disk_id = data_utils.rand_int_id(start=1000)
ram = flavor_base['ram']
vcpus = flavor_base['vcpus']
disk = flavor_base['disk']
- # Create a flavor with extra specs
- flavor = (self.flavor_client.
- create_flavor(name=flavor_with_eph_disk_name,
- ram=ram, vcpus=vcpus, disk=disk,
- id=flavor_with_eph_disk_id,
- ephemeral=1))['flavor']
- self.addCleanup(flavor_clean_up, flavor['id'])
-
- return flavor['id']
-
- def create_flavor_without_extra_specs():
- flavor_no_eph_disk_name = data_utils.rand_name('no_eph_flavor')
- flavor_no_eph_disk_id = data_utils.rand_int_id(start=1000)
-
- ram = flavor_base['ram']
- vcpus = flavor_base['vcpus']
- disk = flavor_base['disk']
-
- # Create a flavor without extra specs
- flavor = (self.flavor_client.
- create_flavor(name=flavor_no_eph_disk_name,
- ram=ram, vcpus=vcpus, disk=disk,
- id=flavor_no_eph_disk_id))['flavor']
+ if ephem_disk > 0:
+ # Create a flavor with ephemeral disk
+ flavor_name = data_utils.rand_name('eph_flavor')
+ flavor = self.flavor_client.create_flavor(
+ name=flavor_name, ram=ram, vcpus=vcpus, disk=disk,
+ id=flavor_with_eph_disk_id, ephemeral=ephem_disk)['flavor']
+ else:
+ # Create a flavor without ephemeral disk
+ flavor_name = data_utils.rand_name('no_eph_flavor')
+ flavor = self.flavor_client.create_flavor(
+ name=flavor_name, ram=ram, vcpus=vcpus, disk=disk,
+ id=flavor_with_eph_disk_id)['flavor']
self.addCleanup(flavor_clean_up, flavor['id'])
return flavor['id']
@@ -307,8 +291,8 @@
self.flavor_client.delete_flavor(flavor_id)
self.flavor_client.wait_for_resource_deletion(flavor_id)
- flavor_with_eph_disk_id = create_flavor_with_extra_specs()
- flavor_no_eph_disk_id = create_flavor_without_extra_specs()
+ flavor_with_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=1)
+ flavor_no_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=0)
admin_pass = self.image_ssh_password
@@ -318,7 +302,7 @@
adminPass=admin_pass,
flavor=flavor_no_eph_disk_id)
- # Get partition number of server without extra specs.
+ # Get partition number of server without ephemeral disk.
server_no_eph_disk = self.client.show_server(
server_no_eph_disk['id'])['server']
linux_client = remote_client.RemoteClient(
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 079465d..07f46c5 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -106,24 +106,15 @@
@test.services('volume')
def test_delete_server_while_in_attached_volume(self):
# Delete a server while a volume is attached to it
- volumes_client = self.volumes_extensions_client
device = '/dev/%s' % CONF.compute.volume_device_name
server = self.create_test_server(wait_until='ACTIVE')
- volume = (volumes_client.create_volume(size=CONF.volume.volume_size)
- ['volume'])
- self.addCleanup(volumes_client.delete_volume, volume['id'])
- waiters.wait_for_volume_status(volumes_client,
- volume['id'], 'available')
- self.client.attach_volume(server['id'],
- volumeId=volume['id'],
- device=device)
- waiters.wait_for_volume_status(volumes_client,
- volume['id'], 'in-use')
+ volume = self.create_volume()
+ self.attach_volume(server, volume, device=device)
self.client.delete_server(server['id'])
waiters.wait_for_server_termination(self.client, server['id'])
- waiters.wait_for_volume_status(volumes_client,
+ waiters.wait_for_volume_status(self.volumes_client,
volume['id'], 'available')
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index 1367629..e50881f 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -28,26 +28,50 @@
@classmethod
def resource_setup(cls):
super(InstanceActionsTestJSON, cls).resource_setup()
- server = cls.create_test_server(wait_until='ACTIVE')
- cls.request_id = server.response['x-compute-request-id']
- cls.server_id = server['id']
+ cls.server = cls.create_test_server(wait_until='ACTIVE')
+ cls.request_id = cls.server.response['x-compute-request-id']
@test.idempotent_id('77ca5cc5-9990-45e0-ab98-1de8fead201a')
def test_list_instance_actions(self):
# List actions of the provided server
- self.client.reboot_server(self.server_id, type='HARD')
- waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
+ self.client.reboot_server(self.server['id'], type='HARD')
+ waiters.wait_for_server_status(self.client,
+ self.server['id'], 'ACTIVE')
- body = (self.client.list_instance_actions(self.server_id)
+ body = (self.client.list_instance_actions(self.server['id'])
['instanceActions'])
- self.assertTrue(len(body) == 2, str(body))
- self.assertTrue(any([i for i in body if i['action'] == 'create']))
- self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
+ self.assertEqual(len(body), 2, str(body))
+ self.assertEqual(sorted([i['action'] for i in body]),
+ ['create', 'reboot'])
@test.idempotent_id('aacc71ca-1d70-4aa5-bbf6-0ff71470e43c')
def test_get_instance_action(self):
# Get the action details of the provided server
body = self.client.show_instance_action(
- self.server_id, self.request_id)['instanceAction']
- self.assertEqual(self.server_id, body['instance_uuid'])
+ self.server['id'], self.request_id)['instanceAction']
+ self.assertEqual(self.server['id'], body['instance_uuid'])
self.assertEqual('create', body['action'])
+
+
+class InstanceActionsV221TestJSON(base.BaseV2ComputeTest):
+
+ min_microversion = '2.21'
+ max_microversion = 'latest'
+
+ @classmethod
+ def setup_clients(cls):
+ super(InstanceActionsV221TestJSON, cls).setup_clients()
+ cls.client = cls.servers_client
+
+ @test.idempotent_id('0a0f85d4-10fa-41f6-bf80-a54fb4aa2ae1')
+ def test_get_list_deleted_instance_actions(self):
+
+ # List actions of the deleted server
+ server = self.create_test_server(wait_until='ACTIVE')
+ self.client.delete_server(server['id'])
+ waiters.wait_for_server_termination(self.client, server['id'])
+ body = (self.client.list_instance_actions(server['id'])
+ ['instanceActions'])
+ self.assertEqual(len(body), 2, str(body))
+ self.assertEqual(sorted([i['action'] for i in body]),
+ ['create', 'delete'])
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index 54ec6aa..33fed08 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -29,8 +29,7 @@
@classmethod
def resource_setup(cls):
super(InstanceActionsNegativeTestJSON, cls).resource_setup()
- server = cls.create_test_server(wait_until='ACTIVE')
- cls.server_id = server['id']
+ cls.server = cls.create_test_server(wait_until='ACTIVE')
@test.attr(type=['negative'])
@test.idempotent_id('67e1fce6-7ec2-45c6-92d4-0a8f1a632910')
@@ -46,4 +45,4 @@
def test_get_instance_action_invalid_request(self):
# Get the action details of the provided server with invalid request
self.assertRaises(lib_exc.NotFound, self.client.show_instance_action,
- self.server_id, '999')
+ self.server['id'], '999')
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 26cbb090..611d5a2 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -119,8 +119,8 @@
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
@test.idempotent_id('ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e')
- def test_list_servers_filter_by_server_status(self):
- # Filter the list of servers by server status
+ def test_list_servers_filter_by_active_status(self):
+ # Filter the list of servers by server active status
params = {'status': 'active'}
body = self.client.list_servers(**params)
servers = body['servers']
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index eb1beb1..9fc30f9 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -14,32 +14,16 @@
# under the License.
from tempest.api.compute import base
-from tempest.common.utils import data_utils
from tempest import test
class MultipleCreateTestJSON(base.BaseV2ComputeTest):
- _name = 'multiple-create-test'
-
- def _generate_name(self):
- return data_utils.rand_name(self._name)
-
- def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
- # NOTE: This is the right way to create_multiple servers and manage to
- # get the created servers into the servers list to be cleaned up after
- # all.
- kwargs['name'] = name if name else self._generate_name()
- if wait_until:
- kwargs['wait_until'] = wait_until
- body = self.create_test_server(**kwargs)
-
- return body
@test.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1')
def test_multiple_create(self):
- body = self._create_multiple_servers(wait_until='ACTIVE',
- min_count=1,
- max_count=2)
+ body = self.create_test_server(wait_until='ACTIVE',
+ min_count=1,
+ max_count=2)
# NOTE(maurosr): do status response check and also make sure that
# reservation_id is not in the response body when the request send
# contains return_reservation_id=False
@@ -47,8 +31,8 @@
@test.idempotent_id('864777fb-2f1e-44e3-b5b9-3eb6fa84f2f7')
def test_multiple_create_with_reservation_return(self):
- body = self._create_multiple_servers(wait_until='ACTIVE',
- min_count=1,
- max_count=2,
- return_reservation_id=True)
+ body = self.create_test_server(wait_until='ACTIVE',
+ min_count=1,
+ max_count=2,
+ return_reservation_id=True)
self.assertIn('reservation_id', body)
diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py
index e5b4f46..d9fb4ca 100644
--- a/tempest/api/compute/servers/test_multiple_create_negative.py
+++ b/tempest/api/compute/servers/test_multiple_create_negative.py
@@ -14,51 +14,38 @@
# under the License.
from tempest.api.compute import base
-from tempest.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
from tempest import test
class MultipleCreateNegativeTestJSON(base.BaseV2ComputeTest):
- _name = 'multiple-create-test'
-
- def _generate_name(self):
- return data_utils.rand_name(self._name)
-
- def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
- # This is the right way to create_multiple servers and manage to get
- # the created servers into the servers list to be cleaned up after all.
- kwargs['name'] = kwargs.get('name', self._generate_name())
- body = self.create_test_server(**kwargs)
-
- return body
@test.attr(type=['negative'])
@test.idempotent_id('daf29d8d-e928-4a01-9a8c-b129603f3fc0')
def test_min_count_less_than_one(self):
invalid_min_count = 0
- self.assertRaises(lib_exc.BadRequest, self._create_multiple_servers,
+ self.assertRaises(lib_exc.BadRequest, self.create_test_server,
min_count=invalid_min_count)
@test.attr(type=['negative'])
@test.idempotent_id('999aa722-d624-4423-b813-0d1ac9884d7a')
def test_min_count_non_integer(self):
invalid_min_count = 2.5
- self.assertRaises(lib_exc.BadRequest, self._create_multiple_servers,
+ self.assertRaises(lib_exc.BadRequest, self.create_test_server,
min_count=invalid_min_count)
@test.attr(type=['negative'])
@test.idempotent_id('a6f9c2ab-e060-4b82-b23c-4532cb9390ff')
def test_max_count_less_than_one(self):
invalid_max_count = 0
- self.assertRaises(lib_exc.BadRequest, self._create_multiple_servers,
+ self.assertRaises(lib_exc.BadRequest, self.create_test_server,
max_count=invalid_max_count)
@test.attr(type=['negative'])
@test.idempotent_id('9c5698d1-d7af-4c80-b971-9d403135eea2')
def test_max_count_non_integer(self):
invalid_max_count = 2.5
- self.assertRaises(lib_exc.BadRequest, self._create_multiple_servers,
+ self.assertRaises(lib_exc.BadRequest, self.create_test_server,
max_count=invalid_max_count)
@test.attr(type=['negative'])
@@ -66,6 +53,6 @@
def test_max_count_less_than_min_count(self):
min_count = 3
max_count = 2
- self.assertRaises(lib_exc.BadRequest, self._create_multiple_servers,
+ self.assertRaises(lib_exc.BadRequest, self.create_test_server,
min_count=min_count,
max_count=max_count)
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
old mode 100755
new mode 100644
index 062e920..9077801
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -24,7 +24,6 @@
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -81,14 +80,19 @@
@testtools.skipUnless(CONF.compute_feature_enabled.change_password,
'Change password not available.')
def test_change_server_password(self):
+ # Since this test messes with the password and makes the
+ # server unreachable, it should create its own server
+ newserver = self.create_test_server(
+ validatable=True,
+ wait_until='ACTIVE')
# The server's password should be set to the provided password
new_password = 'Newpass1234'
- self.client.change_password(self.server_id, adminPass=new_password)
- waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
+ self.client.change_password(newserver['id'], adminPass=new_password)
+ waiters.wait_for_server_status(self.client, newserver['id'], 'ACTIVE')
if CONF.validation.run_validation:
# Verify that the user can authenticate with the new password
- server = self.client.show_server(self.server_id)['server']
+ server = self.client.show_server(newserver['id'])['server']
linux_client = remote_client.RemoteClient(
self.get_server_ip(server),
self.ssh_user,
@@ -235,20 +239,10 @@
@test.services('volume')
def test_rebuild_server_with_volume_attached(self):
# create a new volume and attach it to the server
- volume = self.volumes_client.create_volume(
- size=CONF.volume.volume_size)
- volume = volume['volume']
- self.addCleanup(self.volumes_client.delete_volume, volume['id'])
- waiters.wait_for_volume_status(self.volumes_client, volume['id'],
- 'available')
+ volume = self.create_volume()
- self.client.attach_volume(self.server_id, volumeId=volume['id'])
- self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
- volume['id'], 'available')
- self.addCleanup(self.client.detach_volume,
- self.server_id, volume['id'])
- waiters.wait_for_volume_status(self.volumes_client, volume['id'],
- 'in-use')
+ server = self.client.show_server(self.server_id)['server']
+ self.attach_volume(server, volume)
# run general rebuild test
self.test_rebuild_server()
@@ -336,7 +330,7 @@
elif CONF.image_feature_enabled.api_v2:
glance_client = self.os.image_client_v2
else:
- raise exceptions.InvalidConfiguration(
+ raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 864f38f..d31b6f8 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -49,9 +49,9 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
- self.assertTrue(len(addresses) >= 1)
+ self.assertGreaterEqual(len(addresses), 1)
for network_name, network_addresses in six.iteritems(addresses):
- self.assertTrue(len(network_addresses) >= 1)
+ self.assertGreaterEqual(len(network_addresses), 1)
for address in network_addresses:
self.assertTrue(address['addr'])
self.assertTrue(address['version'])
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index e32f6b0..bc49e7b 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -19,12 +19,13 @@
class ServerGroupTestJSON(base.BaseV2ComputeTest):
- """These tests check for the server-group APIs
+ """These tests check for the server-group APIs.
They create/delete server-groups with different policies.
policies = affinity/anti-affinity
It also adds the tests for list and get details of server-groups
"""
+
@classmethod
def skip_checks(cls):
super(ServerGroupTestJSON, cls).skip_checks()
@@ -40,12 +41,10 @@
@classmethod
def resource_setup(cls):
super(ServerGroupTestJSON, cls).resource_setup()
- server_group_name = data_utils.rand_name('server-group')
cls.policy = ['affinity']
cls.created_server_group = cls.create_test_server_group(
- server_group_name,
- cls.policy)
+ policy=cls.policy)
def _create_server_group(self, name, policy):
# create the test server-group with given policy
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 9c07677..cb66e81 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -28,18 +28,17 @@
@classmethod
def resource_setup(cls):
super(ServerMetadataTestJSON, cls).resource_setup()
- server = cls.create_test_server(metadata={}, wait_until='ACTIVE')
- cls.server_id = server['id']
+ cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE')
def setUp(self):
super(ServerMetadataTestJSON, self).setUp()
meta = {'key1': 'value1', 'key2': 'value2'}
- self.client.set_server_metadata(self.server_id, meta)['metadata']
+ self.client.set_server_metadata(self.server['id'], meta)['metadata']
@test.idempotent_id('479da087-92b3-4dcf-aeb3-fd293b2d14ce')
def test_list_server_metadata(self):
# All metadata key/value pairs for a server should be returned
- resp_metadata = (self.client.list_server_metadata(self.server_id)
+ resp_metadata = (self.client.list_server_metadata(self.server['id'])
['metadata'])
# Verify the expected metadata items are in the list
@@ -51,12 +50,12 @@
# The server's metadata should be replaced with the provided values
# Create a new set of metadata for the server
req_metadata = {'meta2': 'data2', 'meta3': 'data3'}
- self.client.set_server_metadata(self.server_id,
+ self.client.set_server_metadata(self.server['id'],
req_metadata)['metadata']
# Verify the expected values are correct, and that the
# previous values have been removed
- resp_metadata = (self.client.list_server_metadata(self.server_id)
+ resp_metadata = (self.client.list_server_metadata(self.server['id'])
['metadata'])
self.assertEqual(resp_metadata, req_metadata)
@@ -65,10 +64,10 @@
# The server's metadata values should be updated to the
# provided values
meta = {'key1': 'alt1', 'key3': 'value3'}
- self.client.update_server_metadata(self.server_id, meta)
+ self.client.update_server_metadata(self.server['id'], meta)
# Verify the values have been updated to the proper values
- resp_metadata = (self.client.list_server_metadata(self.server_id)
+ resp_metadata = (self.client.list_server_metadata(self.server['id'])
['metadata'])
expected = {'key1': 'alt1', 'key2': 'value2', 'key3': 'value3'}
self.assertEqual(expected, resp_metadata)
@@ -78,8 +77,8 @@
# The original metadata should not be lost if empty metadata body is
# passed
meta = {}
- self.client.update_server_metadata(self.server_id, meta)
- resp_metadata = (self.client.list_server_metadata(self.server_id)
+ self.client.update_server_metadata(self.server['id'], meta)
+ resp_metadata = (self.client.list_server_metadata(self.server['id'])
['metadata'])
expected = {'key1': 'value1', 'key2': 'value2'}
self.assertEqual(expected, resp_metadata)
@@ -87,7 +86,7 @@
@test.idempotent_id('3043c57d-7e0e-49a6-9a96-ad569c265e6a')
def test_get_server_metadata_item(self):
# The value for a specific metadata key should be returned
- meta = self.client.show_server_metadata_item(self.server_id,
+ meta = self.client.show_server_metadata_item(self.server['id'],
'key2')['meta']
self.assertEqual('value2', meta['key2'])
@@ -96,10 +95,10 @@
# The item's value should be updated to the provided value
# Update the metadata value
meta = {'nova': 'alt'}
- self.client.set_server_metadata_item(self.server_id, 'nova', meta)
+ self.client.set_server_metadata_item(self.server['id'], 'nova', meta)
# Verify the meta item's value has been updated
- resp_metadata = (self.client.list_server_metadata(self.server_id)
+ resp_metadata = (self.client.list_server_metadata(self.server['id'])
['metadata'])
expected = {'key1': 'value1', 'key2': 'value2', 'nova': 'alt'}
self.assertEqual(expected, resp_metadata)
@@ -107,10 +106,10 @@
@test.idempotent_id('127642d6-4c7b-4486-b7cd-07265a378658')
def test_delete_server_metadata_item(self):
# The metadata value/key pair should be deleted from the server
- self.client.delete_server_metadata_item(self.server_id, 'key1')
+ self.client.delete_server_metadata_item(self.server['id'], 'key1')
# Verify the metadata item has been removed
- resp_metadata = (self.client.list_server_metadata(self.server_id)
+ resp_metadata = (self.client.list_server_metadata(self.server['id'])
['metadata'])
expected = {'key2': 'value2'}
self.assertEqual(expected, resp_metadata)
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index cbe70e2..aae9101 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -31,9 +31,7 @@
def resource_setup(cls):
super(ServerMetadataNegativeTestJSON, cls).resource_setup()
cls.tenant_id = cls.client.tenant_id
- server = cls.create_test_server(metadata={}, wait_until='ACTIVE')
-
- cls.server_id = server['id']
+ cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE')
@test.attr(type=['negative'])
@test.idempotent_id('fe114a8f-3a57-4eff-9ee2-4e14628df049')
@@ -87,7 +85,7 @@
meta = {'testkey': 'testvalue'}
self.assertRaises(lib_exc.BadRequest,
self.client.set_server_metadata_item,
- self.server_id, 'key', meta)
+ self.server['id'], 'key', meta)
@test.attr(type=['negative'])
@test.idempotent_id('0df38c2a-3d4e-4db5-98d8-d4d9fa843a12')
@@ -118,7 +116,7 @@
meta = {'': 'data1'}
self.assertRaises(lib_exc.BadRequest,
self.client.update_server_metadata,
- self.server_id, meta=meta)
+ self.server['id'], meta=meta)
@test.attr(type=['negative'])
@test.idempotent_id('6bbd88e1-f8b3-424d-ba10-ae21c45ada8d')
@@ -146,14 +144,14 @@
req_metadata['key' + str(num)] = 'val' + str(num)
self.assertRaises((lib_exc.OverLimit, lib_exc.Forbidden),
self.client.set_server_metadata,
- self.server_id, req_metadata)
+ self.server['id'], req_metadata)
# A 403 Forbidden or 413 Overlimit (old behaviour) exception
# will be raised while exceeding metadata items limit for
# tenant.
self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit),
self.client.update_server_metadata,
- self.server_id, req_metadata)
+ self.server['id'], req_metadata)
@test.attr(type=['negative'])
@test.idempotent_id('96100343-7fa9-40d8-80fa-d29ef588ce1c')
@@ -163,7 +161,7 @@
meta = {'': 'data1'}
self.assertRaises(lib_exc.BadRequest,
self.client.set_server_metadata,
- self.server_id, meta=meta)
+ self.server['id'], meta=meta)
@test.attr(type=['negative'])
@test.idempotent_id('64a91aee-9723-4863-be44-4c9d9f1e7d0e')
@@ -173,4 +171,4 @@
meta = {'meta1': 'data1'}
self.assertRaises(lib_exc.BadRequest,
self.client.set_server_metadata,
- self.server_id, meta=meta, no_metadata_field=True)
+ self.server['id'], meta=meta, no_metadata_field=True)
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index cd90473..e5ad7b4 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -137,6 +137,6 @@
server=server,
servers_client=self.client)
for i in person:
- self.assertEqual(base64.b64decode(i['contents']),
+ self.assertEqual(base64.decode_as_text(i['contents']),
linux_client.exec_command(
'sudo cat %s' % i['path']))
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 8d63b6b..41b648c 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -60,20 +60,6 @@
waiters.wait_for_server_status(cls.servers_client,
cls.server_id, 'ACTIVE')
- def _create_volume(self):
- volume = self.volumes_extensions_client.create_volume(
- size=CONF.volume.volume_size, display_name=data_utils.rand_name(
- self.__class__.__name__ + '_volume'))['volume']
- self.addCleanup(self.delete_volume, volume['id'])
- waiters.wait_for_volume_status(self.volumes_extensions_client,
- volume['id'], 'available')
- return volume
-
- def _detach(self, server_id, volume_id):
- self.servers_client.detach_volume(server_id, volume_id)
- waiters.wait_for_volume_status(self.volumes_extensions_client,
- volume_id, 'available')
-
def _unrescue(self, server_id):
self.servers_client.unrescue_server(server_id)
waiters.wait_for_server_status(self.servers_client,
@@ -125,7 +111,7 @@
@test.services('volume')
@test.attr(type=['negative'])
def test_rescued_vm_attach_volume(self):
- volume = self._create_volume()
+ volume = self.create_volume()
# Rescue the server
self.servers_client.rescue_server(self.server_id,
@@ -145,14 +131,11 @@
@test.services('volume')
@test.attr(type=['negative'])
def test_rescued_vm_detach_volume(self):
- volume = self._create_volume()
+ volume = self.create_volume()
# Attach the volume to the server
- self.servers_client.attach_volume(self.server_id,
- volumeId=volume['id'],
- device='/dev/%s' % self.device)
- waiters.wait_for_volume_status(self.volumes_extensions_client,
- volume['id'], 'in-use')
+ server = self.servers_client.show_server(self.server_id)['server']
+ self.attach_volume(server, volume, device='/dev/%s' % self.device)
# Rescue the server
self.servers_client.rescue_server(self.server_id,
@@ -160,7 +143,6 @@
waiters.wait_for_server_status(self.servers_client,
self.server_id, 'RESCUE')
# addCleanup is a LIFO queue
- self.addCleanup(self._detach, self.server_id, volume['id'])
self.addCleanup(self._unrescue, self.server_id)
# Detach the volume from the server expecting failure
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
old mode 100755
new mode 100644
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
old mode 100755
new mode 100644
index 89be3f3..1b1b339
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -490,6 +490,36 @@
self.client.unshelve_server,
self.server_id)
+ @test.attr(type=['negative'])
+ @test.idempotent_id('74085be3-a370-4ca2-bc51-2d0e10e0f573')
+ @test.services('volume', 'image')
+ def test_create_server_from_non_bootable_volume(self):
+ # Create a volume
+ volume = self.create_volume()
+
+ # Update volume bootable status to false
+ self.volumes_client.set_bootable_volume(volume['id'],
+ bootable=False)
+
+ # Verify bootable flag was updated
+ nonbootable_vol = self.volumes_client.show_volume(
+ volume['id'])['volume']
+ self.assertEqual('false', nonbootable_vol['bootable'])
+
+ # Block device mapping
+ bd_map = [{'boot_index': '0',
+ 'uuid': volume['id'],
+ 'source_type': 'volume',
+ 'destination_type': 'volume',
+ 'delete_on_termination': False}]
+
+ # Try creating a server from non-bootable volume
+ self.assertRaises(lib_exc.BadRequest,
+ self.create_test_server,
+ image_id='',
+ wait_until='ACTIVE',
+ block_device_mapping_v2=bd_map)
+
class ServersNegativeTestMultiTenantJSON(base.BaseV2ComputeTest):
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index e620e03..08c34d3 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -40,8 +40,7 @@
@classmethod
def resource_setup(cls):
super(VirtualInterfacesTestJSON, cls).resource_setup()
- server = cls.create_test_server(wait_until='ACTIVE')
- cls.server_id = server['id']
+ cls.server = cls.create_test_server(wait_until='ACTIVE')
@test.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016')
@test.services('network')
@@ -53,9 +52,9 @@
# TODO(mriedem): After a microversion implements the API for
# neutron, a 400 should be a failure for nova-network and neutron.
with testtools.ExpectedException(exceptions.BadRequest):
- self.client.list_virtual_interfaces(self.server_id)
+ self.client.list_virtual_interfaces(self.server['id'])
else:
- output = self.client.list_virtual_interfaces(self.server_id)
+ output = self.client.list_virtual_interfaces(self.server['id'])
self.assertIsNotNone(output)
virt_ifaces = output
self.assertNotEqual(0, len(virt_ifaces['virtual_interfaces']),
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index ffd274f..bd2b185 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -49,9 +49,8 @@
# Migrating to an invalid host should not change the status
target_host = data_utils.rand_name('host')
server = self.create_test_server(wait_until="ACTIVE")
- server_id = server['id']
self.assertRaises(lib_exc.BadRequest, self._migrate_server_to,
- server_id, target_host)
- waiters.wait_for_server_status(self.servers_client, server_id,
+ server['id'], target_host)
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'ACTIVE')
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index ff5dc49..d4831b1 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -71,11 +71,8 @@
def _create_and_attach_volume(self, server):
# Create a volume and wait for it to become ready
- volume = self.volumes_client.create_volume(
- size=CONF.volume.volume_size, display_name='test')['volume']
+ volume = self.create_volume()
self.addCleanup(self.delete_volume, volume['id'])
- waiters.wait_for_volume_status(self.volumes_client,
- volume['id'], 'available')
# Attach the volume to the server
self.attachment = self.servers_client.attach_volume(
@@ -163,7 +160,7 @@
"""Testing volume with shelved instance.
This test checks the attaching and detaching volumes from
- a shelved or shelved ofload instance.
+ a shelved or shelved offload instance.
"""
min_microversion = '2.20'
diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py
new file mode 100644
index 0000000..b7fa0fe
--- /dev/null
+++ b/tempest/api/compute/volumes/test_attach_volume_negative.py
@@ -0,0 +1,41 @@
+# Copyright 2016 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.compute import base
+from tempest import config
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+CONF = config.CONF
+
+
+class AttachVolumeNegativeTest(base.BaseV2ComputeTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(AttachVolumeNegativeTest, cls).skip_checks()
+ if not CONF.service_available.cinder:
+ skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+
+ @test.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7')
+ def test_delete_attached_volume(self):
+ server = self.create_test_server(wait_until='ACTIVE')
+ volume = self.create_volume()
+
+ path = "/dev/%s" % CONF.compute.volume_device_name
+ self.attach_volume(server, volume, device=path)
+
+ self.assertRaises(lib_exc.BadRequest,
+ self.delete_volume, volume['id'])
diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py
old mode 100755
new mode 100644
index e96982d..460c882
--- a/tempest/api/compute/volumes/test_volume_snapshots.py
+++ b/tempest/api/compute/volumes/test_volume_snapshots.py
@@ -40,13 +40,9 @@
@test.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f')
def test_volume_snapshot_create_get_list_delete(self):
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- volume = self.volumes_client.create_volume(
- size=CONF.volume.volume_size,
- display_name=v_name)['volume']
+ volume = self.create_volume()
self.addCleanup(self.delete_volume, volume['id'])
- waiters.wait_for_volume_status(self.volumes_client, volume['id'],
- 'available')
+
s_name = data_utils.rand_name(self.__class__.__name__ + '-Snapshot')
# Create snapshot
snapshot = self.snapshots_client.create_snapshot(
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
old mode 100755
new mode 100644
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
old mode 100755
new mode 100644
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
old mode 100755
new mode 100644
index 7ecad12..5fe4cb3
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -84,13 +84,6 @@
size='0', display_name=v_name, metadata=metadata)
@test.attr(type=['negative'])
- @test.idempotent_id('f01904f2-e975-4915-98ce-cb5fa27bde4f')
- def test_get_invalid_volume_id(self):
- # Negative: Should not be able to get volume with invalid id
- self.assertRaises(lib_exc.NotFound,
- self.client.show_volume, '#$%%&^&^')
-
- @test.attr(type=['negative'])
@test.idempotent_id('62bab09a-4c03-4617-8cca-8572bc94af9b')
def test_get_volume_without_passing_volume_id(self):
# Negative: Should not be able to get volume when empty ID is passed
diff --git a/tempest/api/data_processing/__init__.py b/tempest/api/data_processing/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/data_processing/__init__.py
+++ /dev/null
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
deleted file mode 100644
index c8506ae..0000000
--- a/tempest/api/data_processing/base.py
+++ /dev/null
@@ -1,442 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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 collections
-import copy
-
-import six
-
-from tempest import config
-from tempest import exceptions
-from tempest.lib.common.utils import test_utils
-import tempest.test
-
-
-CONF = config.CONF
-
-"""Default templates.
-There should always be at least a master1 and a worker1 node
-group template."""
-BASE_VANILLA_DESC = {
- 'NODES': {
- 'master1': {
- 'count': 1,
- 'node_processes': ['namenode', 'resourcemanager',
- 'hiveserver']
- },
- 'master2': {
- 'count': 1,
- 'node_processes': ['oozie', 'historyserver',
- 'secondarynamenode']
- },
- 'worker1': {
- 'count': 1,
- 'node_processes': ['datanode', 'nodemanager'],
- 'node_configs': {
- 'MapReduce': {
- 'yarn.app.mapreduce.am.resource.mb': 256,
- 'yarn.app.mapreduce.am.command-opts': '-Xmx256m'
- },
- 'YARN': {
- 'yarn.scheduler.minimum-allocation-mb': 256,
- 'yarn.scheduler.maximum-allocation-mb': 1024,
- 'yarn.nodemanager.vmem-check-enabled': False
- }
- }
- }
- },
- 'cluster_configs': {
- 'HDFS': {
- 'dfs.replication': 1
- }
- }
-}
-
-BASE_SPARK_DESC = {
- 'NODES': {
- 'master1': {
- 'count': 1,
- 'node_processes': ['namenode', 'master']
- },
- 'worker1': {
- 'count': 1,
- 'node_processes': ['datanode', 'slave']
- }
- },
- 'cluster_configs': {
- 'HDFS': {
- 'dfs.replication': 1
- }
- }
-}
-
-BASE_CDH_DESC = {
- 'NODES': {
- 'master1': {
- 'count': 1,
- 'node_processes': ['CLOUDERA_MANAGER']
- },
- 'master2': {
- 'count': 1,
- 'node_processes': ['HDFS_NAMENODE',
- 'YARN_RESOURCEMANAGER']
- },
- 'master3': {
- 'count': 1,
- 'node_processes': ['OOZIE_SERVER', 'YARN_JOBHISTORY',
- 'HDFS_SECONDARYNAMENODE',
- 'HIVE_METASTORE', 'HIVE_SERVER2']
- },
- 'worker1': {
- 'count': 1,
- 'node_processes': ['YARN_NODEMANAGER', 'HDFS_DATANODE']
- }
- },
- 'cluster_configs': {
- 'HDFS': {
- 'dfs_replication': 1
- }
- }
-}
-
-
-DEFAULT_TEMPLATES = {
- 'vanilla': collections.OrderedDict([
- ('2.6.0', copy.deepcopy(BASE_VANILLA_DESC)),
- ('2.7.1', copy.deepcopy(BASE_VANILLA_DESC)),
- ('1.2.1', {
- 'NODES': {
- 'master1': {
- 'count': 1,
- 'node_processes': ['namenode', 'jobtracker']
- },
- 'worker1': {
- 'count': 1,
- 'node_processes': ['datanode', 'tasktracker'],
- 'node_configs': {
- 'HDFS': {
- 'Data Node Heap Size': 1024
- },
- 'MapReduce': {
- 'Task Tracker Heap Size': 1024
- }
- }
- }
- },
- 'cluster_configs': {
- 'HDFS': {
- 'dfs.replication': 1
- },
- 'MapReduce': {
- 'mapred.map.tasks.speculative.execution': False,
- 'mapred.child.java.opts': '-Xmx500m'
- },
- 'general': {
- 'Enable Swift': False
- }
- }
- })
- ]),
- 'hdp': collections.OrderedDict([
- ('2.0.6', {
- 'NODES': {
- 'master1': {
- 'count': 1,
- 'node_processes': ['NAMENODE', 'SECONDARY_NAMENODE',
- 'ZOOKEEPER_SERVER', 'AMBARI_SERVER',
- 'HISTORYSERVER', 'RESOURCEMANAGER',
- 'GANGLIA_SERVER', 'NAGIOS_SERVER',
- 'OOZIE_SERVER']
- },
- 'worker1': {
- 'count': 1,
- 'node_processes': ['HDFS_CLIENT', 'DATANODE',
- 'YARN_CLIENT', 'ZOOKEEPER_CLIENT',
- 'MAPREDUCE2_CLIENT', 'NODEMANAGER',
- 'PIG', 'OOZIE_CLIENT']
- }
- },
- 'cluster_configs': {
- 'HDFS': {
- 'dfs.replication': 1
- }
- }
- })
- ]),
- 'spark': collections.OrderedDict([
- ('1.0.0', copy.deepcopy(BASE_SPARK_DESC)),
- ('1.3.1', copy.deepcopy(BASE_SPARK_DESC))
- ]),
- 'cdh': collections.OrderedDict([
- ('5.4.0', copy.deepcopy(BASE_CDH_DESC)),
- ('5.3.0', copy.deepcopy(BASE_CDH_DESC)),
- ('5', copy.deepcopy(BASE_CDH_DESC))
- ]),
-}
-
-
-class BaseDataProcessingTest(tempest.test.BaseTestCase):
-
- credentials = ['primary']
-
- @classmethod
- def skip_checks(cls):
- super(BaseDataProcessingTest, cls).skip_checks()
- if not CONF.service_available.sahara:
- raise cls.skipException('Sahara support is required')
- cls.default_plugin = cls._get_default_plugin()
-
- @classmethod
- def setup_clients(cls):
- super(BaseDataProcessingTest, cls).setup_clients()
- cls.client = cls.os.data_processing_client
-
- @classmethod
- def resource_setup(cls):
- super(BaseDataProcessingTest, cls).resource_setup()
-
- cls.default_version = cls._get_default_version()
- if cls.default_plugin is not None and cls.default_version is None:
- raise exceptions.InvalidConfiguration(
- message="No known Sahara plugin version was found")
- cls.flavor_ref = CONF.compute.flavor_ref
-
- # add lists for watched resources
- cls._node_group_templates = []
- cls._cluster_templates = []
- cls._data_sources = []
- cls._job_binary_internals = []
- cls._job_binaries = []
- cls._jobs = []
-
- @classmethod
- def resource_cleanup(cls):
- cls.cleanup_resources(getattr(cls, '_cluster_templates', []),
- cls.client.delete_cluster_template)
- cls.cleanup_resources(getattr(cls, '_node_group_templates', []),
- cls.client.delete_node_group_template)
- cls.cleanup_resources(getattr(cls, '_jobs', []), cls.client.delete_job)
- cls.cleanup_resources(getattr(cls, '_job_binaries', []),
- cls.client.delete_job_binary)
- cls.cleanup_resources(getattr(cls, '_job_binary_internals', []),
- cls.client.delete_job_binary_internal)
- cls.cleanup_resources(getattr(cls, '_data_sources', []),
- cls.client.delete_data_source)
- super(BaseDataProcessingTest, cls).resource_cleanup()
-
- @staticmethod
- def cleanup_resources(resource_id_list, method):
- for resource_id in resource_id_list:
- test_utils.call_and_ignore_notfound_exc(method, resource_id)
-
- @classmethod
- def create_node_group_template(cls, name, plugin_name, hadoop_version,
- node_processes, flavor_id,
- node_configs=None, **kwargs):
- """Creates watched node group template with specified params.
-
- It supports passing additional params using kwargs and returns created
- object. All resources created in this method will be automatically
- removed in tearDownClass method.
- """
- resp_body = cls.client.create_node_group_template(name, plugin_name,
- hadoop_version,
- node_processes,
- flavor_id,
- node_configs,
- **kwargs)
- resp_body = resp_body['node_group_template']
- # store id of created node group template
- cls._node_group_templates.append(resp_body['id'])
-
- return resp_body
-
- @classmethod
- def create_cluster_template(cls, name, plugin_name, hadoop_version,
- node_groups, cluster_configs=None, **kwargs):
- """Creates watched cluster template with specified params.
-
- It supports passing additional params using kwargs and returns created
- object. All resources created in this method will be automatically
- removed in tearDownClass method.
- """
- resp_body = cls.client.create_cluster_template(name, plugin_name,
- hadoop_version,
- node_groups,
- cluster_configs,
- **kwargs)
- resp_body = resp_body['cluster_template']
- # store id of created cluster template
- cls._cluster_templates.append(resp_body['id'])
-
- return resp_body
-
- @classmethod
- def create_data_source(cls, name, type, url, **kwargs):
- """Creates watched data source with specified params.
-
- It supports passing additional params using kwargs and returns created
- object. All resources created in this method will be automatically
- removed in tearDownClass method.
- """
- resp_body = cls.client.create_data_source(name, type, url, **kwargs)
- resp_body = resp_body['data_source']
- # store id of created data source
- cls._data_sources.append(resp_body['id'])
-
- return resp_body
-
- @classmethod
- def create_job_binary_internal(cls, name, data):
- """Creates watched job binary internal with specified params.
-
- It returns created object. All resources created in this method will
- be automatically removed in tearDownClass method.
- """
- resp_body = cls.client.create_job_binary_internal(name, data)
- resp_body = resp_body['job_binary_internal']
- # store id of created job binary internal
- cls._job_binary_internals.append(resp_body['id'])
-
- return resp_body
-
- @classmethod
- def create_job_binary(cls, name, url, extra=None, **kwargs):
- """Creates watched job binary with specified params.
-
- It supports passing additional params using kwargs and returns created
- object. All resources created in this method will be automatically
- removed in tearDownClass method.
- """
- resp_body = cls.client.create_job_binary(name, url, extra, **kwargs)
- resp_body = resp_body['job_binary']
- # store id of created job binary
- cls._job_binaries.append(resp_body['id'])
-
- return resp_body
-
- @classmethod
- def create_job(cls, name, job_type, mains, libs=None, **kwargs):
- """Creates watched job with specified params.
-
- It supports passing additional params using kwargs and returns created
- object. All resources created in this method will be automatically
- removed in tearDownClass method.
- """
- resp_body = cls.client.create_job(name,
- job_type, mains, libs, **kwargs)
- resp_body = resp_body['job']
- # store id of created job
- cls._jobs.append(resp_body['id'])
-
- return resp_body
-
- @classmethod
- def _get_default_plugin(cls):
- """Returns the default plugin used for testing."""
- if len(CONF.data_processing_feature_enabled.plugins) == 0:
- return None
-
- for plugin in CONF.data_processing_feature_enabled.plugins:
- if plugin in DEFAULT_TEMPLATES:
- break
- else:
- plugin = ''
- return plugin
-
- @classmethod
- def _get_default_version(cls):
- """Returns the default plugin version used for testing.
-
- This is gathered separately from the plugin to allow
- the usage of plugin name in skip_checks. This method is
- rather invoked into resource_setup, which allows API calls
- and exceptions.
- """
- if not cls.default_plugin:
- return None
- plugin = cls.client.get_plugin(cls.default_plugin)['plugin']
-
- for version in DEFAULT_TEMPLATES[cls.default_plugin].keys():
- if version in plugin['versions']:
- break
- else:
- version = None
-
- return version
-
- @classmethod
- def get_node_group_template(cls, nodegroup='worker1'):
- """Returns a node group template for the default plugin."""
- try:
- plugin_data = (
- DEFAULT_TEMPLATES[cls.default_plugin][cls.default_version]
- )
- nodegroup_data = plugin_data['NODES'][nodegroup]
- node_group_template = {
- 'description': 'Test node group template',
- 'plugin_name': cls.default_plugin,
- 'hadoop_version': cls.default_version,
- 'node_processes': nodegroup_data['node_processes'],
- 'flavor_id': cls.flavor_ref,
- 'node_configs': nodegroup_data.get('node_configs', {}),
- }
- return node_group_template
- except (IndexError, KeyError):
- return None
-
- @classmethod
- def get_cluster_template(cls, node_group_template_ids=None):
- """Returns a cluster template for the default plugin.
-
- node_group_template_defined contains the type and ID of pre-defined
- node group templates that have to be used in the cluster template
- (instead of dynamically defining them with 'node_processes').
- """
- if node_group_template_ids is None:
- node_group_template_ids = {}
- try:
- plugin_data = (
- DEFAULT_TEMPLATES[cls.default_plugin][cls.default_version]
- )
-
- all_node_groups = []
- for ng_name, ng_data in six.iteritems(plugin_data['NODES']):
- node_group = {
- 'name': '%s-node' % (ng_name),
- 'flavor_id': cls.flavor_ref,
- 'count': ng_data['count']
- }
- if ng_name in node_group_template_ids.keys():
- # node group already defined, use it
- node_group['node_group_template_id'] = (
- node_group_template_ids[ng_name]
- )
- else:
- # node_processes list defined on-the-fly
- node_group['node_processes'] = ng_data['node_processes']
- if 'node_configs' in ng_data:
- node_group['node_configs'] = ng_data['node_configs']
- all_node_groups.append(node_group)
-
- cluster_template = {
- 'description': 'Test cluster template',
- 'plugin_name': cls.default_plugin,
- 'hadoop_version': cls.default_version,
- 'cluster_configs': plugin_data.get('cluster_configs', {}),
- 'node_groups': all_node_groups,
- }
- return cluster_template
- except (IndexError, KeyError):
- return None
diff --git a/tempest/api/data_processing/test_cluster_templates.py b/tempest/api/data_processing/test_cluster_templates.py
deleted file mode 100644
index dfd8e27..0000000
--- a/tempest/api/data_processing/test_cluster_templates.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest.common.utils import data_utils
-from tempest import exceptions
-from tempest import test
-
-
-class ClusterTemplateTest(dp_base.BaseDataProcessingTest):
- # Link to the API documentation is http://docs.openstack.org/developer/
- # sahara/restapi/rest_api_v1.0.html#cluster-templates
-
- @classmethod
- def skip_checks(cls):
- super(ClusterTemplateTest, cls).skip_checks()
- if cls.default_plugin is None:
- raise cls.skipException("No Sahara plugins configured")
-
- @classmethod
- def resource_setup(cls):
- super(ClusterTemplateTest, cls).resource_setup()
-
- # pre-define a node group templates
- node_group_template_w = cls.get_node_group_template('worker1')
- if node_group_template_w is None:
- raise exceptions.InvalidConfiguration(
- message="No known Sahara plugin was found")
-
- node_group_template_w['name'] = data_utils.rand_name(
- 'sahara-ng-template')
- resp_body = cls.create_node_group_template(**node_group_template_w)
- node_group_template_id = resp_body['id']
- configured_node_group_templates = {'worker1': node_group_template_id}
-
- cls.full_cluster_template = cls.get_cluster_template(
- configured_node_group_templates)
-
- # create cls.cluster_template variable to use for comparison to cluster
- # template response body. The 'node_groups' field in the response body
- # has some extra info that post body does not have. The 'node_groups'
- # field in the response body is something like this
- #
- # 'node_groups': [
- # {
- # 'count': 3,
- # 'name': 'worker-node',
- # 'volume_mount_prefix': '/volumes/disk',
- # 'created_at': '2014-05-21 14:31:37',
- # 'updated_at': None,
- # 'floating_ip_pool': None,
- # ...
- # },
- # ...
- # ]
- cls.cluster_template = cls.full_cluster_template.copy()
- del cls.cluster_template['node_groups']
-
- def _create_cluster_template(self, template_name=None):
- """Creates Cluster Template with optional name specified.
-
- It creates template, ensures template name and response body.
- Returns id and name of created template.
- """
- if not template_name:
- # generate random name if it's not specified
- template_name = data_utils.rand_name('sahara-cluster-template')
-
- # create cluster template
- resp_body = self.create_cluster_template(template_name,
- **self.full_cluster_template)
-
- # ensure that template created successfully
- self.assertEqual(template_name, resp_body['name'])
- self.assertDictContainsSubset(self.cluster_template, resp_body)
-
- return resp_body['id'], template_name
-
- @test.attr(type='smoke')
- @test.idempotent_id('3525f1f1-3f9c-407d-891a-a996237e728b')
- def test_cluster_template_create(self):
- self._create_cluster_template()
-
- @test.attr(type='smoke')
- @test.idempotent_id('7a161882-e430-4840-a1c6-1d928201fab2')
- def test_cluster_template_list(self):
- template_info = self._create_cluster_template()
-
- # check for cluster template in list
- templates = self.client.list_cluster_templates()['cluster_templates']
- templates_info = [(template['id'], template['name'])
- for template in templates]
- self.assertIn(template_info, templates_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('2b75fe22-f731-4b0f-84f1-89ab25f86637')
- def test_cluster_template_get(self):
- template_id, template_name = self._create_cluster_template()
-
- # check cluster template fetch by id
- template = self.client.get_cluster_template(template_id)
- template = template['cluster_template']
- self.assertEqual(template_name, template['name'])
- self.assertDictContainsSubset(self.cluster_template, template)
-
- @test.attr(type='smoke')
- @test.idempotent_id('ff1fd989-171c-4dd7-91fd-9fbc71b09675')
- def test_cluster_template_delete(self):
- template_id, _ = self._create_cluster_template()
-
- # delete the cluster template by id
- self.client.delete_cluster_template(template_id)
- # TODO(ylobankov): check that cluster template is really deleted
diff --git a/tempest/api/data_processing/test_data_sources.py b/tempest/api/data_processing/test_data_sources.py
deleted file mode 100644
index 67d09a0..0000000
--- a/tempest/api/data_processing/test_data_sources.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-class DataSourceTest(dp_base.BaseDataProcessingTest):
- @classmethod
- def resource_setup(cls):
- super(DataSourceTest, cls).resource_setup()
- cls.swift_data_source_with_creds = {
- 'url': 'swift://sahara-container.sahara/input-source',
- 'description': 'Test data source',
- 'credentials': {
- 'user': cls.os.credentials.username,
- 'password': cls.os.credentials.password
- },
- 'type': 'swift'
- }
- cls.swift_data_source = cls.swift_data_source_with_creds.copy()
- del cls.swift_data_source['credentials']
-
- cls.local_hdfs_data_source = {
- 'url': 'input-source',
- 'description': 'Test data source',
- 'type': 'hdfs'
- }
-
- cls.external_hdfs_data_source = {
- 'url': 'hdfs://172.18.168.2:8020/usr/hadoop/input-source',
- 'description': 'Test data source',
- 'type': 'hdfs'
- }
-
- def _create_data_source(self, source_body, source_name=None):
- """Creates Data Source with optional name specified.
-
- It creates a link to input-source file (it may not exist), ensures
- source name and response body. Returns id and name of created source.
- """
- if not source_name:
- # generate random name if it's not specified
- source_name = data_utils.rand_name('sahara-data-source')
-
- # create data source
- resp_body = self.create_data_source(source_name, **source_body)
-
- # ensure that source created successfully
- self.assertEqual(source_name, resp_body['name'])
- if source_body['type'] == 'swift':
- source_body = self.swift_data_source
- self.assertDictContainsSubset(source_body, resp_body)
-
- return resp_body['id'], source_name
-
- def _list_data_sources(self, source_info):
- # check for data source in list
- sources = self.client.list_data_sources()['data_sources']
- sources_info = [(source['id'], source['name']) for source in sources]
- self.assertIn(source_info, sources_info)
-
- def _get_data_source(self, source_id, source_name, source_body):
- # check data source fetch by id
- source = self.client.get_data_source(source_id)['data_source']
- self.assertEqual(source_name, source['name'])
- self.assertDictContainsSubset(source_body, source)
-
- @test.attr(type='smoke')
- @test.idempotent_id('9e0e836d-c372-4fca-91b7-b66c3e9646c8')
- def test_swift_data_source_create(self):
- self._create_data_source(self.swift_data_source_with_creds)
-
- @test.attr(type='smoke')
- @test.idempotent_id('3cb87a4a-0534-4b97-9edc-8bbc822b68a0')
- def test_swift_data_source_list(self):
- source_info = (
- self._create_data_source(self.swift_data_source_with_creds))
- self._list_data_sources(source_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('fc07409b-6477-4cb3-9168-e633c46b227f')
- def test_swift_data_source_get(self):
- source_id, source_name = (
- self._create_data_source(self.swift_data_source_with_creds))
- self._get_data_source(source_id, source_name, self.swift_data_source)
-
- @test.attr(type='smoke')
- @test.idempotent_id('df53669c-0cd1-4cf7-b408-4cf215d8beb8')
- def test_swift_data_source_delete(self):
- source_id, _ = (
- self._create_data_source(self.swift_data_source_with_creds))
-
- # delete the data source by id
- self.client.delete_data_source(source_id)
-
- @test.attr(type='smoke')
- @test.idempotent_id('88505d52-db01-4229-8f1d-a1137da5fe2d')
- def test_local_hdfs_data_source_create(self):
- self._create_data_source(self.local_hdfs_data_source)
-
- @test.attr(type='smoke')
- @test.idempotent_id('81d7d42a-d7f6-4d9b-b38c-0801a4dfe3c2')
- def test_local_hdfs_data_source_list(self):
- source_info = self._create_data_source(self.local_hdfs_data_source)
- self._list_data_sources(source_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('ec0144c6-db1e-4169-bb06-7abae14a8443')
- def test_local_hdfs_data_source_get(self):
- source_id, source_name = (
- self._create_data_source(self.local_hdfs_data_source))
- self._get_data_source(
- source_id, source_name, self.local_hdfs_data_source)
-
- @test.attr(type='smoke')
- @test.idempotent_id('e398308b-4230-4f86-ba10-9b0b60a59c8d')
- def test_local_hdfs_data_source_delete(self):
- source_id, _ = self._create_data_source(self.local_hdfs_data_source)
-
- # delete the data source by id
- self.client.delete_data_source(source_id)
-
- @test.attr(type='smoke')
- @test.idempotent_id('bfd91128-e642-4d95-a973-3e536962180c')
- def test_external_hdfs_data_source_create(self):
- self._create_data_source(self.external_hdfs_data_source)
-
- @test.attr(type='smoke')
- @test.idempotent_id('92e2be72-f7ab-499d-ae01-fb9943c90d8e')
- def test_external_hdfs_data_source_list(self):
- source_info = self._create_data_source(self.external_hdfs_data_source)
- self._list_data_sources(source_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('a31edb1b-6bc6-4f42-871f-70cd243184ac')
- def test_external_hdfs_data_source_get(self):
- source_id, source_name = (
- self._create_data_source(self.external_hdfs_data_source))
- self._get_data_source(
- source_id, source_name, self.external_hdfs_data_source)
-
- @test.attr(type='smoke')
- @test.idempotent_id('295924cd-a085-4b45-aea8-0707cdb2da7e')
- def test_external_hdfs_data_source_delete(self):
- source_id, _ = self._create_data_source(self.external_hdfs_data_source)
-
- # delete the data source by id
- self.client.delete_data_source(source_id)
diff --git a/tempest/api/data_processing/test_job_binaries.py b/tempest/api/data_processing/test_job_binaries.py
deleted file mode 100644
index a47ddbc..0000000
--- a/tempest/api/data_processing/test_job_binaries.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-class JobBinaryTest(dp_base.BaseDataProcessingTest):
- # Link to the API documentation is http://docs.openstack.org/developer/
- # sahara/restapi/rest_api_v1.1_EDP.html#job-binaries
-
- @classmethod
- def resource_setup(cls):
- super(JobBinaryTest, cls).resource_setup()
- cls.swift_job_binary_with_extra = {
- 'url': 'swift://sahara-container.sahara/example.jar',
- 'description': 'Test job binary',
- 'extra': {
- 'user': cls.os.credentials.username,
- 'password': cls.os.credentials.password
- }
- }
- # Create extra cls.swift_job_binary variable to use for comparison to
- # job binary response body because response body has no 'extra' field.
- cls.swift_job_binary = cls.swift_job_binary_with_extra.copy()
- del cls.swift_job_binary['extra']
-
- name = data_utils.rand_name('sahara-internal-job-binary')
- cls.job_binary_data = 'Some script may be data'
- job_binary_internal = (
- cls.create_job_binary_internal(name, cls.job_binary_data))
- cls.internal_db_job_binary = {
- 'url': 'internal-db://%s' % job_binary_internal['id'],
- 'description': 'Test job binary',
- }
-
- def _create_job_binary(self, binary_body, binary_name=None):
- """Creates Job Binary with optional name specified.
-
- It creates a link to data (jar, pig files, etc.), ensures job binary
- name and response body. Returns id and name of created job binary.
- Data may not exist when using Swift as data storage.
- In other cases data must exist in storage.
- """
- if not binary_name:
- # generate random name if it's not specified
- binary_name = data_utils.rand_name('sahara-job-binary')
-
- # create job binary
- resp_body = self.create_job_binary(binary_name, **binary_body)
-
- # ensure that binary created successfully
- self.assertEqual(binary_name, resp_body['name'])
- if 'swift' in binary_body['url']:
- binary_body = self.swift_job_binary
- self.assertDictContainsSubset(binary_body, resp_body)
-
- return resp_body['id'], binary_name
-
- @test.attr(type='smoke')
- @test.idempotent_id('c00d43f8-4360-45f8-b280-af1a201b12d3')
- def test_swift_job_binary_create(self):
- self._create_job_binary(self.swift_job_binary_with_extra)
-
- @test.attr(type='smoke')
- @test.idempotent_id('f8809352-e79d-4748-9359-ce1efce89f2a')
- def test_swift_job_binary_list(self):
- binary_info = self._create_job_binary(self.swift_job_binary_with_extra)
-
- # check for job binary in list
- binaries = self.client.list_job_binaries()['binaries']
- binaries_info = [(binary['id'], binary['name']) for binary in binaries]
- self.assertIn(binary_info, binaries_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('2d4a670f-e8f1-413c-b5ac-50c1bfe9e1b1')
- def test_swift_job_binary_get(self):
- binary_id, binary_name = (
- self._create_job_binary(self.swift_job_binary_with_extra))
-
- # check job binary fetch by id
- binary = self.client.get_job_binary(binary_id)['job_binary']
- self.assertEqual(binary_name, binary['name'])
- self.assertDictContainsSubset(self.swift_job_binary, binary)
-
- @test.attr(type='smoke')
- @test.idempotent_id('9b0e8f38-04f3-4616-b399-cfa7eb2677ed')
- def test_swift_job_binary_delete(self):
- binary_id, _ = (
- self._create_job_binary(self.swift_job_binary_with_extra))
-
- # delete the job binary by id
- self.client.delete_job_binary(binary_id)
-
- @test.attr(type='smoke')
- @test.idempotent_id('63662f6d-8291-407e-a6fc-f654522ebab6')
- def test_internal_db_job_binary_create(self):
- self._create_job_binary(self.internal_db_job_binary)
-
- @test.attr(type='smoke')
- @test.idempotent_id('38731e7b-6d9d-4ffa-8fd1-193c453e88b1')
- def test_internal_db_job_binary_list(self):
- binary_info = self._create_job_binary(self.internal_db_job_binary)
-
- # check for job binary in list
- binaries = self.client.list_job_binaries()['binaries']
- binaries_info = [(binary['id'], binary['name']) for binary in binaries]
- self.assertIn(binary_info, binaries_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('1b32199b-c3f5-43e1-a37a-3797e57b7066')
- def test_internal_db_job_binary_get(self):
- binary_id, binary_name = (
- self._create_job_binary(self.internal_db_job_binary))
-
- # check job binary fetch by id
- binary = self.client.get_job_binary(binary_id)['job_binary']
- self.assertEqual(binary_name, binary['name'])
- self.assertDictContainsSubset(self.internal_db_job_binary, binary)
-
- @test.attr(type='smoke')
- @test.idempotent_id('3c42b0c3-3e03-46a5-adf0-df0650271a4e')
- def test_internal_db_job_binary_delete(self):
- binary_id, _ = self._create_job_binary(self.internal_db_job_binary)
-
- # delete the job binary by id
- self.client.delete_job_binary(binary_id)
-
- @test.attr(type='smoke')
- @test.idempotent_id('d5d47659-7e2c-4ea7-b292-5b3e559e8587')
- def test_job_binary_get_data(self):
- binary_id, _ = self._create_job_binary(self.internal_db_job_binary)
-
- # get data of job binary by id
- _, data = self.client.get_job_binary_data(binary_id)
- self.assertEqual(data, self.job_binary_data)
diff --git a/tempest/api/data_processing/test_job_binary_internals.py b/tempest/api/data_processing/test_job_binary_internals.py
deleted file mode 100644
index b4f0769..0000000
--- a/tempest/api/data_processing/test_job_binary_internals.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-class JobBinaryInternalTest(dp_base.BaseDataProcessingTest):
- # Link to the API documentation is http://docs.openstack.org/developer/
- # sahara/restapi/rest_api_v1.1_EDP.html#job-binary-internals
-
- @classmethod
- def resource_setup(cls):
- super(JobBinaryInternalTest, cls).resource_setup()
- cls.job_binary_internal_data = 'Some script may be data'
-
- def _create_job_binary_internal(self, binary_name=None):
- """Creates Job Binary Internal with optional name specified.
-
- It puts data into Sahara database and ensures job binary internal name.
- Returns id and name of created job binary internal.
- """
- if not binary_name:
- # generate random name if it's not specified
- binary_name = data_utils.rand_name('sahara-job-binary-internal')
-
- # create job binary internal
- resp_body = (
- self.create_job_binary_internal(binary_name,
- self.job_binary_internal_data))
-
- # ensure that job binary internal created successfully
- self.assertEqual(binary_name, resp_body['name'])
-
- return resp_body['id'], binary_name
-
- @test.attr(type='smoke')
- @test.idempotent_id('249c4dc2-946f-4939-83e6-212ddb6ea0be')
- def test_job_binary_internal_create(self):
- self._create_job_binary_internal()
-
- @test.attr(type='smoke')
- @test.idempotent_id('1e3c2ecd-5673-499d-babe-4fe2fcdf64ee')
- def test_job_binary_internal_list(self):
- binary_info = self._create_job_binary_internal()
-
- # check for job binary internal in list
- binaries = self.client.list_job_binary_internals()['binaries']
- binaries_info = [(binary['id'], binary['name']) for binary in binaries]
- self.assertIn(binary_info, binaries_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('a2046a53-386c-43ab-be35-df54b19db776')
- def test_job_binary_internal_get(self):
- binary_id, binary_name = self._create_job_binary_internal()
-
- # check job binary internal fetch by id
- binary = self.client.get_job_binary_internal(binary_id)
- self.assertEqual(binary_name, binary['job_binary_internal']['name'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('b3568c33-4eed-40d5-aae4-6ff3b2ac58f5')
- def test_job_binary_internal_delete(self):
- binary_id, _ = self._create_job_binary_internal()
-
- # delete the job binary internal by id
- self.client.delete_job_binary_internal(binary_id)
-
- @test.attr(type='smoke')
- @test.idempotent_id('8871f2b0-5782-4d66-9bb9-6f95bcb839ea')
- def test_job_binary_internal_get_data(self):
- binary_id, _ = self._create_job_binary_internal()
-
- # get data of job binary internal by id
- _, data = self.client.get_job_binary_internal_data(binary_id)
- self.assertEqual(data, self.job_binary_internal_data)
diff --git a/tempest/api/data_processing/test_jobs.py b/tempest/api/data_processing/test_jobs.py
deleted file mode 100644
index 8503320..0000000
--- a/tempest/api/data_processing/test_jobs.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-class JobTest(dp_base.BaseDataProcessingTest):
- # NOTE: Link to the API documentation: http://docs.openstack.org/developer/
- # sahara/restapi/rest_api_v1.1_EDP.html#jobs
-
- @classmethod
- def resource_setup(cls):
- super(JobTest, cls).resource_setup()
- # create job binary
- job_binary = {
- 'name': data_utils.rand_name('sahara-job-binary'),
- 'url': 'swift://sahara-container.sahara/example.jar',
- 'description': 'Test job binary',
- 'extra': {
- 'user': cls.os.credentials.username,
- 'password': cls.os.credentials.password
- }
- }
- resp_body = cls.create_job_binary(**job_binary)
- job_binary_id = resp_body['id']
-
- cls.job = {
- 'job_type': 'Pig',
- 'mains': [job_binary_id]
- }
-
- def _create_job(self, job_name=None):
- """Creates Job with optional name specified.
-
- It creates job and ensures job name. Returns id and name of created
- job.
- """
- if not job_name:
- # generate random name if it's not specified
- job_name = data_utils.rand_name('sahara-job')
-
- # create job
- resp_body = self.create_job(job_name, **self.job)
-
- # ensure that job created successfully
- self.assertEqual(job_name, resp_body['name'])
-
- return resp_body['id'], job_name
-
- @test.attr(type='smoke')
- @test.idempotent_id('8cf785ca-adf4-473d-8281-fb9a5efa3073')
- def test_job_create(self):
- self._create_job()
-
- @test.attr(type='smoke')
- @test.idempotent_id('41e253fe-b02a-41a0-b186-5ff1f0463ba3')
- def test_job_list(self):
- job_info = self._create_job()
-
- # check for job in list
- jobs = self.client.list_jobs()['jobs']
- jobs_info = [(job['id'], job['name']) for job in jobs]
- self.assertIn(job_info, jobs_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('3faf17fa-bc94-4a60-b1c3-79e53674c16c')
- def test_job_get(self):
- job_id, job_name = self._create_job()
-
- # check job fetch by id
- job = self.client.get_job(job_id)['job']
- self.assertEqual(job_name, job['name'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('dff85e62-7dda-4ad8-b1ee-850adecb0c6e')
- def test_job_delete(self):
- job_id, _ = self._create_job()
-
- # delete the job by id
- self.client.delete_job(job_id)
diff --git a/tempest/api/data_processing/test_node_group_templates.py b/tempest/api/data_processing/test_node_group_templates.py
deleted file mode 100644
index c2dae85..0000000
--- a/tempest/api/data_processing/test_node_group_templates.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-class NodeGroupTemplateTest(dp_base.BaseDataProcessingTest):
-
- @classmethod
- def skip_checks(cls):
- super(NodeGroupTemplateTest, cls).skip_checks()
- if cls.default_plugin is None:
- raise cls.skipException("No Sahara plugins configured")
-
- def _create_node_group_template(self, template_name=None):
- """Creates Node Group Template with optional name specified.
-
- It creates template, ensures template name and response body.
- Returns id and name of created template.
- """
- self.node_group_template = self.get_node_group_template()
- self.assertIsNotNone(self.node_group_template,
- "No known Sahara plugin was found")
-
- if not template_name:
- # generate random name if it's not specified
- template_name = data_utils.rand_name('sahara-ng-template')
-
- # create node group template
- resp_body = self.create_node_group_template(template_name,
- **self.node_group_template)
-
- # ensure that template created successfully
- self.assertEqual(template_name, resp_body['name'])
- self.assertDictContainsSubset(self.node_group_template, resp_body)
-
- return resp_body['id'], template_name
-
- @test.attr(type='smoke')
- @test.idempotent_id('63164051-e46d-4387-9741-302ef4791cbd')
- def test_node_group_template_create(self):
- self._create_node_group_template()
-
- @test.attr(type='smoke')
- @test.idempotent_id('eb39801d-2612-45e5-88b1-b5d70b329185')
- def test_node_group_template_list(self):
- template_info = self._create_node_group_template()
-
- # check for node group template in list
- templates = self.client.list_node_group_templates()
- templates = templates['node_group_templates']
- templates_info = [(template['id'], template['name'])
- for template in templates]
- self.assertIn(template_info, templates_info)
-
- @test.attr(type='smoke')
- @test.idempotent_id('6ee31539-a708-466f-9c26-4093ce09a836')
- def test_node_group_template_get(self):
- template_id, template_name = self._create_node_group_template()
-
- # check node group template fetch by id
- template = self.client.get_node_group_template(template_id)
- template = template['node_group_template']
- self.assertEqual(template_name, template['name'])
- self.assertDictContainsSubset(self.node_group_template, template)
-
- @test.attr(type='smoke')
- @test.idempotent_id('f4f5cb82-708d-4031-81c4-b0618a706a2f')
- def test_node_group_template_delete(self):
- template_id, _ = self._create_node_group_template()
-
- # delete the node group template by id
- self.client.delete_node_group_template(template_id)
diff --git a/tempest/api/data_processing/test_plugins.py b/tempest/api/data_processing/test_plugins.py
deleted file mode 100644
index 14594e4..0000000
--- a/tempest/api/data_processing/test_plugins.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (c) 2014 Mirantis Inc.
-#
-# 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.data_processing import base as dp_base
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-
-class PluginsTest(dp_base.BaseDataProcessingTest):
- def _list_all_plugin_names(self):
- """Returns all enabled plugin names.
-
- It ensures main plugins availability.
- """
- plugins = self.client.list_plugins()['plugins']
- plugins_names = [plugin['name'] for plugin in plugins]
- for enabled_plugin in CONF.data_processing_feature_enabled.plugins:
- self.assertIn(enabled_plugin, plugins_names)
-
- return plugins_names
-
- @test.attr(type='smoke')
- @test.idempotent_id('01a005a3-426c-4c0b-9617-d09475403e09')
- def test_plugin_list(self):
- self._list_all_plugin_names()
-
- @test.attr(type='smoke')
- @test.idempotent_id('53cf6487-2cfb-4a6f-8671-97c542c6e901')
- def test_plugin_get(self):
- for plugin_name in self._list_all_plugin_names():
- plugin = self.client.get_plugin(plugin_name)['plugin']
- self.assertEqual(plugin_name, plugin['name'])
-
- for plugin_version in plugin['versions']:
- detailed_plugin = self.client.get_plugin(plugin_name,
- plugin_version)
- detailed_plugin = detailed_plugin['plugin']
- self.assertEqual(plugin_name, detailed_plugin['name'])
-
- # check that required image tags contains name and version
- image_tags = detailed_plugin['required_image_tags']
- self.assertIn(plugin_name, image_tags)
- self.assertIn(plugin_version, image_tags)
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 8e63498..4a4b51a 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -234,4 +234,4 @@
# Validate the updated password through getting a token.
body = self.token_client.auth(user['name'], new_pass,
tenant['name'])
- self.assertTrue('id' in body['token'])
+ self.assertIn('id', body['token'])
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 12b236f..a0d8748 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -12,6 +12,7 @@
# 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 oslo_serialization import jsonutils as json
from tempest.api.identity import base
from tempest.common.utils import data_utils
@@ -70,6 +71,7 @@
update_body = self.creds_client.update_credential(
cred['id'], blob=blob, project_id=self.projects[1],
type='ec2')['credential']
+ update_body['blob'] = json.loads(update_body['blob'])
self.assertEqual(cred['id'], update_body['id'])
self.assertEqual(self.projects[1], update_body['project_id'])
self.assertEqual(self.user_body['id'], update_body['user_id'])
@@ -77,6 +79,7 @@
self.assertEqual(update_body['blob']['secret'], new_keys[1])
get_body = self.creds_client.show_credential(cred['id'])['credential']
+ get_body['blob'] = json.loads(get_body['blob'])
for value1 in self.creds_list[0]:
self.assertEqual(update_body[value1],
get_body[value1])
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 373d44b..955b6fb 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -147,3 +147,88 @@
(self.inherited_roles_client.
delete_inherited_role_from_group_on_project(
self.project['id'], self.group['id'], src_role['id']))
+
+ @test.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36')
+ def test_inherit_assign_list_revoke_user_roles_on_domain(self):
+ # Create role
+ src_role = self.roles_client.create_role(
+ name=data_utils.rand_name('Role'))['role']
+ self.addCleanup(self.roles_client.delete_role, src_role['id'])
+
+ # Create a project hierarchy
+ leaf_project_name = data_utils.rand_name('project')
+ leaf_project = self.projects_client.create_project(
+ leaf_project_name, domain_id=self.domain['id'],
+ parent_id=self.project['id'])['project']
+ self.addCleanup(
+ self.projects_client.delete_project, leaf_project['id'])
+
+ # Assign role on domain
+ self.inherited_roles_client.create_inherited_role_on_domains_user(
+ self.domain['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the parent project
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ self.project['id'], self.user['id']))['role_assignments']
+ self.assertNotEmpty(assignments)
+
+ # List "effective" role assignments from user on the leaf project
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertNotEmpty(assignments)
+
+ # Revoke role from domain
+ self.inherited_roles_client.delete_inherited_role_from_user_on_domain(
+ self.domain['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the parent project
+ # should return an empty list
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ self.project['id'], self.user['id']))['role_assignments']
+ self.assertEmpty(assignments)
+
+ # List "effective" role assignments from user on the leaf project
+ # should return an empty list
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertEmpty(assignments)
+
+ @test.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06')
+ def test_inherit_assign_list_revoke_user_roles_on_project_tree(self):
+ # Create role
+ src_role = self.roles_client.create_role(
+ name=data_utils.rand_name('Role'))['role']
+ self.addCleanup(self.roles_client.delete_role, src_role['id'])
+
+ # Create a project hierarchy
+ leaf_project_name = data_utils.rand_name('project')
+ leaf_project = self.projects_client.create_project(
+ leaf_project_name, domain_id=self.domain['id'],
+ parent_id=self.project['id'])['project']
+ self.addCleanup(
+ self.projects_client.delete_project, leaf_project['id'])
+
+ # Assign role on parent project
+ self.inherited_roles_client.create_inherited_role_on_projects_user(
+ self.project['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the leaf project
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertNotEmpty(assignments)
+
+ # Revoke role from parent project
+ self.inherited_roles_client.delete_inherited_role_from_user_on_project(
+ self.project['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the leaf project
+ # should return an empty list
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertEmpty(assignments)
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index f5e4943..14bf4f8 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -182,6 +182,7 @@
cls.creds_client = cls.os_adm.credentials_client
cls.groups_client = cls.os_adm.groups_client
cls.projects_client = cls.os_adm.projects_client
+ cls.role_assignments = cls.os_admin.role_assignments_client
if CONF.identity.admin_domain_scope:
# NOTE(andreaf) When keystone policy requires it, the identity
# admin clients for these tests shall use 'domain' scoped tokens.
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index 4833f9e..33d212c 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -44,6 +44,11 @@
# Clear auth restores the original credentials and deletes
# cached auth data
client.auth_provider.clear_auth()
+ # NOTE(lbragstad): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure we
+ # are passing the second boundary before attempting to
+ # authenticate.
+ time.sleep(1)
client.auth_provider.set_auth()
old_pass = self.creds.password
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index c92e750..1a38f3a 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -44,6 +44,11 @@
# Clear auth restores the original credentials and deletes
# cached auth data
client.auth_provider.clear_auth()
+ # NOTE(lbragstad): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure we
+ # are passing the second boundary before attempting to
+ # authenticate.
+ time.sleep(1)
client.auth_provider.set_auth()
old_pass = self.creds.password
diff --git a/tempest/api/image/admin/v2/test_images.py b/tempest/api/image/admin/v2/test_images.py
index c719b7a..9844a67 100644
--- a/tempest/api/image/admin/v2/test_images.py
+++ b/tempest/api/image/admin/v2/test_images.py
@@ -34,27 +34,26 @@
def test_admin_deactivate_reactivate_image(self):
# Create image by non-admin tenant
image_name = data_utils.rand_name('image')
- body = self.client.create_image(name=image_name,
- container_format='bare',
- disk_format='raw',
- visibility='private')
- image_id = body['id']
- self.addCleanup(self.client.delete_image, image_id)
+ image = self.client.create_image(name=image_name,
+ container_format='bare',
+ disk_format='raw',
+ visibility='private')
+ self.addCleanup(self.client.delete_image, image['id'])
# upload an image file
content = data_utils.random_bytes()
image_file = six.BytesIO(content)
- self.client.store_image_file(image_id, image_file)
+ self.client.store_image_file(image['id'], image_file)
# deactivate image
- self.admin_client.deactivate_image(image_id)
- body = self.client.show_image(image_id)
+ self.admin_client.deactivate_image(image['id'])
+ body = self.client.show_image(image['id'])
self.assertEqual("deactivated", body['status'])
# non-admin user unable to download deactivated image
self.assertRaises(lib_exc.Forbidden, self.client.show_image_file,
- image_id)
+ image['id'])
# reactivate image
- self.admin_client.reactivate_image(image_id)
- body = self.client.show_image(image_id)
+ self.admin_client.reactivate_image(image['id'])
+ body = self.client.show_image(image['id'])
self.assertEqual("active", body['status'])
# non-admin user able to download image after reactivation by admin
- body = self.client.show_image_file(image_id)
+ body = self.client.show_image_file(image['id'])
self.assertEqual(content, body.data)
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
old mode 100755
new mode 100644
index f74f97b..1cc3fa2
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -60,7 +60,7 @@
"""Wrapper that returns a test image."""
if 'name' not in kwargs:
- name = data_utils.rand_name(cls.__name__ + "-instance")
+ name = data_utils.rand_name(cls.__name__ + "-image")
kwargs['name'] = name
params = cls._get_create_params(**kwargs)
@@ -123,8 +123,7 @@
disk_format='raw',
is_public=False,
data=image_file)
- image_id = image['id']
- return image_id
+ return image['id']
class BaseV2ImageTest(BaseImageTest):
@@ -183,9 +182,8 @@
image = self.client.create_image(name=name,
container_format='bare',
disk_format='raw')
- image_id = image['id']
- self.addCleanup(self.client.delete_image, image_id)
- return image_id
+ self.addCleanup(self.client.delete_image, image['id'])
+ return image['id']
class BaseV1ImageAdminTest(BaseImageTest):
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 712b34b..7d52695 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -20,7 +20,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
@@ -49,22 +49,21 @@
# Register, then upload an image
properties = {'prop1': 'val1'}
container_format, disk_format = get_container_and_disk_format()
- body = self.create_image(name='New Name',
- container_format=container_format,
- disk_format=disk_format,
- is_public=False,
- properties=properties)
- self.assertIn('id', body)
- image_id = body.get('id')
- self.assertEqual('New Name', body.get('name'))
- self.assertFalse(body.get('is_public'))
- self.assertEqual('queued', body.get('status'))
+ image = self.create_image(name='New Name',
+ container_format=container_format,
+ disk_format=disk_format,
+ is_public=False,
+ properties=properties)
+ self.assertIn('id', image)
+ self.assertEqual('New Name', image.get('name'))
+ self.assertFalse(image.get('is_public'))
+ self.assertEqual('queued', image.get('status'))
for key, val in properties.items():
- self.assertEqual(val, body.get('properties')[key])
+ self.assertEqual(val, image.get('properties')[key])
# Now try uploading an image file
image_file = six.BytesIO(data_utils.random_bytes())
- body = self.client.update_image(image_id, data=image_file)['image']
+ body = self.client.update_image(image['id'], data=image_file)['image']
self.assertIn('size', body)
self.assertEqual(1024, body.get('size'))
@@ -89,16 +88,15 @@
@test.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816')
def test_register_http_image(self):
container_format, disk_format = get_container_and_disk_format()
- body = self.create_image(name='New Http Image',
- container_format=container_format,
- disk_format=disk_format, is_public=False,
- copy_from=CONF.image.http_image)
- self.assertIn('id', body)
- image_id = body.get('id')
- self.assertEqual('New Http Image', body.get('name'))
- self.assertFalse(body.get('is_public'))
- waiters.wait_for_image_status(self.client, image_id, 'active')
- self.client.show_image(image_id)
+ image = self.create_image(name='New Http Image',
+ container_format=container_format,
+ disk_format=disk_format, is_public=False,
+ copy_from=CONF.image.http_image)
+ self.assertIn('id', image)
+ self.assertEqual('New Http Image', image.get('name'))
+ self.assertFalse(image.get('is_public'))
+ waiters.wait_for_image_status(self.client, image['id'], 'active')
+ self.client.show_image(image['id'])
@test.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
def test_register_image_with_min_ram(self):
@@ -188,8 +186,7 @@
disk_format=disk_format,
is_public=False,
location=location)
- image_id = image['id']
- return image_id
+ return image['id']
@classmethod
def _create_standard_image(cls, name, container_format,
@@ -205,8 +202,7 @@
container_format=container_format,
disk_format=disk_format,
is_public=False, data=image_file)
- image_id = image['id']
- return image_id
+ return image['id']
@test.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
def test_index_no_params(self):
@@ -251,7 +247,7 @@
def test_index_min_size(self):
images_list = self.client.list_images(size_min=142)['images']
for image in images_list:
- self.assertTrue(image['size'] >= 142)
+ self.assertGreaterEqual(image['size'], 142)
result_set = set(map(lambda x: x['id'], images_list))
self.assertTrue(self.size142_set <= result_set)
self.assertFalse(self.size42_set <= result_set)
@@ -301,8 +297,7 @@
disk_format=disk_format,
is_public=False, data=image_file,
properties={'key1': 'value1'})
- image_id = image['id']
- return image_id
+ return image['id']
@test.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928')
def test_list_image_metadata(self):
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index 9e67c25..d8f103a 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -40,13 +40,6 @@
'x-image-meta-disk_format': 'wrong'})
@test.attr(type=['negative'])
- @test.idempotent_id('bb016f15-0820-4f27-a92d-09b2f67d2488')
- def test_delete_image_with_invalid_image_id(self):
- # An image should not be deleted with invalid image id
- self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- '!@$%^&*()')
-
- @test.attr(type=['negative'])
@test.idempotent_id('ec652588-7e3c-4b67-a2f2-0fa96f57c8fc')
def test_delete_non_existent_image(self):
# Return an error while trying to delete a non-existent image
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 443e332..6f8d239 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -44,35 +44,34 @@
image_name = data_utils.rand_name('image')
container_format = CONF.image.container_formats[0]
disk_format = CONF.image.disk_formats[0]
- body = self.create_image(name=image_name,
- container_format=container_format,
- disk_format=disk_format,
- visibility='private',
- ramdisk_id=uuid)
- self.assertIn('id', body)
- image_id = body.get('id')
- self.assertIn('name', body)
- self.assertEqual(image_name, body['name'])
- self.assertIn('visibility', body)
- self.assertEqual('private', body['visibility'])
- self.assertIn('status', body)
- self.assertEqual('queued', body['status'])
+ image = self.create_image(name=image_name,
+ container_format=container_format,
+ disk_format=disk_format,
+ visibility='private',
+ ramdisk_id=uuid)
+ self.assertIn('id', image)
+ self.assertIn('name', image)
+ self.assertEqual(image_name, image['name'])
+ self.assertIn('visibility', image)
+ self.assertEqual('private', image['visibility'])
+ self.assertIn('status', image)
+ self.assertEqual('queued', image['status'])
# Now try uploading an image file
file_content = data_utils.random_bytes()
image_file = six.BytesIO(file_content)
- self.client.store_image_file(image_id, image_file)
+ self.client.store_image_file(image['id'], image_file)
# Now try to get image details
- body = self.client.show_image(image_id)
- self.assertEqual(image_id, body['id'])
+ body = self.client.show_image(image['id'])
+ self.assertEqual(image['id'], body['id'])
self.assertEqual(image_name, body['name'])
self.assertEqual(uuid, body['ramdisk_id'])
self.assertIn('size', body)
self.assertEqual(1024, body.get('size'))
# Now try get image file
- body = self.client.show_image_file(image_id)
+ body = self.client.show_image_file(image['id'])
self.assertEqual(file_content, body.data)
@test.attr(type='smoke')
@@ -84,20 +83,18 @@
image_name = data_utils.rand_name('image')
container_format = CONF.image.container_formats[0]
disk_format = CONF.image.disk_formats[0]
- body = self.client.create_image(name=image_name,
- container_format=container_format,
- disk_format=disk_format,
- visibility='private')
- image_id = body['id']
-
+ image = self.client.create_image(name=image_name,
+ container_format=container_format,
+ disk_format=disk_format,
+ visibility='private')
# Delete Image
- self.client.delete_image(image_id)
- self.client.wait_for_resource_deletion(image_id)
+ self.client.delete_image(image['id'])
+ self.client.wait_for_resource_deletion(image['id'])
# Verifying deletion
images = self.client.list_images()['images']
images_id = [item['id'] for item in images]
- self.assertNotIn(image_id, images_id)
+ self.assertNotIn(image['id'], images_id)
@test.attr(type='smoke')
@test.idempotent_id('f66891a7-a35c-41a8-b590-a065c2a1caa6')
@@ -108,27 +105,26 @@
image_name = data_utils.rand_name('image')
container_format = CONF.image.container_formats[0]
disk_format = CONF.image.disk_formats[0]
- body = self.client.create_image(name=image_name,
- container_format=container_format,
- disk_format=disk_format,
- visibility='private')
- self.addCleanup(self.client.delete_image, body['id'])
- self.assertEqual('queued', body['status'])
- image_id = body['id']
+ image = self.client.create_image(name=image_name,
+ container_format=container_format,
+ disk_format=disk_format,
+ visibility='private')
+ self.addCleanup(self.client.delete_image, image['id'])
+ self.assertEqual('queued', image['status'])
# Now try uploading an image file
image_file = six.BytesIO(data_utils.random_bytes())
- self.client.store_image_file(image_id, image_file)
+ self.client.store_image_file(image['id'], image_file)
# Update Image
new_image_name = data_utils.rand_name('new-image')
- body = self.client.update_image(image_id, [
+ body = self.client.update_image(image['id'], [
dict(replace='/name', value=new_image_name)])
# Verifying updating
- body = self.client.show_image(image_id)
- self.assertEqual(image_id, body['id'])
+ body = self.client.show_image(image['id'])
+ self.assertEqual(image['id'], body['id'])
self.assertEqual(new_image_name, body['name'])
@@ -161,15 +157,12 @@
"""
size = random.randint(1024, 4096)
image_file = six.BytesIO(data_utils.random_bytes(size))
- name = data_utils.rand_name('image')
- body = cls.create_image(name=name,
- container_format=container_format,
- disk_format=disk_format,
- visibility='private')
- image_id = body['id']
- cls.client.store_image_file(image_id, data=image_file)
+ image = cls.create_image(container_format=container_format,
+ disk_format=disk_format,
+ visibility='private')
+ cls.client.store_image_file(image['id'], data=image_file)
- return image_id
+ return image['id']
def _list_by_param_value_and_assert(self, params):
"""Perform list action with given params and validates result."""
@@ -250,6 +243,16 @@
self.assertEqual(len(images_list), params['limit'],
"Failed to get images by limit")
+ @test.idempotent_id('e9a44b91-31c8-4b40-a332-e0a39ffb4dbb')
+ def test_list_image_param_owner(self):
+ # Test to get images by owner
+ image_id = self.created_images[0]
+ # Get image metadata
+ image = self.client.show_image(image_id)
+
+ params = {"owner": image['owner']}
+ self._list_by_param_value_and_assert(params)
+
@test.idempotent_id('622b925c-479f-4736-860d-adeaf13bc371')
def test_get_image_schema(self):
# Test to get image schema
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
index 6fced00..a80a0cf 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespaces.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -40,6 +40,10 @@
protected=True)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self._cleanup_namespace, namespace_name)
+ # list namespaces
+ bodys = self.namespaces_client.list_namespaces()['namespaces']
+ body = [namespace['namespace'] for namespace in bodys]
+ self.assertIn(namespace_name, body)
# get namespace details
body = self.namespaces_client.show_namespace(namespace_name)
self.assertEqual(namespace_name, body['namespace'])
diff --git a/tempest/api/image/v2/test_images_metadefs_resource_types.py b/tempest/api/image/v2/test_images_metadefs_resource_types.py
index a5143a1..3dd432b 100644
--- a/tempest/api/image/v2/test_images_metadefs_resource_types.py
+++ b/tempest/api/image/v2/test_images_metadefs_resource_types.py
@@ -18,7 +18,7 @@
class MetadataResourceTypesTest(base.BaseV2ImageTest):
- """Test the Metadata definition ressource types basic functionality"""
+ """Test the Metadata definition resource types basic functionality"""
@test.idempotent_id('6f358a4e-5ef0-11e6-a795-080027d0d606')
def test_basic_meta_def_resource_type_association(self):
@@ -34,7 +34,7 @@
# NOTE(raiesmh08): Here intentionally I have not added addcleanup
# method for resource type dissociation because its a metadata add and
# being cleaned as soon as namespace is cleaned at test case level.
- # When namespace cleans, resource type associaion will automatically
+ # When namespace cleans, resource type association will automatically
# clean without any error or dependency.
# List resource type associations and validate creation
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index f60fb0c..cd1bca0 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -53,19 +53,19 @@
def test_get_delete_deleted_image(self):
# get and delete the deleted image
# create and delete image
- body = self.client.create_image(name='test',
- container_format='bare',
- disk_format='raw')
- image_id = body['id']
- self.client.delete_image(image_id)
- self.client.wait_for_resource_deletion(image_id)
+ image = self.client.create_image(name='test',
+ container_format='bare',
+ disk_format='raw')
+ self.client.delete_image(image['id'])
+ self.client.wait_for_resource_deletion(image['id'])
# get the deleted image
- self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
+ self.assertRaises(lib_exc.NotFound,
+ self.client.show_image, image['id'])
# delete the deleted image
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- image_id)
+ image['id'])
@test.attr(type=['negative'])
@test.idempotent_id('6fe40f1c-57bd-4918-89cc-8500f850f3de')
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
index 42a4b87..03f29bd 100644
--- a/tempest/api/image/v2/test_images_tags.py
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -21,19 +21,18 @@
@test.idempotent_id('10407036-6059-4f95-a2cd-cbbbee7ed329')
def test_update_delete_tags_for_image(self):
- body = self.create_image(container_format='bare',
- disk_format='raw',
- visibility='private')
- image_id = body['id']
+ image = self.create_image(container_format='bare',
+ disk_format='raw',
+ visibility='private')
tag = data_utils.rand_name('tag')
- self.addCleanup(self.client.delete_image, image_id)
+ self.addCleanup(self.client.delete_image, image['id'])
# Creating image tag and verify it.
- self.client.add_image_tag(image_id, tag)
- body = self.client.show_image(image_id)
+ self.client.add_image_tag(image['id'], tag)
+ body = self.client.show_image(image['id'])
self.assertIn(tag, body['tags'])
# Deleting image tag and verify it.
- self.client.delete_image_tag(image_id, tag)
- body = self.client.show_image(image_id)
+ self.client.delete_image_tag(image['id'], tag)
+ body = self.client.show_image(image['id'])
self.assertNotIn(tag, body['tags'])
diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py
index dd5650f..af4ffcf 100644
--- a/tempest/api/image/v2/test_images_tags_negative.py
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -33,12 +33,11 @@
@test.idempotent_id('39c023a2-325a-433a-9eea-649bf1414b19')
def test_delete_non_existing_tag(self):
# Delete non existing tag.
- body = self.create_image(container_format='bare',
- disk_format='raw',
- visibility='private'
- )
- image_id = body['id']
+ image = self.create_image(container_format='bare',
+ disk_format='raw',
+ visibility='private'
+ )
tag = data_utils.rand_name('non-exist-tag')
- self.addCleanup(self.client.delete_image, image_id)
+ self.addCleanup(self.client.delete_image, image['id'])
self.assertRaises(lib_exc.NotFound, self.client.delete_image_tag,
- image_id, tag)
+ image['id'], tag)
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index d2ab237..b3555b6 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -44,7 +44,7 @@
body = self.admin_networks_client.list_dhcp_agents_on_hosting_network(
self.network['id'])
agents = body['agents']
- self.assertIsNotNone(agents)
+ self.assertNotEmpty(agents, "no dhcp agent")
agent = agents[0]
self.assertTrue(self._check_network_in_dhcp_agent(
self.network['id'], agent))
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index 2686af2..a32e7da 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -14,7 +14,6 @@
# under the License.
from tempest.api.network import base
-from tempest.common.utils import data_utils
from tempest import config
from tempest import test
@@ -44,8 +43,7 @@
cls.floating_ip = cls.create_floatingip(cls.ext_net_id)
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
- cls.router = cls.create_router(data_utils.rand_name('router-'),
- external_network_id=cls.ext_net_id)
+ cls.router = cls.create_router(external_network_id=cls.ext_net_id)
cls.create_router_interface(cls.router['id'], cls.subnet['id'])
cls.port = cls.create_port(cls.network)
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index b2cb003..c2ff038 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -13,9 +13,8 @@
# under the License.
from tempest.api.network import base
-from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
@@ -66,35 +65,36 @@
else:
msg = "L3 Agent Scheduler enabled in conf, but L3 Agent not found"
raise exceptions.InvalidConfiguration(msg)
- cls.router = cls.create_router(data_utils.rand_name('router'))
- # NOTE(armax): If DVR is an available extension, and the created router
- # is indeed a distributed one, more resources need to be provisioned
- # in order to bind the router to the L3 agent.
- # That said, let's preserve the existing test logic, where the extra
- # query and setup steps are only required if the extension is available
- # and only if the router's default type is distributed.
- if test.is_extension_enabled('dvr', 'network'):
- cls.is_dvr_router = cls.admin_routers_client.show_router(
- cls.router['id'])['router'].get('distributed', False)
- if cls.is_dvr_router:
- cls.network = cls.create_network()
- cls.subnet = cls.create_subnet(cls.network)
- cls.port = cls.create_port(cls.network)
- cls.routers_client.add_router_interface(
- cls.router['id'], port_id=cls.port['id'])
- # NOTE: Sometimes we have seen this test fail with dvr in,
- # multinode tests, since the dhcp port is not created before
- # the test gets executed and so the router is not scheduled
- # on the given agent. By adding the external gateway info to
- # the router, the router should be properly scheduled in the
- # dvr_snat node.
- # This is a temporary work around to prevent a race condition.
- external_gateway_info = {
- 'network_id': CONF.network.public_network_id,
- 'enable_snat': True}
- cls.admin_routers_client.update_router(
- cls.router['id'],
- external_gateway_info=external_gateway_info)
+ cls.router = cls.create_router()
+
+ if CONF.network.dvr_extra_resources:
+ # NOTE(armax): If DVR is an available extension, and the created
+ # router is indeed a distributed one, more resources need to be
+ # provisioned in order to bind the router to the L3 agent in the
+ # Liberty release or older, and are not required since the Mitaka
+ # release.
+ if test.is_extension_enabled('dvr', 'network'):
+ cls.is_dvr_router = cls.admin_routers_client.show_router(
+ cls.router['id'])['router'].get('distributed', False)
+ if cls.is_dvr_router:
+ cls.network = cls.create_network()
+ cls.subnet = cls.create_subnet(cls.network)
+ cls.port = cls.create_port(cls.network)
+ cls.routers_client.add_router_interface(
+ cls.router['id'], port_id=cls.port['id'])
+ # NOTE: Sometimes we have seen this test fail with dvr in,
+ # multinode tests, since the dhcp port is not created
+ # before the test gets executed and so the router is not
+ # scheduled on the given agent. By adding the external
+ # gateway info to the router, the router should be properly
+ # scheduled in the dvr_snat node. This is a temporary work
+ # around to prevent a race condition.
+ external_gateway_info = {
+ 'network_id': CONF.network.public_network_id,
+ 'enable_snat': True}
+ cls.admin_routers_client.update_router(
+ cls.router['id'],
+ external_gateway_info=external_gateway_info)
@classmethod
def resource_cleanup(cls):
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 2ff31e0..3a264ff 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -87,5 +87,5 @@
@test.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
def test_quotas(self):
- new_quotas = {'network': 0, 'security_group': 0}
+ new_quotas = {'network': 0, 'port': 0}
self._check_quotas(new_quotas)
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 36cb15f..66feba8 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.network import base_routers as base
from tempest.common.utils import data_utils
from tempest import test
@@ -80,6 +82,8 @@
self.assertFalse(router['router']['distributed'])
@test.idempotent_id('acd43596-c1fb-439d-ada8-31ad48ae3c2e')
+ @testtools.skipUnless(test.is_extension_enabled('l3-ha', 'network'),
+ 'HA routers are not available.')
def test_centralized_router_update_to_dvr(self):
"""Test centralized router update
@@ -95,9 +99,11 @@
"""
name = data_utils.rand_name('router')
# router needs to be in admin state down in order to be upgraded to DVR
+ # l3ha routers are not upgradable to dvr, make it explicitly non ha
router = self.admin_routers_client.create_router(name=name,
distributed=False,
- admin_state_up=False)
+ admin_state_up=False,
+ ha=False)
self.addCleanup(self.admin_routers_client.delete_router,
router['router']['id'])
self.assertFalse(router['router']['distributed'])
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 5c67d68..629926d 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -26,7 +26,7 @@
class BaseNetworkTest(tempest.test.BaseTestCase):
- """Base class for the Neutron tests
+ """Base class for the Neutron tests.
Per the Neutron API Guide, API v1.x was removed from the source code tree
(docs.openstack.org/api/openstack-network/2.0/content/Overview-d1e71.html)
@@ -137,7 +137,8 @@
@classmethod
def create_network(cls, network_name=None):
"""Wrapper utility that returns a test network."""
- network_name = network_name or data_utils.rand_name('test-network-')
+ network_name = network_name or data_utils.rand_name(
+ cls.__name__ + "-network")
body = cls.networks_client.create_network(name=network_name)
network = body['network']
@@ -148,7 +149,6 @@
def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None,
ip_version=None, client=None, **kwargs):
"""Wrapper utility that returns a test subnet."""
-
# allow tests to use admin client
if not client:
client = cls.subnets_client
@@ -208,6 +208,9 @@
def create_router(cls, router_name=None, admin_state_up=False,
external_network_id=None, enable_snat=None,
**kwargs):
+ router_name = router_name or data_utils.rand_name(
+ cls.__name__ + "-router")
+
ext_gw_info = {}
if external_network_id:
ext_gw_info['network_id'] = external_network_id
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 807257f..5fb5232 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -25,7 +25,7 @@
self.delete_router(router)
self.routers.remove(router)
- def _create_router(self, name, admin_state_up=False,
+ def _create_router(self, name=None, admin_state_up=False,
external_network_id=None, enable_snat=None):
# associate a cleanup with created routers to avoid quota limits
router = self.create_router(name, admin_state_up,
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 77008ab..84c48ec 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -20,6 +20,7 @@
from tempest.api.network import base
from tempest.common.utils import data_utils
+from tempest.common.utils import net_info
from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -30,7 +31,7 @@
class NetworksTestDHCPv6(base.BaseNetworkTest):
_ip_version = 6
- """ Test DHCPv6 specific features using SLAAC, stateless and
+ """Test DHCPv6 specific features using SLAAC, stateless and
stateful settings for subnets. Also it shall check dual-stack
functionality (IPv4 + IPv6 together).
The tests include:
@@ -66,7 +67,7 @@
body = self.ports_client.list_ports()
ports = body['ports']
for port in ports:
- if (port['device_owner'].startswith('network:router_interface') and
+ if (net_info.is_router_interface_port(port) and
port['device_id'] in [r['id'] for r in self.routers]):
self.routers_client.remove_router_interface(port['device_id'],
port_id=port['id'])
@@ -347,9 +348,7 @@
def _create_subnet_router(self, kwargs):
subnet = self.create_subnet(self.network, **kwargs)
- router = self.create_router(
- router_name=data_utils.rand_name("routerv6-"),
- admin_state_up=True)
+ router = self.create_router(admin_state_up=True)
port = self.create_router_interface(router['id'],
subnet['id'])
body = self.ports_client.show_port(port['port_id'])
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 2c981a1..84150b4 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -23,9 +23,9 @@
List all available extensions
- v2.0 of the Neutron API is assumed. It is also assumed that the following
- options are defined in the [network] section of etc/tempest.conf:
-
+ v2.0 of the Neutron API is assumed. It is also assumed that api-extensions
+ option is defined in the [network-feature-enabled] section of
+ etc/tempest.conf.
"""
@test.attr(type='smoke')
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index c64b01e..efe8982 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -14,7 +14,6 @@
# under the License.
from tempest.api.network import base
-from tempest.common.utils import data_utils
from tempest.common.utils import net_utils
from tempest import config
from tempest import test
@@ -55,8 +54,7 @@
# Create network, subnet, router and add interface
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network, enable_dhcp=False)
- cls.router = cls.create_router(data_utils.rand_name('router-'),
- external_network_id=cls.ext_net_id)
+ cls.router = cls.create_router(external_network_id=cls.ext_net_id)
cls.create_router_interface(cls.router['id'], cls.subnet['id'])
# Create two ports one each for Creation and Updating of floatingIP
for i in range(2):
@@ -156,8 +154,7 @@
self.assertEqual(created_floating_ip['router_id'], self.router['id'])
network2 = self.create_network()
subnet2 = self.create_subnet(network2)
- router2 = self.create_router(data_utils.rand_name('router-'),
- external_network_id=self.ext_net_id)
+ router2 = self.create_router(external_network_id=self.ext_net_id)
self.create_router_interface(router2['id'], subnet2['id'])
port_other_router = self.create_port(network2)
# Associate floating IP to the other port on another router
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index 963d99d..7ffc30f 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -15,7 +15,6 @@
# under the License.
from tempest.api.network import base
-from tempest.common.utils import data_utils
from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -45,7 +44,7 @@
# Create a network with a subnet connected to a router.
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
- cls.router = cls.create_router(data_utils.rand_name('router'))
+ cls.router = cls.create_router()
cls.create_router_interface(cls.router['id'], cls.subnet['id'])
cls.port = cls.create_port(cls.network)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 3825f84..6b0c20f 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -175,8 +175,7 @@
@test.idempotent_id('0e269138-0da6-4efc-a46d-578161e7b221')
def test_create_update_delete_network_subnet(self):
# Create a network
- name = data_utils.rand_name('network-')
- network = self.create_network(network_name=name)
+ network = self.create_network()
self.addCleanup(self._delete_network, network)
net_id = network['id']
self.assertEqual('ACTIVE', network['status'])
@@ -277,29 +276,22 @@
@test.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe')
def test_delete_network_with_subnet(self):
# Creates a network
- name = data_utils.rand_name('network-')
- body = self.networks_client.create_network(name=name)
- network = body['network']
+ network = self.create_network()
net_id = network['id']
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.networks_client.delete_network, net_id)
+ self._delete_network, network)
# Find a cidr that is not in use yet and create a subnet with it
subnet = self.create_subnet(network)
subnet_id = subnet['id']
# Delete network while the subnet still exists
- body = self.networks_client.delete_network(net_id)
+ self.networks_client.delete_network(net_id)
# Verify that the subnet got automatically deleted.
self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet,
subnet_id)
- # Since create_subnet adds the subnet to the delete list, and it is
- # is actually deleted here - this will create and issue, hence remove
- # it from the list.
- self.subnets.pop()
-
@test.idempotent_id('d2d596e2-8e76-47a9-ac51-d4648009f4d3')
def test_create_delete_subnet_without_gateway(self):
self._create_verify_delete_subnet()
@@ -525,8 +517,7 @@
def test_create_delete_subnet_with_gw(self):
net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
gateway = str(netaddr.IPAddress(net.first + 2))
- name = data_utils.rand_name('network-')
- network = self.create_network(network_name=name)
+ network = self.create_network()
subnet = self.create_subnet(network, gateway)
# Verifies Subnet GW in IPv6
self.assertEqual(subnet['gateway_ip'], gateway)
@@ -535,16 +526,14 @@
def test_create_delete_subnet_with_default_gw(self):
net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
gateway_ip = str(netaddr.IPAddress(net.first + 1))
- name = data_utils.rand_name('network-')
- network = self.create_network(network_name=name)
+ network = self.create_network()
subnet = self.create_subnet(network)
# Verifies Subnet GW in IPv6
self.assertEqual(subnet['gateway_ip'], gateway_ip)
@test.idempotent_id('a9653883-b2a4-469b-8c3c-4518430a7e55')
def test_create_list_subnet_with_no_gw64_one_network(self):
- name = data_utils.rand_name('network-')
- network = self.create_network(name)
+ network = self.create_network()
ipv6_gateway = self.subnet_dict(['gateway'])['gateway']
subnet1 = self.create_subnet(network,
ip_version=6,
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index caf7f14..15d289d 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -16,13 +16,14 @@
import socket
import netaddr
+import testtools
from tempest.api.network import base
from tempest.api.network import base_security_groups as sec_base
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
@@ -71,8 +72,7 @@
@test.idempotent_id('67f1b811-f8db-43e2-86bd-72c074d4a42c')
def test_create_bulk_port(self):
network1 = self.network
- name = data_utils.rand_name('network-')
- network2 = self.create_network(network_name=name)
+ network2 = self.create_network()
network_list = [network1['id'], network2['id']]
port_list = [{'network_id': net_id} for net_id in network_list]
body = self.ports_client.create_bulk_ports(ports=port_list)
@@ -199,7 +199,7 @@
self.addCleanup(self.networks_client.delete_network, network['id'])
subnet = self.create_subnet(network)
self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
- router = self.create_router(data_utils.rand_name('router-'))
+ router = self.create_router()
self.addCleanup(self.routers_client.delete_router, router['id'])
port = self.ports_client.create_port(network_id=network['id'])
# Add router interface to port created above
@@ -308,11 +308,17 @@
self.assertIn(security_group, port_show['security_groups'])
@test.idempotent_id('58091b66-4ff4-4cc1-a549-05d60c7acd1a')
+ @testtools.skipUnless(
+ test.is_extension_enabled('security-group', 'network'),
+ 'security-group extension not enabled.')
def test_update_port_with_security_group_and_extra_attributes(self):
self._update_port_with_security_groups(
[data_utils.rand_name('secgroup')])
@test.idempotent_id('edf6766d-3d40-4621-bc6e-2521a44c257d')
+ @testtools.skipUnless(
+ test.is_extension_enabled('security-group', 'network'),
+ 'security-group extension not enabled.')
def test_update_port_with_two_security_groups_and_extra_attributes(self):
self._update_port_with_security_groups(
[data_utils.rand_name('secgroup'),
@@ -337,6 +343,9 @@
@test.attr(type='smoke')
@test.idempotent_id('4179dcb9-1382-4ced-84fe-1b91c54f5735')
+ @testtools.skipUnless(
+ test.is_extension_enabled('security-group', 'network'),
+ 'security-group extension not enabled.')
def test_create_port_with_no_securitygroups(self):
network = self.create_network()
self.addCleanup(self.networks_client.delete_network, network['id'])
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index ba416e4..de2e71f 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -106,9 +106,8 @@
@test.requires_ext(extension='ext-gw-mode', service='network')
def test_create_router_with_default_snat_value(self):
# Create a router with default snat rule
- name = data_utils.rand_name('router')
router = self._create_router(
- name, external_network_id=CONF.network.public_network_id)
+ external_network_id=CONF.network.public_network_id)
self._verify_router_gateway(
router['id'], {'network_id': CONF.network.public_network_id,
'enable_snat': True})
@@ -136,7 +135,7 @@
def test_add_remove_router_interface_with_subnet_id(self):
network = self.create_network()
subnet = self.create_subnet(network)
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
# Add router interface with subnet id
interface = self.routers_client.add_router_interface(
router['id'], subnet_id=subnet['id'])
@@ -155,7 +154,7 @@
def test_add_remove_router_interface_with_port_id(self):
network = self.create_network()
self.create_subnet(network)
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
port_body = self.ports_client.create_port(
network_id=network['id'])
# add router interface to port created above
@@ -190,15 +189,18 @@
gw_port = list_body['ports'][0]
fixed_ips = gw_port['fixed_ips']
self.assertGreaterEqual(len(fixed_ips), 1)
+ # Assert that all of the IPs from the router gateway port
+ # are allocated from a valid public subnet.
public_net_body = self.admin_networks_client.show_network(
CONF.network.public_network_id)
- public_subnet_id = public_net_body['network']['subnets'][0]
- self.assertIn(public_subnet_id,
- map(lambda x: x['subnet_id'], fixed_ips))
+ public_subnet_ids = public_net_body['network']['subnets']
+ for fixed_ip in fixed_ips:
+ subnet_id = fixed_ip['subnet_id']
+ self.assertIn(subnet_id, public_subnet_ids)
@test.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
def test_update_router_set_gateway(self):
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
self.routers_client.update_router(
router['id'],
external_gateway_info={
@@ -212,7 +214,7 @@
@test.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
@test.requires_ext(extension='ext-gw-mode', service='network')
def test_update_router_set_gateway_with_snat_explicit(self):
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
self.admin_routers_client.update_router(
router['id'],
external_gateway_info={
@@ -227,7 +229,7 @@
@test.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
@test.requires_ext(extension='ext-gw-mode', service='network')
def test_update_router_set_gateway_without_snat(self):
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
self.admin_routers_client.update_router(
router['id'],
external_gateway_info={
@@ -242,7 +244,6 @@
@test.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
def test_update_router_unset_gateway(self):
router = self._create_router(
- data_utils.rand_name('router-'),
external_network_id=CONF.network.public_network_id)
self.routers_client.update_router(router['id'],
external_gateway_info={})
@@ -257,7 +258,6 @@
@test.requires_ext(extension='ext-gw-mode', service='network')
def test_update_router_reset_gateway_without_snat(self):
router = self._create_router(
- data_utils.rand_name('router-'),
external_network_id=CONF.network.public_network_id)
self.admin_routers_client.update_router(
router['id'],
@@ -280,8 +280,7 @@
test_routes = []
routes_num = 4
# Create a router
- router = self._create_router(
- data_utils.rand_name('router-'), True)
+ router = self._create_router(admin_state_up=True)
self.addCleanup(
self._delete_extra_routes,
router['id'])
@@ -335,7 +334,7 @@
@test.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
def test_update_router_admin_state(self):
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
self.assertFalse(router['admin_state_up'])
# Update router admin state
update_body = self.routers_client.update_router(router['id'],
@@ -354,7 +353,7 @@
subnet01 = self.create_subnet(network01)
sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
subnet02 = self.create_subnet(network02, cidr=sub02_cidr)
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
interface01 = self._add_router_interface_with_subnet_id(router['id'],
subnet01['id'])
self._verify_router_interface(router['id'], subnet01['id'],
@@ -368,7 +367,7 @@
def test_router_interface_port_update_with_fixed_ip(self):
network = self.create_network()
subnet = self.create_subnet(network)
- router = self._create_router(data_utils.rand_name('router-'))
+ router = self._create_router()
fixed_ip = [{'subnet_id': subnet['id']}]
interface = self._add_router_interface_with_subnet_id(router['id'],
subnet['id'])
@@ -414,7 +413,7 @@
@test.idempotent_id('644d7a4a-01a1-4b68-bb8d-0c0042cb1729')
def test_convert_centralized_router(self):
- router = self._create_router(data_utils.rand_name('router'))
+ router = self._create_router()
self.assertNotIn('distributed', router)
update_body = self.admin_routers_client.update_router(router['id'],
distributed=True)
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index cd9f6ad..b3983de 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -36,7 +36,7 @@
@classmethod
def resource_setup(cls):
super(RoutersNegativeTest, cls).resource_setup()
- cls.router = cls.create_router(data_utils.rand_name('router-'))
+ cls.router = cls.create_router()
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
cls.tenant_cidr = (CONF.network.project_network_cidr
@@ -55,8 +55,7 @@
@test.attr(type=['negative'])
@test.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd')
def test_router_add_gateway_net_not_external_returns_400(self):
- alt_network = self.create_network(
- network_name=data_utils.rand_name('router-negative-'))
+ alt_network = self.create_network()
sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
self.create_subnet(alt_network, cidr=sub_cidr)
self.assertRaises(lib_exc.BadRequest,
@@ -128,14 +127,12 @@
@classmethod
def resource_setup(cls):
super(DvrRoutersNegativeTest, cls).resource_setup()
- cls.router = cls.create_router(data_utils.rand_name('router'))
+ cls.router = cls.create_router()
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
@test.attr(type=['negative'])
@test.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
def test_router_create_tenant_distributed_returns_forbidden(self):
- self.assertRaises(lib_exc.Forbidden,
- self.create_router,
- data_utils.rand_name('router'),
+ self.assertRaises(lib_exc.Forbidden, self.create_router,
distributed=True)
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 5312979..1031ab8 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -71,7 +71,7 @@
@test.attr(type='smoke')
@test.idempotent_id('e30abd17-fef9-4739-8617-dc26da88e686')
def test_list_security_groups(self):
- # Verify the that security group belonging to project exist in list
+ # Verify the security group belonging to project exist in list
body = self.security_groups_client.list_security_groups()
security_groups = body['security_groups']
found = None
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index fd973c6..1b1ffd1 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -114,7 +114,9 @@
object_client = cls.object_client
for cont in cls.containers:
try:
- objlist = container_client.list_all_container_objects(cont)
+ params = {'limit': 9999, 'format': 'json'}
+ resp, objlist = container_client.list_container_contents(
+ cont, params)
# delete every object in the container
for obj in objlist:
test_utils.call_and_ignore_notfound_exc(
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index a0c0a5f..33e5852 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -79,7 +79,7 @@
# headers is checked without custom matcher.
#
# As the expected response is 204 No Content, Content-Length presence
- # is not checked here intensionally. According to RFC 7230 a server
+ # is not checked here intentionally. According to RFC 7230 a server
# MUST NOT send the header in such responses. Thus, clients should not
# depend on this header. However, the standard does not require them
# to validate the server's behavior. We leverage that to not refuse
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 8522269..dbe8b4a 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -63,7 +63,8 @@
# create container with metadata value
container_name = data_utils.rand_name(name='TestContainer')
- metadata = {'test-container-meta': 'Meta1'}
+ # metadata name using underscores should be converted to hyphens
+ metadata = {'test_container_meta': 'Meta1'}
resp, _ = self.container_client.create_container(
container_name,
metadata=metadata)
@@ -74,7 +75,7 @@
container_name)
self.assertIn('x-container-meta-test-container-meta', resp)
self.assertEqual(resp['x-container-meta-test-container-meta'],
- metadata['test-container-meta'])
+ metadata['test_container_meta'])
@test.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
def test_create_container_with_remove_metadata_key(self):
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
new file mode 100644
index 0000000..7049db0
--- /dev/null
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -0,0 +1,167 @@
+# 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.object_storage import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+from tempest import test
+
+
+class ContainerNegativeTest(base.BaseObjectTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(ContainerNegativeTest, cls).resource_setup()
+
+ # use /info to get default constraints
+ _, body = cls.account_client.list_extensions()
+ cls.constraints = body['swift']
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78')
+ def test_create_container_name_exceeds_max_length(self):
+ # Attempts to create a container name that is longer than max
+ max_length = self.constraints['max_container_name_length']
+ # create a container with long name
+ container_name = data_utils.arbitrary_string(size=max_length + 1)
+ ex = self.assertRaises(exceptions.BadRequest,
+ self.container_client.create_container,
+ container_name)
+ self.assertIn('Container name length of ' + str(max_length + 1) +
+ ' longer than ' + str(max_length), str(ex))
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce')
+ def test_create_container_metadata_name_exceeds_max_length(self):
+ # Attempts to create container with metadata name
+ # that is longer than max.
+ max_length = self.constraints['max_meta_name_length']
+ container_name = data_utils.rand_name(name='TestContainer')
+ metadata_name = data_utils.arbitrary_string(size=max_length + 1)
+ metadata = {metadata_name: 'penguin'}
+ ex = self.assertRaises(exceptions.BadRequest,
+ self.container_client.create_container,
+ container_name, metadata=metadata)
+ self.assertIn('Metadata name too long', str(ex))
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82')
+ def test_create_container_metadata_value_exceeds_max_length(self):
+ # Attempts to create container with metadata value
+ # that is longer than max.
+ max_length = self.constraints['max_meta_value_length']
+ container_name = data_utils.rand_name(name='TestContainer')
+ metadata_value = data_utils.arbitrary_string(size=max_length + 1)
+ metadata = {'animal': metadata_value}
+ ex = self.assertRaises(exceptions.BadRequest,
+ self.container_client.create_container,
+ container_name, metadata=metadata)
+ self.assertIn('Metadata value longer than ' + str(max_length), str(ex))
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732')
+ def test_create_container_metadata_exceeds_overall_metadata_count(self):
+ # Attempts to create container with metadata that exceeds the
+ # default count
+ max_count = self.constraints['max_meta_count']
+ container_name = data_utils.rand_name(name='TestContainer')
+ metadata = {}
+ for i in range(max_count + 1):
+ metadata['animal-' + str(i)] = 'penguin'
+
+ ex = self.assertRaises(exceptions.BadRequest,
+ self.container_client.create_container,
+ container_name, metadata=metadata)
+ self.assertIn('Too many metadata items; max ' + str(max_count),
+ str(ex))
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6')
+ def test_get_metadata_headers_with_invalid_container_name(self):
+ # Attempts to retrieve metadata headers with an invalid
+ # container name.
+ invalid_name = data_utils.rand_name(name="TestInvalidContainer")
+
+ self.assertRaises(exceptions.NotFound,
+ self.container_client.list_container_metadata,
+ invalid_name)
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390')
+ def test_update_metadata_with_nonexistent_container_name(self):
+ # Attempts to update metadata using a nonexistent container name.
+ nonexistent_name = data_utils.rand_name(
+ name="TestNonexistentContainer")
+ metadata = {'animal': 'penguin'}
+
+ self.assertRaises(exceptions.NotFound,
+ self.container_client.update_container_metadata,
+ nonexistent_name, metadata)
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
+ def test_delete_with_nonexistent_container_name(self):
+ # Attempts to delete metadata using a nonexistent container name.
+ nonexistent_name = data_utils.rand_name(
+ name="TestNonexistentContainer")
+ metadata = {'animal': 'penguin'}
+
+ self.assertRaises(exceptions.NotFound,
+ self.container_client.delete_container_metadata,
+ nonexistent_name, metadata)
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')
+ def test_list_all_container_objects_with_nonexistent_container(self):
+ # Attempts to get a listing of all objects on a container
+ # that doesn't exist.
+ nonexistent_name = data_utils.rand_name(
+ name="TestNonexistentContainer")
+ params = {'limit': 9999, 'format': 'json'}
+ self.assertRaises(exceptions.NotFound,
+ self.container_client.list_container_contents,
+ nonexistent_name, params)
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e')
+ def test_list_all_container_objects_on_deleted_container(self):
+ # Attempts to get a listing of all objects on a container
+ # that was deleted.
+ container_name = self.create_container()
+ # delete container
+ resp, _ = self.container_client.delete_container(container_name)
+ self.assertHeaders(resp, 'Container', 'DELETE')
+ params = {'limit': 9999, 'format': 'json'}
+ self.assertRaises(exceptions.NotFound,
+ self.container_client.list_container_contents,
+ container_name, params)
+
+ @test.attr(type=["negative"])
+ @test.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1')
+ def test_delete_non_empty_container(self):
+ # create a container and an object within it
+ # attempt to delete a container that isn't empty.
+ container_name = self.create_container()
+ self.addCleanup(self.container_client.delete_container,
+ container_name)
+ object_name, _ = self.create_object(container_name)
+ self.addCleanup(self.object_client.delete_object,
+ container_name, object_name)
+
+ ex = self.assertRaises(exceptions.Conflict,
+ self.container_client.delete_container,
+ container_name)
+ self.assertIn('An object with that identifier already exists',
+ str(ex))
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 919f695..8736f9a 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -954,10 +954,7 @@
# When the file is not downloaded from Swift server, response does
# not contain 'X-Timestamp' header. This is the special case, therefore
# the existence of response headers is checked without custom matcher.
- self.assertIn('content-type', resp)
- self.assertIn('x-trans-id', resp)
self.assertIn('date', resp)
- self.assertIn('accept-ranges', resp)
# Check only the format of common headers with custom matcher
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 3f45634..a3792b4 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -18,7 +18,7 @@
from tempest.api.orchestration import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index 0400e76..160bf6f 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -72,16 +72,16 @@
for outputs in stack['outputs']:
output_map[outputs['output_key']] = outputs['output_value']
# Test that first key generated public and private keys
- self.assertTrue('KeyPair_PublicKey' in output_map)
- self.assertTrue("Generated" in output_map['KeyPair_PublicKey'])
- self.assertTrue('KeyPair_PrivateKey' in output_map)
- self.assertTrue('-----BEGIN' in output_map['KeyPair_PrivateKey'])
+ self.assertIn('KeyPair_PublicKey', output_map)
+ self.assertIn("Generated", output_map['KeyPair_PublicKey'])
+ self.assertIn('KeyPair_PrivateKey', output_map)
+ self.assertIn('-----BEGIN', output_map['KeyPair_PrivateKey'])
# Test that second key generated public key, and private key is not
# in the output due to save_private_key = false
- self.assertTrue('KeyPairDontSavePrivate_PublicKey' in output_map)
- self.assertTrue('Generated' in
- output_map['KeyPairDontSavePrivate_PublicKey'])
- self.assertTrue(u'KeyPairDontSavePrivate_PrivateKey' in output_map)
+ self.assertIn('KeyPairDontSavePrivate_PublicKey', output_map)
+ self.assertIn('Generated',
+ output_map['KeyPairDontSavePrivate_PublicKey'])
+ self.assertIn(u'KeyPairDontSavePrivate_PrivateKey', output_map)
private_key = output_map['KeyPairDontSavePrivate_PrivateKey']
self.assertTrue(len(private_key) == 0)
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
index 24e10dd..f8245c1 100644
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ b/tempest/api/orchestration/stacks/test_templates_negative.py
@@ -27,7 +27,7 @@
Type: AWS::IAM::User
"""
- invalid_template_url = 'http://www.example.com/template.yaml'
+ invalid_template_url = 'http:///template.yaml'
@classmethod
def resource_setup(cls):
@@ -57,4 +57,4 @@
}
"""
- invalid_template_url = 'http://www.example.com/template.template'
+ invalid_template_url = 'http:///template.template'
diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py
old mode 100755
new mode 100644
index 98139e7..9275d2b
--- a/tempest/api/volume/admin/test_qos.py
+++ b/tempest/api/volume/admin/test_qos.py
@@ -14,6 +14,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils as utils
+from tempest.common import waiters
from tempest import test
@@ -54,16 +55,6 @@
self.admin_volume_qos_client.associate_qos(
self.created_qos['id'], vol_type_id)
- def _test_get_association_qos(self):
- body = self.admin_volume_qos_client.show_association_qos(
- self.created_qos['id'])['qos_associations']
-
- associations = []
- for association in body:
- associations.append(association['id'])
-
- return associations
-
@test.idempotent_id('7e15f883-4bef-49a9-95eb-f94209a1ced1')
def test_create_delete_qos_with_front_end_consumer(self):
"""Tests the creation and deletion of QoS specs
@@ -119,7 +110,9 @@
self.admin_volume_qos_client.unset_qos_key(self.created_qos['id'],
keys)
operation = 'qos-key-unset'
- self.wait_for_qos_operations(self.created_qos['id'], operation, keys)
+ waiters.wait_for_qos_operations(self.admin_volume_qos_client,
+ self.created_qos['id'],
+ operation, keys)
body = self.admin_volume_qos_client.show_qos(
self.created_qos['id'])['qos_specs']
self.assertNotIn(keys[0], body['specs'])
@@ -144,8 +137,9 @@
self._test_associate_qos(vol_type[i]['id'])
# get the association of the qos-specs
- associations = self._test_get_association_qos()
-
+ body = self.admin_volume_qos_client.show_association_qos(
+ self.created_qos['id'])['qos_associations']
+ associations = [association['id'] for association in body]
for i in range(0, 3):
self.assertIn(vol_type[i]['id'], associations)
@@ -153,18 +147,16 @@
self.admin_volume_qos_client.disassociate_qos(
self.created_qos['id'], vol_type[0]['id'])
operation = 'disassociate'
- self.wait_for_qos_operations(self.created_qos['id'],
- operation, vol_type[0]['id'])
- associations = self._test_get_association_qos()
- self.assertNotIn(vol_type[0]['id'], associations)
+ waiters.wait_for_qos_operations(self.admin_volume_qos_client,
+ self.created_qos['id'], operation,
+ vol_type[0]['id'])
# disassociate all volume-types from qos-specs
self.admin_volume_qos_client.disassociate_all_qos(
self.created_qos['id'])
operation = 'disassociate-all'
- self.wait_for_qos_operations(self.created_qos['id'], operation)
- associations = self._test_get_association_qos()
- self.assertEmpty(associations)
+ waiters.wait_for_qos_operations(self.admin_volume_qos_client,
+ self.created_qos['id'], operation)
class QosSpecsV1TestJSON(QosSpecsV2TestJSON):
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 1468e90..5af83b3 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -14,7 +14,6 @@
# under the License.
from tempest.api.volume import base
-from tempest.common.utils import data_utils
from tempest import config
from tempest import test
@@ -38,16 +37,10 @@
super(SnapshotsActionsV2Test, cls).resource_setup()
# Create a test shared volume for tests
- vol_name = data_utils.rand_name(cls.__name__ + '-Volume')
- cls.name_field = cls.special_fields['name_field']
- params = {cls.name_field: vol_name}
- cls.volume = cls.create_volume(**params)
+ cls.volume = cls.create_volume()
# Create a test shared snapshot for tests
- snap_name = data_utils.rand_name(cls.__name__ + '-Snapshot')
- params = {cls.name_field: snap_name}
- cls.snapshot = cls.create_snapshot(
- volume_id=cls.volume['id'], **params)
+ cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id'])
def tearDown(self):
# Set snapshot's status to available after test
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index fe105e8..b47a5f0 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -18,7 +18,7 @@
from tempest.common import waiters
from tempest import test
-QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes']
+QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups']
QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
@@ -54,7 +54,8 @@
self.demo_tenant_id)['quota_set']
new_quota_set = {'gigabytes': 1009,
'volumes': 11,
- 'snapshots': 11}
+ 'snapshots': 11,
+ 'backups': 11}
# Update limits for all quota resources
quota_set = self.admin_quotas_client.update_quota_set(
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
old mode 100755
new mode 100644
index 646bc68..99f0a6b
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -43,10 +43,7 @@
"vendor_name": vendor}
# Create two volume_types
for i in range(2):
- vol_type_name = data_utils.rand_name(
- self.__class__.__name__ + '-volume-type')
vol_type = self.create_volume_type(
- name=vol_type_name,
extra_specs=extra_specs)
volume_types.append(vol_type)
params = {self.name_field: vol_name,
@@ -124,8 +121,7 @@
# Create/get/delete encryption type.
provider = "LuksEncryptor"
control_location = "front-end"
- name = data_utils.rand_name(self.__class__.__name__ + '-volume-type')
- body = self.create_volume_type(name=name)
+ body = self.create_volume_type()
# Create encryption type
encryption_type = \
self.admin_encryption_types_client.create_encryption_type(
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
old mode 100755
new mode 100644
index d50ba27..fdff2df
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -14,7 +14,7 @@
# under the License.
from tempest.api.volume import base
-from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -23,8 +23,7 @@
@classmethod
def resource_setup(cls):
super(VolumeTypesExtraSpecsV2Test, cls).resource_setup()
- vol_type_name = data_utils.rand_name(cls.__name__ + '-Volume-type')
- cls.volume_type = cls.create_volume_type(name=vol_type_name)
+ cls.volume_type = cls.create_volume_type()
@test.idempotent_id('b42923e9-0452-4945-be5b-d362ae533e60')
def test_volume_type_extra_specs_list(self):
@@ -66,13 +65,18 @@
self.assertEqual(extra_specs, body,
"Volume type extra spec incorrectly created")
- self.admin_volume_types_client.show_volume_type_extra_specs(
+ body = self.admin_volume_types_client.show_volume_type_extra_specs(
self.volume_type['id'],
spec_key)
self.assertEqual(extra_specs, body,
"Volume type extra spec incorrectly fetched")
+
self.admin_volume_types_client.delete_volume_type_extra_specs(
self.volume_type['id'], spec_key)
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_volume_types_client.show_volume_type_extra_specs,
+ self.volume_type['id'], spec_key)
class VolumeTypesExtraSpecsV1Test(VolumeTypesExtraSpecsV2Test):
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
old mode 100755
new mode 100644
index 2e07457..8040322
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -24,10 +24,8 @@
@classmethod
def resource_setup(cls):
super(ExtraSpecsNegativeV2Test, cls).resource_setup()
- vol_type_name = data_utils.rand_name(cls.__name__ + '-Volume-type')
cls.extra_specs = {"spec1": "val1"}
- cls.volume_type = cls.create_volume_type(name=vol_type_name,
- extra_specs=cls.extra_specs)
+ cls.volume_type = cls.create_volume_type(extra_specs=cls.extra_specs)
@test.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
def test_update_no_body(self):
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
old mode 100755
new mode 100644
index 9686473..e7a3f62
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -14,8 +14,6 @@
# under the License.
from tempest.api.volume import base
-from tempest.common.utils import data_utils as utils
-from tempest.common import waiters
from tempest import config
from tempest import test
@@ -34,54 +32,28 @@
super(VolumesActionsV2Test, cls).resource_setup()
# Create a test shared volume for tests
- vol_name = utils.rand_name(cls.__name__ + '-Volume')
- cls.name_field = cls.special_fields['name_field']
- params = {cls.name_field: vol_name, 'size': CONF.volume.volume_size}
-
- cls.volume = cls.client.create_volume(**params)['volume']
- waiters.wait_for_volume_status(cls.client,
- cls.volume['id'], 'available')
-
- @classmethod
- def resource_cleanup(cls):
- # Delete the test volume
- cls.delete_volume(cls.client, cls.volume['id'])
-
- super(VolumesActionsV2Test, cls).resource_cleanup()
-
- def _reset_volume_status(self, volume_id, status):
- # Reset the volume status
- body = self.admin_volume_client.reset_volume_status(volume_id,
- status=status)
- return body
+ cls.volume = cls.create_volume()
def tearDown(self):
# Set volume's status to available after test
- self._reset_volume_status(self.volume['id'], status='available')
+ self.admin_volume_client.reset_volume_status(
+ self.volume['id'], status='available')
super(VolumesActionsV2Test, self).tearDown()
- def _create_temp_volume(self):
- # Create a temp volume for force delete tests
- vol_name = utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: vol_name, 'size': CONF.volume.volume_size}
- temp_volume = self.client.create_volume(**params)['volume']
- waiters.wait_for_volume_status(self.client,
- temp_volume['id'], 'available')
-
- return temp_volume
-
def _create_reset_and_force_delete_temp_volume(self, status=None):
# Create volume, reset volume status, and force delete temp volume
- temp_volume = self._create_temp_volume()
+ temp_volume = self.create_volume()
if status:
- self._reset_volume_status(temp_volume['id'], status)
+ self.admin_volume_client.reset_volume_status(
+ temp_volume['id'], status=status)
self.admin_volume_client.force_delete_volume(temp_volume['id'])
self.client.wait_for_resource_deletion(temp_volume['id'])
@test.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845')
def test_volume_reset_status(self):
# test volume reset status : available->error->available
- self._reset_volume_status(self.volume['id'], 'error')
+ self.admin_volume_client.reset_volume_status(
+ self.volume['id'], status='error')
volume_get = self.admin_volume_client.show_volume(
self.volume['id'])['volume']
self.assertEqual('error', volume_get['status'])
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
old mode 100755
new mode 100644
index a26052c..73f1f8f
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -68,8 +68,8 @@
volume_id=self.volume['id'], name=backup_name)['backup'])
self.addCleanup(self._delete_backup, backup['id'])
self.assertEqual(backup_name, backup['name'])
- self.admin_backups_client.wait_for_backup_status(backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.admin_backups_client,
+ backup['id'], 'available')
# Export Backup
export_backup = (self.admin_backups_client.export_backup(backup['id'])
@@ -101,8 +101,8 @@
self.addCleanup(self._delete_backup, new_id)
self.assertIn("id", import_backup)
self.assertEqual(new_id, import_backup['id'])
- self.admin_backups_client.wait_for_backup_status(import_backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.admin_backups_client,
+ import_backup['id'], 'available')
# Verify Import Backup
backups = self.admin_backups_client.list_backups(
@@ -121,8 +121,8 @@
# Verify if restored volume is there in volume list
volumes = self.admin_volume_client.list_volumes()['volumes']
self.assertIn(restore['volume_id'], [v['id'] for v in volumes])
- self.admin_backups_client.wait_for_backup_status(import_backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.admin_backups_client,
+ import_backup['id'], 'available')
@test.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
def test_volume_backup_reset_status(self):
@@ -134,13 +134,13 @@
self.addCleanup(self.admin_backups_client.delete_backup,
backup['id'])
self.assertEqual(backup_name, backup['name'])
- self.admin_backups_client.wait_for_backup_status(backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.admin_backups_client,
+ backup['id'], 'available')
# Reset backup status to error
self.admin_backups_client.reset_backup_status(backup_id=backup['id'],
status="error")
- self.admin_backups_client.wait_for_backup_status(backup['id'],
- 'error')
+ waiters.wait_for_backup_status(self.admin_backups_client,
+ backup['id'], 'error')
class VolumesBackupsAdminV1Test(VolumesBackupsAdminV2Test):
diff --git a/tempest/api/volume/v3/admin/__init__.py b/tempest/api/volume/admin/v2/__init__.py
similarity index 100%
rename from tempest/api/volume/v3/admin/__init__.py
rename to tempest/api/volume/admin/v2/__init__.py
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/v2/test_volume_pools.py
similarity index 100%
rename from tempest/api/volume/admin/test_volume_pools.py
rename to tempest/api/volume/admin/v2/test_volume_pools.py
diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/v2/test_volume_type_access.py
similarity index 100%
rename from tempest/api/volume/admin/test_volume_type_access.py
rename to tempest/api/volume/admin/v2/test_volume_type_access.py
diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/v2/test_volumes_list.py
similarity index 100%
rename from tempest/api/volume/admin/test_volumes_list.py
rename to tempest/api/volume/admin/v2/test_volumes_list.py
diff --git a/tempest/api/volume/v3/admin/__init__.py b/tempest/api/volume/admin/v3/__init__.py
similarity index 100%
copy from tempest/api/volume/v3/admin/__init__.py
copy to tempest/api/volume/admin/v3/__init__.py
diff --git a/tempest/api/volume/v3/admin/test_user_messages.py b/tempest/api/volume/admin/v3/test_user_messages.py
similarity index 100%
rename from tempest/api/volume/v3/admin/test_user_messages.py
rename to tempest/api/volume/admin/v3/test_user_messages.py
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index d1549e2..b9aeb99 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -13,15 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from tempest.common import compute
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
from tempest.lib.common.utils import test_utils
-from tempest.lib import exceptions as lib_exc
+from tempest.lib import exceptions
import tempest.test
CONF = config.CONF
@@ -116,13 +113,12 @@
if 'size' not in kwargs:
kwargs['size'] = CONF.volume.volume_size
- name = data_utils.rand_name(cls.__name__ + '-Volume')
-
name_field = cls.special_fields['name_field']
+ if name_field not in kwargs:
+ name = data_utils.rand_name(cls.__name__ + '-Volume')
+ kwargs[name_field] = name
- kwargs[name_field] = name
volume = cls.volumes_client.create_volume(**kwargs)['volume']
-
cls.volumes.append(volume)
waiters.wait_for_volume_status(cls.volumes_client,
volume['id'], 'available')
@@ -131,6 +127,11 @@
@classmethod
def create_snapshot(cls, volume_id=1, **kwargs):
"""Wrapper utility that returns a test snapshot."""
+ name_field = cls.special_fields['name_field']
+ if name_field not in kwargs:
+ name = data_utils.rand_name(cls.__name__ + '-Snapshot')
+ kwargs[name_field] = name
+
snapshot = cls.snapshots_client.create_snapshot(
volume_id=volume_id, **kwargs)['snapshot']
cls.snapshots.append(snapshot)
@@ -175,7 +176,11 @@
except Exception:
pass
- def create_server(self, name, wait_for_deletion=False, **kwargs):
+ def create_server(self, **kwargs):
+ name = kwargs.pop(
+ 'name',
+ data_utils.rand_name(self.__class__.__name__ + '-instance'))
+
tenant_network = self.get_tenant_network()
body, _ = compute.create_test_server(
self.os,
@@ -183,11 +188,9 @@
name=name,
**kwargs)
- if wait_for_deletion:
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- waiters.wait_for_server_termination,
- self.servers_client, body['id'])
-
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ waiters.wait_for_server_termination,
+ self.servers_client, body['id'])
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.servers_client.delete_server, body['id'])
return body
@@ -279,35 +282,3 @@
test_utils.call_and_ignore_notfound_exc(
cls.admin_volume_types_client.wait_for_resource_deletion,
vol_type)
-
- def wait_for_qos_operations(self, qos_id, operation, args=None):
- """Waits for a qos operations to be completed.
-
- NOTE : operation value is required for wait_for_qos_operations()
- operation = 'qos-key' / 'disassociate' / 'disassociate-all'
- args = keys[] when operation = 'qos-key'
- args = volume-type-id disassociated when operation = 'disassociate'
- args = None when operation = 'disassociate-all'
- """
- start_time = int(time.time())
- client = self.admin_volume_qos_client
- while True:
- if operation == 'qos-key-unset':
- body = client.show_qos(qos_id)['qos_specs']
- if not any(key in body['specs'] for key in args):
- return
- elif operation == 'disassociate':
- body = client.show_association_qos(qos_id)['qos_associations']
- if not any(args in body[i]['id'] for i in range(0, len(body))):
- return
- elif operation == 'disassociate-all':
- body = client.show_association_qos(qos_id)['qos_associations']
- if not body:
- return
- else:
- msg = (" operation value is either not defined or incorrect.")
- raise lib_exc.UnprocessableEntity(msg)
-
- if int(time.time()) - start_time >= self.build_timeout:
- raise exceptions.TimeoutException
- time.sleep(self.build_interval)
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index fe51375..ae4b8f9 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -30,7 +30,7 @@
# List of availability zone
availability_zone = (self.client.list_availability_zones()
['availabilityZoneInfo'])
- self.assertTrue(len(availability_zone) > 0)
+ self.assertGreater(len(availability_zone), 0)
class AvailabilityZoneV1TestJSON(AvailabilityZoneV2TestJSON):
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index e529538..ee1744d 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -26,11 +26,10 @@
super(VolumesV2MetadataTest, cls).resource_setup()
# Create a volume
cls.volume = cls.create_volume()
- cls.volume_id = cls.volume['id']
def tearDown(self):
# Update the metadata to {}
- self.volumes_client.update_volume_metadata(self.volume_id, {})
+ self.volumes_client.update_volume_metadata(self.volume['id'], {})
super(VolumesV2MetadataTest, self).tearDown()
@test.idempotent_id('6f5b125b-f664-44bf-910f-751591fe5769')
@@ -41,17 +40,17 @@
"key3": "value3",
"key4": "<value&special_chars>"}
- body = self.volumes_client.create_volume_metadata(self.volume_id,
+ body = self.volumes_client.create_volume_metadata(self.volume['id'],
metadata)['metadata']
# Get the metadata of the volume
body = self.volumes_client.show_volume_metadata(
- self.volume_id)['metadata']
+ self.volume['id'])['metadata']
self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Delete one item metadata of the volume
self.volumes_client.delete_volume_metadata_item(
- self.volume_id, "key1")
+ self.volume['id'], "key1")
body = self.volumes_client.show_volume_metadata(
- self.volume_id)['metadata']
+ self.volume['id'])['metadata']
self.assertNotIn("key1", body)
del metadata["key1"]
self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
@@ -68,17 +67,17 @@
# Create metadata for the volume
body = self.volumes_client.create_volume_metadata(
- self.volume_id, metadata)['metadata']
+ self.volume['id'], metadata)['metadata']
# Get the metadata of the volume
body = self.volumes_client.show_volume_metadata(
- self.volume_id)['metadata']
+ self.volume['id'])['metadata']
self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Update metadata
body = self.volumes_client.update_volume_metadata(
- self.volume_id, update)['metadata']
+ self.volume['id'], update)['metadata']
# Get the metadata of the volume
body = self.volumes_client.show_volume_metadata(
- self.volume_id)['metadata']
+ self.volume['id'])['metadata']
self.assertEqual(update, body)
@test.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20')
@@ -93,14 +92,14 @@
"key3": "value3_update"}
# Create metadata for the volume
body = self.volumes_client.create_volume_metadata(
- self.volume_id, metadata)['metadata']
+ self.volume['id'], metadata)['metadata']
self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Update metadata item
body = self.volumes_client.update_volume_metadata_item(
- self.volume_id, "key3", update_item)['meta']
+ self.volume['id'], "key3", update_item)['meta']
# Get the metadata of the volume
body = self.volumes_client.show_volume_metadata(
- self.volume_id)['metadata']
+ self.volume['id'])['metadata']
self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
old mode 100755
new mode 100644
index b80a4a4..737ce5e
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -18,8 +18,8 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
from tempest.lib.common.utils import test_utils
+from tempest.lib import exceptions
from tempest import test
CONF = config.CONF
@@ -48,19 +48,13 @@
# Create a test shared volume for attach/detach tests
cls.volume = cls.create_volume()
- waiters.wait_for_volume_status(cls.client,
- cls.volume['id'], 'available')
@test.idempotent_id('fff42874-7db5-4487-a8e1-ddda5fb5288d')
- @test.stresstest(class_setup_per='process')
@test.attr(type='smoke')
@test.services('compute')
def test_attach_detach_volume_to_instance(self):
# Create a server
- srv_name = data_utils.rand_name(self.__class__.__name__ + '-Instance')
- server = self.create_server(
- name=srv_name,
- wait_until='ACTIVE')
+ server = self.create_server(wait_until='ACTIVE')
# Volume is attached and detached successfully from an instance
self.client.attach_volume(self.volume['id'],
instance_uuid=server['id'],
@@ -87,14 +81,10 @@
self.assertEqual(bool_bootable, bool_flag)
@test.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371')
- @test.stresstest(class_setup_per='process')
@test.services('compute')
def test_get_volume_attachment(self):
# Create a server
- srv_name = data_utils.rand_name(self.__class__.__name__ + '-Instance')
- server = self.create_server(
- name=srv_name,
- wait_until='ACTIVE')
+ server = self.create_server(wait_until='ACTIVE')
# Verify that a volume's attachment information is retrieved
self.client.attach_volume(self.volume['id'],
instance_uuid=server['id'],
@@ -102,8 +92,6 @@
CONF.compute.volume_device_name)
waiters.wait_for_volume_status(self.client,
self.volume['id'], 'in-use')
- # NOTE(gfidente): added in reverse order because functions will be
- # called in reverse order to the order they are added (LIFO)
self.addCleanup(waiters.wait_for_volume_status, self.client,
self.volume['id'],
'available')
@@ -156,24 +144,15 @@
@test.idempotent_id('fff74e1e-5bd3-4b33-9ea9-24c103bc3f59')
def test_volume_readonly_update(self):
- # Update volume readonly true
- readonly = True
- self.client.update_volume_readonly(self.volume['id'],
- readonly=readonly)
- # Get Volume information
- fetched_volume = self.client.show_volume(self.volume['id'])['volume']
- bool_flag = self._is_true(fetched_volume['metadata']['readonly'])
- self.assertEqual(True, bool_flag)
-
- # Update volume readonly false
- readonly = False
- self.client.update_volume_readonly(self.volume['id'],
- readonly=readonly)
-
- # Get Volume information
- fetched_volume = self.client.show_volume(self.volume['id'])['volume']
- bool_flag = self._is_true(fetched_volume['metadata']['readonly'])
- self.assertEqual(False, bool_flag)
+ for readonly in [True, False]:
+ # Update volume readonly
+ self.client.update_volume_readonly(self.volume['id'],
+ readonly=readonly)
+ # Get Volume information
+ fetched_volume = self.client.show_volume(
+ self.volume['id'])['volume']
+ bool_flag = self._is_true(fetched_volume['metadata']['readonly'])
+ self.assertEqual(readonly, bool_flag)
class VolumesV1ActionsTest(VolumesV2ActionsTest):
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
old mode 100755
new mode 100644
index 86076b7..141336f
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -46,8 +46,8 @@
self.assertEqual(backup_name, backup['name'])
waiters.wait_for_volume_status(self.volumes_client,
volume['id'], 'available')
- self.backups_client.wait_for_backup_status(backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.backups_client,
+ backup['id'], 'available')
# Get a given backup
backup = self.backups_client.show_backup(backup['id'])['backup']
@@ -67,8 +67,8 @@
self.addCleanup(self.volumes_client.delete_volume,
restore['volume_id'])
self.assertEqual(backup['id'], restore['backup_id'])
- self.backups_client.wait_for_backup_status(backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.backups_client,
+ backup['id'], 'available')
waiters.wait_for_volume_status(self.volumes_client,
restore['volume_id'], 'available')
@@ -84,9 +84,7 @@
volume = self.create_volume()
self.addCleanup(self.volumes_client.delete_volume,
volume['id'])
- server_name = data_utils.rand_name(
- self.__class__.__name__ + '-instance')
- server = self.create_server(name=server_name, wait_until='ACTIVE')
+ server = self.create_server(wait_until='ACTIVE')
# Attach volume to instance
self.servers_client.attach_volume(server['id'],
volumeId=volume['id'])
@@ -103,8 +101,8 @@
volume_id=volume['id'],
name=backup_name, force=True)['backup']
self.addCleanup(self.backups_client.delete_backup, backup['id'])
- self.backups_client.wait_for_backup_status(backup['id'],
- 'available')
+ waiters.wait_for_backup_status(self.backups_client,
+ backup['id'], 'available')
self.assertEqual(backup_name, backup['name'])
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
old mode 100755
new mode 100644
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index b5ef7c0..40793ec 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -32,6 +32,11 @@
VOLUME_FIELDS = ('id', 'name')
def assertVolumesIn(self, fetched_list, expected_list, fields=None):
+ """Check out the list.
+
+ This function is aim at check out whether all of the volumes in
+ expected_list are in fetched_list.
+ """
if fields:
fieldsgetter = operator.itemgetter(*fields)
expected_list = map(fieldsgetter, expected_list)
@@ -58,7 +63,6 @@
def resource_setup(cls):
super(VolumesV2ListTestJSON, cls).resource_setup()
cls.name = cls.VOLUME_FIELDS[1]
-
# Create 3 test volumes
cls.volume_list = []
cls.metadata = {'Type': 'work'}
@@ -146,6 +150,28 @@
self.assertEqual('available', volume['status'])
self.assertVolumesIn(fetched_list, self.volume_list)
+ @test.idempotent_id('2016a942-3020-40d7-95ce-7613bf8407ce')
+ def test_volumes_list_by_bootable(self):
+ """Check out volumes.
+
+ This test function is aim at check out whether all of the volumes
+ in volume_list are not a bootable volume.
+ """
+ params = {'bootable': 'false'}
+ fetched_list = self.client.list_volumes(params=params)['volumes']
+ self._list_by_param_value_and_assert(params)
+ self.assertVolumesIn(fetched_list, self.volume_list,
+ fields=self.VOLUME_FIELDS)
+
+ @test.idempotent_id('2016a939-72ec-482a-bf49-d5ca06216b9f')
+ def test_volumes_list_details_by_bootable(self):
+ params = {'bootable': 'false'}
+ fetched_list = self.client.list_volumes(
+ detail=True, params=params)['volumes']
+ for volume in fetched_list:
+ self.assertEqual('false', volume['bootable'])
+ self.assertVolumesIn(fetched_list, self.volume_list)
+
@test.idempotent_id('c0cfa863-3020-40d7-b587-e35f597d5d87')
def test_volumes_list_by_availability_zone(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
old mode 100755
new mode 100644
index 5bef7f3..fda0dda
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -176,11 +176,7 @@
@test.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
@test.services('compute')
def test_attach_volumes_with_nonexistent_volume_id(self):
- srv_name = data_utils.rand_name(self.__class__.__name__ + '-Instance')
- server = self.create_server(
- name=srv_name,
- wait_for_deletion=True,
- wait_until='ACTIVE')
+ server = self.create_server(wait_until='ACTIVE')
self.assertRaises(lib_exc.NotFound,
self.client.attach_volume,
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
old mode 100755
new mode 100644
index 8f7996a..3c05d3e
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -14,7 +14,6 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest.lib import decorators
from tempest import test
CONF = config.CONF
@@ -32,54 +31,21 @@
def resource_setup(cls):
super(VolumesV2SnapshotTestJSON, cls).resource_setup()
cls.volume_origin = cls.create_volume()
-
cls.name_field = cls.special_fields['name_field']
cls.descrip_field = cls.special_fields['descrip_field']
- # Create 2 snapshots
- for _ in range(2):
- cls.create_snapshot(cls.volume_origin['id'])
- def _detach(self, volume_id):
- """Detach volume."""
- self.volumes_client.detach_volume(volume_id)
- waiters.wait_for_volume_status(self.volumes_client,
- volume_id, 'available')
-
- def _list_by_param_values_and_assert(self, with_detail=False, **params):
- """list or list_details with given params and validates result."""
-
- if with_detail:
- fetched_snap_list = self.snapshots_client.list_snapshots(
- detail=True, **params)['snapshots']
- else:
- fetched_snap_list = self.snapshots_client.list_snapshots(
- **params)['snapshots']
-
- # Validating params of fetched snapshots
- for snap in fetched_snap_list:
- for key in params:
- msg = "Failed to list snapshots %s by %s" % \
- ('details' if with_detail else '', key)
- self.assertEqual(params[key], snap[key], msg)
-
- def _list_snapshots_by_param_limit(self, limit, expected_elements):
- """list snapshots by limit param"""
- # Get snapshots list using limit parameter
- fetched_snap_list = self.snapshots_client.list_snapshots(
- limit=limit)['snapshots']
- # Validating filtered snapshots length equals to expected_elements
- self.assertEqual(expected_elements, len(fetched_snap_list))
+ def cleanup_snapshot(self, snapshot):
+ # Delete the snapshot
+ self.snapshots_client.delete_snapshot(snapshot['id'])
+ self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
+ self.snapshots.remove(snapshot)
@test.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
@test.services('compute')
def test_snapshot_create_with_volume_in_use(self):
# Create a snapshot when volume status is in-use
# Create a test instance
- server_name = data_utils.rand_name(
- self.__class__.__name__ + '-instance')
- server = self.create_server(
- name=server_name,
- wait_until='ACTIVE')
+ server = self.create_server(wait_until='ACTIVE')
self.servers_client.attach_volume(
server['id'], volumeId=self.volume_origin['id'],
device='/dev/%s' % CONF.compute.volume_device_name)
@@ -98,9 +64,7 @@
@test.idempotent_id('2a8abbe4-d871-46db-b049-c41f5af8216e')
def test_snapshot_create_get_list_update_delete(self):
# Create a snapshot
- s_name = data_utils.rand_name(self.__class__.__name__ + '-snap')
- params = {self.name_field: s_name}
- snapshot = self.create_snapshot(self.volume_origin['id'], **params)
+ snapshot = self.create_snapshot(self.volume_origin['id'])
# Get the snap and check for some of its details
snap_get = self.snapshots_client.show_snapshot(
@@ -135,48 +99,6 @@
# Delete the snapshot
self.cleanup_snapshot(snapshot)
- @test.idempotent_id('59f41f43-aebf-48a9-ab5d-d76340fab32b')
- def test_snapshots_list_with_params(self):
- """list snapshots with params."""
- # Create a snapshot
- display_name = data_utils.rand_name(self.__class__.__name__ + '-snap')
- params = {self.name_field: display_name}
- snapshot = self.create_snapshot(self.volume_origin['id'], **params)
- self.addCleanup(self.cleanup_snapshot, snapshot)
-
- # Verify list snapshots by display_name filter
- params = {self.name_field: snapshot[self.name_field]}
- self._list_by_param_values_and_assert(**params)
-
- # Verify list snapshots by status filter
- params = {'status': 'available'}
- self._list_by_param_values_and_assert(**params)
-
- # Verify list snapshots by status and display name filter
- params = {'status': 'available',
- self.name_field: snapshot[self.name_field]}
- self._list_by_param_values_and_assert(**params)
-
- @test.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2')
- def test_snapshots_list_details_with_params(self):
- """list snapshot details with params."""
- # Create a snapshot
- display_name = data_utils.rand_name(self.__class__.__name__ + '-snap')
- params = {self.name_field: display_name}
- snapshot = self.create_snapshot(self.volume_origin['id'], **params)
- self.addCleanup(self.cleanup_snapshot, snapshot)
-
- # Verify list snapshot details by display_name filter
- params = {self.name_field: snapshot[self.name_field]}
- self._list_by_param_values_and_assert(with_detail=True, **params)
- # Verify list snapshot details by status filter
- params = {'status': 'available'}
- self._list_by_param_values_and_assert(with_detail=True, **params)
- # Verify list snapshot details by status and display name filter
- params = {'status': 'available',
- self.name_field: snapshot[self.name_field]}
- self._list_by_param_values_and_assert(with_detail=True, **params)
-
@test.idempotent_id('677863d1-3142-456d-b6ac-9924f667a7f4')
def test_volume_from_snapshot(self):
# Creates a volume a snapshot passing a size different from the source
@@ -193,31 +115,6 @@
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):
- # List returns limited elements
- self._list_snapshots_by_param_limit(limit=1, expected_elements=1)
-
- @test.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400')
- def test_snapshot_list_param_limit_equals_infinite(self):
- # List returns all elements when request limit exceeded
- # snapshots number
- snap_list = self.snapshots_client.list_snapshots()['snapshots']
- self._list_snapshots_by_param_limit(limit=100000,
- expected_elements=len(snap_list))
-
- @decorators.skip_because(bug='1540893')
- @test.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a')
- def test_snapshot_list_param_limit_equals_zero(self):
- # List returns zero elements
- self._list_snapshots_by_param_limit(limit=0, expected_elements=0)
-
- def cleanup_snapshot(self, snapshot):
- # Delete the snapshot
- self.snapshots_client.delete_snapshot(snapshot['id'])
- self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
- self.snapshots.remove(snapshot)
-
class VolumesV1SnapshotTestJSON(VolumesV2SnapshotTestJSON):
_api_version = 1
diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py
new file mode 100644
index 0000000..4416bef
--- /dev/null
+++ b/tempest/api/volume/test_volumes_snapshots_list.py
@@ -0,0 +1,116 @@
+# 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 decorators
+from tempest import test
+
+CONF = config.CONF
+
+
+class VolumesV2SnapshotListTestJSON(base.BaseVolumeTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(VolumesV2SnapshotListTestJSON, cls).skip_checks()
+ if not CONF.volume_feature_enabled.snapshot:
+ raise cls.skipException("Cinder volume snapshots are disabled")
+
+ @classmethod
+ def resource_setup(cls):
+ super(VolumesV2SnapshotListTestJSON, cls).resource_setup()
+ cls.volume_origin = cls.create_volume()
+ cls.name_field = cls.special_fields['name_field']
+ # Create snapshots with params
+ for _ in range(2):
+ cls.snapshot = cls.create_snapshot(cls.volume_origin['id'])
+
+ def _list_by_param_values_and_assert(self, with_detail=False, **params):
+ """list or list_details with given params and validates result."""
+
+ fetched_snap_list = self.snapshots_client.list_snapshots(
+ detail=with_detail, **params)['snapshots']
+
+ # Validating params of fetched snapshots
+ for snap in fetched_snap_list:
+ for key in params:
+ msg = "Failed to list snapshots %s by %s" % \
+ ('details' if with_detail else '', key)
+ self.assertEqual(params[key], snap[key], msg)
+
+ def _list_snapshots_by_param_limit(self, limit, expected_elements):
+ """list snapshots by limit param"""
+ # Get snapshots list using limit parameter
+ fetched_snap_list = self.snapshots_client.list_snapshots(
+ limit=limit)['snapshots']
+ # Validating filtered snapshots length equals to expected_elements
+ self.assertEqual(expected_elements, len(fetched_snap_list))
+
+ @test.idempotent_id('59f41f43-aebf-48a9-ab5d-d76340fab32b')
+ def test_snapshots_list_with_params(self):
+ """list snapshots with params."""
+ # Verify list snapshots by display_name filter
+ params = {self.name_field: self.snapshot[self.name_field]}
+ self._list_by_param_values_and_assert(**params)
+
+ # Verify list snapshots by status filter
+ params = {'status': 'available'}
+ self._list_by_param_values_and_assert(**params)
+
+ # Verify list snapshots by status and display name filter
+ params = {'status': 'available',
+ self.name_field: self.snapshot[self.name_field]}
+ self._list_by_param_values_and_assert(**params)
+
+ @test.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2')
+ def test_snapshots_list_details_with_params(self):
+ """list snapshot details with params."""
+ # Verify list snapshot details by display_name filter
+ params = {self.name_field: self.snapshot[self.name_field]}
+ self._list_by_param_values_and_assert(with_detail=True, **params)
+ # Verify list snapshot details by status filter
+ params = {'status': 'available'}
+ self._list_by_param_values_and_assert(with_detail=True, **params)
+ # Verify list snapshot details by status and display name filter
+ params = {'status': 'available',
+ self.name_field: self.snapshot[self.name_field]}
+ self._list_by_param_values_and_assert(with_detail=True, **params)
+
+ @test.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896')
+ def test_snapshot_list_param_limit(self):
+ # List returns limited elements
+ self._list_snapshots_by_param_limit(limit=1, expected_elements=1)
+
+ @test.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400')
+ def test_snapshot_list_param_limit_equals_infinite(self):
+ # List returns all elements when request limit exceeded
+ # snapshots number
+ snap_list = self.snapshots_client.list_snapshots()['snapshots']
+ self._list_snapshots_by_param_limit(limit=100000,
+ expected_elements=len(snap_list))
+
+ @decorators.skip_because(bug='1540893')
+ @test.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a')
+ def test_snapshot_list_param_limit_equals_zero(self):
+ # List returns zero elements
+ self._list_snapshots_by_param_limit(limit=0, expected_elements=0)
+
+ def cleanup_snapshot(self, snapshot):
+ # Delete the snapshot
+ self.snapshots_client.delete_snapshot(snapshot['id'])
+ self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
+ self.snapshots.remove(snapshot)
+
+
+class VolumesV1SnapshotLimitTestJSON(VolumesV2SnapshotListTestJSON):
+ _api_version = 1
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
old mode 100755
new mode 100644
diff --git a/tempest/api_schema/__init__.py b/tempest/api_schema/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api_schema/__init__.py
+++ /dev/null
diff --git a/tempest/api_schema/request/__init__.py b/tempest/api_schema/request/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api_schema/request/__init__.py
+++ /dev/null
diff --git a/tempest/api_schema/request/compute/__init__.py b/tempest/api_schema/request/compute/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api_schema/request/compute/__init__.py
+++ /dev/null
diff --git a/tempest/api_schema/request/compute/flavors.py b/tempest/api_schema/request/compute/flavors.py
deleted file mode 100644
index adaaf27..0000000
--- a/tempest/api_schema/request/compute/flavors.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# (c) 2014 Deutsche Telekom AG
-# 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.
-
-common_flavor_details = {
- "name": "get-flavor-details",
- "http-method": "GET",
- "url": "flavors/%s",
- "resources": [
- {"name": "flavor", "expected_result": 404}
- ]
-}
-
-common_flavor_list = {
- "name": "list-flavors-with-detail",
- "http-method": "GET",
- "url": "flavors/detail",
- "json-schema": {
- "type": "object",
- "properties": {
- }
- }
-}
-
-common_admin_flavor_create = {
- "name": "flavor-create",
- "http-method": "POST",
- "admin_client": True,
- "url": "flavors",
- "default_result_code": 400,
- "json-schema": {
- "type": "object",
- "properties": {
- "flavor": {
- "type": "object",
- "properties": {
- "name": {"type": "string",
- "exclude_tests": ["gen_str_min_length"]},
- "ram": {"type": "integer", "minimum": 1},
- "vcpus": {"type": "integer", "minimum": 1},
- "disk": {"type": "integer"},
- "id": {"type": "integer",
- "exclude_tests": ["gen_none", "gen_string"]
- },
- }
- }
- }
- }
-}
diff --git a/tempest/api_schema/request/compute/v2/__init__.py b/tempest/api_schema/request/compute/v2/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api_schema/request/compute/v2/__init__.py
+++ /dev/null
diff --git a/tempest/api_schema/request/compute/v2/flavors.py b/tempest/api_schema/request/compute/v2/flavors.py
deleted file mode 100644
index bc459ad..0000000
--- a/tempest/api_schema/request/compute/v2/flavors.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# (c) 2014 Deutsche Telekom AG
-# 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 copy
-
-from tempest.api_schema.request.compute import flavors
-
-flavors_details = copy.deepcopy(flavors.common_flavor_details)
-
-flavor_list = copy.deepcopy(flavors.common_flavor_list)
-
-flavor_create = copy.deepcopy(flavors.common_admin_flavor_create)
-
-flavor_list["json-schema"]["properties"] = {
- "minRam": {
- "type": "integer",
- "results": {
- "gen_none": 400,
- "gen_string": 400
- }
- },
- "minDisk": {
- "type": "integer",
- "results": {
- "gen_none": 400,
- "gen_string": 400
- }
- }
-}
diff --git a/tempest/clients.py b/tempest/clients.py
index 4c677f0..0158efd 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -14,15 +14,15 @@
# under the License.
import copy
+
from oslo_log import log as logging
+
from tempest.common import negative_rest_client
from tempest import config
-from tempest import exceptions
from tempest.lib import auth
from tempest.lib import exceptions as lib_exc
from tempest.lib.services import clients
from tempest.services import baremetal
-from tempest.services import data_processing
from tempest.services import identity
from tempest.services import object_storage
from tempest.services import orchestration
@@ -37,7 +37,7 @@
default_params = config.service_client_config()
- # TODO(andreaf) This is only used by data_processing and baremetal clients,
+ # TODO(andreaf) This is only used by baremetal clients,
# and should be removed once they are out of Tempest
default_params_with_timeout_values = {
'build_interval': CONF.compute.build_interval,
@@ -82,12 +82,6 @@
build_interval=CONF.orchestration.build_interval,
build_timeout=CONF.orchestration.build_timeout,
**self.default_params)
- self.data_processing_client = data_processing.DataProcessingClient(
- self.auth_provider,
- CONF.data_processing.catalog_type,
- CONF.identity.region,
- endpoint_type=CONF.data_processing.endpoint_type,
- **self.default_params_with_timeout_values)
self.negative_client = negative_rest_client.NegativeRestClient(
self.auth_provider, service, **self.default_params)
@@ -115,7 +109,7 @@
configuration[service_for_config] = (
config.service_client_config(service_for_config))
except lib_exc.UnknownServiceClient:
- LOG.warn(
+ LOG.warning(
'Could not load configuration for service %s' % service)
return configuration
@@ -248,6 +242,8 @@
**params_v3)
self.inherited_roles_client = identity.v3.InheritedRolesClient(
self.auth_provider, **params_v3)
+ self.role_assignments_client = identity.v3.RoleAssignmentsClient(
+ self.auth_provider, **params_v3)
self.identity_services_v3_client = identity.v3.ServicesClient(
self.auth_provider, **params_v3)
self.policies_client = identity.v3.PoliciesClient(self.auth_provider,
@@ -270,65 +266,46 @@
CONF.identity.uri, **self.default_params)
else:
msg = 'Identity v2 API enabled, but no identity.uri set'
- raise exceptions.InvalidConfiguration(msg)
+ raise lib_exc.InvalidConfiguration(msg)
if CONF.identity_feature_enabled.api_v3:
if CONF.identity.uri_v3:
self.token_v3_client = identity.v3.V3TokenClient(
CONF.identity.uri_v3, **self.default_params)
else:
msg = 'Identity v3 API enabled, but no identity.uri_v3 set'
- raise exceptions.InvalidConfiguration(msg)
+ raise lib_exc.InvalidConfiguration(msg)
def _set_volume_clients(self):
# Mandatory parameters (always defined)
params = self.parameters['volume']
- self.volume_qos_client = volume.v1.QosSpecsClient(self.auth_provider,
- **params)
- self.volume_qos_v2_client = volume.v2.QosSpecsClient(
- self.auth_provider, **params)
- self.volume_services_client = volume.v1.ServicesClient(
- self.auth_provider, **params)
- self.volume_services_v2_client = volume.v2.ServicesClient(
- self.auth_provider, **params)
- self.backups_client = volume.v1.BackupsClient(self.auth_provider,
- **params)
- self.backups_v2_client = volume.v2.BackupsClient(self.auth_provider,
- **params)
- self.encryption_types_client = volume.v1.EncryptionTypesClient(
- self.auth_provider, **params)
- self.encryption_types_v2_client = volume.v2.EncryptionTypesClient(
- self.auth_provider, **params)
- self.snapshots_client = volume.v1.SnapshotsClient(self.auth_provider,
- **params)
- self.snapshots_v2_client = volume.v2.SnapshotsClient(
- self.auth_provider, **params)
- self.volumes_client = volume.v1.VolumesClient(self.auth_provider,
- **params)
- self.volumes_v2_client = volume.v2.VolumesClient(self.auth_provider,
- **params)
+ self.volume_qos_client = self.volume_v1.QosSpecsClient()
+ self.volume_qos_v2_client = self.volume_v2.QosSpecsClient()
+ self.volume_services_client = self.volume_v1.ServicesClient()
+ self.volume_services_v2_client = self.volume_v2.ServicesClient()
+ self.backups_client = self.volume_v1.BackupsClient()
+ self.backups_v2_client = self.volume_v2.BackupsClient()
+ self.encryption_types_client = self.volume_v1.EncryptionTypesClient()
+ self.encryption_types_v2_client = \
+ self.volume_v2.EncryptionTypesClient()
+ self.snapshots_client = self.volume_v1.SnapshotsClient()
+ self.snapshots_v2_client = self.volume_v2.SnapshotsClient()
+ self.volumes_client = self.volume_v1.VolumesClient()
+ self.volumes_v2_client = self.volume_v2.VolumesClient()
self.volume_messages_client = volume.v3.MessagesClient(
self.auth_provider, **params)
- self.volume_types_client = volume.v1.TypesClient(self.auth_provider,
- **params)
- self.volume_types_v2_client = volume.v2.TypesClient(self.auth_provider,
- **params)
- self.volume_hosts_client = volume.v1.HostsClient(self.auth_provider,
- **params)
- self.volume_hosts_v2_client = volume.v2.HostsClient(self.auth_provider,
- **params)
- self.volume_quotas_client = volume.v1.QuotasClient(self.auth_provider,
- **params)
- self.volume_quotas_v2_client = volume.v2.QuotasClient(
- self.auth_provider, **params)
- self.volumes_extension_client = volume.v1.ExtensionsClient(
- self.auth_provider, **params)
- self.volumes_v2_extension_client = volume.v2.ExtensionsClient(
- self.auth_provider, **params)
+ 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()
+ self.volume_hosts_v2_client = self.volume_v2.HostsClient()
+ self.volume_quotas_client = self.volume_v1.QuotasClient()
+ self.volume_quotas_v2_client = self.volume_v2.QuotasClient()
+ self.volumes_extension_client = self.volume_v1.ExtensionsClient()
+ self.volumes_v2_extension_client = self.volume_v2.ExtensionsClient()
self.volume_availability_zone_client = \
- volume.v1.AvailabilityZoneClient(self.auth_provider, **params)
+ self.volume_v1.AvailabilityZoneClient()
self.volume_v2_availability_zone_client = \
- volume.v2.AvailabilityZoneClient(self.auth_provider, **params)
+ self.volume_v2.AvailabilityZoneClient()
def _set_object_storage_clients(self):
# Mandatory parameters (always defined)
@@ -353,7 +330,7 @@
# kwargs for auth provider match the common ones used by service clients
default_params = config.service_client_config()
if credentials is None:
- raise exceptions.InvalidCredentials(
+ raise lib_exc.InvalidCredentials(
'Credentials must be specified')
auth_provider_class, auth_url = get_auth_provider_class(
credentials)
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index f9d7a9b..3d38e25 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -22,7 +22,7 @@
credentials for created users, so each user will be in separate tenant and
have the username, tenant_name, password and roles.
-**Usage:** ``tempest-account-generator [-h] [OPTIONS] accounts_file.yaml``.
+**Usage:** ``tempest account-generator [-h] [OPTIONS] accounts_file.yaml``.
Positional Arguments
--------------------
@@ -90,7 +90,7 @@
**-i VERSION**, **--identity-version VERSION** (Optional) Provisions accounts
using the specified version of the identity API. (default: '3').
-To see help on specific argument, please do: ``tempest-account-generator
+To see help on specific argument, please do: ``tempest account-generator
[OPTIONS] <accounts_file.yaml> -h``.
"""
import argparse
@@ -144,6 +144,13 @@
identity_version=identity_version,
name=opts.tag,
network_resources=network_resources,
+ neutron_available=CONF.service_available.neutron,
+ create_networks=CONF.auth.create_isolated_networks,
+ identity_admin_role=CONF.identity.admin_role,
+ identity_admin_domain_scope=CONF.identity.admin_domain_scope,
+ project_network_cidr=CONF.network.project_network_cidr,
+ project_network_mask_bits=CONF.network.project_network_mask_bits,
+ public_network_id=CONF.network.public_network_id,
admin_creds=admin_creds,
**credentials_factory.get_dynamic_provider_params())
@@ -255,9 +262,9 @@
def get_options():
- usage_string = ('tempest-account-generator [-h] <ARG> ...\n\n'
+ usage_string = ('tempest account-generator [-h] <ARG> ...\n\n'
'To see help on specific argument, do:\n'
- 'tempest-account-generator <ARG> -h')
+ 'tempest account-generator <ARG> -h')
parser = argparse.ArgumentParser(
description=DESCRIPTION,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 9758061..32b0ebb 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -18,6 +18,7 @@
from tempest.common import credentials_factory as credentials
from tempest.common import identity
+from tempest.common.utils import net_info
from tempest import config
from tempest import test
@@ -463,7 +464,7 @@
rid = router['id']
ports = [port for port
in ports_client.list_ports(device_id=rid)['ports']
- if port["device_owner"] == "network:router_interface"]
+ if net_info.is_router_interface_port(port)]
for port in ports:
client.remove_router_interface(rid, port_id=port['id'])
client.delete_router(rid)
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index ba1f1fa..99185d2 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -14,13 +14,13 @@
import os
import shutil
-import subprocess
import sys
from cliff import command
from oslo_config import generator
from oslo_log import log as logging
from six import moves
+from testrepository import commands
from tempest.cmd import workspace
@@ -93,7 +93,7 @@
testr_conf_file.write(testr_conf)
def get_configparser(self, conf_path):
- config_parse = moves.configparser.SafeConfigParser()
+ config_parse = moves.configparser.ConfigParser()
config_parse.optionxform = str
# get any existing values if a config file already exists
if os.path.isfile(conf_path):
@@ -167,16 +167,17 @@
self.generate_testr_conf(local_dir)
# setup local testr working dir
if not os.path.isdir(testr_dir):
- subprocess.call(['testr', 'init'], cwd=local_dir)
+ commands.run_argv(['testr', 'init', '-d', local_dir], sys.stdin,
+ sys.stdout, sys.stderr)
def take_action(self, parsed_args):
workspace_manager = workspace.WorkspaceManager(
parsed_args.workspace_path)
name = parsed_args.name or parsed_args.dir.split(os.path.sep)[-1]
- workspace_manager.register_new_workspace(
- name, parsed_args.dir, init=True)
config_dir = parsed_args.config_dir or get_tempest_default_config_dir()
if parsed_args.show_global_dir:
print("Global config dir is located at: %s" % config_dir)
sys.exit(0)
self.create_working_dir(parsed_args.dir, config_dir)
+ workspace_manager.register_new_workspace(
+ name, parsed_args.dir, init=True)
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index fef836c..5fa8b74 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -135,6 +135,12 @@
workspace_mgr = workspace.WorkspaceManager(
parsed_args.workspace_path)
path = workspace_mgr.get_workspace(parsed_args.workspace)
+ if not path:
+ sys.exit(
+ "The %r workspace isn't registered in "
+ "%r. Use 'tempest init' to "
+ "register the workspace." %
+ (parsed_args.workspace, workspace_mgr.path))
os.chdir(path)
# NOTE(mtreinish): tempest init should create a .testrepository dir
# but since workspaces can be imported let's sanity check and
@@ -264,8 +270,8 @@
run_thread = threading.Thread(target=run_argv_thread)
run_thread.start()
- returncodes['subunit-trace'] = subunit_trace.trace(subunit_r,
- sys.stdout)
+ returncodes['subunit-trace'] = subunit_trace.trace(
+ subunit_r, sys.stdout, post_fails=True, print_failures=True)
run_thread.join()
subunit_r.close()
# python version of pipefail
diff --git a/tempest/cmd/run_stress.py b/tempest/cmd/run_stress.py
deleted file mode 100755
index 7502c23..0000000
--- a/tempest/cmd/run_stress.py
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2013 Quanta Research Cambridge, Inc.
-#
-# 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 argparse
-import inspect
-import sys
-try:
- from unittest import loader
-except ImportError:
- # unittest in python 2.6 does not contain loader, so uses unittest2
- from unittest2 import loader
-import traceback
-import warnings
-
-from cliff import command
-from oslo_log import log as logging
-from oslo_serialization import jsonutils as json
-from testtools import testsuite
-
-from tempest.stress import driver
-
-LOG = logging.getLogger(__name__)
-
-
-def discover_stress_tests(path="./", filter_attr=None, call_inherited=False):
- """Discovers all tempest tests and create action out of them"""
- LOG.info("Start test discovery")
- tests = []
- testloader = loader.TestLoader()
- list = testloader.discover(path)
- for func in (testsuite.iterate_tests(list)):
- attrs = []
- try:
- method_name = getattr(func, '_testMethodName')
- full_name = "%s.%s.%s" % (func.__module__,
- func.__class__.__name__,
- method_name)
- test_func = getattr(func, method_name)
- # NOTE(mkoderer): this contains a list of all type attributes
- attrs = getattr(test_func, "__testtools_attrs")
- except Exception:
- next
- if 'stress' in attrs:
- if filter_attr is not None and filter_attr not in attrs:
- continue
- class_setup_per = getattr(test_func, "st_class_setup_per")
-
- action = {'action':
- "tempest.stress.actions.unit_test.UnitTest",
- 'kwargs': {"test_method": full_name,
- "class_setup_per": class_setup_per
- }
- }
- if (not call_inherited and
- getattr(test_func, "st_allow_inheritance") is not True):
- class_structure = inspect.getmro(test_func.im_class)
- if test_func.__name__ not in class_structure[0].__dict__:
- continue
- tests.append(action)
- return tests
-
-
-class TempestRunStress(command.Command):
-
- @staticmethod
- def display_deprecation_warning():
- warnings.simplefilter('once', category=DeprecationWarning)
- warnings.warn(
- 'Stress tests are deprecated and will be removed from Tempest '
- 'in the Newton release.',
- DeprecationWarning)
- warnings.resetwarnings()
-
- def get_parser(self, prog_name):
- self.display_deprecation_warning()
- pa = super(TempestRunStress, self).get_parser(prog_name)
- pa = add_arguments(pa)
- return pa
-
- def take_action(self, pa):
- try:
- action(pa)
- except Exception:
- LOG.exception("Failure in the stress test framework")
- traceback.print_exc()
- raise
-
- def get_description(self):
- return 'Run tempest stress tests'
-
-
-def add_arguments(parser):
- parser.add_argument('-d', '--duration', default=300, type=int,
- help="Duration of test in secs")
- parser.add_argument('-s', '--serial', action='store_true',
- help="Trigger running tests serially")
- parser.add_argument('-S', '--stop', action='store_true',
- default=False, help="Stop on first error")
- parser.add_argument('-n', '--number', type=int,
- help="How often an action is executed for each "
- "process")
- group = parser.add_mutually_exclusive_group(required=True)
- group.add_argument('-a', '--all', action='store_true',
- help="Execute all stress tests")
- parser.add_argument('-T', '--type',
- help="Filters tests of a certain type (e.g. gate)")
- parser.add_argument('-i', '--call-inherited', action='store_true',
- default=False,
- help="Call also inherited function with stress "
- "attribute")
- group.add_argument('-t', "--tests", nargs='?',
- help="Name of the file with test description")
- return parser
-
-
-def action(ns):
- result = 0
- if not ns.all:
- tests = json.load(open(ns.tests, 'r'))
- else:
- tests = discover_stress_tests(filter_attr=ns.type,
- call_inherited=ns.call_inherited)
-
- if ns.serial:
- # Duration is total time
- duration = ns.duration / len(tests)
- for test in tests:
- step_result = driver.stress_openstack([test],
- duration,
- ns.number,
- ns.stop)
- # NOTE(mkoderer): we just save the last result code
- if (step_result != 0):
- result = step_result
- if ns.stop:
- return result
- else:
- result = driver.stress_openstack(tests,
- ns.duration,
- ns.number,
- ns.stop)
- return result
-
-
-def main():
- TempestRunStress.display_deprecation_warning()
- parser = argparse.ArgumentParser(description='Run stress tests')
- pa = add_arguments(parser)
- ns = pa.parse_args()
- return action(ns)
-
-
-if __name__ == "__main__":
- try:
- sys.exit(main())
- except Exception:
- LOG.exception("Failure in the stress test framework")
- traceback.print_exc()
- sys.exit(1)
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index c36c9be..381f3df 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -286,7 +286,6 @@
'object_storage': 'swift',
'compute': 'nova',
'orchestration': 'heat',
- 'data_processing': 'sahara',
'baremetal': 'ironic',
'identity': 'keystone',
}
@@ -370,10 +369,9 @@
replace = opts.replace_ext
global CONF_PARSER
- outfile = sys.stdout
if update:
conf_file = _get_config_file()
- CONF_PARSER = moves.configparser.SafeConfigParser()
+ CONF_PARSER = moves.configparser.ConfigParser()
CONF_PARSER.optionxform = str
CONF_PARSER.readfp(conf_file)
diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py
index b36cf4e..3c58648 100644
--- a/tempest/cmd/workspace.py
+++ b/tempest/cmd/workspace.py
@@ -72,7 +72,10 @@
@lockutils.synchronized('workspaces', external=True)
def get_workspace(self, name):
- """Returns the workspace that has the given name"""
+ """Returns the workspace that has the given name
+
+ If the workspace isn't registered then `None` is returned.
+ """
self._populate()
return self.workspaces.get(name)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 8e9f0b0..318eb10 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -129,7 +129,6 @@
**kwargs)
# handle the case of multiple servers
- servers = []
if multiple_create_request:
# Get servers created which name match with name param.
body_servers = clients.servers_client.list_servers()
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index c22afc1..5634958 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -17,8 +17,8 @@
from tempest.common import dynamic_creds
from tempest.common import preprov_creds
from tempest import config
-from tempest import exceptions
from tempest.lib import auth
+from tempest.lib import exceptions
CONF = config.CONF
@@ -80,6 +80,16 @@
network_resources=network_resources,
identity_version=identity_version,
admin_creds=admin_creds,
+ identity_admin_domain_scope=CONF.identity.admin_domain_scope,
+ identity_admin_role=CONF.identity.admin_role,
+ extra_roles=CONF.auth.tempest_roles,
+ neutron_available=CONF.service_available.neutron,
+ project_network_cidr=CONF.network.project_network_cidr,
+ project_network_mask_bits=CONF.network.project_network_mask_bits,
+ public_network_id=CONF.network.public_network_id,
+ create_networks=(CONF.auth.create_isolated_networks and not
+ CONF.baremetal.driver_enabled),
+ resource_prefix=CONF.resources_prefix,
**get_dynamic_provider_params())
else:
if CONF.auth.test_accounts_file:
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 04c9645..2763d16 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -17,21 +17,23 @@
import six
from tempest import clients
-from tempest.common import cred_client
-from tempest.common import cred_provider
-from tempest.common.utils import data_utils
-from tempest import config
-from tempest import exceptions
+from tempest.lib.common import cred_client
+from tempest.lib.common import cred_provider
+from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
-CONF = config.CONF
LOG = logging.getLogger(__name__)
class DynamicCredentialProvider(cred_provider.CredentialProvider):
def __init__(self, identity_version, name=None, network_resources=None,
- credentials_domain=None, admin_role=None, admin_creds=None):
+ credentials_domain=None, admin_role=None, admin_creds=None,
+ identity_admin_domain_scope=False,
+ identity_admin_role='admin', extra_roles=None,
+ neutron_available=False, create_networks=True,
+ project_network_cidr=None, project_network_mask_bits=None,
+ public_network_id=None, resource_prefix=None):
"""Creates credentials dynamically for tests
A credential provider that, based on an initial set of
@@ -48,6 +50,23 @@
:param dict network_resources: network resources to be created for
the created credentials
:param Credentials admin_creds: initial admin credentials
+ :param bool identity_admin_domain_scope: Set to true if admin should be
+ scoped to the domain. By
+ default this is False and the
+ admin role is scoped to the
+ project.
+ :param str identity_admin_role: The role name to use for admin
+ :param list extra_roles: A list of strings for extra roles that should
+ be assigned to all created users
+ :param bool neutron_available: Whether we are running in an environemnt
+ with neutron
+ :param bool create_networks: Whether dynamic project networks should be
+ created or not
+ :param project_network_cidr: The CIDR to use for created project
+ networks
+ :param project_network_mask_bits: The network mask bits to use for
+ created project networks
+ :param public_network_id: The id for the public network to use
"""
super(DynamicCredentialProvider, self).__init__(
identity_version=identity_version, admin_role=admin_role,
@@ -56,7 +75,16 @@
self.network_resources = network_resources
self._creds = {}
self.ports = []
+ self.resource_prefix = resource_prefix or ''
+ self.neutron_available = neutron_available
+ self.create_networks = create_networks
+ self.project_network_cidr = project_network_cidr
+ self.project_network_mask_bits = project_network_mask_bits
+ self.public_network_id = public_network_id
self.default_admin_creds = admin_creds
+ self.identity_admin_domain_scope = identity_admin_domain_scope
+ self.identity_admin_role = identity_admin_role or 'admin'
+ self.extra_roles = extra_roles or []
(self.identity_admin_client,
self.tenants_admin_client,
self.users_admin_client,
@@ -98,7 +126,7 @@
else:
# We use a dedicated client manager for identity client in case we
# need a different token scope for them.
- scope = 'domain' if CONF.identity.admin_domain_scope else 'project'
+ scope = 'domain' if self.identity_admin_domain_scope else 'project'
identity_os = clients.Manager(self.default_admin_creds,
scope=scope)
return (identity_os.identity_v3_client,
@@ -124,7 +152,7 @@
"""
root = self.name
- project_name = data_utils.rand_name(root)
+ project_name = data_utils.rand_name(root, prefix=self.resource_prefix)
project_desc = project_name + "-desc"
project = self.creds_client.create_project(
name=project_name, description=project_desc)
@@ -133,21 +161,20 @@
# having the same ID in both makes it easier to match them and debug.
username = project_name
user_password = data_utils.rand_password()
- email = data_utils.rand_name(root) + "@example.com"
+ email = data_utils.rand_name(
+ root, prefix=self.resource_prefix) + "@example.com"
user = self.creds_client.create_user(
username, user_password, project, email)
- if 'user' in user:
- user = user['user']
role_assigned = False
if admin:
self.creds_client.assign_user_role(user, project, self.admin_role)
role_assigned = True
if (self.identity_version == 'v3' and
- CONF.identity.admin_domain_scope):
+ self.identity_admin_domain_scope):
self.creds_client.assign_user_role_on_domain(
- user, CONF.identity.admin_role)
+ user, self.identity_admin_role)
# Add roles specified in config file
- for conf_role in CONF.auth.tempest_roles:
+ for conf_role in self.extra_roles:
self.creds_client.assign_user_role(user, project, conf_role)
role_assigned = True
# Add roles requested by caller
@@ -191,26 +218,27 @@
if self.network_resources['router']:
if (not self.network_resources['subnet'] or
not self.network_resources['network']):
- raise exceptions.InvalidConfiguration(
+ raise lib_exc.InvalidConfiguration(
'A router requires a subnet and network')
elif self.network_resources['subnet']:
if not self.network_resources['network']:
- raise exceptions.InvalidConfiguration(
+ raise lib_exc.InvalidConfiguration(
'A subnet requires a network')
elif self.network_resources['dhcp']:
- raise exceptions.InvalidConfiguration('DHCP requires a subnet')
+ raise lib_exc.InvalidConfiguration('DHCP requires a subnet')
- data_utils.rand_name_root = data_utils.rand_name(self.name)
+ rand_name_root = data_utils.rand_name(
+ self.name, prefix=self.resource_prefix)
if not self.network_resources or self.network_resources['network']:
- network_name = data_utils.rand_name_root + "-network"
+ network_name = rand_name_root + "-network"
network = self._create_network(network_name, tenant_id)
try:
if not self.network_resources or self.network_resources['subnet']:
- subnet_name = data_utils.rand_name_root + "-subnet"
+ subnet_name = rand_name_root + "-subnet"
subnet = self._create_subnet(subnet_name, tenant_id,
network['id'])
if not self.network_resources or self.network_resources['router']:
- router_name = data_utils.rand_name_root + "-router"
+ router_name = rand_name_root + "-router"
router = self._create_router(router_name, tenant_id)
self._add_router_interface(router['id'], subnet['id'])
except Exception:
@@ -236,8 +264,8 @@
return resp_body['network']
def _create_subnet(self, subnet_name, tenant_id, network_id):
- base_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- mask_bits = CONF.network.project_network_mask_bits
+ base_cidr = netaddr.IPNetwork(self.project_network_cidr)
+ mask_bits = self.project_network_mask_bits
for subnet_cidr in base_cidr.subnet(mask_bits):
try:
if self.network_resources:
@@ -266,7 +294,7 @@
def _create_router(self, router_name, tenant_id):
external_net_id = dict(
- network_id=CONF.network.public_network_id)
+ network_id=self.public_network_id)
resp_body = self.routers_admin_client.create_router(
name=router_name,
external_gateway_info=external_net_id,
@@ -290,9 +318,8 @@
# Maintained until tests are ported
LOG.info("Acquired dynamic creds:\n credentials: %s"
% credentials)
- if (CONF.service_available.neutron and
- not CONF.baremetal.driver_enabled and
- CONF.auth.create_isolated_networks):
+ if (self.neutron_available and
+ self.create_networks):
network, subnet, router = self._create_network_resources(
credentials.tenant_id)
credentials.set_resources(network=network, subnet=subnet,
@@ -407,7 +434,7 @@
# "circular dependency". So here just use try...except to
# ensure tenant deletion without big changes.
try:
- if CONF.service_available.neutron:
+ if self.neutron_available:
self._cleanup_default_secgroup(creds.tenant_id)
except lib_exc.NotFound:
LOG.warning("failed to cleanup tenant %s's secgroup" %
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 5992d24..5e23696 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -21,10 +21,10 @@
import yaml
from tempest import clients
-from tempest.common import cred_provider
from tempest.common import fixed_network
from tempest import exceptions
from tempest.lib import auth
+from tempest.lib.common import cred_provider
from tempest.lib import exceptions as lib_exc
LOG = logging.getLogger(__name__)
@@ -35,7 +35,7 @@
with open(path, 'r') as yaml_file:
accounts = yaml.load(yaml_file)
except IOError:
- raise exceptions.InvalidConfiguration(
+ raise lib_exc.InvalidConfiguration(
'The path for the test accounts file: %s '
'could not be found' % path)
return accounts
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 7cb9ebe..9ec217f 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -19,7 +19,6 @@
from oslo_log import log as logging
from tempest import config
-from tempest import exceptions
from tempest.lib.common import ssh
from tempest.lib.common.utils import test_utils
import tempest.lib.exceptions
@@ -218,8 +217,8 @@
supported_clients = ['udhcpc', 'dhclient']
dhcp_client = CONF.scenario.dhcp_client
if dhcp_client not in supported_clients:
- raise exceptions.InvalidConfiguration('%s DHCP client unsupported'
- % dhcp_client)
+ raise tempest.lib.exceptions.InvalidConfiguration(
+ '%s DHCP client unsupported' % dhcp_client)
if dhcp_client == 'udhcpc' and not fixed_ip:
raise ValueError("need to set 'fixed_ip' for udhcpc client")
return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
diff --git a/tempest/services/volume/v2/json/backups_client.py b/tempest/common/utils/net_info.py
similarity index 64%
rename from tempest/services/volume/v2/json/backups_client.py
rename to tempest/common/utils/net_info.py
index 78bab82..9b0a083 100644
--- a/tempest/services/volume/v2/json/backups_client.py
+++ b/tempest/common/utils/net_info.py
@@ -1,4 +1,3 @@
-# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -12,10 +11,15 @@
# 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 re
-from tempest.services.volume.base import base_backups_client
+RE_OWNER = re.compile('^network:.*router_.*interface.*')
-class BackupsClient(base_backups_client.BaseBackupsClient):
- """Client class to send CRUD Volume V2 API requests"""
- api_version = "v2"
+def _is_owner_router_interface(owner):
+ return bool(RE_OWNER.match(owner))
+
+
+def is_router_interface_port(port):
+ """Based on the port attributes determines is it a router interface."""
+ return _is_owner_router_interface(port['device_owner'])
diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py
index f0d3da3..867b3dd 100644
--- a/tempest/common/utils/net_utils.py
+++ b/tempest/common/utils/net_utils.py
@@ -51,3 +51,23 @@
return addrs
msg = "Insufficient IP addresses available"
raise lib_exc.BadRequest(message=msg)
+
+
+def get_ping_payload_size(mtu, ip_version):
+ """Return the maximum size of ping payload that will fit into MTU."""
+ if not mtu:
+ return None
+ if ip_version == 4:
+ ip_header = 20
+ icmp_header = 8
+ else:
+ ip_header = 40
+ icmp_header = 4
+ res = mtu - ip_header - icmp_header
+ if res < 0:
+ raise lib_exc.BadRequest(
+ message='MTU = %(mtu)d is too low for IPv%(ip_version)d' % {
+ 'mtu': mtu,
+ 'ip_version': ip_version,
+ })
+ return res
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 9d307ee..92bce5f 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -92,7 +92,7 @@
caller = test_utils.find_test_caller()
if caller:
message = '(%s) %s' % (caller, message)
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
old_status = server_status
old_task_state = task_state
@@ -111,7 +111,7 @@
raise exceptions.BuildErrorException(server_id=server_id)
if int(time.time()) - start_time >= client.build_timeout:
- raise exceptions.TimeoutException
+ raise lib_exc.TimeoutException
time.sleep(client.build_interval)
@@ -163,7 +163,7 @@
caller = test_utils.find_test_caller()
if caller:
message = '(%s) %s' % (caller, message)
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
def wait_for_volume_status(client, volume_id, status):
@@ -186,7 +186,7 @@
'within the required time (%s s).' %
(volume_id, status, volume_status,
client.build_timeout))
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
def wait_for_snapshot_status(client, snapshot_id, status):
@@ -207,7 +207,28 @@
'within the required time (%s s).' %
(snapshot_id, status, snapshot_status,
client.build_timeout))
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
+
+
+def wait_for_backup_status(client, backup_id, status):
+ """Waits for a Backup to reach a given status."""
+ body = client.show_backup(backup_id)['backup']
+ backup_status = body['status']
+ start = int(time.time())
+
+ while backup_status != status:
+ time.sleep(client.build_interval)
+ body = client.show_backup(backup_id)['backup']
+ backup_status = body['status']
+ if backup_status == 'error' and backup_status != status:
+ raise lib_exc.VolumeBackupException(backup_id=backup_id)
+
+ if int(time.time()) - start >= client.build_timeout:
+ message = ('Volume backup %s failed to reach %s status '
+ '(current %s) within the required time (%s s).' %
+ (backup_id, status, backup_status,
+ client.build_timeout))
+ raise lib_exc.TimeoutException(message)
def wait_for_bm_node_status(client, node_id, attr, status):
@@ -236,4 +257,36 @@
caller = test_utils.find_test_caller()
if caller:
message = '(%s) %s' % (caller, message)
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
+
+
+def wait_for_qos_operations(client, qos_id, operation, args=None):
+ """Waits for a qos operations to be completed.
+
+ NOTE : operation value is required for wait_for_qos_operations()
+ operation = 'qos-key' / 'disassociate' / 'disassociate-all'
+ args = keys[] when operation = 'qos-key'
+ args = volume-type-id disassociated when operation = 'disassociate'
+ args = None when operation = 'disassociate-all'
+ """
+ start_time = int(time.time())
+ while True:
+ if operation == 'qos-key-unset':
+ body = client.show_qos(qos_id)['qos_specs']
+ if not any(key in body['specs'] for key in args):
+ return
+ elif operation == 'disassociate':
+ body = client.show_association_qos(qos_id)['qos_associations']
+ if not any(args in body[i]['id'] for i in range(0, len(body))):
+ return
+ elif operation == 'disassociate-all':
+ body = client.show_association_qos(qos_id)['qos_associations']
+ if not body:
+ return
+ else:
+ msg = (" operation value is either not defined or incorrect.")
+ raise lib_exc.UnprocessableEntity(msg)
+
+ if int(time.time()) - start_time >= client.build_timeout:
+ raise lib_exc.TimeoutException
+ time.sleep(client.build_interval)
diff --git a/tempest/config.py b/tempest/config.py
index 1d89eb0..bc9215c 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -245,7 +245,7 @@
"projects. If multiple networks are available for a "
"project, this is the network which will be used for "
"creating servers if tempest does not create a network or "
- "s network is not specified elsewhere. It may be used for "
+ "a network is not specified elsewhere. It may be used for "
"ssh validation only if floating IPs are disabled."),
cfg.StrOpt('catalog_type',
default='compute',
@@ -304,6 +304,12 @@
title="Enabled Compute Service Features")
ComputeFeaturesGroup = [
+ # NOTE(mriedem): This is a feature toggle for bug 1175464 which is fixed in
+ # mitaka and newton. This option can be removed after liberty-eol.
+ cfg.BoolOpt('allow_port_security_disabled',
+ default=False,
+ help='Does the test environment support creating ports in a '
+ 'network where port security is disabled?'),
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
@@ -312,7 +318,13 @@
help='A list of enabled compute extensions with a special '
'entry all which indicates every extension is enabled. '
'Each extension should be specified with alias name. '
- 'Empty list indicates all extensions are disabled'),
+ 'Empty list indicates all extensions are disabled',
+ deprecated_for_removal=True,
+ deprecated_reason='The Nova extensions API and mechanism '
+ 'is deprecated. This option will be '
+ 'removed when all releases supported '
+ 'by tempest no longer contain the Nova '
+ 'extensions API and mechanism.'),
cfg.BoolOpt('change_password',
default=False,
help="Does the test environment support changing the admin "
@@ -333,10 +345,12 @@
cfg.BoolOpt('suspend',
default=True,
help="Does the test environment support suspend/resume?"),
+ cfg.BoolOpt('cold_migration',
+ default=True,
+ help="Does the test environment support cold migration?"),
cfg.BoolOpt('live_migration',
default=True,
- help="Does the test environment support live migration "
- "available?"),
+ help="Does the test environment support live migration?"),
cfg.BoolOpt('metadata_service',
default=True,
help="Does the test environment support metadata service? "
@@ -404,7 +418,10 @@
"list indicates all filters are disabled. The full "
"available list of filters is in nova.conf: "
"DEFAULT.scheduler_available_filters"),
-
+ cfg.BoolOpt('swap_volume',
+ default=False,
+ help='Does the test environment support in-place swapping of '
+ 'volumes attached to a server instance?'),
]
@@ -540,6 +557,15 @@
default=["1.0.0.0/16", "2.0.0.0/16"],
help="List of ip pools"
" for subnetpools creation"),
+ # TODO(ylobankov): Delete this option once the Liberty release is EOL.
+ cfg.BoolOpt('dvr_extra_resources',
+ default=True,
+ help="Whether or not to create internal network, subnet, "
+ "port and add network interface to distributed router "
+ "in L3 agent scheduler test. Extra resources need to be "
+ "provisioned in order to bind router to L3 agent in the "
+ "Liberty release or older, and are not required since "
+ "the Mitaka release.")
]
network_feature_group = cfg.OptGroup(name='network-feature-enabled',
@@ -565,6 +591,9 @@
default=True,
help="Does the test environment support changing"
" port admin state"),
+ cfg.BoolOpt('port_security',
+ default=False,
+ help="Does the test environment support port security?"),
]
validation_group = cfg.OptGroup(name='validation',
@@ -870,72 +899,6 @@
help="Value must match heat configuration of the same name."),
]
-data_processing_group = cfg.OptGroup(name="data-processing",
- title="Data Processing options")
-
-DataProcessingGroup = [
- cfg.StrOpt('catalog_type',
- default='data-processing',
- deprecated_group="data_processing",
- help="Catalog type of the data processing service."),
- cfg.StrOpt('endpoint_type',
- default='publicURL',
- choices=['public', 'admin', 'internal',
- 'publicURL', 'adminURL', 'internalURL'],
- deprecated_group="data_processing",
- help="The endpoint type to use for the data processing "
- "service."),
-]
-
-
-data_processing_feature_group = cfg.OptGroup(
- name="data-processing-feature-enabled",
- title="Enabled Data Processing features")
-
-DataProcessingFeaturesGroup = [
- cfg.ListOpt('plugins',
- default=["vanilla", "cdh"],
- deprecated_group="data_processing-feature-enabled",
- help="List of enabled data processing plugins")
-]
-
-stress_group = cfg.OptGroup(name='stress', title='Stress Test Options')
-
-StressGroup = [
- cfg.StrOpt('nova_logdir',
- help='Directory containing log files on the compute nodes'),
- cfg.IntOpt('max_instances',
- default=16,
- help='Maximum number of instances to create during test.'),
- cfg.StrOpt('controller',
- help='Controller host.'),
- # new stress options
- cfg.StrOpt('target_controller',
- help='Controller host.'),
- cfg.StrOpt('target_ssh_user',
- help='ssh user.'),
- cfg.StrOpt('target_private_key_path',
- help='Path to private key.'),
- cfg.StrOpt('target_logfiles',
- help='regexp for list of log files.'),
- cfg.IntOpt('log_check_interval',
- default=60,
- help='time (in seconds) between log file error checks.'),
- cfg.IntOpt('default_thread_number_per_action',
- default=4,
- help='The number of threads created while stress test.'),
- cfg.BoolOpt('leave_dirty_stack',
- default=False,
- help='Prevent the cleaning (tearDownClass()) between'
- ' each stress test run if an exception occurs'
- ' during this run.'),
- cfg.BoolOpt('full_clean_stack',
- default=False,
- help='Allows a full cleaning process after a stress test.'
- ' Caution : this cleanup will remove every objects of'
- ' every project.')
-]
-
scenario_group = cfg.OptGroup(name='scenario', title='Scenario Test Options')
@@ -1144,9 +1107,6 @@
(object_storage_group, ObjectStoreGroup),
(object_storage_feature_group, ObjectStoreFeaturesGroup),
(orchestration_group, OrchestrationGroup),
- (data_processing_group, DataProcessingGroup),
- (data_processing_feature_group, DataProcessingFeaturesGroup),
- (stress_group, StressGroup),
(scenario_group, ScenarioGroup),
(service_available_group, ServiceAvailableGroup),
(debug_group, DebugGroup),
@@ -1211,10 +1171,6 @@
self.object_storage_feature_enabled = _CONF[
'object-storage-feature-enabled']
self.orchestration = _CONF.orchestration
- self.data_processing = _CONF['data-processing']
- self.data_processing_feature_enabled = _CONF[
- 'data-processing-feature-enabled']
- self.stress = _CONF.stress
self.scenario = _CONF.scenario
self.service_available = _CONF.service_available
self.debug = _CONF.debug
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 272f6e3..43f919a 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -17,18 +17,10 @@
from tempest.lib import exceptions
-class InvalidConfiguration(exceptions.TempestException):
- message = "Invalid Configuration"
-
-
class InvalidServiceTag(exceptions.TempestException):
message = "Invalid service tag"
-class TimeoutException(exceptions.TempestException):
- message = "Request timed out"
-
-
class BuildErrorException(exceptions.TempestException):
message = "Server %(server_id)s failed to build and is in ERROR status"
@@ -53,10 +45,6 @@
message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
-class VolumeBackupException(exceptions.TempestException):
- message = "Volume backup %(backup_id)s failed and is in ERROR status"
-
-
class StackBuildErrorException(exceptions.TempestException):
message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
"due to '%(stack_status_reason)s'")
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index e2d6585..4123ae5 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -19,7 +19,7 @@
PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
- 'ironic', 'savanna', 'heat', 'sahara']
+ 'ironic', 'heat', 'sahara']
PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
TEST_DEFINITION = re.compile(r'^\s*def test.*')
diff --git a/tempest/lib/api_schema/response/compute/v2_1/images.py b/tempest/lib/api_schema/response/compute/v2_1/images.py
index b0f1934..f65b9d8 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/images.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/images.py
@@ -19,11 +19,13 @@
image_links = copy.deepcopy(parameter_types.links)
image_links['items']['properties'].update({'type': {'type': 'string'}})
+image_status_enums = ['ACTIVE', 'SAVING', 'DELETED', 'ERROR', 'UNKNOWN']
+
common_image_schema = {
'type': 'object',
'properties': {
'id': {'type': 'string'},
- 'status': {'type': 'string'},
+ 'status': {'enum': image_status_enums},
'updated': {'type': 'string'},
'links': image_links,
'name': {'type': ['string', 'null']},
diff --git a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
index 07cc890..3cc5ca4 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
@@ -94,3 +94,14 @@
'format': 'data-time'
}
}
+
+power_state = {
+ 'type': 'integer',
+ # 0: NOSTATE
+ # 1: RUNNING
+ # 3: PAUSED
+ # 4: SHUTDOWN
+ # 6: CRASHED
+ # 7: SUSPENDED
+ 'enum': [0, 1, 3, 4, 6, 7]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 44497db..63e8467 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -170,7 +170,7 @@
# attributes.
'OS-EXT-STS:task_state': {'type': ['string', 'null']},
'OS-EXT-STS:vm_state': {'type': 'string'},
- 'OS-EXT-STS:power_state': {'type': 'integer'},
+ 'OS-EXT-STS:power_state': parameter_types.power_state,
'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
diff --git a/tempest/lib/api_schema/response/compute/v2_16/servers.py b/tempest/lib/api_schema/response/compute/v2_16/servers.py
index 6868110..3eb658f 100644
--- a/tempest/lib/api_schema/response/compute/v2_16/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_16/servers.py
@@ -77,7 +77,7 @@
'OS-EXT-AZ:availability_zone': {'type': 'string'},
'OS-EXT-STS:task_state': {'type': ['string', 'null']},
'OS-EXT-STS:vm_state': {'type': 'string'},
- 'OS-EXT-STS:power_state': {'type': 'integer'},
+ 'OS-EXT-STS:power_state': parameter_types.power_state,
'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
diff --git a/tempest/lib/api_schema/response/compute/v2_3/servers.py b/tempest/lib/api_schema/response/compute/v2_3/servers.py
index ee16333..f24103e 100644
--- a/tempest/lib/api_schema/response/compute/v2_3/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_3/servers.py
@@ -85,7 +85,7 @@
'OS-EXT-AZ:availability_zone': {'type': 'string'},
'OS-EXT-STS:task_state': {'type': ['string', 'null']},
'OS-EXT-STS:vm_state': {'type': 'string'},
- 'OS-EXT-STS:power_state': {'type': 'integer'},
+ 'OS-EXT-STS:power_state': parameter_types.power_state,
'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index be3aa49..1239ac5 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -69,7 +69,8 @@
lines[line_no - 1] = ''.join(('{%s:s}' % patch_id, lines[line_no - 1]))
self.source_files[filename] = self._quote('\n').join(lines)
- def _save_changes(self, filename, source):
+ @staticmethod
+ def _save_changes(filename, source):
print('%s fixed' % filename)
with open(filename, 'w') as f:
f.write(source)
diff --git a/tempest/common/cred_client.py b/tempest/lib/common/cred_client.py
similarity index 100%
rename from tempest/common/cred_client.py
rename to tempest/lib/common/cred_client.py
diff --git a/tempest/common/cred_provider.py b/tempest/lib/common/cred_provider.py
similarity index 100%
rename from tempest/common/cred_provider.py
rename to tempest/lib/common/cred_provider.py
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 8507f8a..2d2771f 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -661,8 +661,7 @@
time.sleep(delay)
resp, resp_body = self._request(method, url,
headers=headers, body=body)
- self._error_checker(method, url, headers, body,
- resp, resp_body)
+ self._error_checker(resp, resp_body)
return resp, resp_body
def _get_retry_after_delay(self, resp):
@@ -710,8 +709,7 @@
raise ValueError("Failed to parse date %s" % val)
return time.mktime(parts)
- def _error_checker(self, method, url,
- headers, body, resp, resp_body):
+ def _error_checker(self, resp, resp_body):
# NOTE(mtreinish): Check for httplib response from glance_http. The
# object can't be used here because importing httplib breaks httplib2.
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index c13f41a..4226cd6 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -36,9 +36,11 @@
class Client(object):
def __init__(self, host, username, password=None, timeout=300, pkey=None,
- channel_timeout=10, look_for_keys=False, key_filename=None):
+ channel_timeout=10, look_for_keys=False, key_filename=None,
+ port=22):
self.host = host
self.username = username
+ self.port = port
self.password = password
if isinstance(pkey, six.string_types):
pkey = paramiko.RSAKey.from_private_key(
@@ -58,17 +60,17 @@
paramiko.AutoAddPolicy())
_start_time = time.time()
if self.pkey is not None:
- LOG.info("Creating ssh connection to '%s' as '%s'"
+ LOG.info("Creating ssh connection to '%s:%d' as '%s'"
" with public key authentication",
- self.host, self.username)
+ self.host, self.port, self.username)
else:
- LOG.info("Creating ssh connection to '%s' as '%s'"
+ LOG.info("Creating ssh connection to '%s:%d' as '%s'"
" with password %s",
- self.host, self.username, str(self.password))
+ self.host, self.port, self.username, str(self.password))
attempts = 0
while True:
try:
- ssh.connect(self.host, username=self.username,
+ ssh.connect(self.host, port=self.port, username=self.username,
password=self.password,
look_for_keys=self.look_for_keys,
key_filename=self.key_filename,
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 70be40c..4095c77 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -19,6 +19,7 @@
import string
import uuid
+from debtcollector import removals
from oslo_utils import netutils
import six.moves
@@ -153,7 +154,7 @@
This generates a string with an arbitrary number of characters, generated
by looping the base_text string. If the size is smaller than the size of
- base_text, returning string is shrinked to the size.
+ base_text, returning string is shrunk to the size.
:param int size: a returning characters size
:param str base_text: a string you want to repeat
:return: size string
@@ -175,6 +176,10 @@
for i in range(size)])
+@removals.remove(
+ message="use get_ipv6_addr_by_EUI64 from oslo_utils.netutils",
+ version="Newton",
+ removal_version="Ocata")
def get_ipv6_addr_by_EUI64(cidr, mac):
"""Generate a IPv6 addr by EUI-64 with CIDR and MAC
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index e3f25e6..a6c01bb 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -149,6 +149,10 @@
message = "Unexpected response code received"
+class InvalidConfiguration(TempestException):
+ message = "Invalid Configuration"
+
+
class InvalidIdentityVersion(TempestException):
message = "Invalid version %(identity_version)s of the identity service"
@@ -239,3 +243,7 @@
class PluginRegistrationException(TempestException):
message = "Error registering plugin %(name)s: %(detailed_error)s"
+
+
+class VolumeBackupException(TempestException):
+ message = "Volume backup %(backup_id)s failed and is in ERROR status"
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index adf666b..2e5c457 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -25,6 +25,7 @@
from tempest.lib.services import compute
from tempest.lib.services import image
from tempest.lib.services import network
+from tempest.lib.services import volume
LOG = logging.getLogger(__name__)
@@ -40,7 +41,9 @@
'compute': compute,
'image.v1': image.v1,
'image.v2': image.v2,
- 'network': network
+ 'network': network,
+ 'volume.v1': volume.v1,
+ 'volume.v2': volume.v2
}
@@ -49,8 +52,7 @@
# NOTE(andreaf) This list will exists only as long the remain clients
# are migrated to tempest.lib, and it will then be deleted without
# deprecation or advance notice
- return set(['identity.v2', 'identity.v3', 'object-storage', 'volume.v1',
- 'volume.v2', 'volume.v3'])
+ return set(['identity.v2', 'identity.v3', 'object-storage', 'volume.v3'])
def available_modules():
diff --git a/tempest/lib/services/compute/agents_client.py b/tempest/lib/services/compute/agents_client.py
old mode 100755
new mode 100644
index 3f05d3b..169d978
--- a/tempest/lib/services/compute/agents_client.py
+++ b/tempest/lib/services/compute/agents_client.py
@@ -26,8 +26,9 @@
def list_agents(self, **params):
"""List all agent builds.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listbuilds
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listbuilds
"""
url = 'os-agents'
if params:
@@ -40,8 +41,9 @@
def create_agent(self, **kwargs):
"""Create an agent build.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#agentbuild
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#agentbuild
"""
post_body = json.dumps({'agent': kwargs})
resp, body = self.post('os-agents', post_body)
@@ -52,8 +54,9 @@
def delete_agent(self, agent_id):
"""Delete an existing agent build.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteBuild
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteBuild
"""
resp, body = self.delete("os-agents/%s" % agent_id)
self.validate_response(schema.delete_agent, resp, body)
@@ -62,8 +65,9 @@
def update_agent(self, agent_id, **kwargs):
"""Update an agent build.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updatebuild
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updatebuild
"""
put_body = json.dumps({'para': kwargs})
resp, body = self.put('os-agents/%s' % agent_id, put_body)
diff --git a/tempest/lib/services/compute/aggregates_client.py b/tempest/lib/services/compute/aggregates_client.py
index 7ad14bc..c1a6c8c 100644
--- a/tempest/lib/services/compute/aggregates_client.py
+++ b/tempest/lib/services/compute/aggregates_client.py
@@ -40,8 +40,9 @@
def create_aggregate(self, **kwargs):
"""Create a new aggregate.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createAggregate
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createAggregate
"""
post_body = json.dumps({'aggregate': kwargs})
resp, body = self.post('os-aggregates', post_body)
@@ -53,8 +54,9 @@
def update_aggregate(self, aggregate_id, **kwargs):
"""Update an aggregate.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateAggregate
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateAggregate
"""
put_body = json.dumps({'aggregate': kwargs})
resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body)
@@ -84,8 +86,9 @@
def add_host(self, aggregate_id, **kwargs):
"""Add a host to the given aggregate.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#addHost
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#addHost
"""
post_body = json.dumps({'add_host': kwargs})
resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
@@ -97,8 +100,9 @@
def remove_host(self, aggregate_id, **kwargs):
"""Remove a host from the given aggregate.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#removeAggregateHost
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#removeAggregateHost
"""
post_body = json.dumps({'remove_host': kwargs})
resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
@@ -110,8 +114,9 @@
def set_metadata(self, aggregate_id, **kwargs):
"""Replace the aggregate's existing metadata with new metadata.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#addAggregateMetadata
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#addAggregateMetadata
"""
post_body = json.dumps({'set_metadata': kwargs})
resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
diff --git a/tempest/lib/services/compute/fixed_ips_client.py b/tempest/lib/services/compute/fixed_ips_client.py
index c25ac2c..682ee86 100644
--- a/tempest/lib/services/compute/fixed_ips_client.py
+++ b/tempest/lib/services/compute/fixed_ips_client.py
@@ -32,8 +32,9 @@
def reserve_fixed_ip(self, fixed_ip, **kwargs):
"""Reserve/Unreserve a fixed IP.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#reserveIP
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#reserveIP
"""
url = "os-fixed-ips/%s/action" % fixed_ip
resp, body = self.post(url, json.dumps(kwargs))
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
old mode 100755
new mode 100644
index ae1700c..4d1044b
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -30,8 +30,9 @@
def list_flavors(self, detail=False, **params):
"""Lists flavors.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listFlavors
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listFlavors
"""
url = 'flavors'
_schema = schema.list_flavors
@@ -50,8 +51,9 @@
def show_flavor(self, flavor_id):
"""Shows details for a flavor.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showFlavor
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showFlavor
"""
resp, body = self.get("flavors/%s" % flavor_id)
body = json.loads(body)
@@ -61,8 +63,9 @@
def create_flavor(self, **kwargs):
"""Create a new flavor or instance type.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createFlavor
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createFlavor
"""
if kwargs.get('ephemeral'):
kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral')
@@ -79,8 +82,9 @@
def delete_flavor(self, flavor_id):
"""Delete the given flavor.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteFlavor
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteFlavor
"""
resp, body = self.delete("flavors/{0}".format(flavor_id))
self.validate_response(schema.delete_flavor, resp, body)
@@ -104,8 +108,9 @@
def set_flavor_extra_spec(self, flavor_id, **kwargs):
"""Set extra Specs to the mentioned flavor.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createFlavorExtraSpec
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createFlavorExtraSpec
"""
post_body = json.dumps({'extra_specs': kwargs})
resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
@@ -118,8 +123,9 @@
def list_flavor_extra_specs(self, flavor_id):
"""Get extra Specs details of the mentioned flavor.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listFlavorExtraSpecs
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listFlavorExtraSpecs
"""
resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
body = json.loads(body)
@@ -130,8 +136,9 @@
def show_flavor_extra_spec(self, flavor_id, key):
"""Get extra Specs key-value of the mentioned flavor and key.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showFlavorExtraSpec
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showFlavorExtraSpec
"""
resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id,
key))
@@ -144,8 +151,9 @@
def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
"""Update specified extra Specs of the mentioned flavor and key.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateFlavorExtraSpec
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateFlavorExtraSpec
"""
resp, body = self.put('flavors/%s/os-extra_specs/%s' %
(flavor_id, key), json.dumps(kwargs))
@@ -160,8 +168,9 @@
# to keep backwards compatibility.
"""Unset extra Specs from the mentioned flavor.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteFlavorExtraSpec
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteFlavorExtraSpec
"""
resp, body = self.delete('flavors/%s/os-extra_specs/%s' %
(flavor_id, key))
@@ -171,8 +180,9 @@
def list_flavor_access(self, flavor_id):
"""Get flavor access information given the flavor id.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listFlavorAccess
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listFlavorAccess
"""
resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id)
body = json.loads(body)
@@ -183,8 +193,9 @@
def add_flavor_access(self, flavor_id, tenant_id):
"""Add flavor access for the specified tenant.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#addFlavorAccess
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#addFlavorAccess
"""
post_body = {
'addTenantAccess': {
@@ -201,8 +212,9 @@
def remove_flavor_access(self, flavor_id, tenant_id):
"""Remove flavor access from the specified tenant.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#removeFlavorAccess
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#removeFlavorAccess
"""
post_body = {
'removeTenantAccess': {
diff --git a/tempest/lib/services/compute/floating_ips_client.py b/tempest/lib/services/compute/floating_ips_client.py
old mode 100755
new mode 100644
index 6922c48..744e14c
--- a/tempest/lib/services/compute/floating_ips_client.py
+++ b/tempest/lib/services/compute/floating_ips_client.py
@@ -27,8 +27,9 @@
def list_floating_ips(self, **params):
"""Returns a list of all floating IPs filtered by any parameters.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listfloatingipsObject
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listfloatingipsObject
"""
url = 'os-floating-ips'
if params:
@@ -42,8 +43,9 @@
def show_floating_ip(self, floating_ip_id):
"""Get the details of a floating IP.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showFloatingIP
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showFloatingIP
"""
url = "os-floating-ips/%s" % floating_ip_id
resp, body = self.get(url)
@@ -54,8 +56,9 @@
def create_floating_ip(self, **kwargs):
"""Allocate a floating IP to the project.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createFloatingIP
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createFloatingIP
"""
url = 'os-floating-ips'
post_body = json.dumps(kwargs)
@@ -67,8 +70,9 @@
def delete_floating_ip(self, floating_ip_id):
"""Deletes the provided floating IP from the project.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteFloatingIP
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteFloatingIP
"""
url = "os-floating-ips/%s" % floating_ip_id
resp, body = self.delete(url)
diff --git a/tempest/lib/services/compute/hosts_client.py b/tempest/lib/services/compute/hosts_client.py
index 16b5edd..1b93b00 100644
--- a/tempest/lib/services/compute/hosts_client.py
+++ b/tempest/lib/services/compute/hosts_client.py
@@ -45,8 +45,9 @@
def update_host(self, hostname, **kwargs):
"""Update a host.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#enablehost
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#enablehost
"""
request_body = {
diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py
index 3dc3749..e937c13 100644
--- a/tempest/lib/services/compute/images_client.py
+++ b/tempest/lib/services/compute/images_client.py
@@ -27,8 +27,9 @@
def create_image(self, server_id, **kwargs):
"""Create an image of the original server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createImage
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createImage
"""
post_body = {'createImage': kwargs}
@@ -41,8 +42,9 @@
def list_images(self, detail=False, **params):
"""Return a list of all images filtered by any parameter.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listImages
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listImages
"""
url = 'images'
_schema = schema.list_images
@@ -81,8 +83,9 @@
def set_image_metadata(self, image_id, meta):
"""Set the metadata for an image.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createImageMetadata
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createImageMetadata
"""
post_body = json.dumps({'metadata': meta})
resp, body = self.put('images/%s/metadata' % image_id, post_body)
@@ -93,8 +96,9 @@
def update_image_metadata(self, image_id, meta):
"""Update the metadata for an image.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateImageMetadata
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateImageMetadata
"""
post_body = json.dumps({'metadata': meta})
resp, body = self.post('images/%s/metadata' % image_id, post_body)
@@ -112,8 +116,9 @@
def set_image_metadata_item(self, image_id, key, meta):
"""Set the value for a specific image metadata key.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#setImageMetadataItem
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#setImageMetadataItem
"""
post_body = json.dumps({'meta': meta})
resp, body = self.put('images/%s/metadata/%s' % (image_id, key),
diff --git a/tempest/lib/services/compute/interfaces_client.py b/tempest/lib/services/compute/interfaces_client.py
index 80192a1..37157a4 100644
--- a/tempest/lib/services/compute/interfaces_client.py
+++ b/tempest/lib/services/compute/interfaces_client.py
@@ -31,8 +31,9 @@
def create_interface(self, server_id, **kwargs):
"""Create an interface.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createAttachInterface
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createAttachInterface
"""
post_body = {'interfaceAttachment': kwargs}
post_body = json.dumps(post_body)
diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py
old mode 100755
new mode 100644
index 2246739..c3f1781
--- a/tempest/lib/services/compute/keypairs_client.py
+++ b/tempest/lib/services/compute/keypairs_client.py
@@ -30,8 +30,9 @@
def list_keypairs(self, **params):
"""Lists keypairs that are associated with the account.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listKeypairs
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listKeypairs
"""
url = 'os-keypairs'
if params:
@@ -45,8 +46,9 @@
def show_keypair(self, keypair_name, **params):
"""Shows details for a keypair that is associated with the account.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showKeypair
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showKeypair
"""
url = "os-keypairs/%s" % keypair_name
if params:
@@ -60,8 +62,9 @@
def create_keypair(self, **kwargs):
"""Create a keypair.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createKeypair
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createKeypair
"""
post_body = json.dumps({'keypair': kwargs})
resp, body = self.post("os-keypairs", body=post_body)
@@ -73,8 +76,9 @@
def delete_keypair(self, keypair_name, **params):
"""Deletes a keypair.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteKeypair
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteKeypair
"""
url = "os-keypairs/%s" % keypair_name
if params:
diff --git a/tempest/lib/services/compute/migrations_client.py b/tempest/lib/services/compute/migrations_client.py
index c3bdba7..375cbda 100644
--- a/tempest/lib/services/compute/migrations_client.py
+++ b/tempest/lib/services/compute/migrations_client.py
@@ -30,8 +30,9 @@
def list_migrations(self, **params):
"""List all migrations.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listMigrations
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listMigrations
"""
url = 'os-migrations'
diff --git a/tempest/lib/services/compute/quota_classes_client.py b/tempest/lib/services/compute/quota_classes_client.py
index 9dc04ad..523a306 100644
--- a/tempest/lib/services/compute/quota_classes_client.py
+++ b/tempest/lib/services/compute/quota_classes_client.py
@@ -35,8 +35,9 @@
def update_quota_class_set(self, quota_class_id, **kwargs):
"""Update the quota class's limits for one or more resources.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updatequota
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updatequota
"""
post_body = json.dumps({'quota_class_set': kwargs})
diff --git a/tempest/lib/services/compute/quotas_client.py b/tempest/lib/services/compute/quotas_client.py
index 6d41f4b..a2b0397 100644
--- a/tempest/lib/services/compute/quotas_client.py
+++ b/tempest/lib/services/compute/quotas_client.py
@@ -45,8 +45,9 @@
def update_quota_set(self, tenant_id, user_id=None, **kwargs):
"""Updates the tenant's quota limits for one or more resources.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateQuota
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateQuota
"""
post_body = json.dumps({'quota_set': kwargs})
diff --git a/tempest/lib/services/compute/security_group_default_rules_client.py b/tempest/lib/services/compute/security_group_default_rules_client.py
index d57c8e0..e2d3c98 100644
--- a/tempest/lib/services/compute/security_group_default_rules_client.py
+++ b/tempest/lib/services/compute/security_group_default_rules_client.py
@@ -26,9 +26,9 @@
def create_security_default_group_rule(self, **kwargs):
"""Create security group default rule.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html
- #createSecGroupDefaultRule
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createSecGroupDefaultRule
"""
post_body = json.dumps({'security_group_default_rule': kwargs})
url = 'os-security-group-default-rules'
diff --git a/tempest/lib/services/compute/security_group_rules_client.py b/tempest/lib/services/compute/security_group_rules_client.py
index c969b81..3121e24 100644
--- a/tempest/lib/services/compute/security_group_rules_client.py
+++ b/tempest/lib/services/compute/security_group_rules_client.py
@@ -26,8 +26,9 @@
def create_security_group_rule(self, **kwargs):
"""Create a new security group rule.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createSecGroupRule
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createSecGroupRule
"""
post_body = json.dumps({'security_group_rule': kwargs})
url = 'os-security-group-rules'
diff --git a/tempest/lib/services/compute/security_groups_client.py b/tempest/lib/services/compute/security_groups_client.py
old mode 100755
new mode 100644
index 386c214..a247346
--- a/tempest/lib/services/compute/security_groups_client.py
+++ b/tempest/lib/services/compute/security_groups_client.py
@@ -28,8 +28,9 @@
def list_security_groups(self, **params):
"""List all security groups for a user.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listSecGroups
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listSecGroups
"""
url = 'os-security-groups'
@@ -44,8 +45,9 @@
def show_security_group(self, security_group_id):
"""Get the details of a Security Group.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showSecGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showSecGroup
"""
url = "os-security-groups/%s" % security_group_id
resp, body = self.get(url)
@@ -56,8 +58,9 @@
def create_security_group(self, **kwargs):
"""Create a new security group.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createSecGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createSecGroup
"""
post_body = json.dumps({'security_group': kwargs})
resp, body = self.post('os-security-groups', post_body)
@@ -68,8 +71,9 @@
def update_security_group(self, security_group_id, **kwargs):
"""Update a security group.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateSecGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateSecGroup
"""
post_body = json.dumps({'security_group': kwargs})
resp, body = self.put('os-security-groups/%s' % security_group_id,
@@ -81,8 +85,9 @@
def delete_security_group(self, security_group_id):
"""Delete the provided Security Group.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteSecGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteSecGroup
"""
resp, body = self.delete(
'os-security-groups/%s' % security_group_id)
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
index e370457..9ba8d38 100644
--- a/tempest/lib/services/compute/server_groups_client.py
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -26,8 +26,9 @@
def create_server_group(self, **kwargs):
"""Create the server group.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createServerGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createServerGroup
"""
post_body = json.dumps({'server_group': kwargs})
resp, body = self.post('os-server-groups', post_body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
old mode 100755
new mode 100644
index 8b22be0..24557d8
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -47,8 +47,13 @@
def create_server(self, **kwargs):
"""Create server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createServer
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/compute/#create-server
+
+ :param name: Server name
+ :param imageRef: Image reference (UUID)
+ :param flavorRef: Flavor reference (UUID or full URL)
Most parameters except the following are passed to the API without
any changes.
@@ -87,8 +92,9 @@
def update_server(self, server_id, **kwargs):
"""Update server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateServer
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateServer
Most parameters except the following are passed to the API without
any changes.
@@ -107,8 +113,9 @@
def show_server(self, server_id):
"""Get server details.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showServer
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showServer
"""
resp, body = self.get("servers/%s" % server_id)
body = json.loads(body)
@@ -119,8 +126,9 @@
def delete_server(self, server_id):
"""Delete server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteServer
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteServer
"""
resp, body = self.delete("servers/%s" % server_id)
self.validate_response(schema.delete_server, resp, body)
@@ -129,10 +137,10 @@
def list_servers(self, detail=False, **params):
"""List servers.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listServers
- and http://developer.openstack.org/
- api-ref-compute-v2.1.html#listDetailServers
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listServers
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listDetailServers
"""
url = 'servers'
@@ -153,8 +161,9 @@
def list_addresses(self, server_id):
"""Lists all addresses for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#list-ips
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#list-ips
"""
resp, body = self.get("servers/%s/ips" % server_id)
body = json.loads(body)
@@ -183,16 +192,18 @@
def create_backup(self, server_id, **kwargs):
"""Backup a server instance.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createBackup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createBackup
"""
return self.action(server_id, "createBackup", **kwargs)
def change_password(self, server_id, **kwargs):
"""Change the root password for the server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#changePassword
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#changePassword
"""
return self.action(server_id, 'changePassword', **kwargs)
@@ -218,16 +229,18 @@
def reboot_server(self, server_id, **kwargs):
"""Reboot a server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#reboot
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#reboot
"""
return self.action(server_id, 'reboot', **kwargs)
def rebuild_server(self, server_id, image_ref, **kwargs):
"""Rebuild a server with a new image.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#rebuild
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#rebuild
Most parameters except the following are passed to the API without
any changes.
@@ -247,8 +260,9 @@
def resize_server(self, server_id, flavor_ref, **kwargs):
"""Change the flavor of a server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#resize
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#resize
Most parameters except the following are passed to the API without
any changes.
@@ -262,8 +276,9 @@
def confirm_resize_server(self, server_id, **kwargs):
"""Confirm the flavor change for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#confirmResize
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#confirmResize
"""
return self.action(server_id, 'confirmResize',
schema.server_actions_confirm_resize,
@@ -272,16 +287,18 @@
def revert_resize_server(self, server_id, **kwargs):
"""Revert a server back to its original flavor.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#revertResize
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#revertResize
"""
return self.action(server_id, 'revertResize', **kwargs)
def list_server_metadata(self, server_id):
"""Lists all metadata for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listServerMetadata
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listServerMetadata
"""
resp, body = self.get("servers/%s/metadata" % server_id)
body = json.loads(body)
@@ -291,8 +308,9 @@
def set_server_metadata(self, server_id, meta, no_metadata_field=False):
"""Sets one or more metadata items for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createServerMetadata
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createServerMetadata
"""
if no_metadata_field:
post_body = ""
@@ -307,8 +325,9 @@
def update_server_metadata(self, server_id, meta):
"""Updates one or more metadata items for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#updateServerMetadata
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#updateServerMetadata
"""
post_body = json.dumps({'metadata': meta})
resp, body = self.post('servers/%s/metadata' % server_id,
@@ -321,8 +340,9 @@
def show_server_metadata_item(self, server_id, key):
"""Shows details for a metadata item, by key, for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showServerMetadataItem
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showServerMetadataItem
"""
resp, body = self.get("servers/%s/metadata/%s" % (server_id, key))
body = json.loads(body)
@@ -333,8 +353,9 @@
def set_server_metadata_item(self, server_id, key, meta):
"""Sets a metadata item, by key, for a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#setServerMetadataItem
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#setServerMetadataItem
"""
post_body = json.dumps({'meta': meta})
resp, body = self.put('servers/%s/metadata/%s' % (server_id, key),
@@ -347,8 +368,9 @@
def delete_server_metadata_item(self, server_id, key):
"""Deletes a metadata item, by key, from a server.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteServerMetadataItem
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteServerMetadataItem
"""
resp, body = self.delete("servers/%s/metadata/%s" %
(server_id, key))
@@ -359,24 +381,27 @@
def stop_server(self, server_id, **kwargs):
"""Stops a running server and changes its status to SHUTOFF.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#stop
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#stop
"""
return self.action(server_id, 'os-stop', **kwargs)
def start_server(self, server_id, **kwargs):
"""Starts a stopped server and changes its status to ACTIVE.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#start
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#start
"""
return self.action(server_id, 'os-start', **kwargs)
def attach_volume(self, server_id, **kwargs):
"""Attaches a volume to a server instance.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#attachVolume
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#attachVolume
"""
post_body = json.dumps({'volumeAttachment': kwargs})
resp, body = self.post('servers/%s/os-volume_attachments' % server_id,
@@ -397,8 +422,9 @@
def detach_volume(self, server_id, volume_id): # noqa
"""Detaches a volume from a server instance.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteVolumeAttachment
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteVolumeAttachment
"""
resp, body = self.delete('servers/%s/os-volume_attachments/%s' %
(server_id, volume_id))
@@ -408,9 +434,9 @@
def show_volume_attachment(self, server_id, volume_id):
"""Return details about the given volume attachment.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#
- getVolumeAttachmentDetails
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#getVolumeAttachmentDetails
"""
resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
server_id, volume_id))
@@ -421,8 +447,9 @@
def list_volume_attachments(self, server_id):
"""Returns the list of volume attachments for a given instance.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listVolumeAttachments
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listVolumeAttachments
"""
resp, body = self.get('servers/%s/os-volume_attachments' % (
server_id))
@@ -433,8 +460,9 @@
def add_security_group(self, server_id, **kwargs):
"""Add a security group to the server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#addSecurityGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#addSecurityGroup
"""
# TODO(oomichi): The api-site doesn't contain this API description.
# So the above should be changed to the api-site link after
@@ -445,8 +473,9 @@
def remove_security_group(self, server_id, **kwargs):
"""Remove a security group from the server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#removeSecurityGroup
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#removeSecurityGroup
"""
# TODO(oomichi): The api-site doesn't contain this API description.
# So the above should be changed to the api-site link after
@@ -457,104 +486,117 @@
def live_migrate_server(self, server_id, **kwargs):
"""This should be called with administrator privileges.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#migrateLive
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#migrateLive
"""
return self.action(server_id, 'os-migrateLive', **kwargs)
def migrate_server(self, server_id, **kwargs):
"""Migrate a server to a new host.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#migrate
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#migrate
"""
return self.action(server_id, 'migrate', **kwargs)
def lock_server(self, server_id, **kwargs):
"""Lock the given server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#lock
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#lock
"""
return self.action(server_id, 'lock', **kwargs)
def unlock_server(self, server_id, **kwargs):
"""UNlock the given server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#unlock
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#unlock
"""
return self.action(server_id, 'unlock', **kwargs)
def suspend_server(self, server_id, **kwargs):
"""Suspend the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#suspend
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#suspend
"""
return self.action(server_id, 'suspend', **kwargs)
def resume_server(self, server_id, **kwargs):
"""Un-suspend the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#resume
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#resume
"""
return self.action(server_id, 'resume', **kwargs)
def pause_server(self, server_id, **kwargs):
"""Pause the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#pause
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#pause
"""
return self.action(server_id, 'pause', **kwargs)
def unpause_server(self, server_id, **kwargs):
"""Un-pause the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#unpause
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#unpause
"""
return self.action(server_id, 'unpause', **kwargs)
def reset_state(self, server_id, **kwargs):
"""Reset the state of a server to active/error.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#resetState
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#resetState
"""
return self.action(server_id, 'os-resetState', **kwargs)
def shelve_server(self, server_id, **kwargs):
"""Shelve the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#shelve
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#shelve
"""
return self.action(server_id, 'shelve', **kwargs)
def unshelve_server(self, server_id, **kwargs):
"""Un-shelve the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#unshelve
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#unshelve
"""
return self.action(server_id, 'unshelve', **kwargs)
def shelve_offload_server(self, server_id, **kwargs):
"""Shelve-offload the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#shelveOffload
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#shelveOffload
"""
return self.action(server_id, 'shelveOffload', **kwargs)
def get_console_output(self, server_id, **kwargs):
"""Get console output.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#getConsoleOutput
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#getConsoleOutput
"""
return self.action(server_id, 'os-getConsoleOutput',
schema.get_console_output, **kwargs)
@@ -570,16 +612,18 @@
def rescue_server(self, server_id, **kwargs):
"""Rescue the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#rescue
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#rescue
"""
return self.action(server_id, 'rescue', schema.rescue_server, **kwargs)
def unrescue_server(self, server_id):
"""Unrescue the provided server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#unrescue
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#unrescue
"""
return self.action(server_id, 'unrescue')
@@ -607,40 +651,45 @@
def force_delete_server(self, server_id, **kwargs):
"""Force delete a server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#forceDelete
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#forceDelete
"""
return self.action(server_id, 'forceDelete', **kwargs)
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#restore
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#restore
"""
return self.action(server_id, 'restore', **kwargs)
def reset_network(self, server_id, **kwargs):
"""Reset the Network of a server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#resetNetwork
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#resetNetwork
"""
return self.action(server_id, 'resetNetwork', **kwargs)
def inject_network_info(self, server_id, **kwargs):
"""Inject the Network Info into server.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#injectNetworkInfo
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#injectNetworkInfo
"""
return self.action(server_id, 'injectNetworkInfo', **kwargs)
def get_vnc_console(self, server_id, **kwargs):
"""Get URL of VNC console.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#getVNCConsole
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#getVNCConsole
"""
return self.action(server_id, "os-getVNCConsole",
schema.get_vnc_console, **kwargs)
@@ -648,15 +697,17 @@
def add_fixed_ip(self, server_id, **kwargs):
"""Add a fixed IP to server instance.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#addFixedIp
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#addFixedIp
"""
return self.action(server_id, 'addFixedIp', **kwargs)
def remove_fixed_ip(self, server_id, **kwargs):
"""Remove input fixed IP from input server instance.
- Available params: http://developer.openstack.org/
- api-ref-compute-v2.1.html#removeFixedIp
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#removeFixedIp
"""
return self.action(server_id, 'removeFixedIp', **kwargs)
diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py
old mode 100755
new mode 100644
index b6dbe28..0dbd1b2
--- a/tempest/lib/services/compute/services_client.py
+++ b/tempest/lib/services/compute/services_client.py
@@ -27,8 +27,9 @@
def list_services(self, **params):
"""Lists all running Compute services for a tenant.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listServices
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listServices
"""
url = 'os-services'
if params:
@@ -42,8 +43,9 @@
def enable_service(self, **kwargs):
"""Enable service on a host.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#enableScheduling
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#enableScheduling
"""
post_body = json.dumps(kwargs)
resp, body = self.put('os-services/enable', post_body)
@@ -54,8 +56,9 @@
def disable_service(self, **kwargs):
"""Disable service on a host.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#disableScheduling
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#disableScheduling
"""
post_body = json.dumps(kwargs)
resp, body = self.put('os-services/disable', post_body)
diff --git a/tempest/lib/services/compute/snapshots_client.py b/tempest/lib/services/compute/snapshots_client.py
index be41957..fde5288 100644
--- a/tempest/lib/services/compute/snapshots_client.py
+++ b/tempest/lib/services/compute/snapshots_client.py
@@ -27,8 +27,9 @@
def create_snapshot(self, volume_id, **kwargs):
"""Create a snapshot.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createSnapshot
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createSnapshot
"""
post_body = {
'volume_id': volume_id
diff --git a/tempest/lib/services/compute/versions_client.py b/tempest/lib/services/compute/versions_client.py
index eb4e7e9..b2052c3 100644
--- a/tempest/lib/services/compute/versions_client.py
+++ b/tempest/lib/services/compute/versions_client.py
@@ -40,6 +40,7 @@
def list_versions(self):
version_url = self._get_base_version_url()
resp, body = self.raw_request(version_url, 'GET')
+ self._error_checker(resp, body)
body = json.loads(body)
self.validate_response(schema.list_versions, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -56,6 +57,7 @@
# we need a token for this request
resp, body = self.raw_request(version_url, 'GET',
{'X-Auth-Token': self.token})
+ self._error_checker(resp, body)
body = json.loads(body)
self.validate_response(schema.get_one_version, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/volumes_client.py b/tempest/lib/services/compute/volumes_client.py
old mode 100755
new mode 100644
index 2787779..b75f22e
--- a/tempest/lib/services/compute/volumes_client.py
+++ b/tempest/lib/services/compute/volumes_client.py
@@ -27,8 +27,9 @@
def list_volumes(self, detail=False, **params):
"""List all the volumes created.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#listVolumes
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listVolumes
"""
url = 'os-volumes'
@@ -45,8 +46,9 @@
def show_volume(self, volume_id):
"""Return the details of a single volume.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#showVolume
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#showVolume
"""
url = "os-volumes/%s" % volume_id
resp, body = self.get(url)
@@ -57,8 +59,9 @@
def create_volume(self, **kwargs):
"""Create a new Volume.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#createVolume
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#createVolume
"""
post_body = json.dumps({'volume': kwargs})
resp, body = self.post('os-volumes', post_body)
@@ -69,8 +72,9 @@
def delete_volume(self, volume_id):
"""Delete the Specified Volume.
- Available params: see http://developer.openstack.org/
- api-ref-compute-v2.1.html#deleteVolume
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#deleteVolume
"""
resp, body = self.delete("os-volumes/%s" % volume_id)
self.validate_response(schema.delete_volume, resp, body)
diff --git a/tempest/lib/services/identity/v2/endpoints_client.py b/tempest/lib/services/identity/v2/endpoints_client.py
index f7b265d..770e8ae 100644
--- a/tempest/lib/services/identity/v2/endpoints_client.py
+++ b/tempest/lib/services/identity/v2/endpoints_client.py
@@ -23,8 +23,9 @@
def create_endpoint(self, **kwargs):
"""Create an endpoint for service.
- Available params: http://developer.openstack.org/
- api-ref-identity-v2-ext.html#createEndpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#createEndpoint
"""
post_body = json.dumps({'endpoint': kwargs})
diff --git a/tempest/lib/services/identity/v2/roles_client.py b/tempest/lib/services/identity/v2/roles_client.py
index aaa75f1..635d013 100644
--- a/tempest/lib/services/identity/v2/roles_client.py
+++ b/tempest/lib/services/identity/v2/roles_client.py
@@ -22,8 +22,9 @@
def create_role(self, **kwargs):
"""Create a role.
- Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#createRole
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#createRole
"""
post_body = json.dumps({'role': kwargs})
resp, body = self.post('OS-KSADM/roles', post_body)
@@ -34,12 +35,11 @@
def show_role(self, role_id_or_name):
"""Get a role by its id or name.
- Available params: see
- http://developer.openstack.org/
- api-ref-identity-v2-ext.html#showRoleByID
- OR
- http://developer.openstack.org/
- api-ref-identity-v2-ext.html#showRoleByName
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#showRoleByID
+ OR
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#showRoleByName
"""
resp, body = self.get('OS-KSADM/roles/%s' % role_id_or_name)
self.expected_success(200, resp.status)
@@ -49,8 +49,9 @@
def list_roles(self, **params):
"""Returns roles.
- Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#listRoles
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#listRoles
"""
url = 'OS-KSADM/roles'
if params:
@@ -63,8 +64,9 @@
def delete_role(self, role_id):
"""Delete a role.
- Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#deleteRole
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#deleteRole
"""
resp, body = self.delete('OS-KSADM/roles/%s' % role_id)
self.expected_success(204, resp.status)
@@ -73,9 +75,9 @@
def create_user_role_on_project(self, tenant_id, user_id, role_id):
"""Add roles to a user on a tenant.
- Available params: see
- http://developer.openstack.org/
- api-ref-identity-v2-ext.html#grantRoleToUserOnTenant
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#grantRoleToUserOnTenant
"""
resp, body = self.put('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
(tenant_id, user_id, role_id), "")
@@ -97,9 +99,9 @@
def delete_role_from_user_on_project(self, tenant_id, user_id, role_id):
"""Removes a role assignment for a user on a tenant.
- Available params: see
- http://developer.openstack.org/
- api-ref-identity-v2-ext.html#revokeRoleFromUserOnTenant
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#revokeRoleFromUserOnTenant
"""
resp, body = self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
(tenant_id, user_id, role_id))
diff --git a/tempest/lib/services/identity/v2/services_client.py b/tempest/lib/services/identity/v2/services_client.py
old mode 100755
new mode 100644
index c26d419..b3f94aa
--- a/tempest/lib/services/identity/v2/services_client.py
+++ b/tempest/lib/services/identity/v2/services_client.py
@@ -24,8 +24,9 @@
def create_service(self, **kwargs):
"""Create a service.
- Available params: see http://developer.openstack.org/api-ref/identity/
- v2-ext/?expanded=#create-service-admin-extension
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-ext/?expanded=#create-service-admin-extension
"""
post_body = json.dumps({'OS-KSADM:service': kwargs})
resp, body = self.post('/OS-KSADM/services', post_body)
@@ -44,8 +45,9 @@
def list_services(self, **params):
"""List Service - Returns Services.
- Available params: see http://developer.openstack.org/api-ref/identity/
- v2-ext/?expanded=#list-services-admin-extension
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-ext/?expanded=#list-services-admin-extension
"""
url = '/OS-KSADM/services'
if params:
diff --git a/tempest/lib/services/identity/v2/tenants_client.py b/tempest/lib/services/identity/v2/tenants_client.py
index f92c703..b687332 100644
--- a/tempest/lib/services/identity/v2/tenants_client.py
+++ b/tempest/lib/services/identity/v2/tenants_client.py
@@ -24,9 +24,9 @@
def create_tenant(self, **kwargs):
"""Create a tenant
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- create-tenant
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-tenant
"""
post_body = json.dumps({'tenant': kwargs})
resp, body = self.post('tenants', post_body)
@@ -37,8 +37,9 @@
def delete_tenant(self, tenant_id):
"""Delete a tenant.
- Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#deleteTenant
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#deleteTenant
"""
resp, body = self.delete('tenants/%s' % str(tenant_id))
self.expected_success(204, resp.status)
@@ -47,9 +48,9 @@
def show_tenant(self, tenant_id):
"""Get tenant details.
- Available params: see
- http://developer.openstack.org/
- api-ref-identity-v2-ext.html#admin-showTenantById
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#admin-showTenantById
"""
resp, body = self.get('tenants/%s' % str(tenant_id))
self.expected_success(200, resp.status)
@@ -59,9 +60,9 @@
def list_tenants(self, **params):
"""Returns tenants.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- list-tenants-admin-endpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-tenants-admin-endpoint
"""
url = 'tenants'
if params:
@@ -74,9 +75,9 @@
def update_tenant(self, tenant_id, **kwargs):
"""Updates a tenant.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- update-tenant
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#update-tenant
"""
if 'id' not in kwargs:
kwargs['id'] = tenant_id
@@ -89,9 +90,9 @@
def list_tenant_users(self, tenant_id, **params):
"""List users for a Tenant.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- list-users-on-a-tenant
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-users-on-a-tenant
"""
url = '/tenants/%s/users' % tenant_id
if params:
diff --git a/tempest/lib/services/identity/v2/users_client.py b/tempest/lib/services/identity/v2/users_client.py
index 2a266d9..f20fdc4 100644
--- a/tempest/lib/services/identity/v2/users_client.py
+++ b/tempest/lib/services/identity/v2/users_client.py
@@ -22,9 +22,9 @@
def create_user(self, **kwargs):
"""Create a user.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- create-user-admin-endpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-user-admin-endpoint
"""
post_body = json.dumps({'user': kwargs})
resp, body = self.post('users', post_body)
@@ -35,9 +35,9 @@
def update_user(self, user_id, **kwargs):
"""Updates a user.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- update-user-admin-endpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#update-user-admin-endpoint
"""
put_body = json.dumps({'user': kwargs})
resp, body = self.put('users/%s' % user_id, put_body)
@@ -48,8 +48,9 @@
def show_user(self, user_id):
"""GET a user.
- Available params: see http://developer.openstack.org/
- api-ref-identity-admin-v2.html#admin-showUser
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-admin-v2.html#admin-showUser
"""
resp, body = self.get("users/%s" % user_id)
self.expected_success(200, resp.status)
@@ -59,8 +60,9 @@
def delete_user(self, user_id):
"""Delete a user.
- Available params: see http://developer.openstack.org/
- api-ref-identity-admin-v2.html#admin-deleteUser
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-admin-v2.html#admin-deleteUser
"""
resp, body = self.delete("users/%s" % user_id)
self.expected_success(204, resp.status)
@@ -69,9 +71,9 @@
def list_users(self, **params):
"""Get the list of users.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v2-admin/index.html#
- list-users-admin-endpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-users-admin-endpoint
"""
url = "users"
if params:
@@ -84,8 +86,9 @@
def update_user_enabled(self, user_id, **kwargs):
"""Enables or disables a user.
- Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#enableUser
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-identity-v2-ext.html#enableUser
"""
# NOTE: The URL (users/<id>/enabled) is different from the api-site
# one (users/<id>/OS-KSADM/enabled) , but they are the same API
diff --git a/tempest/lib/services/identity/v3/credentials_client.py b/tempest/lib/services/identity/v3/credentials_client.py
index c063cae..6e5fd31 100644
--- a/tempest/lib/services/identity/v3/credentials_client.py
+++ b/tempest/lib/services/identity/v3/credentials_client.py
@@ -29,47 +29,47 @@
def create_credential(self, **kwargs):
"""Creates a credential.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-credential
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-credential
"""
post_body = json.dumps({'credential': kwargs})
resp, body = self.post('credentials', post_body)
self.expected_success(201, resp.status)
body = json.loads(body)
- body['credential']['blob'] = json.loads(body['credential']['blob'])
return rest_client.ResponseBody(resp, body)
def update_credential(self, credential_id, **kwargs):
"""Updates a credential.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-credential
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-credential
"""
post_body = json.dumps({'credential': kwargs})
resp, body = self.patch('credentials/%s' % credential_id, post_body)
self.expected_success(200, resp.status)
body = json.loads(body)
- body['credential']['blob'] = json.loads(body['credential']['blob'])
return rest_client.ResponseBody(resp, body)
def show_credential(self, credential_id):
"""To GET Details of a credential.
- For API details, see http://developer.openstack.org/
- api-ref/identity/v3/index.html#
- show-credential-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#show-credential-details
"""
resp, body = self.get('credentials/%s' % credential_id)
self.expected_success(200, resp.status)
body = json.loads(body)
- body['credential']['blob'] = json.loads(body['credential']['blob'])
return rest_client.ResponseBody(resp, body)
def list_credentials(self, **params):
"""Lists out all the available credentials.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-credentials
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-credentials
"""
url = 'credentials'
if params:
@@ -82,8 +82,9 @@
def delete_credential(self, credential_id):
"""Deletes a credential.
- For API details, see http://developer.openstack.org/
- api-ref/identity/v3/#delete-credential
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#delete-credential
"""
resp, body = self.delete('credentials/%s' % credential_id)
self.expected_success(204, resp.status)
diff --git a/tempest/lib/services/identity/v3/endpoints_client.py b/tempest/lib/services/identity/v3/endpoints_client.py
index 3bb3deb..c4c0d8d 100644
--- a/tempest/lib/services/identity/v3/endpoints_client.py
+++ b/tempest/lib/services/identity/v3/endpoints_client.py
@@ -35,8 +35,9 @@
def create_endpoint(self, **kwargs):
"""Create endpoint.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-endpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-endpoint
"""
post_body = json.dumps({'endpoint': kwargs})
resp, body = self.post('endpoints', post_body)
@@ -47,8 +48,9 @@
def update_endpoint(self, endpoint_id, **kwargs):
"""Updates an endpoint with given parameters.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-endpoint
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-endpoint
"""
post_body = json.dumps({'endpoint': kwargs})
resp, body = self.patch('endpoints/%s' % endpoint_id, post_body)
diff --git a/tempest/lib/services/identity/v3/groups_client.py b/tempest/lib/services/identity/v3/groups_client.py
index 200cb43..5e68939 100644
--- a/tempest/lib/services/identity/v3/groups_client.py
+++ b/tempest/lib/services/identity/v3/groups_client.py
@@ -29,8 +29,9 @@
def create_group(self, **kwargs):
"""Creates a group.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-group
"""
post_body = json.dumps({'group': kwargs})
resp, body = self.post('groups', post_body)
@@ -48,8 +49,9 @@
def list_groups(self, **params):
"""Lists the groups.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-groups
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-groups
"""
url = 'groups'
if params:
@@ -62,8 +64,9 @@
def update_group(self, group_id, **kwargs):
"""Updates a group.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-group
"""
post_body = json.dumps({'group': kwargs})
resp, body = self.patch('groups/%s' % group_id, post_body)
@@ -87,8 +90,9 @@
def list_group_users(self, group_id, **params):
"""List users in group.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-users-in-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-users-in-group
"""
url = 'groups/%s/users' % group_id
if params:
diff --git a/tempest/lib/services/identity/v3/policies_client.py b/tempest/lib/services/identity/v3/policies_client.py
index 4c1b4ae..0282745 100644
--- a/tempest/lib/services/identity/v3/policies_client.py
+++ b/tempest/lib/services/identity/v3/policies_client.py
@@ -28,8 +28,9 @@
def create_policy(self, **kwargs):
"""Creates a Policy.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-policy
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-policy
"""
post_body = json.dumps({'policy': kwargs})
resp, body = self.post('policies', post_body)
@@ -55,8 +56,9 @@
def update_policy(self, policy_id, **kwargs):
"""Updates a policy.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-policy
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-policy
"""
post_body = json.dumps({'policy': kwargs})
url = 'policies/%s' % policy_id
diff --git a/tempest/lib/services/identity/v3/projects_client.py b/tempest/lib/services/identity/v3/projects_client.py
index ff06a19..20787da 100644
--- a/tempest/lib/services/identity/v3/projects_client.py
+++ b/tempest/lib/services/identity/v3/projects_client.py
@@ -25,8 +25,9 @@
def create_project(self, name, **kwargs):
"""Create a Project.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-project
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-project
"""
# Include the project name to the kwargs parameters
@@ -49,8 +50,9 @@
def update_project(self, project_id, **kwargs):
"""Update a Project.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-project
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-project
"""
post_body = json.dumps({'project': kwargs})
diff --git a/tempest/lib/services/identity/v3/regions_client.py b/tempest/lib/services/identity/v3/regions_client.py
index bddfc7b..33c754a 100644
--- a/tempest/lib/services/identity/v3/regions_client.py
+++ b/tempest/lib/services/identity/v3/regions_client.py
@@ -29,8 +29,9 @@
def create_region(self, region_id=None, **kwargs):
"""Create region.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-region
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-region
"""
if region_id is not None:
method = self.put
@@ -47,8 +48,9 @@
def update_region(self, region_id, **kwargs):
"""Updates a region.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-region
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-region
"""
post_body = json.dumps({'region': kwargs})
resp, body = self.patch('regions/%s' % region_id, post_body)
diff --git a/tempest/lib/services/identity/v3/roles_client.py b/tempest/lib/services/identity/v3/roles_client.py
index 2a97caf..f1339dd 100644
--- a/tempest/lib/services/identity/v3/roles_client.py
+++ b/tempest/lib/services/identity/v3/roles_client.py
@@ -24,8 +24,9 @@
def create_role(self, **kwargs):
"""Create a Role.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-role
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-role
"""
post_body = json.dumps({'role': kwargs})
resp, body = self.post('roles', post_body)
@@ -54,8 +55,9 @@
def update_role(self, role_id, **kwargs):
"""Update a Role.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-role
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-role
"""
post_body = json.dumps({'role': kwargs})
resp, body = self.patch('roles/%s' % role_id, post_body)
diff --git a/tempest/lib/services/identity/v3/services_client.py b/tempest/lib/services/identity/v3/services_client.py
index efa0d89..14c81cc 100644
--- a/tempest/lib/services/identity/v3/services_client.py
+++ b/tempest/lib/services/identity/v3/services_client.py
@@ -29,8 +29,9 @@
def update_service(self, service_id, **kwargs):
"""Updates a service.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#update-service
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-service
"""
patch_body = json.dumps({'service': kwargs})
resp, body = self.patch('services/%s' % service_id, patch_body)
@@ -49,8 +50,9 @@
def create_service(self, **kwargs):
"""Creates a service.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#create-service
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-service
"""
body = json.dumps({'service': kwargs})
resp, body = self.post("services", body)
@@ -67,8 +69,9 @@
def list_services(self, **params):
"""List services.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-services
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-services
"""
url = 'services'
if params:
diff --git a/tempest/lib/services/identity/v3/trusts_client.py b/tempest/lib/services/identity/v3/trusts_client.py
index e3d5a41..d113905 100644
--- a/tempest/lib/services/identity/v3/trusts_client.py
+++ b/tempest/lib/services/identity/v3/trusts_client.py
@@ -24,8 +24,9 @@
def create_trust(self, **kwargs):
"""Creates a trust.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3-ext/index.html#create-trust
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3-ext/index.html#create-trust
"""
post_body = json.dumps({'trust': kwargs})
resp, body = self.post('OS-TRUST/trusts', post_body)
@@ -42,8 +43,9 @@
def list_trusts(self, **params):
"""Returns trusts
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3-ext/index.html#list-trusts
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3-ext/index.html#list-trusts
"""
url = "OS-TRUST/trusts/"
if params:
diff --git a/tempest/lib/services/identity/v3/users_client.py b/tempest/lib/services/identity/v3/users_client.py
index 5398621..e99a971 100644
--- a/tempest/lib/services/identity/v3/users_client.py
+++ b/tempest/lib/services/identity/v3/users_client.py
@@ -24,8 +24,9 @@
def create_user(self, **kwargs):
"""Creates a user.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#create-user
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#create-user
"""
post_body = json.dumps({'user': kwargs})
resp, body = self.post('users', post_body)
@@ -36,8 +37,9 @@
def update_user(self, user_id, **kwargs):
"""Updates a user.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#update-user
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#update-user
"""
if 'id' not in kwargs:
kwargs['id'] = user_id
@@ -50,9 +52,9 @@
def update_user_password(self, user_id, **kwargs):
"""Update a user password
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/index.html#
- change-password-for-user
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#change-password-for-user
"""
update_user = json.dumps({'user': kwargs})
resp, _ = self.post('users/%s/password' % user_id, update_user)
@@ -62,8 +64,9 @@
def list_user_projects(self, user_id, **params):
"""Lists the projects on which a user has roles assigned.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-projects-for-user
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-projects-for-user
"""
url = 'users/%s/projects' % user_id
if params:
@@ -76,8 +79,9 @@
def list_users(self, **params):
"""Get the list of users.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-users
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-users
"""
url = 'users'
if params:
@@ -103,8 +107,9 @@
def list_user_groups(self, user_id, **params):
"""Lists groups which a user belongs to.
- Available params: see http://developer.openstack.org/
- api-ref/identity/v3/#list-groups-to-which-a-user-belongs
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/#list-groups-to-which-a-user-belongs
"""
url = 'users/%s/groups' % user_id
if params:
diff --git a/tempest/lib/services/image/v1/images_client.py b/tempest/lib/services/image/v1/images_client.py
index 9737be3..e67a547 100644
--- a/tempest/lib/services/image/v1/images_client.py
+++ b/tempest/lib/services/image/v1/images_client.py
@@ -34,8 +34,7 @@
data = iter(functools.partial(data.read, CHUNKSIZE), b'')
resp, body = self.request('POST', 'images',
headers=headers, body=data, chunked=True)
- self._error_checker('POST', 'images', headers, data, resp,
- body)
+ self._error_checker(resp, body)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -47,8 +46,7 @@
url = 'images/%s' % image_id
resp, body = self.request('PUT', url, headers=headers,
body=data, chunked=True)
- self._error_checker('PUT', url, headers, data,
- resp, body)
+ self._error_checker(resp, body)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/image/v2/image_members_client.py b/tempest/lib/services/image/v2/image_members_client.py
index 941e2e3..e5118a8 100644
--- a/tempest/lib/services/image/v2/image_members_client.py
+++ b/tempest/lib/services/image/v2/image_members_client.py
@@ -21,8 +21,9 @@
def list_image_members(self, image_id):
"""List image members.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#list-image-members
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#list-image-members
"""
url = 'images/%s/members' % image_id
resp, body = self.get(url)
@@ -33,8 +34,9 @@
def create_image_member(self, image_id, **kwargs):
"""Create an image member.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/#create-image-member
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#create-image-member
"""
url = 'images/%s/members' % image_id
data = json.dumps(kwargs)
@@ -46,8 +48,9 @@
def update_image_member(self, image_id, member_id, **kwargs):
"""Update an image member.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/#update-image-member
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#update-image-member
"""
url = 'images/%s/members/%s' % (image_id, member_id)
data = json.dumps(kwargs)
@@ -59,8 +62,9 @@
def show_image_member(self, image_id, member_id):
"""Show an image member.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#show-image-member-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#show-image-member-details
"""
url = 'images/%s/members/%s' % (image_id, member_id)
resp, body = self.get(url)
@@ -70,8 +74,9 @@
def delete_image_member(self, image_id, member_id):
"""Delete an image member.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#delete-image-member
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#delete-image-member
"""
url = 'images/%s/members/%s' % (image_id, member_id)
resp, _ = self.delete(url)
diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py
index a6016a4..bcdae44 100644
--- a/tempest/lib/services/image/v2/images_client.py
+++ b/tempest/lib/services/image/v2/images_client.py
@@ -30,8 +30,9 @@
def update_image(self, image_id, patch):
"""Update an image.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/index.html#update-an-image
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/index.html#update-an-image
"""
data = json.dumps(patch)
headers = {"Content-Type": "application/openstack-images-v2.0"
@@ -44,8 +45,9 @@
def create_image(self, **kwargs):
"""Create an image.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/index.html#create-an-image
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/index.html#create-an-image
"""
data = json.dumps(kwargs)
resp, body = self.post('images', data)
@@ -56,9 +58,10 @@
def deactivate_image(self, image_id):
"""Deactivate image.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/#deactivate-image
- """
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#deactivate-image
+ """
url = 'images/%s/actions/deactivate' % image_id
resp, body = self.post(url, None)
self.expected_success(204, resp.status)
@@ -67,9 +70,10 @@
def reactivate_image(self, image_id):
"""Reactivate image.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/#reactivate-image
- """
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#reactivate-image
+ """
url = 'images/%s/actions/reactivate' % image_id
resp, body = self.post(url, None)
self.expected_success(204, resp.status)
@@ -78,8 +82,9 @@
def delete_image(self, image_id):
"""Delete image.
- Available params: see http://developer.openstack.org/
- /api-ref/image/v2/#delete-an-image
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#delete-an-image
"""
url = 'images/%s' % image_id
resp, _ = self.delete(url)
@@ -89,8 +94,9 @@
def list_images(self, params=None):
"""List images.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/#show-images
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#show-images
"""
url = 'images'
@@ -105,8 +111,9 @@
def show_image(self, image_id):
"""Show image details.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#show-image-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#show-image-details
"""
url = 'images/%s' % image_id
resp, body = self.get(url)
@@ -129,8 +136,9 @@
def store_image_file(self, image_id, data):
"""Upload binary image data.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#upload-binary-image-data
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#upload-binary-image-data
"""
url = 'images/%s/file' % image_id
@@ -147,8 +155,9 @@
def show_image_file(self, image_id):
"""Download binary image data.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#download-binary-image-data
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#download-binary-image-data
"""
url = 'images/%s/file' % image_id
resp, body = self.get(url)
@@ -158,8 +167,9 @@
def add_image_tag(self, image_id, tag):
"""Add an image tag.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#add-image-tag
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#add-image-tag
"""
url = 'images/%s/tags/%s' % (image_id, tag)
resp, body = self.put(url, body=None)
@@ -169,8 +179,9 @@
def delete_image_tag(self, image_id, tag):
"""Delete an image tag.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/#delete-image-tag
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/#delete-image-tag
"""
url = 'images/%s/tags/%s' % (image_id, tag)
resp, _ = self.delete(url)
diff --git a/tempest/lib/services/image/v2/namespaces_client.py b/tempest/lib/services/image/v2/namespaces_client.py
index aafa936..b00de89 100644
--- a/tempest/lib/services/image/v2/namespaces_client.py
+++ b/tempest/lib/services/image/v2/namespaces_client.py
@@ -24,8 +24,9 @@
def create_namespace(self, **kwargs):
"""Create a namespace.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html#create-namespace
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-namespace
"""
data = json.dumps(kwargs)
resp, body = self.post('metadefs/namespaces', data)
@@ -33,11 +34,25 @@
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+ def list_namespaces(self):
+ """List namespaces
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-namespaces
+ """
+ url = 'metadefs/namespaces'
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
def show_namespace(self, namespace):
"""Show namespace details.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html#get-namespace-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get-namespace-details
"""
url = 'metadefs/namespaces/%s' % namespace
resp, body = self.get(url)
@@ -48,8 +63,9 @@
def update_namespace(self, namespace, **kwargs):
"""Update a namespace.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html#update-namespace
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-namespace
"""
# NOTE: On Glance API, we need to pass namespace on both URI
# and a request body.
@@ -65,8 +81,9 @@
def delete_namespace(self, namespace):
"""Delete a namespace.
- Available params: http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html#delete-namespace
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-namespace
"""
url = 'metadefs/namespaces/%s' % namespace
resp, _ = self.delete(url)
diff --git a/tempest/lib/services/image/v2/resource_types_client.py b/tempest/lib/services/image/v2/resource_types_client.py
index 8f2a977..1b6889f 100644
--- a/tempest/lib/services/image/v2/resource_types_client.py
+++ b/tempest/lib/services/image/v2/resource_types_client.py
@@ -24,10 +24,10 @@
def list_resource_types(self):
"""Lists all resource types.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html?expanded=#
- list-resource-types
- """
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#list-resource-types
+ """
url = 'metadefs/resource_types'
resp, body = self.get(url)
self.expected_success(200, resp.status)
@@ -37,10 +37,10 @@
def create_resource_type_association(self, namespace_id, **kwargs):
"""Creates a resource type association in given namespace.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html?expanded=#
- create-resource-type-association
- """
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#create-resource-type-association
+ """
url = 'metadefs/namespaces/%s/resource_types' % namespace_id
data = json.dumps(kwargs)
resp, body = self.post(url, data)
@@ -51,10 +51,10 @@
def list_resource_type_association(self, namespace_id):
"""Lists resource type associations in given namespace.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html?expanded=#
- list-resource-type-associations
- """
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#list-resource-type-associations
+ """
url = 'metadefs/namespaces/%s/resource_types' % namespace_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
@@ -64,10 +64,10 @@
def delete_resource_type_association(self, namespace_id, resource_name):
"""Removes resource type association in given namespace.
- Available params: see http://developer.openstack.org/
- api-ref/image/v2/metadefs-index.html?expanded=#
- remove-resource-type-association
- """
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#remove-resource-type-association
+ """
url = 'metadefs/namespaces/%s/resource_types/%s' % (namespace_id,
resource_name)
resp, _ = self.delete(url)
diff --git a/tempest/lib/services/network/floating_ips_client.py b/tempest/lib/services/network/floating_ips_client.py
old mode 100755
new mode 100644
index 24e0e7d..2bb18e0
--- a/tempest/lib/services/network/floating_ips_client.py
+++ b/tempest/lib/services/network/floating_ips_client.py
@@ -21,9 +21,9 @@
If you specify port information, associates the floating IP with an
internal port.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- create-floating-ip
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-floating-ip
"""
uri = '/floatingips'
post_data = {'floatingip': kwargs}
@@ -32,9 +32,9 @@
def update_floatingip(self, floatingip_id, **kwargs):
"""Updates a floating IP and its association with an internal port.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- update-floating-ip
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-floating-ip
"""
uri = '/floatingips/%s' % floatingip_id
post_data = {'floatingip': kwargs}
@@ -43,9 +43,9 @@
def show_floatingip(self, floatingip_id, **fields):
"""Shows details for a floating IP.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- show-floating-ip-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-floating-ip-details
"""
uri = '/floatingips/%s' % floatingip_id
return self.show_resource(uri, **fields)
@@ -57,9 +57,9 @@
def list_floatingips(self, **filters):
"""Lists floating IPs.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- list-floating-ips
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-floating-ips
"""
uri = '/floatingips'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/metering_labels_client.py b/tempest/lib/services/network/metering_labels_client.py
old mode 100755
new mode 100644
index 6932a62..411da1f
--- a/tempest/lib/services/network/metering_labels_client.py
+++ b/tempest/lib/services/network/metering_labels_client.py
@@ -18,9 +18,9 @@
def create_metering_label(self, **kwargs):
"""Creates an L3 metering label.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- create-metering-label
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-metering-label
"""
uri = '/metering/metering-labels'
post_data = {'metering_label': kwargs}
@@ -29,9 +29,9 @@
def show_metering_label(self, metering_label_id, **fields):
"""Shows details for a metering label.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- show-metering-label-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-metering-label-details
"""
uri = '/metering/metering-labels/%s' % metering_label_id
return self.show_resource(uri, **fields)
@@ -39,9 +39,9 @@
def delete_metering_label(self, metering_label_id):
"""Deletes an L3 metering label.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- delete-metering-label
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#delete-metering-label
"""
uri = '/metering/metering-labels/%s' % metering_label_id
return self.delete_resource(uri)
@@ -49,9 +49,9 @@
def list_metering_labels(self, **filters):
"""Lists all L3 metering labels that belong to the tenant.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- list-metering-labels
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-metering-labels
"""
uri = '/metering/metering-labels'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/networks_client.py b/tempest/lib/services/network/networks_client.py
old mode 100755
new mode 100644
index 6b601ee..77d4823
--- a/tempest/lib/services/network/networks_client.py
+++ b/tempest/lib/services/network/networks_client.py
@@ -18,8 +18,9 @@
def create_network(self, **kwargs):
"""Creates a network.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#create-network
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-network
"""
uri = '/networks'
post_data = {'network': kwargs}
@@ -28,8 +29,9 @@
def update_network(self, network_id, **kwargs):
"""Updates a network.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#update-network
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-network
"""
uri = '/networks/%s' % network_id
post_data = {'network': kwargs}
@@ -38,8 +40,9 @@
def show_network(self, network_id, **fields):
"""Shows details for a network.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#show-network-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-network-details
"""
uri = '/networks/%s' % network_id
return self.show_resource(uri, **fields)
@@ -51,8 +54,9 @@
def list_networks(self, **filters):
"""Lists networks to which the tenant has access.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#list-networks
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-networks
"""
uri = '/networks'
return self.list_resources(uri, **filters)
@@ -60,8 +64,9 @@
def create_bulk_networks(self, **kwargs):
"""Create multiple networks in a single request.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#bulk-create-networks
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-networks
"""
uri = '/networks'
return self.create_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/ports_client.py b/tempest/lib/services/network/ports_client.py
old mode 100755
new mode 100644
index 85f5a1d..93138b9
--- a/tempest/lib/services/network/ports_client.py
+++ b/tempest/lib/services/network/ports_client.py
@@ -19,8 +19,9 @@
def create_port(self, **kwargs):
"""Creates a port on a network.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#create-port
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-port
"""
uri = '/ports'
post_data = {'port': kwargs}
@@ -29,8 +30,9 @@
def update_port(self, port_id, **kwargs):
"""Updates a port.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#update-port
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-port
"""
uri = '/ports/%s' % port_id
post_data = {'port': kwargs}
@@ -39,8 +41,9 @@
def show_port(self, port_id, **fields):
"""Shows details for a port.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#show-port-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-port-details
"""
uri = '/ports/%s' % port_id
return self.show_resource(uri, **fields)
@@ -48,8 +51,9 @@
def delete_port(self, port_id):
"""Deletes a port.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#delete-port
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#delete-port
"""
uri = '/ports/%s' % port_id
return self.delete_resource(uri)
@@ -57,8 +61,9 @@
def list_ports(self, **filters):
"""Lists ports to which the tenant has access.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#list-ports
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-ports
"""
uri = '/ports'
return self.list_resources(uri, **filters)
@@ -66,8 +71,9 @@
def create_bulk_ports(self, **kwargs):
"""Create multiple ports in a single request.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html?expanded=#bulk-create-ports
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html?expanded=#bulk-create-ports
"""
uri = '/ports'
return self.create_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/routers_client.py b/tempest/lib/services/network/routers_client.py
old mode 100755
new mode 100644
index 5a72b5e..19b7627
--- a/tempest/lib/services/network/routers_client.py
+++ b/tempest/lib/services/network/routers_client.py
@@ -18,8 +18,9 @@
def create_router(self, **kwargs):
"""Create a router.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#create-router
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-router
"""
post_body = {'router': kwargs}
uri = '/routers'
@@ -28,8 +29,9 @@
def update_router(self, router_id, **kwargs):
"""Updates a logical router.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#update-router
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-router
"""
uri = '/routers/%s' % router_id
update_body = {'router': kwargs}
@@ -38,9 +40,9 @@
def show_router(self, router_id, **fields):
"""Shows details for a router.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- show-router-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-router-details
"""
uri = '/routers/%s' % router_id
return self.show_resource(uri, **fields)
@@ -52,8 +54,9 @@
def list_routers(self, **filters):
"""Lists logical routers.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#list-routers
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-routers
"""
uri = '/routers'
return self.list_resources(uri, **filters)
@@ -61,9 +64,9 @@
def add_router_interface(self, router_id, **kwargs):
"""Add router interface.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- add-interface-to-router
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#add-interface-to-router
"""
uri = '/routers/%s/add_router_interface' % router_id
return self.update_resource(uri, kwargs)
@@ -71,9 +74,9 @@
def remove_router_interface(self, router_id, **kwargs):
"""Remove router interface.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- remove-interface-from-router
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#remove-interface-from-router
"""
uri = '/routers/%s/remove_router_interface' % router_id
return self.update_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/security_group_rules_client.py b/tempest/lib/services/network/security_group_rules_client.py
old mode 100755
new mode 100644
index e6f1bb8..d2bc4a9
--- a/tempest/lib/services/network/security_group_rules_client.py
+++ b/tempest/lib/services/network/security_group_rules_client.py
@@ -18,9 +18,9 @@
def create_security_group_rule(self, **kwargs):
"""Creates an OpenStack Networking security group rule.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- create-security-group-rule
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-security-group-rule
"""
uri = '/security-group-rules'
post_data = {'security_group_rule': kwargs}
@@ -29,9 +29,9 @@
def show_security_group_rule(self, security_group_rule_id, **fields):
"""Shows detailed information for a security group rule.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- show-security-group-rule
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-security-group-rule
"""
uri = '/security-group-rules/%s' % security_group_rule_id
return self.show_resource(uri, **fields)
@@ -43,9 +43,9 @@
def list_security_group_rules(self, **filters):
"""Lists a summary of all OpenStack Networking security group rules.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- list-security-group-rules
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-security-group-rules
"""
uri = '/security-group-rules'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/security_groups_client.py b/tempest/lib/services/network/security_groups_client.py
old mode 100755
new mode 100644
index d5ac61c..1f30216
--- a/tempest/lib/services/network/security_groups_client.py
+++ b/tempest/lib/services/network/security_groups_client.py
@@ -18,9 +18,9 @@
def create_security_group(self, **kwargs):
"""Creates an OpenStack Networking security group.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- create-security-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-security-group
"""
uri = '/security-groups'
post_data = {'security_group': kwargs}
@@ -29,9 +29,9 @@
def update_security_group(self, security_group_id, **kwargs):
"""Updates a security group.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- update-security-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-security-group
"""
uri = '/security-groups/%s' % security_group_id
post_data = {'security_group': kwargs}
@@ -40,9 +40,9 @@
def show_security_group(self, security_group_id, **fields):
"""Shows details for a security group.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- show-security-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-security-group
"""
uri = '/security-groups/%s' % security_group_id
return self.show_resource(uri, **fields)
@@ -50,9 +50,9 @@
def delete_security_group(self, security_group_id):
"""Deletes an OpenStack Networking security group.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- delete-security-group
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#delete-security-group
"""
uri = '/security-groups/%s' % security_group_id
return self.delete_resource(uri)
@@ -60,9 +60,9 @@
def list_security_groups(self, **filters):
"""Lists OpenStack Networking security groups.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- list-security-groups
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-security-groups
"""
uri = '/security-groups'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/subnetpools_client.py b/tempest/lib/services/network/subnetpools_client.py
old mode 100755
new mode 100644
index ec110b9..7e77e30
--- a/tempest/lib/services/network/subnetpools_client.py
+++ b/tempest/lib/services/network/subnetpools_client.py
@@ -20,9 +20,9 @@
def list_subnetpools(self, **filters):
"""Lists subnet pools to which the tenant has access.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- list-subnet-pools
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-subnet-pools
"""
uri = '/subnetpools'
return self.list_resources(uri, **filters)
@@ -30,9 +30,9 @@
def create_subnetpool(self, **kwargs):
"""Creates a subnet pool.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- create-subnet-pool
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-subnet-pool
"""
uri = '/subnetpools'
post_data = {'subnetpool': kwargs}
@@ -41,8 +41,9 @@
def show_subnetpool(self, subnetpool_id, **fields):
"""Shows information for a subnet pool.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#show-subnet-pool
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-subnet-pool
"""
uri = '/subnetpools/%s' % subnetpool_id
return self.show_resource(uri, **fields)
@@ -50,9 +51,9 @@
def update_subnetpool(self, subnetpool_id, **kwargs):
"""Updates a subnet pool.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#
- update-subnet-pool
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-subnet-pool
"""
uri = '/subnetpools/%s' % subnetpool_id
post_data = {'subnetpool': kwargs}
diff --git a/tempest/lib/services/network/subnets_client.py b/tempest/lib/services/network/subnets_client.py
old mode 100755
new mode 100644
index 203b360..b843f84
--- a/tempest/lib/services/network/subnets_client.py
+++ b/tempest/lib/services/network/subnets_client.py
@@ -18,8 +18,9 @@
def create_subnet(self, **kwargs):
"""Creates a subnet on a network.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#create-subnet
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#create-subnet
"""
uri = '/subnets'
post_data = {'subnet': kwargs}
@@ -28,8 +29,9 @@
def update_subnet(self, subnet_id, **kwargs):
"""Updates a subnet.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#update-subnet
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#update-subnet
"""
uri = '/subnets/%s' % subnet_id
post_data = {'subnet': kwargs}
@@ -38,8 +40,9 @@
def show_subnet(self, subnet_id, **fields):
"""Shows details for a subnet.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#show-subnet-details
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#show-subnet-details
"""
uri = '/subnets/%s' % subnet_id
return self.show_resource(uri, **fields)
@@ -51,8 +54,9 @@
def list_subnets(self, **filters):
"""Lists subnets to which the tenant has access.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#list-subnets
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#list-subnets
"""
uri = '/subnets'
return self.list_resources(uri, **filters)
@@ -60,8 +64,9 @@
def create_bulk_subnets(self, **kwargs):
"""Create multiple subnets in a single request.
- Available params: see http://developer.openstack.org/
- api-ref/networking/v2/index.html#bulk-create-subnet
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-subnet
"""
uri = '/subnets'
return self.create_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/versions_client.py b/tempest/lib/services/network/versions_client.py
index 0202927..a9c3bbf 100644
--- a/tempest/lib/services/network/versions_client.py
+++ b/tempest/lib/services/network/versions_client.py
@@ -35,6 +35,7 @@
start = time.time()
self._log_request_start('GET', version_url)
response, body = self.raw_request(version_url, 'GET')
+ self._error_checker(response, body)
end = time.time()
self._log_request('GET', version_url, response,
secs=(end - start), resp_body=body)
diff --git a/tempest/lib/services/volume/__init__.py b/tempest/lib/services/volume/__init__.py
index e69de29..11da06c 100644
--- a/tempest/lib/services/volume/__init__.py
+++ b/tempest/lib/services/volume/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
+#
+# 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 import v1
+from tempest.lib.services.volume import v2
+
+__all__ = ['v1', 'v2']
diff --git a/tempest/lib/services/volume/v1/__init__.py b/tempest/lib/services/volume/v1/__init__.py
index e69de29..9c98542 100644
--- a/tempest/lib/services/volume/v1/__init__.py
+++ b/tempest/lib/services/volume/v1/__init__.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
+#
+# 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.v1.availability_zone_client \
+ import AvailabilityZoneClient
+from tempest.lib.services.volume.v1.backups_client import BackupsClient
+from tempest.lib.services.volume.v1.encryption_types_client import \
+ EncryptionTypesClient
+from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient
+from tempest.lib.services.volume.v1.hosts_client import HostsClient
+from tempest.lib.services.volume.v1.qos_client import QosSpecsClient
+from tempest.lib.services.volume.v1.quotas_client import QuotasClient
+from tempest.lib.services.volume.v1.services_client import ServicesClient
+from tempest.lib.services.volume.v1.snapshots_client import SnapshotsClient
+from tempest.lib.services.volume.v1.types_client import TypesClient
+from tempest.lib.services.volume.v1.volumes_client import VolumesClient
+
+__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
+ 'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
+ 'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient']
diff --git a/tempest/services/volume/base/base_backups_client.py b/tempest/lib/services/volume/v1/backups_client.py
similarity index 76%
copy from tempest/services/volume/base/base_backups_client.py
copy to tempest/lib/services/volume/v1/backups_client.py
index a57e628..2728c67 100644
--- a/tempest/services/volume/base/base_backups_client.py
+++ b/tempest/lib/services/volume/v1/backups_client.py
@@ -13,17 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from oslo_serialization import jsonutils as json
-from tempest import exceptions
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
-class BaseBackupsClient(rest_client.RestClient):
- """Client class to send CRUD Volume backup API requests"""
+class BackupsClient(rest_client.RestClient):
+ """Volume V1 Backups client"""
+ api_version = "v1"
def create_backup(self, **kwargs):
"""Creates a backup of volume.
@@ -96,26 +94,6 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
- def wait_for_backup_status(self, backup_id, status):
- """Waits for a Backup to reach a given status."""
- body = self.show_backup(backup_id)['backup']
- backup_status = body['status']
- start = int(time.time())
-
- while backup_status != status:
- time.sleep(self.build_interval)
- body = self.show_backup(backup_id)['backup']
- backup_status = body['status']
- if backup_status == 'error' and backup_status != status:
- raise exceptions.VolumeBackupException(backup_id=backup_id)
-
- if int(time.time()) - start >= self.build_timeout:
- message = ('Volume backup %s failed to reach %s status '
- '(current %s) within the required time (%s s).' %
- (backup_id, status, backup_status,
- self.build_timeout))
- raise exceptions.TimeoutException(message)
-
def is_resource_deleted(self, id):
try:
self.show_backup(id)
diff --git a/tempest/services/volume/v1/json/encryption_types_client.py b/tempest/lib/services/volume/v1/encryption_types_client.py
similarity index 100%
rename from tempest/services/volume/v1/json/encryption_types_client.py
rename to tempest/lib/services/volume/v1/encryption_types_client.py
diff --git a/tempest/services/volume/base/base_qos_client.py b/tempest/lib/services/volume/v1/qos_client.py
similarity index 96%
rename from tempest/services/volume/base/base_qos_client.py
rename to tempest/lib/services/volume/v1/qos_client.py
index 0ce76a7..65ae274 100644
--- a/tempest/services/volume/base/base_qos_client.py
+++ b/tempest/lib/services/volume/v1/qos_client.py
@@ -18,8 +18,13 @@
from tempest.lib import exceptions as lib_exc
-class BaseQosSpecsClient(rest_client.RestClient):
- """Client class to send CRUD QoS API requests"""
+class QosSpecsClient(rest_client.RestClient):
+ """Volume V1 QoS client.
+
+ Client class to send CRUD QoS API requests
+ """
+
+ api_version = "v1"
def is_resource_deleted(self, qos_id):
try:
diff --git a/tempest/lib/services/volume/v1/quotas_client.py b/tempest/lib/services/volume/v1/quotas_client.py
index 8924b42..678fd82 100644
--- a/tempest/lib/services/volume/v1/quotas_client.py
+++ b/tempest/lib/services/volume/v1/quotas_client.py
@@ -45,8 +45,9 @@
def update_quota_set(self, tenant_id, **kwargs):
"""Updates quota set
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v1.html#updateQuota
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-blockstorage-v1.html#updateQuota
"""
put_body = jsonutils.dumps({'quota_set': kwargs})
resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body)
diff --git a/tempest/services/volume/base/base_snapshots_client.py b/tempest/lib/services/volume/v1/snapshots_client.py
old mode 100755
new mode 100644
similarity index 91%
copy from tempest/services/volume/base/base_snapshots_client.py
copy to tempest/lib/services/volume/v1/snapshots_client.py
index 38a6dc7..1881078
--- a/tempest/services/volume/base/base_snapshots_client.py
+++ b/tempest/lib/services/volume/v1/snapshots_client.py
@@ -17,8 +17,8 @@
from tempest.lib import exceptions as lib_exc
-class BaseSnapshotsClient(rest_client.RestClient):
- """Base Client class to send CRUD Volume API requests."""
+class SnapshotsClient(rest_client.RestClient):
+ """Client class to send CRUD Volume V1 API requests."""
create_resp = 200
@@ -26,7 +26,7 @@
"""List all the snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#listSnapshots
+ api-ref-blockstorage-v1.html#listSnapshots
"""
url = 'snapshots'
if detail:
@@ -43,7 +43,7 @@
"""Returns the details of a single snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#showSnapshot
+ api-ref-blockstorage-v1.html#showSnapshot
"""
url = "snapshots/%s" % snapshot_id
resp, body = self.get(url)
@@ -55,7 +55,7 @@
"""Creates a new snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#createSnapshot
+ api-ref-blockstorage-v1.html#createSnapshot
"""
post_body = json.dumps({'snapshot': kwargs})
resp, body = self.post('snapshots', post_body)
@@ -63,23 +63,11 @@
self.expected_success(self.create_resp, resp.status)
return rest_client.ResponseBody(resp, body)
- def update_snapshot(self, snapshot_id, **kwargs):
- """Updates a snapshot.
-
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#updateSnapshot
- """
- put_body = json.dumps({'snapshot': kwargs})
- resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
def delete_snapshot(self, snapshot_id):
"""Delete Snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#deleteSnapshot
+ api-ref-blockstorage-v1.html#deleteSnapshot
"""
resp, body = self.delete("snapshots/%s" % snapshot_id)
self.expected_success(202, resp.status)
@@ -126,11 +114,24 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+ def update_snapshot(self, snapshot_id, **kwargs):
+ """Updates a snapshot.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v1.html#
+ updateSnapshotMetadata
+ """
+ put_body = json.dumps({'snapshot': kwargs})
+ resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def show_snapshot_metadata(self, snapshot_id):
"""Get metadata of the snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#
+ api-ref-blockstorage-v1.html#
showSnapshotMetadata
"""
url = "snapshots/%s/metadata" % snapshot_id
@@ -143,7 +144,7 @@
"""Update metadata for the snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#
+ api-ref-blockstorage-v1.html#
updateSnapshotMetadata
"""
put_body = json.dumps(kwargs)
diff --git a/tempest/services/volume/v1/json/admin/types_client.py b/tempest/lib/services/volume/v1/types_client.py
similarity index 100%
rename from tempest/services/volume/v1/json/admin/types_client.py
rename to tempest/lib/services/volume/v1/types_client.py
diff --git a/tempest/services/volume/base/base_volumes_client.py b/tempest/lib/services/volume/v1/volumes_client.py
old mode 100755
new mode 100644
similarity index 97%
rename from tempest/services/volume/base/base_volumes_client.py
rename to tempest/lib/services/volume/v1/volumes_client.py
index 1cb1ef5..cc98c91
--- a/tempest/services/volume/base/base_volumes_client.py
+++ b/tempest/lib/services/volume/v1/volumes_client.py
@@ -21,10 +21,8 @@
from tempest.lib import exceptions as lib_exc
-class BaseVolumesClient(rest_client.RestClient):
- """Base client class to send CRUD Volume API requests"""
-
- create_resp = 200
+class VolumesClient(rest_client.RestClient):
+ """Client class to send CRUD Volume V1 API requests"""
def _prepare_params(self, params):
"""Prepares params for use in get or _ext_get methods.
@@ -69,7 +67,7 @@
post_body = json.dumps({'volume': kwargs})
resp, body = self.post('volumes', post_body)
body = json.loads(body)
- self.expected_success(self.create_resp, resp.status)
+ self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
def update_volume(self, volume_id, **kwargs):
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index e69de29..f547d7d 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
+#
+# 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.v2.availability_zone_client \
+ import AvailabilityZoneClient
+from tempest.lib.services.volume.v2.backups_client import BackupsClient
+from tempest.lib.services.volume.v2.encryption_types_client import \
+ EncryptionTypesClient
+from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
+from tempest.lib.services.volume.v2.hosts_client import HostsClient
+from tempest.lib.services.volume.v2.qos_client import QosSpecsClient
+from tempest.lib.services.volume.v2.quotas_client import QuotasClient
+from tempest.lib.services.volume.v2.services_client import ServicesClient
+from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient
+from tempest.lib.services.volume.v2.types_client import TypesClient
+from tempest.lib.services.volume.v2.volumes_client import VolumesClient
+
+__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
+ 'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
+ 'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient']
diff --git a/tempest/services/volume/base/base_backups_client.py b/tempest/lib/services/volume/v2/backups_client.py
similarity index 76%
rename from tempest/services/volume/base/base_backups_client.py
rename to tempest/lib/services/volume/v2/backups_client.py
index a57e628..61f865d 100644
--- a/tempest/services/volume/base/base_backups_client.py
+++ b/tempest/lib/services/volume/v2/backups_client.py
@@ -13,17 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from oslo_serialization import jsonutils as json
-from tempest import exceptions
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
-class BaseBackupsClient(rest_client.RestClient):
- """Client class to send CRUD Volume backup API requests"""
+class BackupsClient(rest_client.RestClient):
+ """Volume V2 Backups client"""
+ api_version = "v2"
def create_backup(self, **kwargs):
"""Creates a backup of volume.
@@ -96,26 +94,6 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
- def wait_for_backup_status(self, backup_id, status):
- """Waits for a Backup to reach a given status."""
- body = self.show_backup(backup_id)['backup']
- backup_status = body['status']
- start = int(time.time())
-
- while backup_status != status:
- time.sleep(self.build_interval)
- body = self.show_backup(backup_id)['backup']
- backup_status = body['status']
- if backup_status == 'error' and backup_status != status:
- raise exceptions.VolumeBackupException(backup_id=backup_id)
-
- if int(time.time()) - start >= self.build_timeout:
- message = ('Volume backup %s failed to reach %s status '
- '(current %s) within the required time (%s s).' %
- (backup_id, status, backup_status,
- self.build_timeout))
- raise exceptions.TimeoutException(message)
-
def is_resource_deleted(self, id):
try:
self.show_backup(id)
diff --git a/tempest/services/volume/v2/json/encryption_types_client.py b/tempest/lib/services/volume/v2/encryption_types_client.py
similarity index 100%
rename from tempest/services/volume/v2/json/encryption_types_client.py
rename to tempest/lib/services/volume/v2/encryption_types_client.py
diff --git a/tempest/services/volume/base/base_qos_client.py b/tempest/lib/services/volume/v2/qos_client.py
similarity index 78%
copy from tempest/services/volume/base/base_qos_client.py
copy to tempest/lib/services/volume/v2/qos_client.py
index 0ce76a7..40d4a3f 100644
--- a/tempest/services/volume/base/base_qos_client.py
+++ b/tempest/lib/services/volume/v2/qos_client.py
@@ -18,8 +18,13 @@
from tempest.lib import exceptions as lib_exc
-class BaseQosSpecsClient(rest_client.RestClient):
- """Client class to send CRUD QoS API requests"""
+class QosSpecsClient(rest_client.RestClient):
+ """Volume V2 QoS client.
+
+ Client class to send CRUD QoS API requests
+ """
+
+ api_version = "v2"
def is_resource_deleted(self, qos_id):
try:
@@ -36,8 +41,11 @@
def create_qos(self, **kwargs):
"""Create a QoS Specification.
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#createQoSSpec
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/index.html
+ ?expanded=create-qos-specification-detail
+ #quality-of-service-qos-specifications-qos-specs
"""
post_body = json.dumps({'qos_specs': kwargs})
resp, body = self.post('qos-specs', post_body)
@@ -71,8 +79,11 @@
def set_qos_key(self, qos_id, **kwargs):
"""Set the specified keys/values of QoS specification.
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#setQoSKey
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/index.html
+ ?expanded=set-keys-in-qos-specification-detail
+ #quality-of-service-qos-specifications-qos-specs
"""
put_body = json.dumps({"qos_specs": kwargs})
resp, body = self.put('qos-specs/%s' % qos_id, put_body)
@@ -85,7 +96,11 @@
:param keys: keys to delete from the QoS specification.
- TODO(jordanP): Add a link once LP #1524877 is fixed.
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/index.html
+ ?expanded=unset-keys-in-qos-specification-detail
+ #quality-of-service-qos-specifications-qos-specs
"""
put_body = json.dumps({'keys': keys})
resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
diff --git a/tempest/lib/services/volume/v2/quotas_client.py b/tempest/lib/services/volume/v2/quotas_client.py
index a302045..430957d 100644
--- a/tempest/lib/services/volume/v2/quotas_client.py
+++ b/tempest/lib/services/volume/v2/quotas_client.py
@@ -47,8 +47,9 @@
def update_quota_set(self, tenant_id, **kwargs):
"""Updates quota set
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#updateQuotas-v2
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-blockstorage-v2.html#updateQuota
"""
put_body = jsonutils.dumps({'quota_set': kwargs})
resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body)
diff --git a/tempest/services/volume/base/base_snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
old mode 100755
new mode 100644
similarity index 97%
rename from tempest/services/volume/base/base_snapshots_client.py
rename to tempest/lib/services/volume/v2/snapshots_client.py
index 38a6dc7..c84e557
--- a/tempest/services/volume/base/base_snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -17,10 +17,10 @@
from tempest.lib import exceptions as lib_exc
-class BaseSnapshotsClient(rest_client.RestClient):
- """Base Client class to send CRUD Volume API requests."""
-
- create_resp = 200
+class SnapshotsClient(rest_client.RestClient):
+ """Client class to send CRUD Volume V2 API requests."""
+ api_version = "v2"
+ create_resp = 202
def list_snapshots(self, detail=False, **params):
"""List all the snapshot.
diff --git a/tempest/services/volume/v2/json/admin/types_client.py b/tempest/lib/services/volume/v2/types_client.py
similarity index 100%
rename from tempest/services/volume/v2/json/admin/types_client.py
rename to tempest/lib/services/volume/v2/types_client.py
diff --git a/tempest/services/volume/base/base_volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
old mode 100755
new mode 100644
similarity index 84%
copy from tempest/services/volume/base/base_volumes_client.py
copy to tempest/lib/services/volume/v2/volumes_client.py
index 1cb1ef5..b1930e1
--- a/tempest/services/volume/base/base_volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -21,10 +21,9 @@
from tempest.lib import exceptions as lib_exc
-class BaseVolumesClient(rest_client.RestClient):
- """Base client class to send CRUD Volume API requests"""
-
- create_resp = 200
+class VolumesClient(rest_client.RestClient):
+ """Client class to send CRUD Volume V2 API requests"""
+ api_version = "v2"
def _prepare_params(self, params):
"""Prepares params for use in get or _ext_get methods.
@@ -69,7 +68,7 @@
post_body = json.dumps({'volume': kwargs})
resp, body = self.post('volumes', post_body)
body = json.loads(body)
- self.expected_success(self.create_resp, resp.status)
+ self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
def update_volume(self, volume_id, **kwargs):
@@ -293,3 +292,49 @@
post_body = json.dumps({'os-retype': kwargs})
resp, body = self.post('volumes/%s/action' % volume_id, post_body)
self.expected_success(202, resp.status)
+
+ def update_volume_image_metadata(self, volume_id, **kwargs):
+ """Update image metadata for the volume.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #setVolumeimagemetadata
+ """
+ post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
+ url = "volumes/%s/action" % (volume_id)
+ resp, body = self.post(url, post_body)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_volume_image_metadata(self, volume_id, key_name):
+ """Delete image metadata item for the volume."""
+ post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}})
+ url = "volumes/%s/action" % (volume_id)
+ resp, body = self.post(url, post_body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_pools(self, detail=False):
+ # List all the volumes pools (hosts)
+ url = 'scheduler-stats/get_pools'
+ if detail:
+ url += '?detail=True'
+
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_backend_capabilities(self, host):
+ """Shows capabilities for a storage back end.
+
+ Output params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #showBackendCapabilities
+ """
+ url = 'capabilities/%s' % host
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index a88194c..dd1adc7 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -26,6 +26,7 @@
from tempest.common import image as common_image
from tempest.common.utils import data_utils
from tempest.common.utils.linux import remote_client
+from tempest.common.utils import net_utils
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -57,7 +58,7 @@
elif CONF.image_feature_enabled.api_v2:
cls.image_client = cls.manager.image_client_v2
else:
- raise exceptions.InvalidConfiguration(
+ raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
# Compute image client
@@ -80,12 +81,12 @@
cls.security_group_rules_client = (
cls.manager.security_group_rules_client)
- if CONF.volume_feature_enabled.api_v1:
- cls.volumes_client = cls.manager.volumes_client
- cls.snapshots_client = cls.manager.snapshots_client
- else:
+ if CONF.volume_feature_enabled.api_v2:
cls.volumes_client = cls.manager.volumes_v2_client
cls.snapshots_client = cls.manager.snapshots_v2_client
+ else:
+ cls.volumes_client = cls.manager.volumes_client
+ cls.snapshots_client = cls.manager.snapshots_client
# ## Test functions library
#
@@ -216,7 +217,7 @@
if size is None:
size = CONF.volume.volume_size
if name is None:
- name = data_utils.rand_name(self.__class__.__name__)
+ name = data_utils.rand_name(self.__class__.__name__ + "-volume")
kwargs = {'display_name': name,
'snapshot_id': snapshot_id,
'imageRef': imageRef,
@@ -417,7 +418,7 @@
# Compute client
_images_client = self.compute_images_client
if name is None:
- name = data_utils.rand_name('scenario-snapshot')
+ name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
LOG.debug("Creating a snapshot image for server: %s", server['name'])
image = _images_client.create_image(server['id'], name=name)
image_id = image.response['location'].split('images/')[1]
@@ -495,9 +496,18 @@
server_id, 'ACTIVE')
def ping_ip_address(self, ip_address, should_succeed=True,
- ping_timeout=None):
+ ping_timeout=None, mtu=None):
timeout = ping_timeout or CONF.validation.ping_timeout
- cmd = ['ping', '-c1', '-w1', ip_address]
+ cmd = ['ping', '-c1', '-w1']
+
+ if mtu:
+ cmd += [
+ # don't fragment
+ '-M', 'do',
+ # ping receives just the size of ICMP payload
+ '-s', str(net_utils.get_ping_payload_size(mtu, 4))
+ ]
+ cmd.append(ip_address)
def ping():
proc = subprocess.Popen(cmd,
@@ -525,7 +535,8 @@
def check_vm_connectivity(self, ip_address,
username=None,
private_key=None,
- should_connect=True):
+ should_connect=True,
+ mtu=None):
"""Check server connectivity
:param ip_address: server to test against
@@ -534,6 +545,7 @@
:param should_connect: True/False indicates positive/negative test
positive - attempt ping and ssh
negative - attempt ping and fail if succeed
+ :param mtu: network MTU to use for connectivity validation
:raises: AssertError if the result of the connectivity check does
not match the value of the should_connect param
@@ -543,7 +555,8 @@
else:
msg = "ip address %s is reachable" % ip_address
self.assertTrue(self.ping_ip_address(ip_address,
- should_succeed=should_connect),
+ should_succeed=should_connect,
+ mtu=mtu),
msg=msg)
if should_connect:
# no need to check ssh for negative connectivity
@@ -551,7 +564,7 @@
def check_public_network_connectivity(self, ip_address, username,
private_key, should_connect=True,
- msg=None, servers=None):
+ msg=None, servers=None, mtu=None):
# The target login is assumed to have been configured for
# key-based authentication by cloud-init.
LOG.debug('checking network connections to IP %s with user: %s' %
@@ -560,7 +573,8 @@
self.check_vm_connectivity(ip_address,
username,
private_key,
- should_connect=should_connect)
+ should_connect=should_connect,
+ mtu=mtu)
except Exception:
ex_msg = 'Public network connectivity check failed'
if msg:
@@ -622,13 +636,24 @@
# method is creating the floating IP there.
return self.create_floating_ip(server)['ip']
elif CONF.validation.connect_method == 'fixed':
- addresses = server['addresses'][CONF.validation.network_for_ssh]
+ # Determine the network name to look for based on config or creds
+ # provider network resources.
+ if CONF.validation.network_for_ssh:
+ addresses = server['addresses'][
+ CONF.validation.network_for_ssh]
+ else:
+ creds_provider = self._get_credentials_provider()
+ net_creds = creds_provider.get_primary_creds()
+ network = getattr(net_creds, 'network', None)
+ addresses = (server['addresses'][network['name']]
+ if network else [])
for address in addresses:
- if address['version'] == CONF.validation.ip_version_for_ssh:
+ if (address['version'] == CONF.validation.ip_version_for_ssh
+ and address['OS-EXT-IPS:type'] == 'fixed'):
return address['addr']
raise exceptions.ServerUnreachable(server_id=server['id'])
else:
- raise exceptions.InvalidConfiguration()
+ raise lib_exc.InvalidConfiguration()
class NetworkScenarioTest(ScenarioTest):
@@ -658,7 +683,8 @@
def _create_network(self, networks_client=None,
routers_client=None, tenant_id=None,
- namestart='network-smoke-'):
+ namestart='network-smoke-',
+ port_security_enabled=True):
if not networks_client:
networks_client = self.networks_client
if not routers_client:
@@ -666,7 +692,12 @@
if not tenant_id:
tenant_id = networks_client.tenant_id
name = data_utils.rand_name(namestart)
- result = networks_client.create_network(name=name, tenant_id=tenant_id)
+ network_kwargs = dict(name=name, tenant_id=tenant_id)
+ # Neutron disables port security by default so we have to check the
+ # config before trying to create the network with port_security_enabled
+ if CONF.network_feature_enabled.port_security:
+ network_kwargs['port_security_enabled'] = port_security_enabled
+ result = networks_client.create_network(**network_kwargs)
network = result['network']
self.assertEqual(network['name'], name)
@@ -772,7 +803,7 @@
def _get_server_port_id_and_ip4(self, server, ip_addr=None):
ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
- # A port can have more then one IP address in some cases.
+ # A port can have more than one IP address in some cases.
# If the network is dual-stack (IPv4 + IPv6), this port is associated
# with 2 subnets
p_status = ['ACTIVE']
@@ -1141,7 +1172,8 @@
def create_networks(self, networks_client=None,
routers_client=None, subnets_client=None,
- tenant_id=None, dns_nameservers=None):
+ tenant_id=None, dns_nameservers=None,
+ port_security_enabled=True):
"""Create a network with a subnet connected to a router.
The baremetal driver is a special case since all nodes are
@@ -1159,7 +1191,7 @@
# https://blueprints.launchpad.net/tempest/+spec/test-accounts
if not CONF.compute.fixed_network_name:
m = 'fixed_network_name must be specified in config'
- raise exceptions.InvalidConfiguration(m)
+ raise lib_exc.InvalidConfiguration(m)
network = self._get_network_by_name(
CONF.compute.fixed_network_name)
router = None
@@ -1167,7 +1199,8 @@
else:
network = self._create_network(
networks_client=networks_client,
- tenant_id=tenant_id)
+ tenant_id=tenant_id,
+ port_security_enabled=port_security_enabled)
router = self._get_router(client=routers_client,
tenant_id=tenant_id)
subnet_kwargs = dict(network=network,
@@ -1254,7 +1287,7 @@
check_state, timeout, interval):
msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
(node_id, state_attr, target_states))
- raise exceptions.TimeoutException(msg)
+ raise lib_exc.TimeoutException(msg)
def wait_provisioning_state(self, node_id, state, timeout):
self._node_state_timeout(
@@ -1278,7 +1311,7 @@
_get_node, CONF.baremetal.association_timeout, 1):
msg = ('Timed out waiting to get Ironic node by instance id %s'
% instance_id)
- raise exceptions.TimeoutException(msg)
+ raise lib_exc.TimeoutException(msg)
def get_node(self, node_id=None, instance_id=None):
if node_id:
@@ -1344,14 +1377,14 @@
@classmethod
def setup_clients(cls):
super(EncryptionScenarioTest, cls).setup_clients()
- if CONF.volume_feature_enabled.api_v1:
- cls.admin_volume_types_client = cls.os_adm.volume_types_client
- cls.admin_encryption_types_client =\
- cls.os_adm.encryption_types_client
- else:
+ if CONF.volume_feature_enabled.api_v2:
cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
cls.admin_encryption_types_client =\
cls.os_adm.encryption_types_v2_client
+ else:
+ cls.admin_volume_types_client = cls.os_adm.volume_types_client
+ cls.admin_encryption_types_client =\
+ cls.os_adm.encryption_types_client
def create_volume_type(self, client=None, name=None):
if not client:
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 086b82d..8de3561 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -36,7 +36,6 @@
super(TestAggregatesBasicOps, cls).setup_clients()
# Use admin client by default
cls.manager = cls.admin_manager
- super(TestAggregatesBasicOps, cls).resource_setup()
cls.aggregates_client = cls.manager.aggregates_client
cls.hosts_client = cls.manager.hosts_client
@@ -53,7 +52,7 @@
def _get_host_name(self):
hosts = self.hosts_client.list_hosts()['hosts']
- self.assertTrue(len(hosts) >= 1)
+ self.assertGreaterEqual(len(hosts), 1)
computes = [x for x in hosts if x['service'] == 'compute']
return computes[0]['host_name']
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index dba1c92..3ac6759 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -47,12 +47,6 @@
10. Check SSH connection to instance after reboot
"""
-
- def nova_list(self):
- servers = self.servers_client.list_servers()
- # The list servers in the compute client is inconsistent...
- return servers['servers']
-
def nova_show(self, server):
got_server = (self.servers_client.show_server(server['id'])
['server'])
@@ -96,6 +90,13 @@
'%s' % (secgroup['id'], server['id']))
raise exceptions.TimeoutException(msg)
+ def _get_floating_ip_in_server_addresses(self, floating_ip, server):
+ for network_name, addresses in server['addresses'].items():
+ for address in addresses:
+ if (address['OS-EXT-IPS:type'] == 'floating' and
+ address['addr'] == floating_ip['ip']):
+ return address
+
@test.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
@test.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
@@ -105,7 +106,7 @@
server = self.create_server(image_id=image,
key_name=keypair['name'],
wait_until='ACTIVE')
- servers = self.nova_list()
+ servers = self.servers_client.list_servers()['servers']
self.assertIn(server['id'], [x['id'] for x in servers])
self.nova_show(server)
@@ -121,6 +122,16 @@
self.cinder_show(volume)
floating_ip = self.create_floating_ip(server)
+ # fetch the server again to make sure the addresses were refreshed
+ # after associating the floating IP
+ server = self.servers_client.show_server(server['id'])['server']
+ address = self._get_floating_ip_in_server_addresses(
+ floating_ip, server)
+ self.assertIsNotNone(
+ address,
+ "Failed to find floating IP '%s' in server addresses: %s" %
+ (floating_ip['ip'], server['addresses']))
+
self.create_and_add_security_group_to_server(server)
# check that we can SSH to the server before reboot
@@ -135,3 +146,21 @@
floating_ip['ip'], private_key=keypair['private_key'])
self.check_partitions()
+
+ # delete the floating IP, this should refresh the server addresses
+ self.compute_floating_ips_client.delete_floating_ip(floating_ip['id'])
+
+ def is_floating_ip_detached_from_server():
+ server_info = self.servers_client.show_server(
+ server['id'])['server']
+ address = self._get_floating_ip_in_server_addresses(
+ floating_ip, server_info)
+ return (not address)
+
+ if not test_utils.call_until_true(
+ is_floating_ip_detached_from_server,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
+ msg = ("Floating IP '%s' should not be in server addresses: %s" %
+ (floating_ip['ip'], server['addresses']))
+ raise exceptions.TimeoutException(msg)
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 8f27a5d..60b030d 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -15,7 +15,6 @@
import testtools
-from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
from tempest.scenario import manager
@@ -50,28 +49,28 @@
cls.set_network_resources()
super(TestNetworkAdvancedServerOps, cls).setup_credentials()
- def _setup_network_and_servers(self):
- keypair = self.create_keypair()
+ def _setup_server(self, keypair):
security_groups = []
if test.is_extension_enabled('security-group', 'network'):
security_group = self._create_security_group()
security_groups = [{'name': security_group['name']}]
network, subnet, router = self.create_networks()
- public_network_id = CONF.network.public_network_id
- server_name = data_utils.rand_name(self.__class__.__name__ + '-server')
server = self.create_server(
- name=server_name,
networks=[{'uuid': network['id']}],
key_name=keypair['name'],
security_groups=security_groups,
wait_until='ACTIVE')
+ return server
+
+ def _setup_network(self, server, keypair):
+ public_network_id = CONF.network.public_network_id
floating_ip = self.create_floating_ip(server, public_network_id)
# Verify that we can indeed connect to the server before we mess with
# it's state
self._wait_server_status_and_check_network_connectivity(
server, keypair, floating_ip)
- return server, keypair, floating_ip
+ return floating_ip
def _check_network_connectivity(self, server, keypair, floating_ip,
should_connect=True):
@@ -96,10 +95,11 @@
self._check_network_connectivity(server, keypair, floating_ip)
@test.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021')
- @test.stresstest(class_setup_per='process')
@test.services('compute', 'network')
def test_server_connectivity_stop_start(self):
- server, keypair, floating_ip = self._setup_network_and_servers()
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
self.servers_client.stop_server(server['id'])
waiters.wait_for_server_status(self.servers_client, server['id'],
'SHUTOFF')
@@ -112,7 +112,9 @@
@test.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08')
@test.services('compute', 'network')
def test_server_connectivity_reboot(self):
- server, keypair, floating_ip = self._setup_network_and_servers()
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
self.servers_client.reboot_server(server['id'], type='SOFT')
self._wait_server_status_and_check_network_connectivity(
server, keypair, floating_ip)
@@ -120,7 +122,9 @@
@test.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699')
@test.services('compute', 'network')
def test_server_connectivity_rebuild(self):
- server, keypair, floating_ip = self._setup_network_and_servers()
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
image_ref_alt = CONF.compute.image_ref_alt
self.servers_client.rebuild_server(server['id'],
image_ref=image_ref_alt)
@@ -132,7 +136,9 @@
'Pause is not available.')
@test.services('compute', 'network')
def test_server_connectivity_pause_unpause(self):
- server, keypair, floating_ip = self._setup_network_and_servers()
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
self.servers_client.pause_server(server['id'])
waiters.wait_for_server_status(self.servers_client, server['id'],
'PAUSED')
@@ -147,7 +153,9 @@
'Suspend is not available.')
@test.services('compute', 'network')
def test_server_connectivity_suspend_resume(self):
- server, keypair, floating_ip = self._setup_network_and_servers()
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
self.servers_client.suspend_server(server['id'])
waiters.wait_for_server_status(self.servers_client, server['id'],
'SUSPENDED')
@@ -166,7 +174,9 @@
if resize_flavor == CONF.compute.flavor_ref:
msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
raise self.skipException(msg)
- server, keypair, floating_ip = self._setup_network_and_servers()
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
self.servers_client.resize_server(server['id'],
flavor_ref=resize_flavor)
waiters.wait_for_server_status(self.servers_client, server['id'],
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 519dbec..125d61a 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -22,9 +22,9 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
+from tempest.lib import exceptions
from tempest.scenario import manager
from tempest import test
@@ -183,7 +183,7 @@
def check_public_network_connectivity(
self, should_connect=True, msg=None,
- should_check_floating_ip_status=True):
+ should_check_floating_ip_status=True, mtu=None):
"""Verifies connectivty to a VM via public network and floating IP
and verifies floating IP has resource status is correct.
@@ -195,6 +195,7 @@
to indicate the context of the failure
:param should_check_floating_ip_status: bool. should status of
floating_ip be checked or not
+ :param mtu: int. MTU network to use for connectivity validation
"""
ssh_login = CONF.validation.image_ssh_user
floating_ip, server = self.floating_ip_tuple
@@ -210,7 +211,7 @@
# call the common method in the parent class
super(TestNetworkBasicOps, self).check_public_network_connectivity(
ip_address, ssh_login, private_key, should_connect, msg,
- self.servers)
+ self.servers, mtu=mtu)
def _disassociate_floating_ips(self):
floating_ip, server = self.floating_ip_tuple
@@ -410,6 +411,16 @@
msg="after re-associate "
"floating ip")
+ @test.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
+ @testtools.skipUnless(test.is_extension_enabled('net-mtu', 'network'),
+ 'No way to calculate MTU for networks')
+ @test.services('compute', 'network')
+ def test_mtu_sized_frames(self):
+ """Validate that network MTU sized frames fit through."""
+ self._setup_network_and_servers()
+ self.check_public_network_connectivity(
+ should_connect=True, mtu=self.network['mtu'])
+
@test.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15')
@testtools.skipIf(CONF.baremetal.driver_enabled,
'Baremetal relies on a shared physical network.')
@@ -473,11 +484,11 @@
def test_hotplug_nic(self):
"""Test hotplug network interface
- 1. create a new network, with no gateway (to prevent overwriting VM's
- gateway)
- 2. connect VM to new network
- 3. set static ip and bring new nic up
- 4. check VM can ping new network dhcp port
+ 1. Create a network and a VM.
+ 2. Check connectivity to the VM via a public network.
+ 3. Create a new network, with no gateway.
+ 4. Bring up a new interface
+ 5. check the VM reach the new network
"""
self._setup_network_and_servers()
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index dd86d90..496f07e 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -18,7 +18,6 @@
from tempest import config
from tempest.lib.common.utils import test_utils
-from tempest.lib import decorators
from tempest.scenario import manager
from tempest import test
@@ -255,7 +254,6 @@
self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2,
dualnet=True)
- @decorators.skip_because(bug="1540983")
@test.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd')
@test.services('compute', 'network')
def test_dualnet_multi_prefix_slaac(self):
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 86185c8..32f5d9f 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -13,9 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
+import testtools
from tempest import clients
from tempest.common.utils import data_utils
+from tempest.common.utils import net_info
from tempest import config
from tempest.scenario import manager
from tempest import test
@@ -246,17 +248,11 @@
myport = (tenant.router['id'], tenant.subnet['id'])
router_ports = [(i['device_id'], i['fixed_ips'][0]['subnet_id']) for i
in self._list_ports()
- if self._is_router_port(i)]
+ if net_info.is_router_interface_port(i)]
self.assertIn(myport, router_ports)
- def _is_router_port(self, port):
- """Return True if port is a router interface."""
- # NOTE(armando-migliaccio): match device owner for both centralized
- # and distributed routers; 'device_owner' is "" by default.
- return port['device_owner'].startswith('network:router_interface')
-
- def _create_server(self, name, tenant, security_groups=None, **kwargs):
+ def _create_server(self, name, tenant, security_groups, **kwargs):
"""Creates a server and assigns it to security group.
If multi-host is enabled, Ensures servers are created on different
@@ -264,8 +260,6 @@
as scheduler_hints on creation.
Validates servers are created as requested, using admin client.
"""
- if security_groups is None:
- security_groups = [tenant.security_groups['default']]
security_groups_names = [{'name': s['name']} for s in security_groups]
if self.multi_node:
kwargs["scheduler_hints"] = {'different_host': self.servers}
@@ -277,9 +271,10 @@
wait_until='ACTIVE',
clients=tenant.manager,
**kwargs)
- self.assertEqual(
- sorted([s['name'] for s in security_groups]),
- sorted([s['name'] for s in server['security_groups']]))
+ if 'security_groups' in server:
+ self.assertEqual(
+ sorted([s['name'] for s in security_groups]),
+ sorted([s['name'] for s in server['security_groups']]))
# Verify servers are on different compute nodes
if self.multi_node:
@@ -303,7 +298,8 @@
num=i
)
name = data_utils.rand_name(name)
- server = self._create_server(name, tenant)
+ server = self._create_server(name, tenant,
+ [tenant.security_groups['default']])
tenant.servers.append(server)
def _set_access_point(self, tenant):
@@ -326,11 +322,12 @@
client=tenant.manager.floating_ips_client)
self.floating_ips.setdefault(server['id'], floating_ip)
- def _create_tenant_network(self, tenant):
+ def _create_tenant_network(self, tenant, port_security_enabled=True):
network, subnet, router = self.create_networks(
networks_client=tenant.manager.networks_client,
routers_client=tenant.manager.routers_client,
- subnets_client=tenant.manager.subnets_client)
+ subnets_client=tenant.manager.subnets_client,
+ port_security_enabled=port_security_enabled)
tenant.set_network(network, subnet, router)
def _deploy_tenant(self, tenant_or_id):
@@ -533,7 +530,8 @@
tenant=new_tenant.creds.tenant_name
)
name = data_utils.rand_name(name)
- server = self._create_server(name, new_tenant)
+ server = self._create_server(name, new_tenant,
+ [new_tenant.security_groups['default']])
# Check connectivity failure with default security group
try:
@@ -599,7 +597,8 @@
tenant=new_tenant.creds.tenant_name
)
name = data_utils.rand_name(name)
- server = self._create_server(name, new_tenant)
+ server = self._create_server(name, new_tenant,
+ [new_tenant.security_groups['default']])
access_point_ssh = self._connect_to_access_point(new_tenant)
server_id = server['id']
@@ -624,3 +623,32 @@
for tenant in self.tenants.values():
self._log_console_output(servers=tenant.servers)
raise
+
+ @test.requires_ext(service='network', extension='port-security')
+ @test.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
+ @testtools.skipUnless(
+ CONF.compute_feature_enabled.allow_port_security_disabled,
+ 'Port security must be enabled.')
+ # TODO(mriedem): We shouldn't actually need to check this since neutron
+ # disables the port_security extension by default, but the problem is nova
+ # assumes port_security_enabled=True if it's not set on the network
+ # resource, which will mean nova may attempt to apply a security group on
+ # a port on that network which would fail. This is really a bug in nova.
+ @testtools.skipUnless(
+ CONF.network_feature_enabled.port_security,
+ 'Port security must be enabled.')
+ @test.services('compute', 'network')
+ def test_boot_into_disabled_port_security_network_without_secgroup(self):
+ tenant = self.primary_tenant
+ self._create_tenant_network(tenant, port_security_enabled=False)
+ self.assertFalse(tenant.network['port_security_enabled'])
+ name = data_utils.rand_name('server-smoke')
+ sec_groups = []
+ server = self._create_server(name, tenant, sec_groups)
+ server_id = server['id']
+ ports = self._list_ports(device_id=server_id)
+ self.assertEqual(1, len(ports))
+ for port in ports:
+ self.assertEmpty(port['security_groups'],
+ "Neutron shouldn't even use it's default sec "
+ "group.")
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index e031ff7..c66128d 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -119,14 +119,13 @@
@test.services('compute', 'network')
def test_server_basic_ops(self):
keypair = self.create_keypair()
- self.security_group = self._create_security_group()
- security_groups = [{'name': self.security_group['name']}]
+ security_group = self._create_security_group()
self.md = {'meta1': 'data1', 'meta2': 'data2', 'metaN': 'dataN'}
self.instance = self.create_server(
image_id=self.image_ref,
flavor=self.flavor_ref,
key_name=keypair['name'],
- security_groups=security_groups,
+ security_groups=[{'name': security_group['name']}],
config_drive=CONF.compute_feature_enabled.config_drive,
metadata=self.md,
wait_until='ACTIVE')
diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py
index 0cf72c3..170d220 100644
--- a/tempest/scenario/test_server_multinode.py
+++ b/tempest/scenario/test_server_multinode.py
@@ -15,7 +15,7 @@
from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
from tempest.scenario import manager
from tempest import test
@@ -42,15 +42,22 @@
# this is needed so that we can use the availability_zone:host
# scheduler hint, which is admin_only by default
cls.servers_client = cls.admin_manager.servers_client
- super(TestServerMultinode, cls).resource_setup()
@test.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30')
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_schedule_to_all_nodes(self):
- host_client = self.manager.hosts_client
- hosts = host_client.list_hosts()['hosts']
- hosts = [x for x in hosts if x['service'] == 'compute']
+ available_zone = \
+ self.os_adm.availability_zone_client.list_availability_zones(
+ detail=True)['availabilityZoneInfo']
+ hosts = []
+ for zone in available_zone:
+ if zone['zoneState']['available']:
+ for host in zone['hosts']:
+ if 'nova-compute' in zone['hosts'][host] and \
+ zone['hosts'][host]['nova-compute']['available']:
+ hosts.append({'zone': zone['zoneName'],
+ 'host_name': host})
# ensure we have at least as many compute hosts as we expect
if len(hosts) < CONF.compute.min_compute_nodes:
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 5fd934c..0f2c78c 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -21,7 +21,6 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest import exceptions
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
@@ -93,7 +92,7 @@
if not test_utils.call_until_true(_func,
CONF.compute.build_timeout,
CONF.compute.build_interval):
- raise exceptions.TimeoutException
+ raise lib_exc.TimeoutException
@decorators.skip_because(bug="1205344")
@test.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
old mode 100755
new mode 100644
index 3f6d9c4..db5e009
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -24,18 +24,6 @@
class TestVolumeBootPattern(manager.ScenarioTest):
- """This test case attempts to reproduce the following steps:
-
- * Create in Cinder some bootable volume importing a Glance image
- * Boot an instance from the bootable volume
- * Write content to the volume
- * Delete an instance and Boot a new instance from the volume
- * Check written content in the instance
- * Create a volume snapshot while the instance is running
- * Boot an additional instance from the new snapshot based volume
- * Check written content in the instance booted from snapshot
- """
-
# Boot from volume scenario is quite slow, and needs extra
# breathing room to get through deletes in the time allotted.
TIMEOUT_SCALING_FACTOR = 2
@@ -100,11 +88,6 @@
return snap
- def _create_volume_from_snapshot(self, snap_id):
- vol_name = data_utils.rand_name(
- self.__class__.__name__ + '-volume')
- return self.create_volume(name=vol_name, snapshot_id=snap_id)
-
def _delete_server(self, server):
self.servers_client.delete_server(server['id'])
waiters.wait_for_server_termination(self.servers_client, server['id'])
@@ -113,6 +96,19 @@
@test.attr(type='smoke')
@test.services('compute', 'volume', 'image')
def test_volume_boot_pattern(self):
+
+ """This test case attempts to reproduce the following steps:
+
+ * Create in Cinder some bootable volume importing a Glance image
+ * Boot an instance from the bootable volume
+ * Write content to the volume
+ * Delete an instance and Boot a new instance from the volume
+ * Check written content in the instance
+ * Create a volume snapshot while the instance is running
+ * Boot an additional instance from the new snapshot based volume
+ * Check written content in the instance booted from snapshot
+ """
+
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
security_group = self._create_security_group()
@@ -152,7 +148,7 @@
# create a 3rd instance from snapshot
LOG.info("Creating third instance from snapshot: %s" % snapshot['id'])
- volume = self._create_volume_from_snapshot(snapshot['id'])
+ volume = self.create_volume(snapshot_id=snapshot['id'])
server_from_snapshot = (
self._boot_instance_from_volume(volume['id'],
keypair, security_group))
@@ -173,8 +169,7 @@
instance = self._boot_instance_from_volume(volume_origin['id'],
delete_on_termination=True)
# create EBS image
- name = data_utils.rand_name(self.__class__.__name__ + '-image')
- image = self.create_server_snapshot(instance, name=name)
+ image = self.create_server_snapshot(instance)
# delete instance
self._delete_server(instance)
diff --git a/tempest/services/baremetal/v1/json/baremetal_client.py b/tempest/services/baremetal/v1/json/baremetal_client.py
old mode 100755
new mode 100644
index ede0d90..7405871
--- a/tempest/services/baremetal/v1/json/baremetal_client.py
+++ b/tempest/services/baremetal/v1/json/baremetal_client.py
@@ -84,7 +84,7 @@
def show_node_by_instance_uuid(self, instance_uuid):
"""Gets a node associated with given instance uuid.
- :param uuid: Unique identifier of the node in UUID format.
+ :param instance_uuid: Unique identifier of the instance in UUID format.
:return: Serialized node as a dictionary.
"""
@@ -138,6 +138,7 @@
def create_node(self, chassis_id=None, **kwargs):
"""Create a baremetal node with the specified parameters.
+ :param chassis_id: The unique identifier of the chassis.
:param cpu_arch: CPU architecture of the node. Default: x86_64.
:param cpus: Number of CPUs. Default: 8.
:param local_gb: Disk size. Default: 1024.
@@ -269,7 +270,7 @@
"""Set power state of the specified node.
:param node_uuid: The unique identifier of the node.
- :state: desired state to set (on/off/reboot).
+ :param state: desired state to set (on/off/reboot).
"""
target = {'target': state}
@@ -280,7 +281,7 @@
def validate_driver_interface(self, node_uuid):
"""Get all driver interfaces of a specific node.
- :param uuid: Unique identifier of the node in UUID format.
+ :param node_uuid: Unique identifier of the node in UUID format.
"""
diff --git a/tempest/services/data_processing/__init__.py b/tempest/services/data_processing/__init__.py
deleted file mode 100644
index c49bc5c..0000000
--- a/tempest/services/data_processing/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
-#
-# 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.services.data_processing.v1_1.data_processing_client import \
- DataProcessingClient
-
-__all__ = ['DataProcessingClient']
diff --git a/tempest/services/data_processing/v1_1/__init__.py b/tempest/services/data_processing/v1_1/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/data_processing/v1_1/__init__.py
+++ /dev/null
diff --git a/tempest/services/data_processing/v1_1/data_processing_client.py b/tempest/services/data_processing/v1_1/data_processing_client.py
deleted file mode 100644
index c74672f..0000000
--- a/tempest/services/data_processing/v1_1/data_processing_client.py
+++ /dev/null
@@ -1,280 +0,0 @@
-# Copyright (c) 2013 Mirantis Inc.
-#
-# 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 oslo_serialization import jsonutils as json
-
-from tempest.lib.common import rest_client
-
-
-class DataProcessingClient(rest_client.RestClient):
-
- def _request_and_check_resp(self, request_func, uri, resp_status):
- """Make a request and check response status code.
-
- It returns a ResponseBody.
- """
- resp, body = request_func(uri)
- self.expected_success(resp_status, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def _request_and_check_resp_data(self, request_func, uri, resp_status):
- """Make a request and check response status code.
-
- It returns pair: resp and response data.
- """
- resp, body = request_func(uri)
- self.expected_success(resp_status, resp.status)
- return resp, body
-
- def _request_check_and_parse_resp(self, request_func, uri,
- resp_status, *args, **kwargs):
- """Make a request, check response status code and parse response body.
-
- It returns a ResponseBody.
- """
- headers = {'Content-Type': 'application/json'}
- resp, body = request_func(uri, headers=headers, *args, **kwargs)
- self.expected_success(resp_status, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def list_node_group_templates(self):
- """List all node group templates for a user."""
-
- uri = 'node-group-templates'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_node_group_template(self, tmpl_id):
- """Returns the details of a single node group template."""
-
- uri = 'node-group-templates/%s' % tmpl_id
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def create_node_group_template(self, name, plugin_name, hadoop_version,
- node_processes, flavor_id,
- node_configs=None, **kwargs):
- """Creates node group template with specified params.
-
- It supports passing additional params using kwargs and returns created
- object.
- """
- uri = 'node-group-templates'
- body = kwargs.copy()
- body.update({
- 'name': name,
- 'plugin_name': plugin_name,
- 'hadoop_version': hadoop_version,
- 'node_processes': node_processes,
- 'flavor_id': flavor_id,
- 'node_configs': node_configs or dict(),
- })
- return self._request_check_and_parse_resp(self.post, uri, 202,
- body=json.dumps(body))
-
- def delete_node_group_template(self, tmpl_id):
- """Deletes the specified node group template by id."""
-
- uri = 'node-group-templates/%s' % tmpl_id
- return self._request_and_check_resp(self.delete, uri, 204)
-
- def list_plugins(self):
- """List all enabled plugins."""
-
- uri = 'plugins'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_plugin(self, plugin_name, plugin_version=None):
- """Returns the details of a single plugin."""
-
- uri = 'plugins/%s' % plugin_name
- if plugin_version:
- uri += '/%s' % plugin_version
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def list_cluster_templates(self):
- """List all cluster templates for a user."""
-
- uri = 'cluster-templates'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_cluster_template(self, tmpl_id):
- """Returns the details of a single cluster template."""
-
- uri = 'cluster-templates/%s' % tmpl_id
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def create_cluster_template(self, name, plugin_name, hadoop_version,
- node_groups, cluster_configs=None,
- **kwargs):
- """Creates cluster template with specified params.
-
- It supports passing additional params using kwargs and returns created
- object.
- """
- uri = 'cluster-templates'
- body = kwargs.copy()
- body.update({
- 'name': name,
- 'plugin_name': plugin_name,
- 'hadoop_version': hadoop_version,
- 'node_groups': node_groups,
- 'cluster_configs': cluster_configs or dict(),
- })
- return self._request_check_and_parse_resp(self.post, uri, 202,
- body=json.dumps(body))
-
- def delete_cluster_template(self, tmpl_id):
- """Deletes the specified cluster template by id."""
-
- uri = 'cluster-templates/%s' % tmpl_id
- return self._request_and_check_resp(self.delete, uri, 204)
-
- def list_data_sources(self):
- """List all data sources for a user."""
-
- uri = 'data-sources'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_data_source(self, source_id):
- """Returns the details of a single data source."""
-
- uri = 'data-sources/%s' % source_id
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def create_data_source(self, name, data_source_type, url, **kwargs):
- """Creates data source with specified params.
-
- It supports passing additional params using kwargs and returns created
- object.
- """
- uri = 'data-sources'
- body = kwargs.copy()
- body.update({
- 'name': name,
- 'type': data_source_type,
- 'url': url
- })
- return self._request_check_and_parse_resp(self.post, uri,
- 202, body=json.dumps(body))
-
- def delete_data_source(self, source_id):
- """Deletes the specified data source by id."""
-
- uri = 'data-sources/%s' % source_id
- return self._request_and_check_resp(self.delete, uri, 204)
-
- def list_job_binary_internals(self):
- """List all job binary internals for a user."""
-
- uri = 'job-binary-internals'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_job_binary_internal(self, job_binary_id):
- """Returns the details of a single job binary internal."""
-
- uri = 'job-binary-internals/%s' % job_binary_id
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def create_job_binary_internal(self, name, data):
- """Creates job binary internal with specified params."""
-
- uri = 'job-binary-internals/%s' % name
- return self._request_check_and_parse_resp(self.put, uri, 202, data)
-
- def delete_job_binary_internal(self, job_binary_id):
- """Deletes the specified job binary internal by id."""
-
- uri = 'job-binary-internals/%s' % job_binary_id
- return self._request_and_check_resp(self.delete, uri, 204)
-
- def get_job_binary_internal_data(self, job_binary_id):
- """Returns data of a single job binary internal."""
-
- uri = 'job-binary-internals/%s/data' % job_binary_id
- return self._request_and_check_resp_data(self.get, uri, 200)
-
- def list_job_binaries(self):
- """List all job binaries for a user."""
-
- uri = 'job-binaries'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_job_binary(self, job_binary_id):
- """Returns the details of a single job binary."""
-
- uri = 'job-binaries/%s' % job_binary_id
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def create_job_binary(self, name, url, extra=None, **kwargs):
- """Creates job binary with specified params.
-
- It supports passing additional params using kwargs and returns created
- object.
- """
- uri = 'job-binaries'
- body = kwargs.copy()
- body.update({
- 'name': name,
- 'url': url,
- 'extra': extra or dict(),
- })
- return self._request_check_and_parse_resp(self.post, uri,
- 202, body=json.dumps(body))
-
- def delete_job_binary(self, job_binary_id):
- """Deletes the specified job binary by id."""
-
- uri = 'job-binaries/%s' % job_binary_id
- return self._request_and_check_resp(self.delete, uri, 204)
-
- def get_job_binary_data(self, job_binary_id):
- """Returns data of a single job binary."""
-
- uri = 'job-binaries/%s/data' % job_binary_id
- return self._request_and_check_resp_data(self.get, uri, 200)
-
- def list_jobs(self):
- """List all jobs for a user."""
-
- uri = 'jobs'
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def get_job(self, job_id):
- """Returns the details of a single job."""
-
- uri = 'jobs/%s' % job_id
- return self._request_check_and_parse_resp(self.get, uri, 200)
-
- def create_job(self, name, job_type, mains, libs=None, **kwargs):
- """Creates job with specified params.
-
- It supports passing additional params using kwargs and returns created
- object.
- """
- uri = 'jobs'
- body = kwargs.copy()
- body.update({
- 'name': name,
- 'type': job_type,
- 'mains': mains,
- 'libs': libs or list(),
- })
- return self._request_check_and_parse_resp(self.post, uri,
- 202, body=json.dumps(body))
-
- def delete_job(self, job_id):
- """Deletes the specified job by id."""
-
- uri = 'jobs/%s' % job_id
- return self._request_and_check_resp(self.delete, uri, 204)
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index 3f5c3d5..9b40b77 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -28,8 +28,11 @@
from tempest.lib.services.identity.v3.trusts_client import TrustsClient
from tempest.lib.services.identity.v3.users_client import UsersClient
from tempest.services.identity.v3.json.domains_client import DomainsClient
+from tempest.services.identity.v3.json.role_assignments_client import \
+ RoleAssignmentsClient
__all__ = ['CredentialsClient', 'EndPointsClient', 'GroupsClient',
'IdentityClient', 'InheritedRolesClient', 'PoliciesClient',
- 'ProjectsClient', 'RegionsClient', 'RolesClient', 'ServicesClient',
- 'V3TokenClient', 'TrustsClient', 'UsersClient', 'DomainsClient', ]
+ 'ProjectsClient', 'RegionsClient', 'RoleAssignmentsClient',
+ 'RolesClient', 'ServicesClient', 'V3TokenClient', 'TrustsClient',
+ 'UsersClient', 'DomainsClient', ]
diff --git a/tempest/services/identity/v3/json/role_assignments_client.py b/tempest/services/identity/v3/json/role_assignments_client.py
new file mode 100644
index 0000000..9fd7736
--- /dev/null
+++ b/tempest/services/identity/v3/json/role_assignments_client.py
@@ -0,0 +1,31 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class RoleAssignmentsClient(rest_client.RestClient):
+ api_version = "v3"
+
+ def list_user_project_effective_assignments(
+ self, project_id, user_id):
+ """List the effective role assignments for a user in a project."""
+ resp, body = self.get(
+ "role_assignments?scope.project.id=%s&user.id=%s&effective" %
+ (project_id, user_id))
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index 5a26bfc..2509156 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -96,28 +96,6 @@
self.expected_success(204, resp.status)
return resp, body
- def list_all_container_objects(self, container, params=None):
- """Returns complete list of all objects in the container
-
- even if item count is beyond 10,000 item listing limit.
- Does not require any parameters aside from container name.
- """
- # TODO(dwalleck): Rewrite using json format to avoid newlines at end of
- # obj names. Set limit to API limit - 1 (max returned items = 9999)
- limit = 9999
- if params is not None:
- if 'limit' in params:
- limit = params['limit']
-
- if 'marker' in params:
- limit = params['marker']
-
- resp, objlist = self.list_container_contents(
- container,
- params={'limit': limit, 'format': 'json'})
- self.expected_success(200, resp.status)
- return objlist
-
def list_container_contents(self, container, params=None):
"""List the objects in a container, given the container name
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index ec36fb7..9445e34 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -164,7 +164,7 @@
chunked=True
)
- self._error_checker('PUT', None, headers, contents, resp, body)
+ self._error_checker(resp, body)
self.expected_success(201, resp.status)
return resp.status, resp.reason, resp
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index ea5dbe5..9fec548 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -178,7 +178,7 @@
'within the required time (%s s).' %
(stack_name, status, stack_status,
self.build_timeout))
- raise exceptions.TimeoutException(message)
+ raise lib_exc.TimeoutException(message)
time.sleep(self.build_interval)
def show_resource_metadata(self, stack_identifier, resource_name):
diff --git a/tempest/services/volume/__init__.py b/tempest/services/volume/__init__.py
index 4d29cdd..c62dd53 100644
--- a/tempest/services/volume/__init__.py
+++ b/tempest/services/volume/__init__.py
@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations under
# the License.
-from tempest.services.volume import v1
-from tempest.services.volume import v2
from tempest.services.volume import v3
-__all__ = ['v1', 'v2', 'v3']
+__all__ = ['v3']
diff --git a/tempest/services/volume/v1/__init__.py b/tempest/services/volume/v1/__init__.py
deleted file mode 100644
index 72868bc..0000000
--- a/tempest/services/volume/v1/__init__.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
-#
-# 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.v1.availability_zone_client import \
- AvailabilityZoneClient
-from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient
-from tempest.lib.services.volume.v1.hosts_client import HostsClient
-from tempest.lib.services.volume.v1.quotas_client import QuotasClient
-from tempest.lib.services.volume.v1.services_client import ServicesClient
-from tempest.services.volume.v1.json.admin.types_client import TypesClient
-from tempest.services.volume.v1.json.backups_client import BackupsClient
-from tempest.services.volume.v1.json.encryption_types_client import \
- EncryptionTypesClient
-from tempest.services.volume.v1.json.qos_client import QosSpecsClient
-from tempest.services.volume.v1.json.snapshots_client import SnapshotsClient
-from tempest.services.volume.v1.json.volumes_client import VolumesClient
-
-__all__ = ['HostsClient', 'QuotasClient', 'ServicesClient', 'TypesClient',
- 'AvailabilityZoneClient', 'BackupsClient', 'ExtensionsClient',
- 'QosSpecsClient', 'SnapshotsClient', 'VolumesClient',
- 'EncryptionTypesClient']
diff --git a/tempest/services/volume/v1/json/__init__.py b/tempest/services/volume/v1/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/v1/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/v1/json/admin/__init__.py b/tempest/services/volume/v1/json/admin/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/v1/json/admin/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/v1/json/backups_client.py b/tempest/services/volume/v1/json/backups_client.py
deleted file mode 100644
index ac6db6a..0000000
--- a/tempest/services/volume/v1/json/backups_client.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2014 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.services.volume.base import base_backups_client
-
-
-class BackupsClient(base_backups_client.BaseBackupsClient):
- """Volume V1 Backups client"""
diff --git a/tempest/services/volume/v1/json/qos_client.py b/tempest/services/volume/v1/json/qos_client.py
deleted file mode 100644
index b2b2195..0000000
--- a/tempest/services/volume/v1/json/qos_client.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.services.volume.base import base_qos_client
-
-
-class QosSpecsClient(base_qos_client.BaseQosSpecsClient):
- """Volume V1 QoS client."""
diff --git a/tempest/services/volume/v1/json/snapshots_client.py b/tempest/services/volume/v1/json/snapshots_client.py
deleted file mode 100644
index b039c2b..0000000
--- a/tempest/services/volume/v1/json/snapshots_client.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.services.volume.base import base_snapshots_client
-
-
-class SnapshotsClient(base_snapshots_client.BaseSnapshotsClient):
- """Client class to send CRUD Volume V1 API requests."""
diff --git a/tempest/services/volume/v1/json/volumes_client.py b/tempest/services/volume/v1/json/volumes_client.py
deleted file mode 100644
index 7782043..0000000
--- a/tempest/services/volume/v1/json/volumes_client.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2012 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.services.volume.base import base_volumes_client
-
-
-class VolumesClient(base_volumes_client.BaseVolumesClient):
- """Client class to send CRUD Volume V1 API requests"""
diff --git a/tempest/services/volume/v2/__init__.py b/tempest/services/volume/v2/__init__.py
deleted file mode 100644
index 4afcc29..0000000
--- a/tempest/services/volume/v2/__init__.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
-#
-# 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.v2.availability_zone_client import \
- AvailabilityZoneClient
-from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
-from tempest.lib.services.volume.v2.hosts_client import HostsClient
-from tempest.lib.services.volume.v2.quotas_client import QuotasClient
-from tempest.lib.services.volume.v2.services_client import ServicesClient
-from tempest.services.volume.v2.json.admin.types_client import TypesClient
-from tempest.services.volume.v2.json.backups_client import BackupsClient
-from tempest.services.volume.v2.json.encryption_types_client import \
- EncryptionTypesClient
-from tempest.services.volume.v2.json.qos_client import QosSpecsClient
-from tempest.services.volume.v2.json.snapshots_client import SnapshotsClient
-from tempest.services.volume.v2.json.volumes_client import VolumesClient
-
-__all__ = ['HostsClient', 'QuotasClient', 'ServicesClient', 'TypesClient',
- 'AvailabilityZoneClient', 'BackupsClient', 'ExtensionsClient',
- 'QosSpecsClient', 'SnapshotsClient', 'VolumesClient',
- 'EncryptionTypesClient']
diff --git a/tempest/services/volume/v2/json/__init__.py b/tempest/services/volume/v2/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/v2/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/v2/json/admin/__init__.py b/tempest/services/volume/v2/json/admin/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/v2/json/admin/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/v2/json/qos_client.py b/tempest/services/volume/v2/json/qos_client.py
deleted file mode 100644
index 3c0f74f..0000000
--- a/tempest/services/volume/v2/json/qos_client.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.services.volume.base import base_qos_client
-
-
-class QosSpecsClient(base_qos_client.BaseQosSpecsClient):
- api_version = "v2"
diff --git a/tempest/services/volume/v2/json/snapshots_client.py b/tempest/services/volume/v2/json/snapshots_client.py
deleted file mode 100644
index a2d415f..0000000
--- a/tempest/services/volume/v2/json/snapshots_client.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.services.volume.base import base_snapshots_client
-
-
-class SnapshotsClient(base_snapshots_client.BaseSnapshotsClient):
- """Client class to send CRUD Volume V2 API requests."""
- api_version = "v2"
- create_resp = 202
diff --git a/tempest/services/volume/v2/json/volumes_client.py b/tempest/services/volume/v2/json/volumes_client.py
deleted file mode 100644
index f21a1a3..0000000
--- a/tempest/services/volume/v2/json/volumes_client.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2012 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 oslo_serialization import jsonutils as json
-
-from tempest.lib.common import rest_client
-from tempest.services.volume.base import base_volumes_client
-
-
-class VolumesClient(base_volumes_client.BaseVolumesClient):
- """Client class to send CRUD Volume V2 API requests"""
- api_version = "v2"
- create_resp = 202
-
- def update_volume_image_metadata(self, volume_id, **kwargs):
- """Update image metadata for the volume.
-
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html
- #setVolumeimagemetadata
- """
- post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
- url = "volumes/%s/action" % (volume_id)
- resp, body = self.post(url, post_body)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def delete_volume_image_metadata(self, volume_id, key_name):
- """Delete image metadata item for the volume."""
- post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}})
- url = "volumes/%s/action" % (volume_id)
- resp, body = self.post(url, post_body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def show_pools(self, detail=False):
- # List all the volumes pools (hosts)
- url = 'scheduler-stats/get_pools'
- if detail:
- url += '?detail=True'
-
- resp, body = self.get(url)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def show_backend_capabilities(self, host):
- """Shows capabilities for a storage back end.
-
- Output params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html
- #showBackendCapabilities
- """
- url = 'capabilities/%s' % host
- resp, body = self.get(url)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
diff --git a/tempest/stress/README.rst b/tempest/stress/README.rst
deleted file mode 100644
index 33842fd..0000000
--- a/tempest/stress/README.rst
+++ /dev/null
@@ -1,60 +0,0 @@
-.. _stress_field_guide:
-
-Tempest Field Guide to Stress Tests
-===================================
-
-OpenStack is a distributed, asynchronous system that is prone to race condition
-bugs. These bugs will not be easily found during
-functional testing but will be encountered by users in large deployments in a
-way that is hard to debug. The stress test tries to cause these bugs to happen
-in a more controlled environment.
-
-
-Environment
------------
-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 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
-location of the log files:
-
- target_logfiles = "regexp to all log files to be checked for errors"
- target_private_key_path = "private ssh key for controller and log file nodes"
- target_ssh_user = "username for controller and log file nodes"
- target_controller = "hostname or ip of controller node (for nova-manage)
- log_check_interval = "time between checking logs for errors (default 60s)"
-
-To activate logging on your console please make sure that you activate `use_stderr`
-in tempest.conf or use the default `logging.conf.sample` file.
-
-Running default stress test set
--------------------------------
-
-The stress test framework can automatically discover test inside the tempest
-test suite. All test flag with the `@stresstest` decorator will be executed.
-In order to use this discovery you have to install tempest CLI, be in the
-tempest root directory and execute the following:
-
- tempest run-stress -a -d 30
-
-Running the sample test
------------------------
-
-To test installation, do the following:
-
- tempest run-stress -t tempest/stress/etc/server-create-destroy-test.json -d 30
-
-This sample test tries to create a few VMs and kill a few VMs.
-
-
-Additional Tools
-----------------
-
-Sometimes the tests don't finish, or there are failures. In these
-cases, you may want to clean out the nova cluster. We have provided
-some scripts to do this in the ``tools`` subdirectory.
-You can use the following script to destroy any keypairs,
-floating ips, and servers:
-
-tempest/stress/tools/cleanup.py
diff --git a/tempest/stress/__init__.py b/tempest/stress/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/stress/__init__.py
+++ /dev/null
diff --git a/tempest/stress/actions/__init__.py b/tempest/stress/actions/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/stress/actions/__init__.py
+++ /dev/null
diff --git a/tempest/stress/actions/server_create_destroy.py b/tempest/stress/actions/server_create_destroy.py
deleted file mode 100644
index 183bc6c..0000000
--- a/tempest/stress/actions/server_create_destroy.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2013 Quanta Research Cambridge, Inc.
-#
-# 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.common.utils import data_utils
-from tempest.common import waiters
-from tempest import config
-import tempest.stress.stressaction as stressaction
-
-CONF = config.CONF
-
-
-class ServerCreateDestroyTest(stressaction.StressAction):
-
- def setUp(self, **kwargs):
- self.image = CONF.compute.image_ref
- self.flavor = CONF.compute.flavor_ref
-
- def run(self):
- name = data_utils.rand_name(self.__class__.__name__ + "-instance")
- self.logger.info("creating %s" % name)
- server = self.manager.servers_client.create_server(
- name=name, imageRef=self.image, flavorRef=self.flavor)['server']
- server_id = server['id']
- waiters.wait_for_server_status(self.manager.servers_client, server_id,
- 'ACTIVE')
- self.logger.info("created %s" % server_id)
- self.logger.info("deleting %s" % name)
- self.manager.servers_client.delete_server(server_id)
- waiters.wait_for_server_termination(self.manager.servers_client,
- server_id)
- self.logger.info("deleted %s" % server_id)
diff --git a/tempest/stress/actions/ssh_floating.py b/tempest/stress/actions/ssh_floating.py
deleted file mode 100644
index 845b4a7..0000000
--- a/tempest/stress/actions/ssh_floating.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# 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 socket
-import subprocess
-
-from tempest.common.utils import data_utils
-from tempest.common import waiters
-from tempest import config
-from tempest.lib.common.utils import test_utils
-import tempest.stress.stressaction as stressaction
-
-CONF = config.CONF
-
-
-class FloatingStress(stressaction.StressAction):
-
- # from the scenario manager
- def ping_ip_address(self, ip_address):
- cmd = ['ping', '-c1', '-w1', ip_address]
-
- proc = subprocess.Popen(cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- proc.communicate()
- success = proc.returncode == 0
- return success
-
- def tcp_connect_scan(self, addr, port):
- # like tcp
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- s.connect((addr, port))
- except socket.error as exc:
- self.logger.info("%s(%s): %s", self.server_id, self.floating['ip'],
- str(exc))
- return False
- self.logger.info("%s(%s): Connected :)", self.server_id,
- self.floating['ip'])
- s.close()
- return True
-
- def check_port_ssh(self):
- def func():
- return self.tcp_connect_scan(self.floating['ip'], 22)
- if not test_utils.call_until_true(func, self.check_timeout,
- self.check_interval):
- raise RuntimeError("Cannot connect to the ssh port.")
-
- def check_icmp_echo(self):
- self.logger.info("%s(%s): Pinging..",
- self.server_id, self.floating['ip'])
-
- def func():
- return self.ping_ip_address(self.floating['ip'])
- if not test_utils.call_until_true(func, self.check_timeout,
- self.check_interval):
- raise RuntimeError("%s(%s): Cannot ping the machine.",
- self.server_id, self.floating['ip'])
- self.logger.info("%s(%s): pong :)",
- self.server_id, self.floating['ip'])
-
- def _create_vm(self):
- self.name = name = data_utils.rand_name(
- self.__class__.__name__ + "-instance")
- servers_client = self.manager.servers_client
- self.logger.info("creating %s" % name)
- vm_args = self.vm_extra_args.copy()
- vm_args['security_groups'] = [self.sec_grp]
- server = servers_client.create_server(name=name, imageRef=self.image,
- flavorRef=self.flavor,
- **vm_args)['server']
- self.server_id = server['id']
- if self.wait_after_vm_create:
- waiters.wait_for_server_status(self.manager.servers_client,
- self.server_id, 'ACTIVE')
-
- def _destroy_vm(self):
- self.logger.info("deleting %s" % self.server_id)
- self.manager.servers_client.delete_server(self.server_id)
- waiters.wait_for_server_termination(self.manager.servers_client,
- self.server_id)
- self.logger.info("deleted %s" % self.server_id)
-
- def _create_sec_group(self):
- sec_grp_cli = self.manager.compute_security_groups_client
- s_name = data_utils.rand_name(self.__class__.__name__ + '-sec_grp')
- s_description = data_utils.rand_name('desc')
- self.sec_grp = sec_grp_cli.create_security_group(
- name=s_name, description=s_description)['security_group']
- create_rule = sec_grp_cli.create_security_group_rule
- create_rule(parent_group_id=self.sec_grp['id'], ip_protocol='tcp',
- from_port=22, to_port=22)
- create_rule(parent_group_id=self.sec_grp['id'], ip_protocol='icmp',
- from_port=-1, to_port=-1)
-
- def _destroy_sec_grp(self):
- sec_grp_cli = self.manager.compute_security_groups_client
- sec_grp_cli.delete_security_group(self.sec_grp['id'])
-
- def _create_floating_ip(self):
- floating_cli = self.manager.compute_floating_ips_client
- self.floating = (floating_cli.create_floating_ip(self.floating_pool)
- ['floating_ip'])
-
- def _destroy_floating_ip(self):
- cli = self.manager.compute_floating_ips_client
- cli.delete_floating_ip(self.floating['id'])
- cli.wait_for_resource_deletion(self.floating['id'])
- self.logger.info("Deleted Floating IP %s", str(self.floating['ip']))
-
- def setUp(self, **kwargs):
- self.image = CONF.compute.image_ref
- self.flavor = CONF.compute.flavor_ref
- self.vm_extra_args = kwargs.get('vm_extra_args', {})
- self.wait_after_vm_create = kwargs.get('wait_after_vm_create',
- True)
- self.new_vm = kwargs.get('new_vm', False)
- self.new_sec_grp = kwargs.get('new_sec_group', False)
- self.new_floating = kwargs.get('new_floating', False)
- self.reboot = kwargs.get('reboot', False)
- self.floating_pool = kwargs.get('floating_pool', None)
- self.verify = kwargs.get('verify', ('check_port_ssh',
- 'check_icmp_echo'))
- self.check_timeout = kwargs.get('check_timeout', 120)
- self.check_interval = kwargs.get('check_interval', 1)
- self.wait_for_disassociate = kwargs.get('wait_for_disassociate',
- True)
-
- # allocate floating
- if not self.new_floating:
- self._create_floating_ip()
- # add security group
- if not self.new_sec_grp:
- self._create_sec_group()
- # create vm
- if not self.new_vm:
- self._create_vm()
-
- def wait_disassociate(self):
- cli = self.manager.compute_floating_ips_client
-
- def func():
- floating = (cli.show_floating_ip(self.floating['id'])
- ['floating_ip'])
- return floating['instance_id'] is None
-
- if not test_utils.call_until_true(func, self.check_timeout,
- self.check_interval):
- raise RuntimeError("IP disassociate timeout!")
-
- def run_core(self):
- cli = self.manager.compute_floating_ips_client
- cli.associate_floating_ip_to_server(self.floating['ip'],
- self.server_id)
- for method in self.verify:
- m = getattr(self, method)
- m()
- cli.disassociate_floating_ip_from_server(self.floating['ip'],
- self.server_id)
- if self.wait_for_disassociate:
- self.wait_disassociate()
-
- def run(self):
- if self.new_sec_grp:
- self._create_sec_group()
- if self.new_floating:
- self._create_floating_ip()
- if self.new_vm:
- self._create_vm()
- if self.reboot:
- self.manager.servers_client.reboot(self.server_id, 'HARD')
- waiters.wait_for_server_status(self.manager.servers_client,
- self.server_id, 'ACTIVE')
-
- self.run_core()
-
- if self.new_vm:
- self._destroy_vm()
- if self.new_floating:
- self._destroy_floating_ip()
- if self.new_sec_grp:
- self._destroy_sec_grp()
-
- def tearDown(self):
- if not self.new_vm:
- self._destroy_vm()
- if not self.new_floating:
- self._destroy_floating_ip()
- if not self.new_sec_grp:
- self._destroy_sec_grp()
diff --git a/tempest/stress/actions/unit_test.py b/tempest/stress/actions/unit_test.py
deleted file mode 100644
index e016c61..0000000
--- a/tempest/stress/actions/unit_test.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# 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 oslo_log import log as logging
-from oslo_utils import importutils
-
-from tempest import config
-import tempest.stress.stressaction as stressaction
-
-CONF = config.CONF
-
-
-class SetUpClassRunTime(object):
-
- process = 'process'
- action = 'action'
- application = 'application'
-
- allowed = set((process, action, application))
-
- @classmethod
- def validate(cls, name):
- if name not in cls.allowed:
- raise KeyError("\'%s\' not a valid option" % name)
-
-
-class UnitTest(stressaction.StressAction):
- """This is a special action for running existing unittests as stress test.
-
- You need to pass ``test_method`` and ``class_setup_per``
- using ``kwargs`` in the JSON descriptor;
- ``test_method`` should be the fully qualified name of a unittest,
- ``class_setup_per`` should be one from:
- ``application``: once in the stress job lifetime
- ``process``: once in the worker process lifetime
- ``action``: on each action
- Not all combination working in every case.
- """
-
- def setUp(self, **kwargs):
- method = kwargs['test_method'].split('.')
- self.test_method = method.pop()
- self.klass = importutils.import_class('.'.join(method))
- self.logger = logging.getLogger('.'.join(method))
- # valid options are 'process', 'application' , 'action'
- self.class_setup_per = kwargs.get('class_setup_per',
- SetUpClassRunTime.process)
- SetUpClassRunTime.validate(self.class_setup_per)
-
- if self.class_setup_per == SetUpClassRunTime.application:
- self.klass.setUpClass()
- self.setupclass_called = False
-
- @property
- def action(self):
- if self.test_method:
- return self.test_method
- return super(UnitTest, self).action
-
- def run_core(self):
- res = self.klass(self.test_method).run()
- if res.errors:
- raise RuntimeError(res.errors)
-
- def run(self):
- if self.class_setup_per != SetUpClassRunTime.application:
- if (self.class_setup_per == SetUpClassRunTime.action
- or self.setupclass_called is False):
- self.klass.setUpClass()
- self.setupclass_called = True
-
- try:
- self.run_core()
- finally:
- if (CONF.stress.leave_dirty_stack is False
- and self.class_setup_per == SetUpClassRunTime.action):
- self.klass.tearDownClass()
- else:
- self.run_core()
-
- def tearDown(self):
- if self.class_setup_per != SetUpClassRunTime.action:
- self.klass.tearDownClass()
diff --git a/tempest/stress/actions/volume_attach_delete.py b/tempest/stress/actions/volume_attach_delete.py
deleted file mode 100644
index 5fc006e..0000000
--- a/tempest/stress/actions/volume_attach_delete.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# (c) 2013 Deutsche Telekom AG
-# 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.common.utils import data_utils
-from tempest.common import waiters
-from tempest import config
-import tempest.stress.stressaction as stressaction
-
-CONF = config.CONF
-
-
-class VolumeAttachDeleteTest(stressaction.StressAction):
-
- def setUp(self, **kwargs):
- self.image = CONF.compute.image_ref
- self.flavor = CONF.compute.flavor_ref
-
- def run(self):
- # Step 1: create volume
- name = data_utils.rand_name(self.__class__.__name__ + "-volume")
- self.logger.info("creating volume: %s" % name)
- volume = self.manager.volumes_client.create_volume(
- display_name=name, size=CONF.volume.volume_size)['volume']
- self.manager.volumes_client.wait_for_volume_status(volume['id'],
- 'available')
- self.logger.info("created volume: %s" % volume['id'])
-
- # Step 2: create vm instance
- vm_name = data_utils.rand_name(self.__class__.__name__ + "-instance")
- self.logger.info("creating vm: %s" % vm_name)
- server = self.manager.servers_client.create_server(
- name=vm_name, imageRef=self.image, flavorRef=self.flavor)['server']
- server_id = server['id']
- waiters.wait_for_server_status(self.manager.servers_client, server_id,
- 'ACTIVE')
- self.logger.info("created vm %s" % server_id)
-
- # Step 3: attach volume to vm
- self.logger.info("attach volume (%s) to vm %s" %
- (volume['id'], server_id))
- self.manager.servers_client.attach_volume(server_id,
- volumeId=volume['id'],
- device='/dev/vdc')
- self.manager.volumes_client.wait_for_volume_status(volume['id'],
- 'in-use')
- self.logger.info("volume (%s) attached to vm %s" %
- (volume['id'], server_id))
-
- # Step 4: delete vm
- self.logger.info("deleting vm: %s" % vm_name)
- self.manager.servers_client.delete_server(server_id)
- waiters.wait_for_server_termination(self.manager.servers_client,
- server_id)
- self.logger.info("deleted vm: %s" % server_id)
-
- # Step 5: delete volume
- self.logger.info("deleting volume: %s" % volume['id'])
- self.manager.volumes_client.delete_volume(volume['id'])
- self.manager.volumes_client.wait_for_resource_deletion(volume['id'])
- self.logger.info("deleted volume: %s" % volume['id'])
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
deleted file mode 100644
index 4fbb851..0000000
--- a/tempest/stress/actions/volume_attach_verify.py
+++ /dev/null
@@ -1,233 +0,0 @@
-# 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 re
-
-from tempest.common.utils import data_utils
-from tempest.common.utils.linux import remote_client
-from tempest.common import waiters
-from tempest import config
-from tempest.lib.common.utils import test_utils
-import tempest.stress.stressaction as stressaction
-
-CONF = config.CONF
-
-
-class VolumeVerifyStress(stressaction.StressAction):
-
- def _create_keypair(self):
- keyname = data_utils.rand_name("key")
- self.key = (self.manager.keypairs_client.create_keypair(name=keyname)
- ['keypair'])
-
- def _delete_keypair(self):
- self.manager.keypairs_client.delete_keypair(self.key['name'])
-
- def _create_vm(self):
- self.name = name = data_utils.rand_name(
- self.__class__.__name__ + "-instance")
- servers_client = self.manager.servers_client
- self.logger.info("creating %s" % name)
- vm_args = self.vm_extra_args.copy()
- vm_args['security_groups'] = [self.sec_grp]
- vm_args['key_name'] = self.key['name']
- server = servers_client.create_server(name=name, imageRef=self.image,
- flavorRef=self.flavor,
- **vm_args)['server']
- self.server_id = server['id']
- waiters.wait_for_server_status(self.manager.servers_client,
- self.server_id, 'ACTIVE')
-
- def _destroy_vm(self):
- self.logger.info("deleting server: %s" % self.server_id)
- self.manager.servers_client.delete_server(self.server_id)
- waiters.wait_for_server_termination(self.manager.servers_client,
- self.server_id)
- self.logger.info("deleted server: %s" % self.server_id)
-
- def _create_sec_group(self):
- sec_grp_cli = self.manager.compute_security_groups_client
- s_name = data_utils.rand_name(self.__class__.__name__ + '-sec_grp')
- s_description = data_utils.rand_name('desc')
- self.sec_grp = sec_grp_cli.create_security_group(
- name=s_name, description=s_description)['security_group']
- create_rule = sec_grp_cli.create_security_group_rule
- create_rule(parent_group_id=self.sec_grp['id'], ip_protocol='tcp',
- from_port=22, to_port=22)
- create_rule(parent_group_id=self.sec_grp['id'], ip_protocol='icmp',
- from_port=-1, to_port=-1)
-
- def _destroy_sec_grp(self):
- sec_grp_cli = self.manager.compute_security_groups_client
- sec_grp_cli.delete_security_group(self.sec_grp['id'])
-
- def _create_floating_ip(self):
- floating_cli = self.manager.compute_floating_ips_client
- self.floating = (floating_cli.create_floating_ip(self.floating_pool)
- ['floating_ip'])
-
- def _destroy_floating_ip(self):
- cli = self.manager.compute_floating_ips_client
- cli.delete_floating_ip(self.floating['id'])
- cli.wait_for_resource_deletion(self.floating['id'])
- self.logger.info("Deleted Floating IP %s", str(self.floating['ip']))
-
- def _create_volume(self):
- name = data_utils.rand_name(self.__class__.__name__ + "-volume")
- self.logger.info("creating volume: %s" % name)
- volumes_client = self.manager.volumes_client
- self.volume = volumes_client.create_volume(
- display_name=name, size=CONF.volume.volume_size)['volume']
- volumes_client.wait_for_volume_status(self.volume['id'],
- 'available')
- self.logger.info("created volume: %s" % self.volume['id'])
-
- def _delete_volume(self):
- self.logger.info("deleting volume: %s" % self.volume['id'])
- volumes_client = self.manager.volumes_client
- volumes_client.delete_volume(self.volume['id'])
- volumes_client.wait_for_resource_deletion(self.volume['id'])
- self.logger.info("deleted volume: %s" % self.volume['id'])
-
- def _wait_disassociate(self):
- cli = self.manager.compute_floating_ips_client
-
- def func():
- floating = (cli.show_floating_ip(self.floating['id'])
- ['floating_ip'])
- return floating['instance_id'] is None
-
- if not test_utils.call_until_true(func, CONF.compute.build_timeout,
- CONF.compute.build_interval):
- raise RuntimeError("IP disassociate timeout!")
-
- def new_server_ops(self):
- self._create_vm()
- cli = self.manager.compute_floating_ips_client
- cli.associate_floating_ip_to_server(self.floating['ip'],
- self.server_id)
- if self.ssh_test_before_attach and self.enable_ssh_verify:
- self.logger.info("Scanning for block devices via ssh on %s"
- % self.server_id)
- self.part_wait(self.detach_match_count)
-
- def setUp(self, **kwargs):
- """Note able configuration combinations:
-
- Closest options to the test_stamp_pattern:
- new_server = True
- new_volume = True
- enable_ssh_verify = True
- ssh_test_before_attach = False
- Just attaching:
- new_server = False
- new_volume = False
- enable_ssh_verify = True
- ssh_test_before_attach = True
- Mostly API load by repeated attachment:
- new_server = False
- new_volume = False
- enable_ssh_verify = False
- ssh_test_before_attach = False
- Minimal Nova load, but cinder load not decreased:
- new_server = False
- new_volume = True
- enable_ssh_verify = True
- ssh_test_before_attach = True
- """
- self.image = CONF.compute.image_ref
- self.flavor = CONF.compute.flavor_ref
- self.vm_extra_args = kwargs.get('vm_extra_args', {})
- self.floating_pool = kwargs.get('floating_pool', None)
- self.new_volume = kwargs.get('new_volume', True)
- self.new_server = kwargs.get('new_server', False)
- self.enable_ssh_verify = kwargs.get('enable_ssh_verify', True)
- self.ssh_test_before_attach = kwargs.get('ssh_test_before_attach',
- False)
- self.part_line_re = re.compile(kwargs.get('part_line_re', '.*vd.*'))
- self.detach_match_count = kwargs.get('detach_match_count', 1)
- self.attach_match_count = kwargs.get('attach_match_count', 2)
- self.part_name = kwargs.get('part_name', '/dev/vdc')
-
- self._create_floating_ip()
- self._create_sec_group()
- self._create_keypair()
- private_key = self.key['private_key']
- username = CONF.validation.image_ssh_user
- self.remote_client = remote_client.RemoteClient(self.floating['ip'],
- username,
- pkey=private_key)
- if not self.new_volume:
- self._create_volume()
- if not self.new_server:
- self.new_server_ops()
-
- # now we just test that the number of partitions has increased or decreased
- def part_wait(self, num_match):
- def _part_state():
- self.partitions = self.remote_client.get_partitions().split('\n')
- matching = 0
- for part_line in self.partitions[1:]:
- if self.part_line_re.match(part_line):
- matching += 1
- return matching == num_match
- if test_utils.call_until_true(_part_state,
- CONF.compute.build_timeout,
- CONF.compute.build_interval):
- return
- else:
- raise RuntimeError("Unexpected partitions: %s",
- str(self.partitions))
-
- def run(self):
- if self.new_server:
- self.new_server_ops()
- if self.new_volume:
- self._create_volume()
- servers_client = self.manager.servers_client
- self.logger.info("attach volume (%s) to vm %s" %
- (self.volume['id'], self.server_id))
- servers_client.attach_volume(self.server_id,
- volumeId=self.volume['id'],
- device=self.part_name)
- self.manager.volumes_client.wait_for_volume_status(self.volume['id'],
- 'in-use')
- if self.enable_ssh_verify:
- self.logger.info("Scanning for new block device on %s"
- % self.server_id)
- self.part_wait(self.attach_match_count)
-
- servers_client.detach_volume(self.server_id,
- self.volume['id'])
- self.manager.volumes_client.wait_for_volume_status(self.volume['id'],
- 'available')
- if self.enable_ssh_verify:
- self.logger.info("Scanning for block device disappearance on %s"
- % self.server_id)
- self.part_wait(self.detach_match_count)
- if self.new_volume:
- self._delete_volume()
- if self.new_server:
- self._destroy_vm()
-
- def tearDown(self):
- cli = self.manager.compute_floating_ips_client
- cli.disassociate_floating_ip_from_server(self.floating['ip'],
- self.server_id)
- self._wait_disassociate()
- if not self.new_server:
- self._destroy_vm()
- self._delete_keypair()
- self._destroy_floating_ip()
- self._destroy_sec_grp()
- if not self.new_volume:
- self._delete_volume()
diff --git a/tempest/stress/actions/volume_create_delete.py b/tempest/stress/actions/volume_create_delete.py
deleted file mode 100644
index 66971ea..0000000
--- a/tempest/stress/actions/volume_create_delete.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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.common.utils import data_utils
-from tempest import config
-import tempest.stress.stressaction as stressaction
-
-CONF = config.CONF
-
-
-class VolumeCreateDeleteTest(stressaction.StressAction):
-
- def run(self):
- name = data_utils.rand_name("volume")
- self.logger.info("creating %s" % name)
- volumes_client = self.manager.volumes_client
- volume = volumes_client.create_volume(
- display_name=name, size=CONF.volume.volume_size)['volume']
- vol_id = volume['id']
- volumes_client.wait_for_volume_status(vol_id, 'available')
- self.logger.info("created %s" % volume['id'])
- self.logger.info("deleting %s" % name)
- volumes_client.delete_volume(vol_id)
- volumes_client.wait_for_resource_deletion(vol_id)
- self.logger.info("deleted %s" % vol_id)
diff --git a/tempest/stress/cleanup.py b/tempest/stress/cleanup.py
deleted file mode 100644
index 3b0a937..0000000
--- a/tempest/stress/cleanup.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2013 Quanta Research Cambridge, Inc.
-#
-# 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 oslo_log import log as logging
-
-from tempest.common import credentials_factory as credentials
-from tempest.common import waiters
-
-LOG = logging.getLogger(__name__)
-
-
-def cleanup():
- admin_manager = credentials.AdminManager()
-
- body = admin_manager.servers_client.list_servers(all_tenants=True)
- LOG.info("Cleanup::remove %s servers" % len(body['servers']))
- for s in body['servers']:
- try:
- admin_manager.servers_client.delete_server(s['id'])
- except Exception:
- pass
-
- for s in body['servers']:
- try:
- waiters.wait_for_server_termination(admin_manager.servers_client,
- s['id'])
- except Exception:
- pass
-
- keypairs = admin_manager.keypairs_client.list_keypairs()['keypairs']
- LOG.info("Cleanup::remove %s keypairs" % len(keypairs))
- for k in keypairs:
- try:
- admin_manager.keypairs_client.delete_keypair(k['name'])
- except Exception:
- pass
-
- secgrp_client = admin_manager.compute_security_groups_client
- secgrp = (secgrp_client.list_security_groups(all_tenants=True)
- ['security_groups'])
- secgrp_del = [grp for grp in secgrp if grp['name'] != 'default']
- LOG.info("Cleanup::remove %s Security Group" % len(secgrp_del))
- for g in secgrp_del:
- try:
- secgrp_client.delete_security_group(g['id'])
- except Exception:
- pass
-
- admin_floating_ips_client = admin_manager.compute_floating_ips_client
- floating_ips = (admin_floating_ips_client.list_floating_ips()
- ['floating_ips'])
- LOG.info("Cleanup::remove %s floating ips" % len(floating_ips))
- for f in floating_ips:
- try:
- admin_floating_ips_client.delete_floating_ip(f['id'])
- except Exception:
- pass
-
- users = admin_manager.users_client.list_users()['users']
- LOG.info("Cleanup::remove %s users" % len(users))
- for user in users:
- if user['name'].startswith("stress_user"):
- admin_manager.users_client.delete_user(user['id'])
- tenants = admin_manager.tenants_client.list_tenants()['tenants']
- LOG.info("Cleanup::remove %s tenants" % len(tenants))
- for tenant in tenants:
- if tenant['name'].startswith("stress_tenant"):
- admin_manager.tenants_client.delete_tenant(tenant['id'])
-
- # We have to delete snapshots first or
- # volume deletion may block
-
- _, snaps = admin_manager.snapshots_client.list_snapshots(
- all_tenants=True)['snapshots']
- LOG.info("Cleanup::remove %s snapshots" % len(snaps))
- for v in snaps:
- try:
- waiters.wait_for_snapshot_status(
- admin_manager.snapshots_client, v['id'], 'available')
- admin_manager.snapshots_client.delete_snapshot(v['id'])
- except Exception:
- pass
-
- for v in snaps:
- try:
- admin_manager.snapshots_client.wait_for_resource_deletion(v['id'])
- except Exception:
- pass
-
- vols = admin_manager.volumes_client.list_volumes(
- params={"all_tenants": True})
- LOG.info("Cleanup::remove %s volumes" % len(vols))
- for v in vols:
- try:
- waiters.wait_for_volume_status(
- admin_manager.volumes_client, v['id'], 'available')
- admin_manager.volumes_client.delete_volume(v['id'])
- except Exception:
- pass
-
- for v in vols:
- try:
- admin_manager.volumes_client.wait_for_resource_deletion(v['id'])
- except Exception:
- pass
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
deleted file mode 100644
index 1e33e88..0000000
--- a/tempest/stress/driver.py
+++ /dev/null
@@ -1,264 +0,0 @@
-# Copyright 2013 Quanta Research Cambridge, Inc.
-#
-# 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 multiprocessing
-import os
-import signal
-import time
-
-from oslo_log import log as logging
-from oslo_utils import importutils
-import six
-
-from tempest import clients
-from tempest.common import cred_client
-from tempest.common import credentials_factory as credentials
-from tempest.common.utils import data_utils
-from tempest import config
-from tempest import exceptions
-from tempest.lib.common import ssh
-from tempest.stress import cleanup
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-processes = []
-
-
-def do_ssh(command, host, ssh_user, ssh_key=None):
- ssh_client = ssh.Client(host, ssh_user, key_filename=ssh_key)
- try:
- return ssh_client.exec_command(command)
- except exceptions.SSHExecCommandFailed:
- LOG.error('do_ssh raise exception. command:%s, host:%s.'
- % (command, host))
- return None
-
-
-def _get_compute_nodes(controller, ssh_user, ssh_key=None):
- """Returns a list of active compute nodes.
-
- List is generated by running nova-manage on the controller.
- """
- nodes = []
- cmd = "nova-manage service list | grep ^nova-compute"
- output = do_ssh(cmd, controller, ssh_user, ssh_key)
- if not output:
- return nodes
- # For example: nova-compute xg11eth0 nova enabled :-) 2011-10-31 18:57:46
- # This is fragile but there is, at present, no other way to get this info.
- for line in output.split('\n'):
- words = line.split()
- if len(words) > 0 and words[4] == ":-)":
- nodes.append(words[1])
- return nodes
-
-
-def _has_error_in_logs(logfiles, nodes, ssh_user, ssh_key=None,
- stop_on_error=False):
- """Detect errors in nova log files on the controller and compute nodes."""
- grep = 'egrep "ERROR|TRACE" %s' % logfiles
- ret = False
- for node in nodes:
- errors = do_ssh(grep, node, ssh_user, ssh_key)
- if len(errors) > 0:
- LOG.error('%s: %s' % (node, errors))
- ret = True
- if stop_on_error:
- break
- return ret
-
-
-def sigchld_handler(signalnum, frame):
- """Signal handler (only active if stop_on_error is True)."""
- for process in processes:
- if (not process['process'].is_alive() and
- process['process'].exitcode != 0):
- signal.signal(signalnum, signal.SIG_DFL)
- terminate_all_processes()
- break
-
-
-def terminate_all_processes(check_interval=20):
- """Goes through the process list and terminates all child processes."""
- LOG.info("Stopping all processes.")
- for process in processes:
- if process['process'].is_alive():
- try:
- process['process'].terminate()
- except Exception:
- pass
- time.sleep(check_interval)
- for process in processes:
- if process['process'].is_alive():
- try:
- pid = process['process'].pid
- LOG.warning("Process %d hangs. Send SIGKILL." % pid)
- os.kill(pid, signal.SIGKILL)
- except Exception:
- pass
- process['process'].join()
-
-
-def stress_openstack(tests, duration, max_runs=None, stop_on_error=False):
- """Workload driver. Executes an action function against a nova-cluster."""
- admin_manager = credentials.AdminManager()
-
- ssh_user = CONF.stress.target_ssh_user
- ssh_key = CONF.stress.target_private_key_path
- logfiles = CONF.stress.target_logfiles
- log_check_interval = int(CONF.stress.log_check_interval)
- default_thread_num = int(CONF.stress.default_thread_number_per_action)
- if logfiles:
- controller = CONF.stress.target_controller
- computes = _get_compute_nodes(controller, ssh_user, ssh_key)
- for node in computes:
- do_ssh("rm -f %s" % logfiles, node, ssh_user, ssh_key)
- skip = False
- for test in tests:
- for service in test.get('required_services', []):
- if not CONF.service_available.get(service):
- skip = True
- break
- if skip:
- break
- # TODO(andreaf) This has to be reworked to use the credential
- # provider interface. For now only tests marked as 'use_admin' will
- # work.
- if test.get('use_admin', False):
- manager = admin_manager
- else:
- raise NotImplemented('Non admin tests are not supported')
- for p_number in range(test.get('threads', default_thread_num)):
- if test.get('use_isolated_tenants', False):
- username = data_utils.rand_name("stress_user")
- tenant_name = data_utils.rand_name("stress_tenant")
- password = "pass"
- if CONF.identity.auth_version == 'v2':
- identity_client = admin_manager.identity_client
- projects_client = admin_manager.tenants_client
- roles_client = admin_manager.roles_client
- users_client = admin_manager.users_client
- domains_client = None
- else:
- identity_client = admin_manager.identity_v3_client
- projects_client = admin_manager.projects_client
- roles_client = admin_manager.roles_v3_client
- users_client = admin_manager.users_v3_client
- domains_client = admin_manager.domains_client
- domain = (identity_client.auth_provider.credentials.
- get('project_domain_name', 'Default'))
- credentials_client = cred_client.get_creds_client(
- identity_client, projects_client, users_client,
- roles_client, domains_client, project_domain_name=domain)
- project = credentials_client.create_project(
- name=tenant_name, description=tenant_name)
- user = credentials_client.create_user(username, password,
- project, "email")
- # Add roles specified in config file
- for conf_role in CONF.auth.tempest_roles:
- credentials_client.assign_user_role(user, project,
- conf_role)
- creds = credentials_client.get_credentials(user, project,
- password)
- manager = clients.Manager(credentials=creds)
-
- test_obj = importutils.import_class(test['action'])
- test_run = test_obj(manager, max_runs, stop_on_error)
-
- kwargs = test.get('kwargs', {})
- test_run.setUp(**dict(six.iteritems(kwargs)))
-
- LOG.debug("calling Target Object %s" %
- test_run.__class__.__name__)
-
- mp_manager = multiprocessing.Manager()
- shared_statistic = mp_manager.dict()
- shared_statistic['runs'] = 0
- shared_statistic['fails'] = 0
-
- p = multiprocessing.Process(target=test_run.execute,
- args=(shared_statistic,))
-
- process = {'process': p,
- 'p_number': p_number,
- 'action': test_run.action,
- 'statistic': shared_statistic}
-
- processes.append(process)
- p.start()
- if stop_on_error:
- # NOTE(mkoderer): only the parent should register the handler
- signal.signal(signal.SIGCHLD, sigchld_handler)
- end_time = time.time() + duration
- had_errors = False
- try:
- while True:
- if max_runs is None:
- remaining = end_time - time.time()
- if remaining <= 0:
- break
- else:
- remaining = log_check_interval
- all_proc_term = True
- for process in processes:
- if process['process'].is_alive():
- all_proc_term = False
- break
- if all_proc_term:
- break
-
- time.sleep(min(remaining, log_check_interval))
- if stop_on_error:
- if any([True for proc in processes
- if proc['statistic']['fails'] > 0]):
- break
-
- if not logfiles:
- continue
- if _has_error_in_logs(logfiles, computes, ssh_user, ssh_key,
- stop_on_error):
- had_errors = True
- break
- except KeyboardInterrupt:
- LOG.warning("Interrupted, going to print statistics and exit ...")
-
- if stop_on_error:
- signal.signal(signal.SIGCHLD, signal.SIG_DFL)
- terminate_all_processes()
-
- sum_fails = 0
- sum_runs = 0
-
- LOG.info("Statistics (per process):")
- for process in processes:
- if process['statistic']['fails'] > 0:
- had_errors = True
- sum_runs += process['statistic']['runs']
- sum_fails += process['statistic']['fails']
- print("Process %d (%s): Run %d actions (%d failed)" % (
- process['p_number'],
- process['action'],
- process['statistic']['runs'],
- process['statistic']['fails']))
- print("Summary:")
- print("Run %d actions (%d failed)" % (sum_runs, sum_fails))
-
- if not had_errors and CONF.stress.full_clean_stack:
- LOG.info("cleaning up")
- cleanup.cleanup()
- if had_errors:
- return 1
- else:
- return 0
diff --git a/tempest/stress/etc/sample-unit-test.json b/tempest/stress/etc/sample-unit-test.json
deleted file mode 100644
index 54433d5..0000000
--- a/tempest/stress/etc/sample-unit-test.json
+++ /dev/null
@@ -1,8 +0,0 @@
-[{"action": "tempest.stress.actions.unit_test.UnitTest",
- "threads": 8,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {"test_method": "tempest.cli.simple_read_only.test_glance.SimpleReadOnlyGlanceClientTest.test_glance_fake_action",
- "class_setup_per": "process"}
- }
-]
diff --git a/tempest/stress/etc/server-create-destroy-test.json b/tempest/stress/etc/server-create-destroy-test.json
deleted file mode 100644
index bbb5352..0000000
--- a/tempest/stress/etc/server-create-destroy-test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[{"action": "tempest.stress.actions.server_create_destroy.ServerCreateDestroyTest",
- "threads": 8,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {}
- }
-]
diff --git a/tempest/stress/etc/ssh_floating.json b/tempest/stress/etc/ssh_floating.json
deleted file mode 100644
index c502e96..0000000
--- a/tempest/stress/etc/ssh_floating.json
+++ /dev/null
@@ -1,16 +0,0 @@
-[{"action": "tempest.stress.actions.ssh_floating.FloatingStress",
- "threads": 8,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {"vm_extra_args": {},
- "new_vm": true,
- "new_sec_group": true,
- "new_floating": true,
- "verify": ["check_icmp_echo", "check_port_ssh"],
- "check_timeout": 120,
- "check_interval": 1,
- "wait_after_vm_create": true,
- "wait_for_disassociate": true,
- "reboot": false}
-}
-]
diff --git a/tempest/stress/etc/stress-tox-job.json b/tempest/stress/etc/stress-tox-job.json
deleted file mode 100644
index bfa448d..0000000
--- a/tempest/stress/etc/stress-tox-job.json
+++ /dev/null
@@ -1,28 +0,0 @@
-[{"action": "tempest.stress.actions.server_create_destroy.ServerCreateDestroyTest",
- "threads": 8,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {}
- },
- {"action": "tempest.stress.actions.volume_create_delete.VolumeCreateDeleteTest",
- "threads": 4,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {}
- },
- {"action": "tempest.stress.actions.volume_attach_delete.VolumeAttachDeleteTest",
- "threads": 2,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {}
- },
- {"action": "tempest.stress.actions.unit_test.UnitTest",
- "threads": 4,
- "use_admin": true,
- "use_isolated_tenants": true,
- "required_services": ["neutron"],
- "kwargs": {"test_method": "tempest.scenario.test_network_advanced_server_ops.TestNetworkAdvancedServerOps.test_server_connectivity_stop_start",
- "class_setup_per": "process"}
- }
-]
-
diff --git a/tempest/stress/etc/volume-attach-delete-test.json b/tempest/stress/etc/volume-attach-delete-test.json
deleted file mode 100644
index d468967..0000000
--- a/tempest/stress/etc/volume-attach-delete-test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[{"action": "tempest.stress.actions.volume_attach_delete.VolumeAttachDeleteTest",
- "threads": 4,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {}
- }
-]
diff --git a/tempest/stress/etc/volume-attach-verify.json b/tempest/stress/etc/volume-attach-verify.json
deleted file mode 100644
index d8c96fd..0000000
--- a/tempest/stress/etc/volume-attach-verify.json
+++ /dev/null
@@ -1,11 +0,0 @@
-[{"action": "tempest.stress.actions.volume_attach_verify.VolumeVerifyStress",
- "threads": 1,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {"vm_extra_args": {},
- "new_volume": true,
- "new_server": false,
- "ssh_test_before_attach": false,
- "enable_ssh_verify": true}
-}
-]
diff --git a/tempest/stress/etc/volume-create-delete-test.json b/tempest/stress/etc/volume-create-delete-test.json
deleted file mode 100644
index a60cde6..0000000
--- a/tempest/stress/etc/volume-create-delete-test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[{"action": "tempest.stress.actions.volume_create_delete.VolumeCreateDeleteTest",
- "threads": 4,
- "use_admin": true,
- "use_isolated_tenants": true,
- "kwargs": {}
- }
-]
diff --git a/tempest/stress/stressaction.py b/tempest/stress/stressaction.py
deleted file mode 100644
index cf0a08a..0000000
--- a/tempest/stress/stressaction.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
-#
-# 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 abc
-import signal
-import sys
-
-import six
-
-from oslo_log import log as logging
-
-
-@six.add_metaclass(abc.ABCMeta)
-class StressAction(object):
-
- def __init__(self, manager, max_runs=None, stop_on_error=False):
- full_cname = self.__module__ + "." + self.__class__.__name__
- self.logger = logging.getLogger(full_cname)
- self.manager = manager
- self.max_runs = max_runs
- self.stop_on_error = stop_on_error
-
- def _shutdown_handler(self, signal, frame):
- try:
- self.tearDown()
- except Exception:
- self.logger.exception("Error while tearDown")
- sys.exit(0)
-
- @property
- def action(self):
- """This methods returns the action.
-
- Overload this if you create a stress test wrapper.
- """
- return self.__class__.__name__
-
- def setUp(self, **kwargs):
- """Initialize test structures/resources
-
- This method is called before "run" method to help the test
- initialize any structures. kwargs contains arguments passed
- in from the configuration json file.
-
- setUp doesn't count against the time duration.
- """
- self.logger.debug("setUp")
-
- def tearDown(self):
- """Cleanup test structures/resources
-
- This method is called to do any cleanup after the test is complete.
- """
- self.logger.debug("tearDown")
-
- def execute(self, shared_statistic):
- """This is the main execution entry point called by the driver.
-
- We register a signal handler to allow us to tearDown gracefully,
- and then exit. We also keep track of how many runs we do.
- """
- signal.signal(signal.SIGHUP, self._shutdown_handler)
- signal.signal(signal.SIGTERM, self._shutdown_handler)
-
- while self.max_runs is None or (shared_statistic['runs'] <
- self.max_runs):
- self.logger.debug("Trigger new run (run %d)" %
- shared_statistic['runs'])
- try:
- self.run()
- except Exception:
- shared_statistic['fails'] += 1
- self.logger.exception("Failure in run")
- finally:
- shared_statistic['runs'] += 1
- if self.stop_on_error and (shared_statistic['fails'] > 1):
- self.logger.warning("Stop process due to"
- "\"stop-on-error\" argument")
- self.tearDown()
- sys.exit(1)
-
- @abc.abstractmethod
- def run(self):
- """This method is where the stress test code runs."""
- return
diff --git a/tempest/stress/tools/cleanup.py b/tempest/stress/tools/cleanup.py
deleted file mode 100755
index 3885ba0..0000000
--- a/tempest/stress/tools/cleanup.py
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2013 Quanta Research Cambridge, Inc.
-#
-# 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.stress import cleanup
-
-cleanup.cleanup()
diff --git a/tempest/test.py b/tempest/test.py
index 609f1f6..b75ae48 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -16,28 +16,21 @@
import atexit
import functools
import os
-import re
import sys
import debtcollector.moves
import fixtures
from oslo_log import log as logging
-from oslo_serialization import jsonutils as json
-from oslo_utils import importutils
import six
-from six.moves import urllib
-import testscenarios
import testtools
from tempest import clients
-from tempest.common import cred_client
from tempest.common import credentials_factory as credentials
from tempest.common import fixed_network
-import tempest.common.generator.valid_generator as valid
import tempest.common.validation_resources as vresources
from tempest import config
from tempest import exceptions
-from tempest.lib.common.utils import data_utils
+from tempest.lib.common import cred_client
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
@@ -109,32 +102,6 @@
return decorator
-def stresstest(**kwargs):
- """Add stress test decorator
-
- For all functions with this decorator a attr stress will be
- set automatically.
-
- @param class_setup_per: allowed values are application, process, action
- ``application``: once in the stress job lifetime
- ``process``: once in the worker process lifetime
- ``action``: on each action
- @param allow_inheritance: allows inheritance of this attribute
- """
- def decorator(f):
- if 'class_setup_per' in kwargs:
- setattr(f, "st_class_setup_per", kwargs['class_setup_per'])
- else:
- setattr(f, "st_class_setup_per", 'process')
- if 'allow_inheritance' in kwargs:
- setattr(f, "st_allow_inheritance", kwargs['allow_inheritance'])
- else:
- setattr(f, "st_allow_inheritance", False)
- attr(type='stress')(f)
- return f
- return decorator
-
-
def requires_ext(**kwargs):
"""A decorator to skip tests if an extension is not enabled
@@ -649,224 +616,6 @@
self.assertTrue(len(list) > 0, msg)
-class NegativeAutoTest(BaseTestCase):
-
- _resources = {}
-
- @classmethod
- def setUpClass(cls):
- super(NegativeAutoTest, cls).setUpClass()
- os = cls.get_client_manager(credential_type='primary')
- cls.client = os.negative_client
-
- @staticmethod
- def load_tests(*args):
- """Wrapper for testscenarios
-
- To set the mandatory scenarios variable only in case a real test
- loader is in place. Will be automatically called in case the variable
- "load_tests" is set.
- """
- if getattr(args[0], 'suiteClass', None) is not None:
- loader, standard_tests, pattern = args
- else:
- standard_tests, module, loader = args
- for test in testtools.iterate_tests(standard_tests):
- schema = getattr(test, '_schema', None)
- if schema is not None:
- setattr(test, 'scenarios',
- NegativeAutoTest.generate_scenario(schema))
- return testscenarios.load_tests_apply_scenarios(*args)
-
- @staticmethod
- def generate_scenario(description):
- """Generates the test scenario list for a given description.
-
- :param description: A file or dictionary with the following entries:
- name (required) name for the api
- http-method (required) one of HEAD,GET,PUT,POST,PATCH,DELETE
- url (required) the url to be appended to the catalog url with '%s'
- for each resource mentioned
- resources: (optional) A list of resource names such as "server",
- "flavor", etc. with an element for each '%s' in the url. This
- method will call self.get_resource for each element when
- constructing the positive test case template so negative
- subclasses are expected to return valid resource ids when
- appropriate.
- json-schema (optional) A valid json schema that will be used to
- create invalid data for the api calls. For "GET" and "HEAD",
- the data is used to generate query strings appended to the url,
- otherwise for the body of the http call.
- """
- LOG.debug(description)
- generator = importutils.import_class(
- CONF.negative.test_generator)()
- generator.validate_schema(description)
- schema = description.get("json-schema", None)
- resources = description.get("resources", [])
- scenario_list = []
- expected_result = None
- for resource in resources:
- if isinstance(resource, dict):
- expected_result = resource['expected_result']
- resource = resource['name']
- LOG.debug("Add resource to test %s" % resource)
- scn_name = "inv_res_%s" % (resource)
- scenario_list.append((scn_name, {
- "resource": (resource, data_utils.rand_uuid()),
- "expected_result": expected_result
- }))
- if schema is not None:
- for scenario in generator.generate_scenarios(schema):
- scenario_list.append((scenario['_negtest_name'],
- scenario))
- LOG.debug(scenario_list)
- return scenario_list
-
- def execute(self, description):
- """Execute a http call
-
- Execute a http call on an api that are expected to
- result in client errors. First it uses invalid resources that are part
- of the url, and then invalid data for queries and http request bodies.
-
- :param description: A json file or dictionary with the following
- entries:
- name (required) name for the api
- http-method (required) one of HEAD,GET,PUT,POST,PATCH,DELETE
- url (required) the url to be appended to the catalog url with '%s'
- for each resource mentioned
- resources: (optional) A list of resource names such as "server",
- "flavor", etc. with an element for each '%s' in the url. This
- method will call self.get_resource for each element when
- constructing the positive test case template so negative
- subclasses are expected to return valid resource ids when
- appropriate.
- json-schema (optional) A valid json schema that will be used to
- create invalid data for the api calls. For "GET" and "HEAD",
- the data is used to generate query strings appended to the url,
- otherwise for the body of the http call.
-
- """
- LOG.info("Executing %s" % description["name"])
- LOG.debug(description)
- generator = importutils.import_class(
- CONF.negative.test_generator)()
- schema = description.get("json-schema", None)
- method = description["http-method"]
- url = description["url"]
- expected_result = None
- if "default_result_code" in description:
- expected_result = description["default_result_code"]
-
- resources = [self.get_resource(r) for
- r in description.get("resources", [])]
-
- if hasattr(self, "resource"):
- # Note(mkoderer): The resources list already contains an invalid
- # entry (see get_resource).
- # We just send a valid json-schema with it
- valid_schema = None
- if schema:
- valid_schema = \
- valid.ValidTestGenerator().generate_valid(schema)
- new_url, body = self._http_arguments(valid_schema, url, method)
- elif hasattr(self, "_negtest_name"):
- schema_under_test = \
- valid.ValidTestGenerator().generate_valid(schema)
- local_expected_result = \
- generator.generate_payload(self, schema_under_test)
- if local_expected_result is not None:
- expected_result = local_expected_result
- new_url, body = \
- self._http_arguments(schema_under_test, url, method)
- else:
- raise Exception("testscenarios are not active. Please make sure "
- "that your test runner supports the load_tests "
- "mechanism")
-
- if "admin_client" in description and description["admin_client"]:
- if not credentials.is_admin_available(
- identity_version=self.get_identity_version()):
- msg = ("Missing Identity Admin API credentials in"
- "configuration.")
- raise self.skipException(msg)
- creds = self.credentials_provider.get_admin_creds()
- os_adm = clients.Manager(credentials=creds)
- client = os_adm.negative_client
- else:
- client = self.client
- resp, resp_body = client.send_request(method, new_url,
- resources, body=body)
- self._check_negative_response(expected_result, resp.status, resp_body)
-
- def _http_arguments(self, json_dict, url, method):
- LOG.debug("dict: %s url: %s method: %s" % (json_dict, url, method))
- if not json_dict:
- return url, None
- elif method in ["GET", "HEAD", "PUT", "DELETE"]:
- return "%s?%s" % (url, urllib.parse.urlencode(json_dict)), None
- else:
- return url, json.dumps(json_dict)
-
- def _check_negative_response(self, expected_result, result, body):
- self.assertTrue(result >= 400 and result < 500 and result != 413,
- "Expected client error, got %s:%s" %
- (result, body))
- self.assertTrue(expected_result is None or expected_result == result,
- "Expected %s, got %s:%s" %
- (expected_result, result, body))
-
- @classmethod
- def set_resource(cls, name, resource):
- """Register a resource for a test
-
- This function can be used in setUpClass context to register a resource
- for a test.
-
- :param name: The name of the kind of resource such as "flavor", "role",
- etc.
- :resource: The id of the resource
- """
- cls._resources[name] = resource
-
- def get_resource(self, name):
- """Return a valid uuid for a type of resource.
-
- If a real resource is needed as part of a url then this method should
- return one. Otherwise it can return None.
-
- :param name: The name of the kind of resource such as "flavor", "role",
- etc.
- """
- if isinstance(name, dict):
- name = name['name']
- if hasattr(self, "resource") and self.resource[0] == name:
- LOG.debug("Return invalid resource (%s) value: %s" %
- (self.resource[0], self.resource[1]))
- return self.resource[1]
- if name in self._resources:
- return self._resources[name]
- return None
-
-
-def SimpleNegativeAutoTest(klass):
- """This decorator registers a test function on basis of the class name."""
- @attr(type=['negative'])
- def generic_test(self):
- if hasattr(self, '_schema'):
- self.execute(self._schema)
-
- cn = klass.__name__
- cn = cn.replace('JSON', '')
- cn = cn.replace('Test', '')
- # NOTE(mkoderer): replaces uppercase chars inside the class name with '_'
- lower_cn = re.sub('(?<!^)(?=[A-Z])', '_', cn).lower()
- func_name = 'test_%s' % lower_cn
- setattr(klass, func_name, generic_test)
- return klass
-
-
call_until_true = debtcollector.moves.moved_function(
test_utils.call_until_true, 'call_until_true', __name__,
version='Newton', removal_version='Ocata')
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index eb50126..f8d5d9d 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -157,8 +157,10 @@
registry = clients.ClientsRegistry()
for plug in self.ext_plugins:
try:
- registry.register_service_client(
- plug.name, plug.obj.get_service_clients())
+ service_clients = plug.obj.get_service_clients()
+ if service_clients:
+ registry.register_service_client(
+ plug.name, service_clients)
except Exception:
LOG.exception('Plugin %s raised an exception trying to run '
'get_service_clients' % plug.name)
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
old mode 100755
new mode 100644
index b3931d1..b08954f
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -146,7 +146,7 @@
identity_version = 2
identity_response = fake_identity._fake_v2_response
- cred_client = 'tempest.common.cred_client.V2CredsClient'
+ cred_client = 'tempest.lib.common.cred_client.V2CredsClient'
dynamic_creds = 'tempest.common.dynamic_creds.DynamicCredentialProvider'
def setUp(self):
@@ -245,7 +245,7 @@
identity_version = 3
identity_response = fake_identity._fake_v3_response
- cred_client = 'tempest.common.cred_client.V3CredsClient'
+ cred_client = 'tempest.lib.common.cred_client.V3CredsClient'
def setUp(self):
self.mock_domains()
@@ -256,7 +256,7 @@
identity_version = 2
identity_response = fake_identity._fake_v2_response
- cred_client = 'tempest.common.cred_client.V2CredsClient'
+ cred_client = 'tempest.lib.common.cred_client.V2CredsClient'
dynamic_creds = 'tempest.common.dynamic_creds.DynamicCredentialProvider'
domain_is_in = False
@@ -338,7 +338,7 @@
identity_version = 3
identity_response = fake_identity._fake_v3_response
- cred_client = 'tempest.common.cred_client.V3CredsClient'
+ cred_client = 'tempest.lib.common.cred_client.V3CredsClient'
domain_is_in = True
def setUp(self):
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index 772391f..7ac347d 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -18,6 +18,7 @@
import subprocess
import tempfile
+import fixtures
import mock
from tempest.cmd import run
@@ -122,3 +123,32 @@
# too.
subprocess.call(['git', 'init'], stderr=DEVNULL)
self.assertRunExit(['tempest', 'run'], 1)
+
+
+class TestTakeAction(base.TestCase):
+ def test_workspace_not_registered(self):
+ class Exception_(Exception):
+ pass
+
+ m_exit = self.useFixture(fixtures.MockPatch('sys.exit')).mock
+ # sys.exit must not continue (or exit)
+ m_exit.side_effect = Exception_
+
+ workspace = self.getUniqueString()
+
+ tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock())
+ parsed_args = mock.Mock()
+ parsed_args.config_file = []
+
+ # Override $HOME so that empty workspace gets created in temp dir.
+ self.useFixture(fixtures.TempHomeDir())
+
+ # Force use of the temporary home directory.
+ parsed_args.workspace_path = None
+
+ # Simulate --workspace argument.
+ parsed_args.workspace = workspace
+
+ self.assertRaises(Exception_, tempest_run.take_action, parsed_args)
+ exit_msg = m_exit.call_args[0][0]
+ self.assertIn(workspace, exit_msg)
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 2844371..79510be 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -137,3 +137,18 @@
self.assertTrue(os.path.isfile(fake_file_moved))
self.assertTrue(os.path.isfile(local_conf_file))
self.assertTrue(os.path.isfile(local_testr_conf))
+
+ def test_take_action_fails(self):
+ class ParsedArgs(object):
+ workspace_dir = self.useFixture(fixtures.TempDir()).path
+ workspace_path = os.path.join(workspace_dir, 'workspace.yaml')
+ name = 'test'
+ dir_base = self.useFixture(fixtures.TempDir()).path
+ dir = os.path.join(dir_base, 'foo', 'bar')
+ config_dir = self.useFixture(fixtures.TempDir()).path
+ show_global_dir = False
+ pa = ParsedArgs()
+ init_cmd = init.TempestInit(None, None)
+ self.assertRaises(OSError, init_cmd.take_action, pa)
+ # one more trying should be a same error not "workspace already exists"
+ self.assertRaises(OSError, init_cmd.take_action, pa)
diff --git a/tempest/tests/common/test_custom_matchers.py b/tempest/tests/common/test_custom_matchers.py
index 2656a47..07867fc 100644
--- a/tempest/tests/common/test_custom_matchers.py
+++ b/tempest/tests/common/test_custom_matchers.py
@@ -16,11 +16,47 @@
from tempest.common import custom_matchers
from tempest.tests import base
-from testtools.tests.matchers import helpers
+
+# Stolen from testtools/testtools/tests/matchers/helpers.py
+class TestMatchersInterface(object):
+
+ def test_matches_match(self):
+ matcher = self.matches_matcher
+ matches = self.matches_matches
+ mismatches = self.matches_mismatches
+ for candidate in matches:
+ self.assertEqual(None, matcher.match(candidate))
+ for candidate in mismatches:
+ mismatch = matcher.match(candidate)
+ self.assertNotEqual(None, mismatch)
+ self.assertNotEqual(None, getattr(mismatch, 'describe', None))
+
+ def test__str__(self):
+ # [(expected, object to __str__)].
+ from testtools.matchers._doctest import DocTestMatches
+ examples = self.str_examples
+ for expected, matcher in examples:
+ self.assertThat(matcher, DocTestMatches(expected))
+
+ def test_describe_difference(self):
+ # [(expected, matchee, matcher), ...]
+ examples = self.describe_examples
+ for difference, matchee, matcher in examples:
+ mismatch = matcher.match(matchee)
+ self.assertEqual(difference, mismatch.describe())
+
+ def test_mismatch_details(self):
+ # The mismatch object must provide get_details, which must return a
+ # dictionary mapping names to Content objects.
+ examples = self.describe_examples
+ for difference, matchee, matcher in examples:
+ mismatch = matcher.match(matchee)
+ details = mismatch.get_details()
+ self.assertEqual(dict(details), details)
class TestMatchesDictExceptForKeys(base.TestCase,
- helpers.TestMatchersInterface):
+ TestMatchersInterface):
matches_matcher = custom_matchers.MatchesDictExceptForKeys(
{'a': 1, 'b': 2, 'c': 3, 'd': 4}, ['c', 'd'])
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index 0033d4e..a90ca8a 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -19,7 +19,6 @@
from tempest.common import credentials_factory as credentials
from tempest.common import dynamic_creds
from tempest import config
-from tempest import exceptions
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.identity.v2 import identity_client as v2_iden_client
@@ -176,7 +175,6 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_primary_creds(self, MockRestClient):
- cfg.CONF.set_default('neutron', False, 'service_available')
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
@@ -191,7 +189,6 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_admin_creds(self, MockRestClient):
- cfg.CONF.set_default('neutron', False, 'service_available')
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_list_roles('1234', 'admin')
self._mock_user_create('1234', 'fake_admin_user')
@@ -214,7 +211,6 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_role_creds(self, MockRestClient):
- cfg.CONF.set_default('neutron', False, 'service_available')
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_list_2_roles()
self._mock_user_create('1234', 'fake_role_user')
@@ -243,7 +239,6 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_all_cred_cleanup(self, MockRestClient):
- cfg.CONF.set_default('neutron', False, 'service_available')
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
@@ -281,7 +276,6 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_alt_creds(self, MockRestClient):
- cfg.CONF.set_default('neutron', False, 'service_available')
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
@@ -296,8 +290,10 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_no_network_creation_with_config_set(self, MockRestClient):
- cfg.CONF.set_default('create_isolated_networks', False, group='auth')
- creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True, create_networks=False,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
+ **self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
self._mock_user_create('1234', 'fake_prim_user')
@@ -325,7 +321,10 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_network_creation(self, MockRestClient):
- creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
+ **self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
self._mock_user_create('1234', 'fake_prim_user')
@@ -356,7 +355,10 @@
"description": args['name'],
"security_group_rules": [],
"id": "sg-%s" % args['tenant_id']}]}
- creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
+ **self.fixed_params)
# Create primary tenant and network
self._mock_assign_user_role()
self._mock_list_role()
@@ -460,7 +462,10 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_network_alt_creation(self, MockRestClient):
- creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
+ **self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
self._mock_user_create('1234', 'fake_alt_user')
@@ -485,7 +490,10 @@
@mock.patch('tempest.lib.common.rest_client.RestClient')
def test_network_admin_creation(self, MockRestClient):
- creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
+ **self.fixed_params)
self._mock_assign_user_role()
self._mock_user_create('1234', 'fake_admin_user')
self._mock_tenant_create('1234', 'fake_admin_tenant')
@@ -517,6 +525,8 @@
'dhcp': False,
}
creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
network_resources=net_dict,
**self.fixed_params)
self._mock_assign_user_role()
@@ -553,13 +563,15 @@
'dhcp': False,
}
creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
network_resources=net_dict,
**self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
self._mock_user_create('1234', 'fake_prim_user')
self._mock_tenant_create('1234', 'fake_prim_tenant')
- self.assertRaises(exceptions.InvalidConfiguration,
+ self.assertRaises(lib_exc.InvalidConfiguration,
creds.get_primary_creds)
@mock.patch('tempest.lib.common.rest_client.RestClient')
@@ -571,13 +583,15 @@
'dhcp': False,
}
creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
network_resources=net_dict,
**self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
self._mock_user_create('1234', 'fake_prim_user')
self._mock_tenant_create('1234', 'fake_prim_tenant')
- self.assertRaises(exceptions.InvalidConfiguration,
+ self.assertRaises(lib_exc.InvalidConfiguration,
creds.get_primary_creds)
@mock.patch('tempest.lib.common.rest_client.RestClient')
@@ -589,13 +603,15 @@
'dhcp': True,
}
creds = dynamic_creds.DynamicCredentialProvider(
+ neutron_available=True,
+ project_network_cidr='10.100.0.0/16', project_network_mask_bits=28,
network_resources=net_dict,
**self.fixed_params)
self._mock_assign_user_role()
self._mock_list_role()
self._mock_user_create('1234', 'fake_prim_user')
self._mock_tenant_create('1234', 'fake_prim_tenant')
- self.assertRaises(exceptions.InvalidConfiguration,
+ self.assertRaises(lib_exc.InvalidConfiguration,
creds.get_primary_creds)
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index 13d4713..f824b6c 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -23,10 +23,10 @@
import shutil
import six
-from tempest.common import cred_provider
from tempest.common import preprov_creds
from tempest import config
from tempest.lib import auth
+from tempest.lib.common import cred_provider
from tempest.lib import exceptions as lib_exc
from tempest.tests import base
from tempest.tests import fake_config
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index a56f837..b113c04 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -18,7 +18,8 @@
from tempest.common import waiters
from tempest import exceptions
-from tempest.services.volume.base import base_volumes_client
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.volume.v2 import volumes_client
from tempest.tests import base
import tempest.tests.utils as utils
@@ -43,7 +44,7 @@
time_mock.side_effect = utils.generate_timeout_series(1)
self.client.show_image.return_value = ({'status': 'saving'})
- self.assertRaises(exceptions.TimeoutException,
+ self.assertRaises(lib_exc.TimeoutException,
waiters.wait_for_image_status,
self.client, 'fake_image_id', 'active')
@@ -57,7 +58,7 @@
def test_wait_for_volume_status_error_restoring(self, mock_sleep):
# Tests that the wait method raises VolumeRestoreErrorException if
# the volume status is 'error_restoring'.
- client = mock.Mock(spec=base_volumes_client.BaseVolumesClient,
+ client = mock.Mock(spec=volumes_client.VolumesClient,
build_interval=1)
volume1 = {'volume': {'status': 'restoring-backup'}}
volume2 = {'volume': {'status': 'error_restoring'}}
diff --git a/tempest/tests/common/utils/test_net_utils.py b/tempest/tests/common/utils/test_net_utils.py
new file mode 100644
index 0000000..83c6bcc
--- /dev/null
+++ b/tempest/tests/common/utils/test_net_utils.py
@@ -0,0 +1,33 @@
+# 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 mock
+
+from tempest.common.utils import net_utils
+from tempest.lib import exceptions as lib_exc
+from tempest.tests import base
+
+
+class TestGetPingPayloadSize(base.TestCase):
+
+ def test_ipv4(self):
+ self.assertEqual(1422, net_utils.get_ping_payload_size(1450, 4))
+
+ def test_ipv6(self):
+ self.assertEqual(1406, net_utils.get_ping_payload_size(1450, 6))
+
+ def test_too_low_mtu(self):
+ self.assertRaises(
+ lib_exc.BadRequest, net_utils.get_ping_payload_size, 10, 4)
+
+ def test_None(self):
+ self.assertIsNone(net_utils.get_ping_payload_size(None, mock.Mock()))
diff --git a/tempest/tests/lib/common/test_cred_client.py b/tempest/tests/lib/common/test_cred_client.py
new file mode 100644
index 0000000..1cb3103
--- /dev/null
+++ b/tempest/tests/lib/common/test_cred_client.py
@@ -0,0 +1,78 @@
+# Copyright 2016 Hewlett Packard Enterprise Development LP
+# 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 mock
+
+from tempest.lib.common import cred_client
+from tempest.tests import base
+
+
+class TestCredClientV2(base.TestCase):
+ def setUp(self):
+ super(TestCredClientV2, self).setUp()
+ self.identity_client = mock.MagicMock()
+ self.projects_client = mock.MagicMock()
+ self.users_client = mock.MagicMock()
+ self.roles_client = mock.MagicMock()
+ self.creds_client = cred_client.V2CredsClient(self.identity_client,
+ self.projects_client,
+ self.users_client,
+ self.roles_client)
+
+ def test_create_project(self):
+ self.projects_client.create_tenant.return_value = {
+ 'tenant': 'a_tenant'
+ }
+ res = self.creds_client.create_project('fake_name', 'desc')
+ self.assertEqual('a_tenant', res)
+ self.projects_client.create_tenant.assert_called_once_with(
+ name='fake_name', description='desc')
+
+ def test_delete_project(self):
+ self.creds_client.delete_project('fake_id')
+ self.projects_client.delete_tenant.assert_called_once_with(
+ 'fake_id')
+
+
+class TestCredClientV3(base.TestCase):
+ def setUp(self):
+ super(TestCredClientV3, self).setUp()
+ self.identity_client = mock.MagicMock()
+ self.projects_client = mock.MagicMock()
+ self.users_client = mock.MagicMock()
+ self.roles_client = mock.MagicMock()
+ self.domains_client = mock.MagicMock()
+ self.domains_client.list_domains.return_value = {
+ 'domains': [{'id': 'fake_domain_id'}]
+ }
+ self.creds_client = cred_client.V3CredsClient(self.identity_client,
+ self.projects_client,
+ self.users_client,
+ self.roles_client,
+ self.domains_client,
+ 'fake_domain')
+
+ def test_create_project(self):
+ self.projects_client.create_project.return_value = {
+ 'project': 'a_tenant'
+ }
+ res = self.creds_client.create_project('fake_name', 'desc')
+ self.assertEqual('a_tenant', res)
+ self.projects_client.create_project.assert_called_once_with(
+ name='fake_name', description='desc', domain_id='fake_domain_id')
+
+ def test_delete_project(self):
+ self.creds_client.delete_project('fake_id')
+ print(self.projects_client.calls)
+ self.projects_client.delete_project.assert_called_once_with(
+ 'fake_id')
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 3165689..a244aa2 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import copy
from oslo_serialization import jsonutils as json
from oslotest import mockpatch
@@ -32,7 +31,7 @@
def check_service_client_function(self, function, function2mock,
body, to_utf=False, status=200,
- headers=None, cr_blob=False, **kwargs):
+ headers=None, **kwargs):
mocked_response = self.create_response(body, to_utf, status, headers)
self.useFixture(mockpatch.Patch(
function2mock, return_value=mocked_response))
@@ -40,11 +39,4 @@
resp = function(**kwargs)
else:
resp = function()
-
- if cr_blob:
- evaluated_body = copy.deepcopy(body)
- nested_json = json.loads(evaluated_body['credential']['blob'])
- evaluated_body['credential']['blob'] = nested_json
- self.assertEqual(evaluated_body, resp)
- else:
- self.assertEqual(body, resp)
+ self.assertEqual(body, resp)
diff --git a/tempest/tests/lib/services/identity/v3/test_credentials_client.py b/tempest/tests/lib/services/identity/v3/test_credentials_client.py
index a2a22ff..29d7496 100644
--- a/tempest/tests/lib/services/identity/v3/test_credentials_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_credentials_client.py
@@ -121,14 +121,14 @@
self.client.create_credential,
'tempest.lib.common.rest_client.RestClient.post',
self.FAKE_CREATE_CREDENTIAL,
- bytes_body, status=201, cr_blob=True)
+ bytes_body, status=201)
def _test_show_credential(self, bytes_body=False):
self.check_service_client_function(
self.client.show_credential,
'tempest.lib.common.rest_client.RestClient.get',
self.FAKE_INFO_CREDENTIAL,
- bytes_body, cr_blob=True,
+ bytes_body,
credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f")
def _test_update_credential(self, bytes_body=False):
@@ -136,7 +136,7 @@
self.client.update_credential,
'tempest.lib.common.rest_client.RestClient.patch',
self.FAKE_INFO_CREDENTIAL,
- bytes_body, cr_blob=True,
+ bytes_body,
credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f")
def _test_list_credentials(self, bytes_body=False):
diff --git a/tempest/tests/stress/__init__.py b/tempest/tests/lib/services/volume/__init__.py
similarity index 100%
rename from tempest/tests/stress/__init__.py
rename to tempest/tests/lib/services/volume/__init__.py
diff --git a/tempest/tests/stress/__init__.py b/tempest/tests/lib/services/volume/v1/__init__.py
similarity index 100%
copy from tempest/tests/stress/__init__.py
copy to tempest/tests/lib/services/volume/v1/__init__.py
diff --git a/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py
new file mode 100644
index 0000000..585904e
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py
@@ -0,0 +1,86 @@
+# Copyright 2016 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.v1 import encryption_types_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestEncryptionTypesClient(base.BaseServiceTest):
+ FAKE_CREATE_ENCRYPTION_TYPE = {
+ "encryption": {
+ "id": "cbc36478b0bd8e67e89",
+ "name": "FakeEncryptionType",
+ "type": "fakeType",
+ "provider": "LuksEncryptor",
+ "cipher": "aes-xts-plain64",
+ "key_size": "512",
+ "control_location": "front-end"
+ }
+ }
+
+ FAKE_INFO_ENCRYPTION_TYPE = {
+ "encryption": {
+ "name": "FakeEncryptionType",
+ "type": "fakeType",
+ "description": "test_description",
+ "volume_type": "fakeType",
+ "provider": "LuksEncryptor",
+ "cipher": "aes-xts-plain64",
+ "key_size": "512",
+ "control_location": "front-end"
+ }
+ }
+
+ def setUp(self):
+ super(TestEncryptionTypesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = encryption_types_client.EncryptionTypesClient(fake_auth,
+ 'volume',
+ 'regionOne'
+ )
+
+ def _test_create_encryption(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_encryption_type,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_ENCRYPTION_TYPE,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+
+ def _test_show_encryption_type(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_encryption_type,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_INFO_ENCRYPTION_TYPE,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+
+ def test_create_encryption_type_with_str_body(self):
+ self._test_create_encryption()
+
+ def test_create_encryption_type_with_bytes_body(self):
+ self._test_create_encryption(bytes_body=True)
+
+ def test_show_encryption_type_with_str_body(self):
+ self._test_show_encryption_type()
+
+ def test_show_encryption_type_with_bytes_body(self):
+ self._test_show_encryption_type(bytes_body=True)
+
+ def test_delete_encryption_type(self):
+ self.check_service_client_function(
+ self.client.delete_encryption_type,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ volume_type_id="cbc36478b0bd8e67e89",
+ status=202)
diff --git a/tempest/tests/lib/services/volume/v1/test_quotas_client.py b/tempest/tests/lib/services/volume/v1/test_quotas_client.py
new file mode 100644
index 0000000..f9e76af
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v1/test_quotas_client.py
@@ -0,0 +1,96 @@
+# Copyright 2016 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.v1 import quotas_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+ FAKE_QUOTAS = {
+ "quota_set": {
+ "cores": 20,
+ "fixed_ips": -1,
+ "floating_ips": 10,
+ "id": "fake_tenant",
+ "injected_file_content_bytes": 10240,
+ "injected_file_path_bytes": 255,
+ "injected_files": 5,
+ "instances": 10,
+ "key_pairs": 100,
+ "metadata_items": 128,
+ "ram": 51200,
+ "security_group_rules": 20,
+ "security_groups": 10
+ }
+ }
+
+ FAKE_UPDATE_QUOTAS_REQUEST = {
+ "quota_set": {
+ "security_groups": 45
+ }
+ }
+
+ def setUp(self):
+ super(TestQuotasClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = quotas_client.QuotasClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_show_default_quota_set(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_default_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_QUOTAS,
+ bytes_body, tenant_id="fake_tenant")
+
+ def _test_show_quota_set(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_QUOTAS,
+ bytes_body, tenant_id="fake_tenant")
+
+ def _test_update_quota_set(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_QUOTAS_REQUEST,
+ bytes_body, tenant_id="fake_tenant")
+
+ def test_show_default_quota_set_with_str_body(self):
+ self._test_show_default_quota_set()
+
+ def test_show_default_quota_set_with_bytes_body(self):
+ self._test_show_default_quota_set(bytes_body=True)
+
+ def test_show_quota_set_with_str_body(self):
+ self._test_show_quota_set()
+
+ def test_show_quota_set_with_bytes_body(self):
+ self._test_show_quota_set(bytes_body=True)
+
+ def test_update_quota_set_with_str_body(self):
+ self._test_update_quota_set()
+
+ def test_update_quota_set_with_bytes_body(self):
+ self._test_update_quota_set(bytes_body=True)
+
+ def test_delete_quota_set(self):
+ self.check_service_client_function(
+ self.client.delete_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ tenant_id="fake_tenant")
diff --git a/tempest/tests/lib/services/volume/v1/test_snapshots_client.py b/tempest/tests/lib/services/volume/v1/test_snapshots_client.py
new file mode 100644
index 0000000..49191e3
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v1/test_snapshots_client.py
@@ -0,0 +1,200 @@
+# Copyright 2016 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.v1 import snapshots_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSnapshotsClient(base.BaseServiceTest):
+ FAKE_CREATE_SNAPSHOT = {
+ "snapshot": {
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "force": True
+ }
+ }
+
+ FAKE_UPDATE_SNAPSHOT_REQUEST = {
+ "metadata": {
+ "key": "v1"
+ }
+ }
+
+ FAKE_INFO_SNAPSHOT = {
+ "snapshot": {
+ "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "status": "available",
+ "size": 30,
+ "created_at": "2012-02-29T03:50:07Z"
+ }
+ }
+
+ FAKE_LIST_SNAPSHOTS = {
+ "snapshots": [
+ {
+ "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "status": "available",
+ "size": 30,
+ "created_at": "2012-02-29T03:50:07Z",
+ "metadata": {
+ "contents": "junk"
+ }
+ },
+ {
+ "id": "e479997c-650b-40a4-9dfe-77655818b0d2",
+ "display_name": "snap-002",
+ "display_description": "Weekly backup",
+ "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358",
+ "status": "available",
+ "size": 25,
+ "created_at": "2012-03-19T01:52:47Z",
+ "metadata": {}
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestSnapshotsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = snapshots_client.SnapshotsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_create_snapshot(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_SNAPSHOT,
+ bytes_body)
+
+ def _test_show_snapshot(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_INFO_SNAPSHOT,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_list_snapshots(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_snapshots,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_SNAPSHOTS,
+ bytes_body,
+ detail=True)
+
+ def _test_create_snapshot_metadata(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_snapshot_metadata,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_INFO_SNAPSHOT,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ metadata={"key": "v1"})
+
+ def _test_update_snapshot(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_show_snapshot_metadata(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_snapshot_metadata,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_update_snapshot_metadata(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_snapshot_metadata,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+ bytes_body, snapshot_id="cbc36478b0bd8e67e89")
+
+ def _test_update_snapshot_metadata_item(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_snapshot_metadata_item,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_INFO_SNAPSHOT,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+
+ def test_create_snapshot_with_str_body(self):
+ self._test_create_snapshot()
+
+ def test_create_snapshot_with_bytes_body(self):
+ self._test_create_snapshot(bytes_body=True)
+
+ def test_show_snapshot_with_str_body(self):
+ self._test_show_snapshot()
+
+ def test_show_snapshot_with_bytes_body(self):
+ self._test_show_snapshot(bytes_body=True)
+
+ def test_list_snapshots_with_str_body(self):
+ self._test_list_snapshots()
+
+ def test_list_snapshots_with_bytes_body(self):
+ self._test_list_snapshots(bytes_body=True)
+
+ def test_create_snapshot_metadata_with_str_body(self):
+ self._test_create_snapshot_metadata()
+
+ def test_create_snapshot_metadata_with_bytes_body(self):
+ self._test_create_snapshot_metadata(bytes_body=True)
+
+ def test_update_snapshot_with_str_body(self):
+ self._test_update_snapshot()
+
+ def test_update_snapshot_with_bytes_body(self):
+ self._test_update_snapshot(bytes_body=True)
+
+ def test_show_snapshot_metadata_with_str_body(self):
+ self._test_show_snapshot_metadata()
+
+ def test_show_snapshot_metadata_with_bytes_body(self):
+ self._test_show_snapshot_metadata(bytes_body=True)
+
+ def test_update_snapshot_metadata_with_str_body(self):
+ self._test_update_snapshot_metadata()
+
+ def test_update_snapshot_metadata_with_bytes_body(self):
+ self._test_update_snapshot_metadata(bytes_body=True)
+
+ def test_force_delete_snapshot(self):
+ self.check_service_client_function(
+ self.client.force_delete_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ {},
+ snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ status=202)
+
+ def test_delete_snapshot(self):
+ self.check_service_client_function(
+ self.client.delete_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ status=202)
diff --git a/tempest/tests/stress/__init__.py b/tempest/tests/lib/services/volume/v2/__init__.py
similarity index 100%
copy from tempest/tests/stress/__init__.py
copy to tempest/tests/lib/services/volume/v2/__init__.py
diff --git a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
new file mode 100644
index 0000000..d029091
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
@@ -0,0 +1,86 @@
+# Copyright 2016 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.v2 import encryption_types_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestEncryptionTypesClient(base.BaseServiceTest):
+ FAKE_CREATE_ENCRYPTION_TYPE = {
+ "encryption": {
+ "id": "cbc36478b0bd8e67e89",
+ "name": "FakeEncryptionType",
+ "type": "fakeType",
+ "provider": "LuksEncryptor",
+ "cipher": "aes-xts-plain64",
+ "key_size": "512",
+ "control_location": "front-end"
+ }
+ }
+
+ FAKE_INFO_ENCRYPTION_TYPE = {
+ "encryption": {
+ "name": "FakeEncryptionType",
+ "type": "fakeType",
+ "description": "test_description",
+ "volume_type": "fakeType",
+ "provider": "LuksEncryptor",
+ "cipher": "aes-xts-plain64",
+ "key_size": "512",
+ "control_location": "front-end"
+ }
+ }
+
+ def setUp(self):
+ super(TestEncryptionTypesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = encryption_types_client.EncryptionTypesClient(fake_auth,
+ 'volume',
+ 'regionOne'
+ )
+
+ def _test_create_encryption(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_encryption_type,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_ENCRYPTION_TYPE,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+
+ def _test_show_encryption_type(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_encryption_type,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_INFO_ENCRYPTION_TYPE,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+
+ def test_create_encryption_type_with_str_body(self):
+ self._test_create_encryption()
+
+ def test_create_encryption_type_with_bytes_body(self):
+ self._test_create_encryption(bytes_body=True)
+
+ def test_show_encryption_type_with_str_body(self):
+ self._test_show_encryption_type()
+
+ def test_show_encryption_type_with_bytes_body(self):
+ self._test_show_encryption_type(bytes_body=True)
+
+ def test_delete_encryption_type(self):
+ self.check_service_client_function(
+ self.client.delete_encryption_type,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ volume_type_id="cbc36478b0bd8e67e89",
+ status=202)
diff --git a/tempest/tests/lib/services/volume/v2/test_quotas_client.py b/tempest/tests/lib/services/volume/v2/test_quotas_client.py
new file mode 100644
index 0000000..6384350
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_quotas_client.py
@@ -0,0 +1,86 @@
+# Copyright 2016 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.v2 import quotas_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+ FAKE_QUOTAS = {
+ "quota_set": {
+ "gigabytes": 5,
+ "snapshots": 10,
+ "volumes": 20
+ }
+ }
+
+ FAKE_UPDATE_QUOTAS_REQUEST = {
+ "quota_set": {
+ "security_groups": 45
+ }
+ }
+
+ def setUp(self):
+ super(TestQuotasClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = quotas_client.QuotasClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_show_default_quota_set(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_default_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_QUOTAS,
+ bytes_body, tenant_id="fake_tenant")
+
+ def _test_show_quota_set(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_QUOTAS,
+ bytes_body, tenant_id="fake_tenant")
+
+ def _test_update_quota_set(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_QUOTAS_REQUEST,
+ bytes_body, tenant_id="fake_tenant")
+
+ def test_show_default_quota_set_with_str_body(self):
+ self._test_show_default_quota_set()
+
+ def test_show_default_quota_set_with_bytes_body(self):
+ self._test_show_default_quota_set(bytes_body=True)
+
+ def test_show_quota_set_with_str_body(self):
+ self._test_show_quota_set()
+
+ def test_show_quota_set_with_bytes_body(self):
+ self._test_show_quota_set(bytes_body=True)
+
+ def test_update_quota_set_with_str_body(self):
+ self._test_update_quota_set()
+
+ def test_update_quota_set_with_bytes_body(self):
+ self._test_update_quota_set(bytes_body=True)
+
+ def test_delete_quota_set(self):
+ self.check_service_client_function(
+ self.client.delete_quota_set,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ tenant_id="fake_tenant")
diff --git a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py b/tempest/tests/lib/services/volume/v2/test_snapshots_client.py
new file mode 100644
index 0000000..7d656f1
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_snapshots_client.py
@@ -0,0 +1,201 @@
+# Copyright 2016 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.v2 import snapshots_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSnapshotsClient(base.BaseServiceTest):
+ FAKE_CREATE_SNAPSHOT = {
+ "snapshot": {
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "force": True
+ }
+ }
+
+ FAKE_UPDATE_SNAPSHOT_REQUEST = {
+ "metadata": {
+ "key": "v1"
+ }
+ }
+
+ FAKE_INFO_SNAPSHOT = {
+ "snapshot": {
+ "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "status": "available",
+ "size": 30,
+ "created_at": "2012-02-29T03:50:07Z"
+ }
+ }
+
+ FAKE_LIST_SNAPSHOTS = {
+ "snapshots": [
+ {
+ "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "status": "available",
+ "size": 30,
+ "created_at": "2012-02-29T03:50:07Z",
+ "metadata": {
+ "contents": "junk"
+ }
+ },
+ {
+ "id": "e479997c-650b-40a4-9dfe-77655818b0d2",
+ "display_name": "snap-002",
+ "display_description": "Weekly backup",
+ "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358",
+ "status": "available",
+ "size": 25,
+ "created_at": "2012-03-19T01:52:47Z",
+ "metadata": {}
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestSnapshotsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = snapshots_client.SnapshotsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_create_snapshot(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_SNAPSHOT,
+ bytes_body,
+ status=202)
+
+ def _test_show_snapshot(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_INFO_SNAPSHOT,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_list_snapshots(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_snapshots,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_SNAPSHOTS,
+ bytes_body,
+ detail=True)
+
+ def _test_create_snapshot_metadata(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_snapshot_metadata,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_INFO_SNAPSHOT,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ metadata={"key": "v1"})
+
+ def _test_update_snapshot(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_show_snapshot_metadata(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_snapshot_metadata,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+ bytes_body,
+ snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_update_snapshot_metadata(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_snapshot_metadata,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+ bytes_body, snapshot_id="cbc36478b0bd8e67e89")
+
+ def _test_update_snapshot_metadata_item(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_snapshot_metadata_item,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_INFO_SNAPSHOT,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+
+ def test_create_snapshot_with_str_body(self):
+ self._test_create_snapshot()
+
+ def test_create_snapshot_with_bytes_body(self):
+ self._test_create_snapshot(bytes_body=True)
+
+ def test_show_snapshot_with_str_body(self):
+ self._test_show_snapshot()
+
+ def test_show_snapshot_with_bytes_body(self):
+ self._test_show_snapshot(bytes_body=True)
+
+ def test_list_snapshots_with_str_body(self):
+ self._test_list_snapshots()
+
+ def test_list_snapshots_with_bytes_body(self):
+ self._test_list_snapshots(bytes_body=True)
+
+ def test_create_snapshot_metadata_with_str_body(self):
+ self._test_create_snapshot_metadata()
+
+ def test_create_snapshot_metadata_with_bytes_body(self):
+ self._test_create_snapshot_metadata(bytes_body=True)
+
+ def test_update_snapshot_with_str_body(self):
+ self._test_update_snapshot()
+
+ def test_update_snapshot_with_bytes_body(self):
+ self._test_update_snapshot(bytes_body=True)
+
+ def test_show_snapshot_metadata_with_str_body(self):
+ self._test_show_snapshot_metadata()
+
+ def test_show_snapshot_metadata_with_bytes_body(self):
+ self._test_show_snapshot_metadata(bytes_body=True)
+
+ def test_update_snapshot_metadata_with_str_body(self):
+ self._test_update_snapshot_metadata()
+
+ def test_update_snapshot_metadata_with_bytes_body(self):
+ self._test_update_snapshot_metadata(bytes_body=True)
+
+ def test_force_delete_snapshot(self):
+ self.check_service_client_function(
+ self.client.force_delete_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ {},
+ snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ status=202)
+
+ def test_delete_snapshot(self):
+ self.check_service_client_function(
+ self.client.delete_snapshot,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ status=202)
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py
index 057f57b..e6cf047 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/test_rest_client.py
@@ -296,10 +296,6 @@
status=int(r_code),
body=json.dumps(resp_body))
data = {
- "method": "fake_method",
- "url": "fake_url",
- "headers": "fake_headers",
- "body": "fake_body",
"resp": resp,
"resp_body": json.dumps(resp_body)
}
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index b07f6bc..8a0a84c 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -69,6 +69,7 @@
mock.sentinel.aa)
expected_connect = [mock.call(
'localhost',
+ port=22,
username='root',
pkey=None,
key_filename=None,
diff --git a/tempest/tests/negative/test_negative_auto_test.py b/tempest/tests/negative/test_negative_auto_test.py
deleted file mode 100644
index 44ce567..0000000
--- a/tempest/tests/negative/test_negative_auto_test.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright 2014 Deutsche Telekom AG
-# 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 import config
-import tempest.test as test
-from tempest.tests import base
-from tempest.tests import fake_config
-
-
-class TestNegativeAutoTest(base.TestCase):
- # Fake entries
- _service = 'compute'
-
- fake_input_desc = {"name": "list-flavors-with-detail",
- "http-method": "GET",
- "url": "flavors/detail",
- "json-schema": {"type": "object",
- "properties":
- {"minRam": {"type": "integer"},
- "minDisk": {"type": "integer"}}
- },
- "resources": ["flavor", "volume", "image"]
- }
-
- def setUp(self):
- super(TestNegativeAutoTest, self).setUp()
- self.useFixture(fake_config.ConfigFixture())
- self.patchobject(config, 'TempestConfigPrivate',
- fake_config.FakePrivate)
-
- def _check_prop_entries(self, result, entry):
- entries = [a for a in result if entry in a[0]]
- self.assertIsNotNone(entries)
- self.assertGreater(len(entries), 1)
- for entry in entries:
- self.assertIsNotNone(entry[1]['_negtest_name'])
-
- def _check_resource_entries(self, result, entry):
- entries = [a for a in result if entry in a[0]]
- self.assertIsNotNone(entries)
- self.assertIs(len(entries), 3)
- for entry in entries:
- self.assertIsNotNone(entry[1]['resource'])
-
- def test_generate_scenario(self):
- scenarios = test.NegativeAutoTest.\
- generate_scenario(self.fake_input_desc)
- self.assertIsInstance(scenarios, list)
- for scenario in scenarios:
- self.assertIsInstance(scenario, tuple)
- self.assertIsInstance(scenario[0], str)
- self.assertIsInstance(scenario[1], dict)
- self._check_prop_entries(scenarios, "minRam")
- self._check_prop_entries(scenarios, "minDisk")
- self._check_resource_entries(scenarios, "inv_res")
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index 2e45ef7..7e1ee2c 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -107,7 +107,7 @@
def _validate_result(self, valid_schema, invalid_schema):
for k, v in six.iteritems(valid_schema):
- self.assertTrue(k in invalid_schema)
+ self.assertIn(k, invalid_schema)
def test_generator_mandatory_functions(self):
for data_type in self.types:
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
deleted file mode 100644
index dfe0291..0000000
--- a/tempest/tests/stress/test_stress.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2013 Deutsche Telekom AG
-# 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 shlex
-import subprocess
-
-from oslo_log import log as logging
-from tempest.lib import exceptions
-from tempest.tests import base
-
-LOG = logging.getLogger(__name__)
-
-
-class StressFrameworkTest(base.TestCase):
- """Basic test for the stress test framework."""
-
- def _cmd(self, cmd, param):
- """Executes specified command."""
- cmd = ' '.join([cmd, param])
- LOG.info("running: '%s'" % cmd)
- cmd_str = cmd
- cmd = shlex.split(cmd)
- result = ''
- result_err = ''
- try:
- stdout = subprocess.PIPE
- stderr = subprocess.PIPE
- proc = subprocess.Popen(
- cmd, stdout=stdout, stderr=stderr)
- result, result_err = proc.communicate()
- if proc.returncode != 0:
- LOG.debug('error of %s:\n%s' % (cmd_str, result_err))
- raise exceptions.CommandFailed(proc.returncode,
- cmd,
- result)
- finally:
- LOG.debug('output of %s:\n%s' % (cmd_str, result))
- return proc.returncode
-
- def test_help_function(self):
- result = self._cmd("python", "-m tempest.cmd.run_stress -h")
- self.assertEqual(0, result)
diff --git a/tempest/tests/stress/test_stressaction.py b/tempest/tests/stress/test_stressaction.py
deleted file mode 100644
index 1a1bb67..0000000
--- a/tempest/tests/stress/test_stressaction.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2013 Deutsche Telekom AG
-# 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 tempest.stress.stressaction as stressaction
-import tempest.test
-
-
-class FakeStressAction(stressaction.StressAction):
- def __init__(self, manager, max_runs=None, stop_on_error=False):
- super(self.__class__, self).__init__(manager, max_runs, stop_on_error)
- self._run_called = False
-
- def run(self):
- self._run_called = True
-
- @property
- def run_called(self):
- return self._run_called
-
-
-class FakeStressActionFailing(stressaction.StressAction):
- def run(self):
- raise Exception('FakeStressActionFailing raise exception')
-
-
-class TestStressAction(tempest.test.BaseTestCase):
- def _bulid_stats_dict(self, runs=0, fails=0):
- return {'runs': runs, 'fails': fails}
-
- def testStressTestRun(self):
- stressAction = FakeStressAction(manager=None, max_runs=1)
- stats = self._bulid_stats_dict()
- stressAction.execute(stats)
- self.assertTrue(stressAction.run_called)
- self.assertEqual(stats['runs'], 1)
- self.assertEqual(stats['fails'], 0)
-
- def testStressMaxTestRuns(self):
- stressAction = FakeStressAction(manager=None, max_runs=500)
- stats = self._bulid_stats_dict(runs=499)
- stressAction.execute(stats)
- self.assertTrue(stressAction.run_called)
- self.assertEqual(stats['runs'], 500)
- self.assertEqual(stats['fails'], 0)
-
- def testStressTestRunWithException(self):
- stressAction = FakeStressActionFailing(manager=None, max_runs=1)
- stats = self._bulid_stats_dict()
- stressAction.execute(stats)
- self.assertEqual(stats['runs'], 1)
- self.assertEqual(stats['fails'], 1)
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 8c5d861..ae2f2a3 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import mock
from oslo_config import cfg
from oslotest import mockpatch
import testtools
@@ -154,36 +153,6 @@
continue
-class TestStressDecorator(BaseDecoratorsTest):
- def _test_stresstest_helper(self, expected_frequency='process',
- expected_inheritance=False,
- **decorator_args):
- @test.stresstest(**decorator_args)
- def foo():
- pass
- self.assertEqual(getattr(foo, 'st_class_setup_per'),
- expected_frequency)
- self.assertEqual(getattr(foo, 'st_allow_inheritance'),
- expected_inheritance)
- self.assertEqual(set(['stress']), getattr(foo, '__testtools_attrs'))
-
- def test_stresstest_decorator_default(self):
- self._test_stresstest_helper()
-
- def test_stresstest_decorator_class_setup_frequency(self):
- self._test_stresstest_helper('process', class_setup_per='process')
-
- def test_stresstest_decorator_class_setup_frequency_non_default(self):
- self._test_stresstest_helper(expected_frequency='application',
- class_setup_per='application')
-
- def test_stresstest_decorator_set_frequency_and_inheritance(self):
- self._test_stresstest_helper(expected_frequency='application',
- expected_inheritance=True,
- class_setup_per='application',
- allow_inheritance=True)
-
-
class TestRequiresExtDecorator(BaseDecoratorsTest):
def setUp(self):
super(TestRequiresExtDecorator, self).setUp()
@@ -232,22 +201,6 @@
service='bad_service')
-class TestSimpleNegativeDecorator(BaseDecoratorsTest):
- @test.SimpleNegativeAutoTest
- class FakeNegativeJSONTest(test.NegativeAutoTest):
- _schema = {}
-
- def test_testfunc_exist(self):
- self.assertIn("test_fake_negative", dir(self.FakeNegativeJSONTest))
-
- @mock.patch('tempest.test.NegativeAutoTest.execute')
- def test_testfunc_calls_execute(self, mock):
- obj = self.FakeNegativeJSONTest("test_fake_negative")
- self.assertIn("test_fake_negative", dir(obj))
- obj.test_fake_negative()
- mock.assert_called_once_with(self.FakeNegativeJSONTest._schema)
-
-
class TestConfigDecorators(BaseDecoratorsTest):
def setUp(self):
super(TestConfigDecorators, self).setUp()
diff --git a/tempest/tests/test_tempest_plugin.py b/tempest/tests/test_tempest_plugin.py
index dd50125..13e2499 100644
--- a/tempest/tests/test_tempest_plugin.py
+++ b/tempest/tests/test_tempest_plugin.py
@@ -75,7 +75,5 @@
fake_obj = fake_plugin.FakeStevedoreObjNoServiceClients()
manager.ext_plugins = [fake_obj]
manager._register_service_clients()
- expected_result = []
registered_clients = registry.get_service_clients()
- self.assertIn(fake_obj.name, registered_clients)
- self.assertEqual(expected_result, registered_clients[fake_obj.name])
+ self.assertNotIn(fake_obj.name, registered_clients)
diff --git a/test-requirements.txt b/test-requirements.txt
index 04c3d6d..9e3165c 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,10 +3,9 @@
# process, which may cause wedges in the gate later.
hacking<0.12,>=0.11.0 # Apache-2.0
# needed for doc build
-sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
-python-subunit>=0.0.18 # Apache-2.0/BSD
-oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
-reno>=1.8.0 # Apache2
+sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
+oslosphinx>=4.7.0 # Apache-2.0
+reno>=1.8.0 # Apache-2.0
mock>=2.0 # BSD
-coverage>=3.6 # Apache-2.0
+coverage>=4.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
index fb4e6d5..0b83b91 100755
--- a/tools/pretty_tox.sh
+++ b/tools/pretty_tox.sh
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
+echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
+
set -o pipefail
TESTRARGS=$1
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index e0fca0f..1f8204e 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
+echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
+
set -o pipefail
TESTRARGS=$@
diff --git a/tox.ini b/tox.ini
index a621492..82dba92 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = pep8,py35,py34,py27
+envlist = pep8,py35,py34,py27,pip-check-reqs
minversion = 2.3.1
skipsdist = True
@@ -16,6 +16,7 @@
setenv =
VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/tests
+ PYTHONWARNINGS=default::DeprecationWarning
passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
usedevelop = True
install_command = pip install -U {opts} {packages}
@@ -25,7 +26,7 @@
-r{toxinidir}/test-requirements.txt
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '{posargs}'
+ ostestr {posargs}
[testenv:genconfig]
commands = oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf
@@ -44,7 +45,7 @@
deps = {[tempestenv]deps}
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '{posargs}'
+ tempest run --regex {posargs}
[testenv:ostestr]
sitepackages = {[tempestenv]sitepackages}
@@ -66,7 +67,7 @@
deps = {[tempestenv]deps}
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '{posargs}'
+ tempest run --regex {posargs}
[testenv:full]
envdir = .tox/tempest
@@ -77,7 +78,7 @@
# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)) {posargs}'
+ tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
[testenv:full-serial]
envdir = .tox/tempest
@@ -88,7 +89,7 @@
# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)) {posargs}'
+ tempest run --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
[testenv:smoke]
envdir = .tox/tempest
@@ -97,7 +98,7 @@
deps = {[tempestenv]deps}
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '\[.*\bsmoke\b.*\] {posargs}'
+ tempest run --regex '\[.*\bsmoke\b.*\]' {posargs}
[testenv:smoke-serial]
envdir = .tox/tempest
@@ -109,15 +110,7 @@
# job would fail if we moved it to parallel.
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox_serial.sh '\[.*\bsmoke\b.*\] {posargs}'
-
-[testenv:stress]
-envdir = .tox/tempest
-sitepackages = {[tempestenv]sitepackages}
-setenv = {[tempestenv]setenv}
-deps = {[tempestenv]deps}
-commands =
- run-tempest-stress {posargs}
+ tempest run --serial --regex '\[.*\bsmoke\b.*\]' {posargs}
[testenv:venv]
commands = {posargs}
@@ -153,7 +146,18 @@
# Skipped because of new hacking 0.9: H405
ignore = E125,E123,E129
show-source = True
-exclude = .git,.venv,.tox,dist,doc,openstack,*egg
+exclude = .git,.venv,.tox,dist,doc,*egg
[testenv:releasenotes]
commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
+
+[testenv:pip-check-reqs]
+# Do not install test-requirements as that will pollute the virtualenv for
+# determining missing packages.
+# This also means that pip-check-reqs must be installed separately, outside
+# of the requirements.txt files
+deps = pip_check_reqs
+ -r{toxinidir}/requirements.txt
+commands=
+ pip-extra-reqs -d --ignore-file=tempest/tests/* tempest
+ pip-missing-reqs -d --ignore-file=tempest/tests/* tempest