Retire oswin-tempest-plugin: remove repo content
Winstackers project has been retired - https://review.opendev.org/c/openstack/governance/+/886880 this commit removes the content of oswin-tempest-plugin deliverables of this project Change-Id: I489d36a539cb943c1d7216390e469a471719a2cf
This commit is contained in:
parent
9e95d33d9e
commit
0976964257
@ -1,6 +0,0 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = oswin_tempest_plugin
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
56
.gitignore
vendored
56
.gitignore
vendored
@ -1,56 +0,0 @@
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Packages
|
||||
*.egg*
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
lib
|
||||
lib64
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
cover/
|
||||
.coverage*
|
||||
!.coveragerc
|
||||
.tox
|
||||
nosetests.xml
|
||||
.stestr
|
||||
.venv
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# Complexity
|
||||
output/*.html
|
||||
output/*/index.html
|
||||
|
||||
# Sphinx
|
||||
doc/build
|
||||
|
||||
# pbr generates these
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
|
||||
# Editors
|
||||
*~
|
||||
.*.swp
|
||||
.*sw?
|
||||
|
3
.mailmap
3
.mailmap
@ -1,3 +0,0 @@
|
||||
# Format is:
|
||||
# <preferred e-mail> <other e-mail 1>
|
||||
# <preferred e-mail> <other e-mail 2>
|
@ -1,3 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_path=${OS_TEST_PATH:-./oswin_tempest_plugin/tests}
|
||||
top_dir=./
|
@ -1,5 +0,0 @@
|
||||
- project:
|
||||
templates:
|
||||
- openstack-python3-zed-jobs
|
||||
- check-requirements
|
||||
queue: os-win
|
@ -1,19 +0,0 @@
|
||||
The source repository for this project can be found at:
|
||||
|
||||
https://opendev.org/openstack/oswin-tempest-plugin
|
||||
|
||||
Pull requests submitted through GitHub are not monitored.
|
||||
|
||||
To start contributing to OpenStack, follow the steps in the contribution guide
|
||||
to set up and use Gerrit:
|
||||
|
||||
https://docs.openstack.org/contributors/code-and-documentation/quick-start.html
|
||||
|
||||
Bugs should be filed on Launchpad:
|
||||
|
||||
https://bugs.launchpad.net/oswin-tempest-plugin
|
||||
|
||||
For more specific information about contributing to this repository, see the
|
||||
oswin-tempest-plugin contributor guide:
|
||||
|
||||
https://docs.openstack.org/oswin-tempest-plugin/latest/contributor/contributing.html
|
@ -1,4 +0,0 @@
|
||||
oswin-tempest-plugin Style Commandments
|
||||
=======================================
|
||||
|
||||
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/
|
176
LICENSE
176
LICENSE
@ -1,176 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
25
README.rst
25
README.rst
@ -1,19 +1,10 @@
|
||||
====================
|
||||
oswin-tempest-plugin
|
||||
====================
|
||||
This project is no longer maintained.
|
||||
|
||||
This project contains Tempest tests to cover the os_win project, as well as a plugin to automatically load these tests into Tempest.
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
Please fill here a long description which must be at least 3 lines wrapped on
|
||||
80 cols, so that distribution package maintainers can use it in their packages.
|
||||
Note that this is a hard requirement.
|
||||
|
||||
* Free software: Apache license
|
||||
* Documentation: http://docs.openstack.org/developer/oswin-tempest-plugin
|
||||
* Source: http://opendev.org/openstack/oswin-tempest-plugin
|
||||
* Bugs: http://bugs.launchpad.net/oswin-tempest-plugin
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* TODO
|
||||
For any further questions, please email
|
||||
openstack-discuss@lists.openstack.org or join #openstack-dev on
|
||||
OFTC.
|
||||
|
@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIR_OSWIN_TEMPEST_PLUGIN=$DEST/oswin-tempest-plugin
|
||||
|
||||
if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
||||
cd $DIR_OSWIN_TEMPEST_PLUGIN
|
||||
echo "Installing oswin-tempest-plugin"
|
||||
setup_develop $DIR_OSWIN_TEMPEST_PLUGIN
|
||||
|
||||
echo "Sucessfully installed oswin-tempest-plugin"
|
||||
|
||||
fi
|
@ -1,2 +0,0 @@
|
||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
@ -1,82 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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 os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
#'sphinx.ext.intersphinx',
|
||||
'openstackdocstheme'
|
||||
]
|
||||
|
||||
# openstackdocstheme options
|
||||
openstackdocs_repo_name = 'openstack/oswin-tempest-plugin'
|
||||
openstackdocs_auto_name = False
|
||||
openstackdocs_bug_project = 'os-win'
|
||||
openstackdocs_bug_tag = ''
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'oswin-tempest-plugin'
|
||||
copyright = '2017, Cloudbase Solutions'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'native'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = ['static']
|
||||
html_theme = 'openstackdocs'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
'%s Documentation' % project,
|
||||
'Cloudbase Solutions', 'manual'),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
@ -1,93 +0,0 @@
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
|
||||
For general information on contributing to OpenStack, please check out the
|
||||
`contributor guide <https://docs.openstack.org/contributors/>`_ to get started.
|
||||
It covers all the basics that are common to all OpenStack projects: the accounts
|
||||
you need, the basics of interacting with our Gerrit review system, how we
|
||||
communicate as a community, etc.
|
||||
|
||||
Below will cover the more project specific information you need to get started
|
||||
with oswin-tempest-plugin.
|
||||
|
||||
Communication
|
||||
~~~~~~~~~~~~~
|
||||
.. This would be a good place to put the channel you chat in as a project; when/
|
||||
where your meeting is, the tags you prepend to your ML threads, etc.
|
||||
|
||||
We recommend using the standard communication channels, such as the OpenStack
|
||||
mailing list or IRC channels. The official IRC channel (#openstack-hyper-v) is
|
||||
not archived at the moment, so we recommend using #openstack-dev.
|
||||
|
||||
Please include one of the following tags when using the OpenStack mailing
|
||||
list:
|
||||
|
||||
* winstackers
|
||||
* windows
|
||||
* hyper-v
|
||||
|
||||
Feel free to reach out to the Winstackers PTL or other core members.
|
||||
|
||||
Contacting the Core Team
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. This section should list the core team, their irc nicks, emails, timezones
|
||||
etc. If all this info is maintained elsewhere (i.e. a wiki), you can link to
|
||||
that instead of enumerating everyone here.
|
||||
|
||||
The Winstackers core team is composed of:
|
||||
|
||||
* Lucian Petrut <lpetrut@cloudbasesolutions.com> (lpetrut)
|
||||
* Claudiu Belu <cbelu@cloudbasesolutions.com> (claudiub)
|
||||
* Alessandro Pilotti <apilotti@cloudbasesolutions.com> (apilotti)
|
||||
|
||||
New Feature Planning
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
.. This section is for talking about the process to get a new feature in. Some
|
||||
projects use blueprints, some want specs, some want both! Some projects
|
||||
stick to a strict schedule when selecting what new features will be reviewed
|
||||
for a release.
|
||||
|
||||
If you want to propose a new feature, we recommend `filing a blueprint
|
||||
<https://blueprints.launchpad.net/oswin-tempest-plugin>`__ and then contacting
|
||||
the core team.
|
||||
|
||||
Once the feature is approved, please propose the patches on Gerrit, following
|
||||
the Openstack contributor guide.
|
||||
|
||||
Task Tracking
|
||||
~~~~~~~~~~~~~
|
||||
.. This section is about where you track tasks- launchpad? storyboard? is there
|
||||
more than one launchpad project? what's the name of the project group in
|
||||
storyboard?
|
||||
|
||||
We track our tasks in `Launchpad <https://bugs.launchpad.net/oswin-tempest-plugin>`__.
|
||||
|
||||
Reporting a Bug
|
||||
~~~~~~~~~~~~~~~
|
||||
.. Pretty self explanatory section, link directly to where people should report
|
||||
bugs for your project.
|
||||
|
||||
You found an issue and want to make sure we are aware of it? You can do so on
|
||||
`Launchpad <https://bugs.launchpad.net/oswin-tempest-plugin/+filebug>`__.
|
||||
More info about Launchpad usage can be found on `OpenStack docs page
|
||||
<https://docs.openstack.org/contributors/common/task-tracking.html#launchpad>`_.
|
||||
|
||||
Getting Your Patch Merged
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. This section should have info about what it takes to get something merged. Do
|
||||
you require one or two +2's before +W? Do some of your repos require unit
|
||||
test changes with all patches? etc.
|
||||
|
||||
Changes proposed to oswin-tempest-plugin generally require two ``Code-Review +2``
|
||||
votes from oswin-tempest-plugin core reviewers before merging. In case of trivial
|
||||
patches and urgent bug fixes, this rule is sometimes ignored.
|
||||
|
||||
Project Team Lead Duties
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. this section is where you can put PTL specific duties not already listed in
|
||||
the common PTL guide (linked below), or if you already have them written
|
||||
up elsewhere you can link to that doc here.
|
||||
|
||||
All common PTL duties are enumerated in the `PTL guide
|
||||
<https://docs.openstack.org/project-team-guide/ptl.html>`_.
|
@ -1,25 +0,0 @@
|
||||
.. oswin-tempest-plugin documentation master file, created by
|
||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to oswin-tempest-plugin's documentation!
|
||||
================================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
readme
|
||||
installation
|
||||
usage
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
@ -1,12 +0,0 @@
|
||||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install oswin-tempest-plugin
|
||||
|
||||
Or, if you have virtualenvwrapper installed::
|
||||
|
||||
$ mkvirtualenv oswin-tempest-plugin
|
||||
$ pip install oswin-tempest-plugin
|
@ -1 +0,0 @@
|
||||
.. include:: ../../README.rst
|
@ -1,7 +0,0 @@
|
||||
=====
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use oswin-tempest-plugin in a project::
|
||||
|
||||
import oswin_tempest_plugin
|
@ -1,90 +0,0 @@
|
||||
# Copyright 2013 Cloudbase Solutions Srl
|
||||
# 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 os
|
||||
|
||||
from oslo_log import log as logging
|
||||
from winrm import protocol
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin import exceptions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = config.CONF
|
||||
|
||||
protocol.Protocol.DEFAULT_TIMEOUT = "PT3600S"
|
||||
|
||||
|
||||
def run_wsman_cmd(host, cmd, username, password=None,
|
||||
cert_pem_path=None, cert_key_pem_path=None,
|
||||
transport_method='plaintext', fail_on_error=True):
|
||||
url = 'https://%s:5986/wsman' % host
|
||||
|
||||
if transport_method == 'ssl':
|
||||
if not (os.path.exists(cert_pem_path)
|
||||
and os.path.exists(cert_key_pem_path)):
|
||||
raise exceptions.WSManException('Could not find certificate path '
|
||||
'or certificate key path.')
|
||||
|
||||
LOG.debug('Connecting to: %s', host)
|
||||
p = protocol.Protocol(endpoint=url,
|
||||
transport=transport_method,
|
||||
server_cert_validation='ignore',
|
||||
username=username,
|
||||
password=password,
|
||||
cert_pem=cert_pem_path,
|
||||
cert_key_pem=cert_key_pem_path)
|
||||
|
||||
shell_id = p.open_shell()
|
||||
LOG.debug('Running command on host %(host)s: %(cmd)s',
|
||||
{'host': host, 'cmd': cmd})
|
||||
command_id = p.run_command(shell_id, cmd)
|
||||
std_out, std_err, return_code = p.get_command_output(shell_id, command_id)
|
||||
|
||||
p.cleanup_command(shell_id, command_id)
|
||||
p.close_shell(shell_id)
|
||||
|
||||
LOG.debug('Results from %(host)s: return_code: %(return_code)s, std_out: '
|
||||
'%(std_out)s, std_err: %(std_err)s',
|
||||
{'host': host, 'return_code': return_code, 'std_out': std_out,
|
||||
'std_err': std_err})
|
||||
|
||||
if fail_on_error and return_code:
|
||||
raise exceptions.WSManException(
|
||||
cmd=cmd, host=host, return_code=return_code,
|
||||
std_out=std_out, std_err=std_err)
|
||||
|
||||
return (std_out, std_err, return_code)
|
||||
|
||||
|
||||
def run_wsman_ps(host, cmd, username, password, cert_pem_path=None,
|
||||
cert_key_pem_path=None, transport_method='plaintext',
|
||||
fail_on_error=True):
|
||||
|
||||
cmd = ("powershell -NonInteractive -ExecutionPolicy RemoteSigned "
|
||||
"-Command \"%s\"" % cmd)
|
||||
return run_wsman_cmd(host, cmd, username, password, cert_pem_path,
|
||||
cert_key_pem_path, transport_method, fail_on_error)
|
||||
|
||||
|
||||
def run_hv_host_wsman_ps(host, cmd, fail_on_error=True):
|
||||
return run_wsman_ps(
|
||||
host, cmd,
|
||||
username=CONF.hyperv_host_auth.username,
|
||||
password=CONF.hyperv_host_auth.password,
|
||||
cert_pem_path=CONF.hyperv_host_auth.cert_pem_path,
|
||||
cert_key_pem_path=CONF.hyperv_host_auth.cert_key_pem_path,
|
||||
transport_method=CONF.hyperv_host_auth.transport_method,
|
||||
fail_on_error=fail_on_error)
|
@ -1,117 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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_config import cfg
|
||||
from oslo_config import types
|
||||
from tempest import config
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
hyperv_group = cfg.OptGroup(name='hyperv',
|
||||
title='Hyper-V Driver Tempest Options')
|
||||
|
||||
HyperVGroup = [
|
||||
cfg.IntOpt('hypervisor_version',
|
||||
default=0,
|
||||
help="Compute nodes' hypervisor version, used to determine "
|
||||
"which tests to run. It must have following value: "
|
||||
"major_version * 1000 + minor_version"
|
||||
"For example, Windows / Hyper-V Server 2012 R2 would have "
|
||||
"the value 6003"),
|
||||
cfg.StrOpt('vhd_image_ref',
|
||||
help="Valid VHD image reference to be used in tests."),
|
||||
cfg.StrOpt('vhdx_image_ref',
|
||||
help="Valid VHDX image reference to be used in tests."),
|
||||
cfg.StrOpt('gen2_image_ref',
|
||||
help="Valid Generation 2 VM VHDX image reference to be used "
|
||||
"in tests."),
|
||||
cfg.StrOpt('secure_boot_image_ref',
|
||||
help="Valid secure boot VM VHDX image reference to be used "
|
||||
"in tests."),
|
||||
cfg.StrOpt('secure_boot_image_ssh_user',
|
||||
help='User for secure boot image to be used in tests.'),
|
||||
cfg.BoolOpt('cluster_enabled',
|
||||
default=False,
|
||||
help="The compute nodes are joined into a Hyper-V Cluster."),
|
||||
cfg.IntOpt('failover_timeout',
|
||||
default=120,
|
||||
help='The maximum amount of time to wait for a failover to '
|
||||
'occur.'),
|
||||
cfg.IntOpt('failover_sleep_interval',
|
||||
default=5,
|
||||
help='The amount of time to wait between failover checks.'),
|
||||
cfg.BoolOpt('remotefx_enabled',
|
||||
default=False,
|
||||
help="RemoteFX feature is enabled and supported on the "
|
||||
"compute nodes."),
|
||||
cfg.IntOpt('available_numa_nodes',
|
||||
default=1,
|
||||
help="The maximum number of NUMA cells the compute nodes "
|
||||
"have. If it's less than 2, resize negative tests for "
|
||||
"vNUMA will be skipped."),
|
||||
cfg.ListOpt('collected_metrics',
|
||||
item_type=types.String(
|
||||
choices=('cpu', 'network.outgoing.bytes',
|
||||
'disk.read.bytes')),
|
||||
default=[],
|
||||
help="The ceilometer metrics to check. If this config value "
|
||||
"is empty, the telemetry tests are skipped. This config "
|
||||
"option assumes that the compute nodes are configured "
|
||||
"and capable of collecting ceilometer metrics. WARNING: "
|
||||
"neutron-ovs-agent is not capable of enabling network "
|
||||
"metrics collection."),
|
||||
cfg.IntOpt('polled_metrics_delay',
|
||||
default=620,
|
||||
help="The number of seconds to wait for the metrics to be "
|
||||
"published by the compute node's ceilometer-polling "
|
||||
"agent. The value must be greater by ~15-20 seconds "
|
||||
"than the agent's publish interval, defined in its "
|
||||
"polling.yaml file (typically, the intervals are 600 "
|
||||
"seconds)."),
|
||||
]
|
||||
|
||||
hyperv_host_auth_group = cfg.OptGroup(name='hyperv_host_auth',
|
||||
title='Hyper-V host '
|
||||
'authentication options')
|
||||
|
||||
hyperv_host_auth_opts = [
|
||||
cfg.StrOpt('username',
|
||||
help="The username of the Hyper-V hosts."),
|
||||
cfg.StrOpt('password',
|
||||
secret=True,
|
||||
help='The password of the Hyper-V hosts.'),
|
||||
cfg.StrOpt('cert_pem_path',
|
||||
default=None,
|
||||
help='SSL certificate for WinRM remote PS connection.'),
|
||||
cfg.StrOpt('cert_key_pem_path',
|
||||
default=None,
|
||||
help='SSL key paired with cert_pem_path for WinRM remote PS '
|
||||
'connection.'),
|
||||
cfg.StrOpt('transport_method',
|
||||
default='plaintext',
|
||||
choices=('ssl', 'ntlm', 'plaintext'),
|
||||
help='The method that should be used to establish a connection '
|
||||
'to a Hyper-V host.')
|
||||
]
|
||||
|
||||
_opts = [
|
||||
(hyperv_group, HyperVGroup),
|
||||
(hyperv_host_auth_group, hyperv_host_auth_opts),
|
||||
]
|
||||
|
||||
|
||||
def list_opts():
|
||||
return _opts
|
@ -1,31 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 import exceptions
|
||||
|
||||
|
||||
class ResizeException(exceptions.TempestException):
|
||||
message = ("Server %(server_id)s failed to resize to the given "
|
||||
"flavor %(flavor)s")
|
||||
|
||||
|
||||
class NotFoundException(exceptions.TempestException):
|
||||
message = "Resource %(resource)s (%(res_type)s) was not found."
|
||||
|
||||
|
||||
class WSManException(exceptions.TempestException):
|
||||
message = ('Command "%(cmd)s" failed on host %(host)s failed with the '
|
||||
'return code %(return_code)s. std_out: %(std_out)s, '
|
||||
'std_err: %(std_err)s')
|
@ -1,65 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 os
|
||||
|
||||
from tempest import config
|
||||
from tempest.test_discover import plugins
|
||||
|
||||
from oswin_tempest_plugin import config as project_config
|
||||
|
||||
|
||||
class OSWinTempestPlugin(plugins.TempestPlugin):
|
||||
def load_tests(self):
|
||||
base_path = os.path.split(os.path.dirname(
|
||||
os.path.abspath(__file__)))[0]
|
||||
test_dir = "oswin_tempest_plugin/tests"
|
||||
full_test_dir = os.path.join(base_path, test_dir)
|
||||
return full_test_dir, base_path
|
||||
|
||||
def register_opts(self, conf):
|
||||
"""Add additional configuration options to tempest.
|
||||
|
||||
This method will be run for the plugin during the register_opts()
|
||||
function in tempest.config
|
||||
|
||||
:param conf: The conf object that can be used to register additional
|
||||
config options on.
|
||||
"""
|
||||
|
||||
for config_opt_group, config_opts in project_config.list_opts():
|
||||
config.register_opt_group(conf, config_opt_group, config_opts)
|
||||
|
||||
def get_opt_lists(self):
|
||||
"""Get a list of options for sample config generation.
|
||||
|
||||
:return: A list of tuples with the group name and options in that
|
||||
group.
|
||||
:return type: list
|
||||
"""
|
||||
return [(group.name, opts)
|
||||
for group, opts in project_config.list_opts()]
|
||||
|
||||
def get_service_clients(self):
|
||||
metric_config = config.service_client_config('metric')
|
||||
metric_v1_params = {
|
||||
'name': 'metric_v1',
|
||||
'service_version': 'metric.v1',
|
||||
'module_path': 'oswin_tempest_plugin.services.gnocchi_client',
|
||||
'client_names': ['GnocchiClient'],
|
||||
}
|
||||
metric_v1_params.update(metric_config)
|
||||
|
||||
return [metric_v1_params]
|
@ -1,50 +0,0 @@
|
||||
# Copyright 2018 Cloudbase Solutions Srl
|
||||
#
|
||||
# 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 oswin_tempest_plugin import config
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class GnocchiClient(rest_client.RestClient):
|
||||
|
||||
uri_prefix = 'v1'
|
||||
|
||||
def deserialize(self, body):
|
||||
return json.loads(body.replace("\n", ""))
|
||||
|
||||
def _helper_list(self, uri):
|
||||
resp, body = self.get(uri)
|
||||
self.expected_success(200, resp.status)
|
||||
body = self.deserialize(body)
|
||||
return rest_client.ResponseBodyList(resp, body)
|
||||
|
||||
def list_resources(self):
|
||||
uri = '%s/resource/generic' % self.uri_prefix
|
||||
return self._helper_list(uri)
|
||||
|
||||
def list_samples(self, resource_id, meter_name):
|
||||
"""Returns a list of samples for the given resource and meter.
|
||||
|
||||
:returns: list, each item being a list containing the following values
|
||||
in this order: timestamp, granularity, value.
|
||||
"""
|
||||
uri = '%s/resource/generic/%s/metric/%s/measures' % (
|
||||
self.uri_prefix, resource_id, meter_name)
|
||||
return self._helper_list(uri)
|
@ -1,107 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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.common import waiters
|
||||
import testtools
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class _MigrateMixin(object):
|
||||
"""Cold migration mixin.
|
||||
|
||||
This mixin will add a cold migration test. It will perform the
|
||||
following operations:
|
||||
|
||||
* Spawn instance.
|
||||
* Cold migrate the instance.
|
||||
* Check the server connectivity.
|
||||
"""
|
||||
|
||||
def _migrate_server(self, server_tuple):
|
||||
server = server_tuple.server
|
||||
self.admin_servers_client.migrate_server(server['id'])
|
||||
self._wait_for_server_status(server, 'VERIFY_RESIZE')
|
||||
self.servers_client.confirm_resize_server(server['id'])
|
||||
|
||||
@testtools.skipUnless(CONF.compute.min_compute_nodes >= 2,
|
||||
'Expected at least 2 compute nodes.')
|
||||
def test_migration(self):
|
||||
server_tuple = self._create_server()
|
||||
self._migrate_server(server_tuple)
|
||||
self._check_scenario(server_tuple)
|
||||
|
||||
|
||||
class _LiveMigrateMixin(object):
|
||||
"""Live migration mixin.
|
||||
|
||||
This mixin will add a live migration test. It will perform the
|
||||
following operations:
|
||||
|
||||
* Spawn instance.
|
||||
* Live migrate the instance.
|
||||
* Check the server connectivity.
|
||||
"""
|
||||
|
||||
# TODO(amuresan): Different mixins may be used at the same time.
|
||||
# Each of them may override some fields such as
|
||||
# 'max_microversion'. This has to be sorted out.
|
||||
max_microversion = '2.24'
|
||||
|
||||
def _live_migrate_server(self, server_tuple, destination_host=None,
|
||||
state='ACTIVE', volume_backed=False):
|
||||
server = server_tuple.server
|
||||
admin_server = self._get_server_as_admin(server)
|
||||
current_host = admin_server['OS-EXT-SRV-ATTR:host']
|
||||
|
||||
block_migration = (CONF.compute_feature_enabled.
|
||||
block_migration_for_live_migration
|
||||
and not volume_backed)
|
||||
|
||||
self.admin_servers_client.live_migrate_server(
|
||||
server['id'],
|
||||
host=destination_host,
|
||||
block_migration=block_migration,
|
||||
disk_over_commit=False)
|
||||
|
||||
waiters.wait_for_server_status(self.admin_servers_client, server['id'],
|
||||
state)
|
||||
|
||||
admin_server = self._get_server_as_admin(server)
|
||||
after_migration_host = admin_server['OS-EXT-SRV-ATTR:host']
|
||||
|
||||
migration_list = (self.admin_migrations_client.list_migrations()
|
||||
['migrations'])
|
||||
|
||||
msg = ("Live Migration failed. Migrations list for Instance "
|
||||
"%s: [" % server['id'])
|
||||
for live_migration in migration_list:
|
||||
if live_migration['instance_uuid'] == server['id']:
|
||||
msg += "\n%s" % live_migration
|
||||
msg += "]"
|
||||
|
||||
if destination_host:
|
||||
self.assertEqual(destination_host, after_migration_host, msg)
|
||||
else:
|
||||
self.assertNotEqual(current_host, after_migration_host, msg)
|
||||
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
|
||||
'Live migration option enabled.')
|
||||
def test_live_migration(self):
|
||||
server_tuple = self._create_server()
|
||||
self._live_migrate_server(server_tuple)
|
||||
self._check_scenario(server_tuple)
|
@ -1,86 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 testtools
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin.tests._mixins import resize
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class _OptionalFeatureMixin(resize._ResizeUtils):
|
||||
"""Optional Feature mixin.
|
||||
|
||||
Some features are optional, and can be turned on / off through resize
|
||||
with certain flavors.
|
||||
Examples of optional features: vNUMA, QoS, SR-IOV, PCI passthrough,
|
||||
RemoteFX.
|
||||
|
||||
This mixin will add the following tests:
|
||||
* test_feature
|
||||
* test_resize_add_feature
|
||||
* test_resize_remove_feature
|
||||
|
||||
The resize tests will create a new instance, resize it to a new flavor (
|
||||
turning on / off the optional feature), and check its network
|
||||
connectivity.
|
||||
|
||||
The optional feature flavor is based on the test suite's configured
|
||||
_FLAVOR_REF (typically compute.flavor_ref or compute.flavor_ref_alt),
|
||||
with some updates. For example, if the vNUMA configuration is to be tested,
|
||||
the new flavor would contain the flavor extra_spec {'hw:numa_nodes="1"'}.
|
||||
Keep in mind that all the extra_spec keys and values have to be strings.
|
||||
"""
|
||||
|
||||
# NOTE(claudiub): This flavor dict contains updates to the base flavor
|
||||
# tempest is configured with. For example, _FEATURE_FLAVOR can be:
|
||||
# _BIGGER_FLAVOR = {'extra_specs': {'hw:numa_nodes': 1'}}
|
||||
# which means a flavor having that flavor extra_spec will be created, and
|
||||
# a created instance will be resize to / from it.
|
||||
|
||||
_FEATURE_FLAVOR = {}
|
||||
|
||||
def _get_flavor_ref(self):
|
||||
"""Gets a new optional feature flavor ref.
|
||||
|
||||
Creates a new flavor based on the test suite's configured _FLAVOR_REF,
|
||||
with some updates specific to the optional feature.
|
||||
|
||||
:returns: nova flavor ID.
|
||||
"""
|
||||
# NOTE(claudiub): Unless explicitly given another flavor,
|
||||
# _create_server will call this method to get the flavor reference
|
||||
# needed to spawn a new instance. Thus, any other test will spawn
|
||||
# instances with this Optional Feature.
|
||||
new_flavor = self._create_new_flavor(self._FLAVOR_REF,
|
||||
self._FEATURE_FLAVOR)
|
||||
return new_flavor['id']
|
||||
|
||||
def test_feature(self):
|
||||
server_tuple = self._create_server()
|
||||
self._check_scenario(server_tuple)
|
||||
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
|
||||
'Resize is not available.')
|
||||
def test_resize_add_feature(self):
|
||||
new_flavor = self._get_flavor_ref()
|
||||
self._check_resize(new_flavor, self._FLAVOR_REF)
|
||||
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
|
||||
'Resize is not available.')
|
||||
def test_resize_remove_feature(self):
|
||||
new_flavor = self._get_flavor_ref()
|
||||
self._check_resize(self._FLAVOR_REF, new_flavor)
|
@ -1,127 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
import testtools
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin import exceptions
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _ResizeUtils(object):
|
||||
|
||||
def _get_server_migration(self, server_id):
|
||||
final_states = ['error', 'confirmed']
|
||||
for i in range(10):
|
||||
migrations = (
|
||||
self.admin_migrations_client.list_migrations()['migrations'])
|
||||
server_migration = [m for m in migrations
|
||||
if m['instance_uuid'] == server_id]
|
||||
if server_migration:
|
||||
migration_status = server_migration[0]['status']
|
||||
LOG.debug("Server's %s migration status: %s",
|
||||
server_id, migration_status)
|
||||
if migration_status in final_states:
|
||||
return server_migration[0]
|
||||
else:
|
||||
# NOTE(claudiub): the migration might not appear *immediately*
|
||||
# after the cold resize was requested.
|
||||
LOG.info("Server's %s migration was not found.", server_id)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
return server_migration[0] if server_migration else None
|
||||
|
||||
def _resize_server(self, server_tuple, new_flavor_id):
|
||||
server = server_tuple.server
|
||||
self.servers_client.resize_server(server['id'],
|
||||
flavor_ref=new_flavor_id)
|
||||
|
||||
migration = self._get_server_migration(server['id'])
|
||||
if migration and migration['status'] == 'error':
|
||||
# the migration ended up in an error state. Raise an exception.
|
||||
raise exceptions.ResizeException(server_id=server['id'],
|
||||
flavor=new_flavor_id)
|
||||
|
||||
self._wait_for_server_status(server, 'VERIFY_RESIZE')
|
||||
self.servers_client.confirm_resize_server(server['id'])
|
||||
|
||||
def _check_resize(self, resize_flavor_id, original_flavor_id=None,
|
||||
expected_fail=False):
|
||||
original_flavor_id = original_flavor_id or self._get_flavor_ref()
|
||||
server_tuple = self._create_server(original_flavor_id)
|
||||
|
||||
if expected_fail:
|
||||
self.assertRaises(exceptions.ResizeException,
|
||||
self._resize_server,
|
||||
server_tuple, resize_flavor_id)
|
||||
else:
|
||||
self._resize_server(server_tuple, resize_flavor_id)
|
||||
|
||||
# assert that the server is still reachable, even if the resize
|
||||
# failed.
|
||||
self._check_scenario(server_tuple)
|
||||
|
||||
|
||||
class _ResizeMixin(_ResizeUtils):
|
||||
"""Cold resize mixin.
|
||||
|
||||
This mixin will add cold resize tests. The tests will create a new
|
||||
instance, resize it to a new flavor, and check its network connectivity.
|
||||
|
||||
The new flavor is based on the test suite's configured _FLAVOR_REF (
|
||||
typically compute.flavor_ref or compute.flavor_ref_alt), with some
|
||||
updates. For example, if the vNUMA configuration is to be tested, the new
|
||||
flavor would contain the flavor extra_spec 'hw:numa_nodes=1'.
|
||||
"""
|
||||
|
||||
# NOTE(claudiub): These flavor dicts are updates to the base flavor
|
||||
# tempest is configured with. For example, _BIGGER_FLAVOR can be:
|
||||
# _BIGGER_FLAVOR = {'disk': 1}
|
||||
# which means a flavor having +1 GB disk size will be created, and
|
||||
# a created instance will be resized to it.
|
||||
|
||||
_SMALLER_FLAVOR = {}
|
||||
_BIGGER_FLAVOR = {}
|
||||
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
|
||||
'Resize is not available.')
|
||||
def test_resize(self):
|
||||
new_flavor = self._create_new_flavor(self._get_flavor_ref(),
|
||||
self._BIGGER_FLAVOR)
|
||||
self._check_resize(new_flavor['id'])
|
||||
|
||||
|
||||
class _ResizeNegativeMixin(_ResizeUtils):
|
||||
"""Cold resize negative mixin.
|
||||
|
||||
This mixin will add cold resize negative tests. The tests will create a
|
||||
new instance, resize it to an invalid flavor, check that the resize
|
||||
failed, and check the instance's connectivity.
|
||||
"""
|
||||
|
||||
_BAD_FLAVOR = {}
|
||||
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
|
||||
'Resize is not available.')
|
||||
def test_resize_negative(self):
|
||||
new_flavor = self._create_new_flavor(self._get_flavor_ref(),
|
||||
self._BAD_FLAVOR)
|
||||
self._check_resize(new_flavor['id'], expected_fail=True)
|
@ -1,153 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from oswin_tempest_plugin.clients import wsman
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin import exceptions
|
||||
from oswin_tempest_plugin.tests._mixins import migrate
|
||||
from oswin_tempest_plugin.tests._mixins import resize
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HyperVClusterTest(migrate._MigrateMixin,
|
||||
migrate._LiveMigrateMixin,
|
||||
resize._ResizeMixin,
|
||||
test_base.TestBase):
|
||||
|
||||
"""The test suite for the Hyper-V Cluster.
|
||||
|
||||
This test suite will test the functionality of the Hyper-V Cluster Driver
|
||||
in OpenStack. The tests will force a failover on its newly created
|
||||
instance, and asserts the following:
|
||||
|
||||
* the instance moves to another host.
|
||||
* the nova instance's host is properly updated.
|
||||
* the instance's network connection still works.
|
||||
* different nova operations can be performed properly.
|
||||
|
||||
This test suite relies on the fact that there are at least 2 compute nodes
|
||||
available, that they are clustered, and have WSMan configured.
|
||||
|
||||
The test suite contains the following tests:
|
||||
|
||||
* test_check_clustered_vm
|
||||
* test_check_migration
|
||||
* test_check_resize
|
||||
* test_check_resize_negative
|
||||
"""
|
||||
|
||||
_BIGGER_FLAVOR = {'disk': 1}
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(HyperVClusterTest, cls).skip_checks()
|
||||
|
||||
# check if the cluster Tests can be run.
|
||||
if not CONF.hyperv.cluster_enabled:
|
||||
msg = 'Hyper-V cluster tests are disabled.'
|
||||
raise cls.skipException(msg)
|
||||
|
||||
if not CONF.hyperv_host_auth.username:
|
||||
msg = ('No Hyper-V host username has been provided. '
|
||||
'Skipping cluster tests.')
|
||||
raise cls.skipException(msg)
|
||||
|
||||
if not CONF.compute.min_compute_nodes >= 2:
|
||||
msg = 'Expected at least 2 compute nodes.'
|
||||
raise cls.skipException(msg)
|
||||
|
||||
def _failover_server(self, server_name, host_ip):
|
||||
"""Triggers the failover for the given server on the given host."""
|
||||
|
||||
resource_name = "Virtual Machine %s" % server_name
|
||||
cmd = "Test-ClusterResourceFailure -Name '%s'" % resource_name
|
||||
# NOTE(claudiub): we issue the failover command twice, because on
|
||||
# the first failure, the Hyper-V Cluster will prefer the current
|
||||
# node, and will try to reactivate the VM on the it, and it will
|
||||
# succeed. On the 2nd failure, the VM will failover to another
|
||||
# node. Also, there needs to be a delay between commands, so the
|
||||
# original failover has time to finish.
|
||||
wsman.run_hv_host_wsman_ps(host_ip, cmd)
|
||||
time.sleep(CONF.hyperv.failover_sleep_interval)
|
||||
wsman.run_hv_host_wsman_ps(host_ip, cmd)
|
||||
|
||||
def _wait_for_failover(self, server, original_host):
|
||||
"""Waits for the given server to failover to another host.
|
||||
|
||||
:raises TimeoutException: if the given server did not failover to
|
||||
another host within the configured "CONF.hyperv.failover_timeout"
|
||||
interval.
|
||||
"""
|
||||
LOG.debug('Waiting for server %(server)s to failover from '
|
||||
'compute node %(host)s',
|
||||
dict(server=server['id'], host=original_host))
|
||||
|
||||
start_time = int(time.time())
|
||||
timeout = CONF.hyperv.failover_timeout
|
||||
while True:
|
||||
elapsed_time = int(time.time()) - start_time
|
||||
admin_server = self._get_server_as_admin(server)
|
||||
current_host = admin_server['OS-EXT-SRV-ATTR:host']
|
||||
if current_host != original_host:
|
||||
LOG.debug('Server %(server)s failovered from compute node '
|
||||
'%(host)s in %(seconds)s seconds.',
|
||||
dict(server=server['id'], host=original_host,
|
||||
seconds=elapsed_time))
|
||||
return
|
||||
|
||||
if elapsed_time >= timeout:
|
||||
msg = ('Server %(server)s did not failover in the given '
|
||||
'amount of time (%(timeout)s s).')
|
||||
raise lib_exc.TimeoutException(
|
||||
msg % dict(server=server['id'], timeout=timeout))
|
||||
|
||||
time.sleep(CONF.hyperv.failover_sleep_interval)
|
||||
|
||||
def _get_hypervisor(self, hostname):
|
||||
hypervisors = self.admin_hypervisor_client.list_hypervisors(
|
||||
detail=True)['hypervisors']
|
||||
hypervisor = [h for h in hypervisors if
|
||||
h['hypervisor_hostname'] == hostname]
|
||||
|
||||
if not hypervisor:
|
||||
raise exceptions.NotFoundException(resource=hostname,
|
||||
res_type='hypervisor')
|
||||
return hypervisor[0]
|
||||
|
||||
def _create_server(self, flavor=None):
|
||||
server_tuple = super(HyperVClusterTest, self)._create_server(flavor)
|
||||
server = server_tuple.server
|
||||
admin_server = self._get_server_as_admin(server)
|
||||
|
||||
server_name = admin_server['OS-EXT-SRV-ATTR:instance_name']
|
||||
hostname = admin_server['OS-EXT-SRV-ATTR:host']
|
||||
host_ip = self._get_hypervisor(hostname)['host_ip']
|
||||
|
||||
self._failover_server(server_name, host_ip)
|
||||
self._wait_for_failover(server, hostname)
|
||||
|
||||
return server_tuple
|
||||
|
||||
def test_clustered_vm(self):
|
||||
server_tuple = self._create_server()
|
||||
self._check_scenario(server_tuple)
|
@ -1,91 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 testtools
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin.tests._mixins import migrate
|
||||
from oswin_tempest_plugin.tests._mixins import resize
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class _BaseDiskTestMixin(migrate._MigrateMixin,
|
||||
resize._ResizeMixin,
|
||||
resize._ResizeNegativeMixin):
|
||||
"""Image types / formats test suite.
|
||||
|
||||
This test suite will spawn instances with a configured image and will
|
||||
check their network connectivity. The purpose of this test suite is to
|
||||
cover different image formats and types (VHD, VHDX, Generation 2 VMs).
|
||||
"""
|
||||
|
||||
_CONF_OPTION_NAME = ''
|
||||
|
||||
_BIGGER_FLAVOR = {'disk': 1}
|
||||
_BAD_FLAVOR = {'disk': -1}
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(_BaseDiskTestMixin, cls).skip_checks()
|
||||
# check if the needed image ref has been configured.
|
||||
if not cls._IMAGE_REF:
|
||||
msg = ('The config option "%s" has not been set. Skipping.' %
|
||||
cls._CONF_OPTION_NAME)
|
||||
raise cls.skipException(msg)
|
||||
|
||||
def test_disk(self):
|
||||
server_tuple = self._create_server()
|
||||
self._check_scenario(server_tuple)
|
||||
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
|
||||
'Resize is not available.')
|
||||
def test_resize_negative(self):
|
||||
# NOTE(claudiub): This test will try to downsize a VM's disk, which is
|
||||
# unsupported. The configured flavor might have disk set to 1GB.
|
||||
# The nova-api does not allow disks to be resized on 0 GB.
|
||||
flavor = self._get_flavor_ref()
|
||||
new_flavor = self._create_new_flavor(flavor, self._BIGGER_FLAVOR)
|
||||
self._check_resize(flavor, new_flavor['id'], expected_fail=True)
|
||||
|
||||
|
||||
class VhdDiskTest(_BaseDiskTestMixin, test_base.TestBase):
|
||||
|
||||
_IMAGE_REF = CONF.hyperv.vhd_image_ref
|
||||
_CONF_OPTION_NAME = 'hyperv.vhd_image_ref'
|
||||
_FLAVOR_SUFFIX = 'vhd'
|
||||
|
||||
# TODO(claudiub): validate that the images really are VHD / VHDX.
|
||||
|
||||
|
||||
class VhdxDiskTest(_BaseDiskTestMixin, test_base.TestBase):
|
||||
|
||||
_IMAGE_REF = CONF.hyperv.vhdx_image_ref
|
||||
_CONF_OPTION_NAME = 'hyperv.vhdx_image_ref'
|
||||
_FLAVOR_SUFFIX = 'vhdx'
|
||||
|
||||
|
||||
class Generation2DiskTest(_BaseDiskTestMixin, test_base.TestBase):
|
||||
|
||||
# Generation 2 VMs have been introduced in Windows / Hyper-V Server 2012 R2
|
||||
_MIN_HYPERV_VERSION = 6003
|
||||
|
||||
_IMAGE_REF = CONF.hyperv.gen2_image_ref
|
||||
_CONF_OPTION_NAME = 'hyperv.gen2_image_ref'
|
||||
_FLAVOR_SUFFIX = 'gen2'
|
||||
|
||||
# TODO(claudiub): Add validation that the given gen2_image_ref really has
|
||||
# the 'hw_machine_type=hyperv-gen2' property.
|
@ -1,166 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from tempest import clients
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClientManager(clients.Manager):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ClientManager, self).__init__(*args, **kwargs)
|
||||
|
||||
self.set_gnocchi_client()
|
||||
|
||||
def set_gnocchi_client(self):
|
||||
self.gnocchi_client = self.metric_v1.GnocchiClient()
|
||||
|
||||
|
||||
class MetricsCollectionTestCase(test_base.TestBase):
|
||||
"""Adds metrics collection scenario tests.
|
||||
|
||||
This test suite verifies that the instance metrics are properly published
|
||||
and collected and have non-zero values. The verification is done via the
|
||||
ceilometer API.
|
||||
|
||||
setup:
|
||||
1. spins a new instance.
|
||||
2. waits until the instance was created succesfully (ACTIVE status).
|
||||
3. wait an interval of time which represents the polling period of the
|
||||
ceilometer-polling agent.
|
||||
|
||||
Waiting for the ceilometer-polling agent to poll the resources is crucial,
|
||||
otherwise the test suite will fail due to the fact that no samples
|
||||
would be found published before checking the samples.
|
||||
|
||||
The test suite's polled_metrics_delay must have a greater value than the
|
||||
ceilometer agent's polling interval. This can be done in two ways:
|
||||
a. Configure tempest's polled_metric_delay, by adding the
|
||||
following line in tempest.conf, in the hyperv section:
|
||||
polled_metrics_delay = <desired value>
|
||||
b. Set the interval value in polling.yaml on the compute node to
|
||||
the desired value and restart the ceilometer polling agent. The
|
||||
interval value is set either for the 'meter_source' or for each
|
||||
of the following: 'cpu_source', 'disk_source', 'network_source'.
|
||||
|
||||
Note: If the polled_metrics_delay value is too low, the tests might not
|
||||
find any samples and fail because of this. As a recommandation,
|
||||
polled_metrics_delay's value should be:
|
||||
polled_metric_delay = <polling.yaml interval value> + <15-20 seconds>
|
||||
|
||||
tests:
|
||||
1. test_metrics - tests values for the following metrics:
|
||||
- cpu
|
||||
- network.outgoing.bytes
|
||||
- disk.read.bytes
|
||||
|
||||
assumptions:
|
||||
1. Ceilometer agent on the compute node is running.
|
||||
2. Ceilometer agent on the compute node has the polling interval
|
||||
defined in polling.yaml lower than the polled_metrics_delay defined
|
||||
in this test suite.
|
||||
3. The compute nodes' nova-compute and neutron-hyperv-agent services
|
||||
have been configured to enable metrics collection.
|
||||
"""
|
||||
|
||||
client_manager = ClientManager
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(MetricsCollectionTestCase, cls).skip_checks()
|
||||
|
||||
for service in ['ceilometer', 'gnocchi']:
|
||||
if not getattr(CONF.service_available, service):
|
||||
raise cls.skipException("%s service is required." % service)
|
||||
|
||||
if not CONF.hyperv.collected_metrics:
|
||||
raise cls.skipException("Collected metrics not configured.")
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(MetricsCollectionTestCase, cls).setup_clients()
|
||||
|
||||
# Telemetry client
|
||||
cls.telemetry_client = cls.os_primary.gnocchi_client
|
||||
|
||||
def _check_samples(self, resource_id, meter_name):
|
||||
LOG.info("Checking %(meter_name)s for resource %(resource_id)s" % {
|
||||
'meter_name': meter_name, 'resource_id': resource_id})
|
||||
|
||||
samples = self.telemetry_client.list_samples(resource_id, meter_name)
|
||||
self.assertNotEmpty(
|
||||
samples,
|
||||
'Client returned no samples for the given resource '
|
||||
'"%(resource_id)s" and meter "%(meter_name)s".' % {
|
||||
'resource_id': resource_id, 'meter_name': meter_name})
|
||||
|
||||
non_zero_valued_samples = [s for s in samples if s[2] > 0]
|
||||
self.assertNotEmpty(
|
||||
non_zero_valued_samples,
|
||||
'All meter %(meter_name)s samples for resource '
|
||||
'%(resource_id)s are 0.' % {'meter_name': meter_name,
|
||||
'resource_id': resource_id})
|
||||
|
||||
def _get_instance_cpu_resource_id(self, server):
|
||||
return server['id']
|
||||
|
||||
def _get_instance_disk_resource_id(self, server):
|
||||
return server['id']
|
||||
|
||||
def _get_instance_port_resource_id(self, server):
|
||||
# Note(claudiub): the format for the instance_port_resource_id is:
|
||||
# %(OS-EXT-SRV-ATTR:instance_name)s-%(instance_id)s-%(port_id)s
|
||||
# the instance returned by self.servers_client does not contain the
|
||||
# OS-EXT-SRV-ATTR:instance_name field. Which means that the resource_id
|
||||
# must be found in gnocchi's resources.
|
||||
start_res_id = server['id']
|
||||
resources = self.telemetry_client.list_resources()
|
||||
res_ids = [r['id'] for r in resources
|
||||
if r['original_resource_id'].startswith('instance-')
|
||||
and start_res_id in r['original_resource_id']]
|
||||
|
||||
self.assertEqual(1, len(res_ids))
|
||||
return res_ids[0]
|
||||
|
||||
def _check_scenario(self, server_tuple):
|
||||
server = server_tuple.server
|
||||
LOG.info("Waiting %s seconds for the ceilometer compute agents to "
|
||||
"publish the samples.", CONF.hyperv.polled_metrics_delay)
|
||||
time.sleep(CONF.hyperv.polled_metrics_delay)
|
||||
|
||||
# TODO(claudiub): Add more metrics.
|
||||
if 'cpu' in CONF.hyperv.collected_metrics:
|
||||
cpu_res_id = self._get_instance_cpu_resource_id(server)
|
||||
self._check_samples(cpu_res_id, 'cpu')
|
||||
|
||||
if 'network.outgoing.bytes' in CONF.hyperv.collected_metrics:
|
||||
port_res_id = self._get_instance_port_resource_id(server)
|
||||
self._check_samples(port_res_id, 'network.outgoing.bytes')
|
||||
|
||||
if 'disk.read.bytes' in CONF.hyperv.collected_metrics:
|
||||
disk_resource_id = self._get_instance_disk_resource_id(server)
|
||||
self._check_samples(disk_resource_id, 'disk.read.bytes')
|
||||
|
||||
def test_metrics(self):
|
||||
server_tuple = self._create_server()
|
||||
self._check_scenario(server_tuple)
|
@ -1,37 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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_utils import units
|
||||
|
||||
from oswin_tempest_plugin.tests._mixins import optional_feature
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
|
||||
class QosTestCase(optional_feature._OptionalFeatureMixin,
|
||||
test_base.TestBase):
|
||||
"""QoS test suite.
|
||||
|
||||
This test suite will spawn instances with QoS specs.
|
||||
|
||||
Hyper-V uses normalized IOPS (8 KB increments), and the minimum IOPS that
|
||||
can be set is 1.
|
||||
"""
|
||||
|
||||
# Hyper-V disk QoS is supported on Windows / Hyper-v Server 2012 R2
|
||||
# or newer.
|
||||
_MIN_HYPERV_VERSION = 6003
|
||||
|
||||
_FEATURE_FLAVOR = {
|
||||
'extra_specs': {'quota:disk_total_bytes_sec': str(units.Mi)}}
|
@ -1,44 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin.tests._mixins import optional_feature
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class RemoteFxTestCase(optional_feature._OptionalFeatureMixin,
|
||||
test_base.TestBase):
|
||||
"""RemoteFX test suite.
|
||||
|
||||
This test suit will spawn instances with RemoteFX enabled.
|
||||
"""
|
||||
|
||||
# RemoteFX is supported in Windows / Hyper-V Server 2012 R2 and newer.
|
||||
_MIN_HYPERV_VERSION = 6003
|
||||
|
||||
_FEATURE_FLAVOR = {'extra_specs': {'os_resolution': '1920x1200',
|
||||
'os_monitors': '1',
|
||||
'os_vram': '1024'}}
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(RemoteFxTestCase, cls).skip_checks()
|
||||
# the CONF.hyperv.remotefx_enabled config option needs to be enabled.
|
||||
if not CONF.hyperv.remotefx_enabled:
|
||||
msg = ('The config option "hyperv.remotefx_enabled" is False. '
|
||||
'Skipping.')
|
||||
raise cls.skipException(msg)
|
@ -1,70 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin.tests._mixins import optional_feature
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class SecureBootTestCase(optional_feature._OptionalFeatureMixin,
|
||||
test_base.TestBase):
|
||||
"""Secure boot test suite.
|
||||
|
||||
This test suite will spawn instances requiring secure boot to be
|
||||
enabled.
|
||||
|
||||
This test suite will require a Generation 2 VHDX image, with a
|
||||
Linux guest OS (it tests connectivity via SSH).
|
||||
|
||||
The configured image must contain the following properties:
|
||||
* os_type=linux
|
||||
* hw_machine_type=hyperv-gen2
|
||||
|
||||
Hyper-V Secure Boot was first introduced in Windows / Hyper-V Server 2012
|
||||
R2, but support for Linux guests was introduced in Windows / Hyper-V
|
||||
Server 2016, which is why this test suite will require compute nodes
|
||||
with the OS version 10.0 or newer.
|
||||
"""
|
||||
|
||||
_MIN_HYPERV_VERSION = 10000
|
||||
|
||||
# NOTE(amuresan):Images supporting secure boot usually require more disk
|
||||
# space. We're trying to use the largest of the configured
|
||||
# flavors.
|
||||
|
||||
_FLAVOR_REF = CONF.compute.flavor_ref_alt
|
||||
_IMAGE_REF = CONF.hyperv.secure_boot_image_ref
|
||||
_IMAGE_SSH_USER = CONF.hyperv.secure_boot_image_ssh_user
|
||||
_FEATURE_FLAVOR = {'extra_specs': {'os:secure_boot': 'required'}}
|
||||
|
||||
# TODO(amuresan): the secure_boot_image_ref should be reused in
|
||||
# more than one test case so we don't have to add a different
|
||||
# image for every test.
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(SecureBootTestCase, cls).skip_checks()
|
||||
# check if the needed image ref has been configured.
|
||||
if not cls._IMAGE_REF:
|
||||
msg = ('The config option "hyperv.secure_boot_image_ref" '
|
||||
'has not been set. Skipping secure boot tests.')
|
||||
raise cls.skipException(msg)
|
||||
|
||||
if not cls._IMAGE_SSH_USER:
|
||||
msg = ('The config option "hyperv.secure_boot_image_ssh_user" '
|
||||
'has not been set. Skipping.')
|
||||
raise cls.skipException(msg)
|
@ -1,61 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 testtools
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
from oswin_tempest_plugin.tests._mixins import migrate
|
||||
from oswin_tempest_plugin.tests._mixins import optional_feature
|
||||
from oswin_tempest_plugin.tests._mixins import resize
|
||||
from oswin_tempest_plugin.tests import test_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class HyperVvNumaTestCase(migrate._MigrateMixin,
|
||||
migrate._LiveMigrateMixin,
|
||||
optional_feature._OptionalFeatureMixin,
|
||||
resize._ResizeMixin,
|
||||
resize._ResizeNegativeMixin,
|
||||
test_base.TestBase):
|
||||
"""Hyper-V vNUMA test suite.
|
||||
|
||||
This test suite will spawn instances requiring NUMA placement.
|
||||
"""
|
||||
|
||||
_FEATURE_FLAVOR = {'extra_specs': {'hw:numa_nodes': '1'}}
|
||||
_BIGGER_FLAVOR = {'ram': 128, 'extra_specs': {'hw:numa_nodes': '1'}}
|
||||
|
||||
# NOTE(claudiub): Hyper-V does not support asymmetric NUMA topologies.
|
||||
# The resize should fail in this case.
|
||||
_BAD_FLAVOR = {'ram': 64, 'extra_specs': {
|
||||
'hw:numa_nodes': '2', 'hw:numa_mem.0': '64', 'hw:numa_cpus.0': '0'}}
|
||||
|
||||
@testtools.skipUnless(CONF.hyperv.available_numa_nodes > 1,
|
||||
'At least 2 NUMA nodes are required.')
|
||||
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
|
||||
'Resize is not available.')
|
||||
def test_resize_negative(self):
|
||||
new_flavor = self._create_new_flavor(self._get_flavor_ref(),
|
||||
self._BAD_FLAVOR)
|
||||
|
||||
# NOTE(claudiub): all NUMA nodes have to be properly defined.
|
||||
vcpus = [i for i in range(1, int(new_flavor['vcpus']))]
|
||||
extra_specs = {'hw:numa_mem.1': str(int(new_flavor['ram']) - 64),
|
||||
'hw:numa_cpus.1': ','.join(vcpus)}
|
||||
self.admin_flavors_client.set_flavor_extra_spec(
|
||||
new_flavor['id'], **extra_specs)
|
||||
|
||||
self._check_resize(new_flavor['id'], expected_fail=True)
|
@ -1,287 +0,0 @@
|
||||
# Copyright 2017 Cloudbase Solutions SRL
|
||||
# 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 collections
|
||||
|
||||
from oslo_log import log as logging
|
||||
from tempest.common import compute
|
||||
from tempest.common.utils.linux import remote_client
|
||||
from tempest.common import waiters
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import exceptions
|
||||
import tempest.scenario.manager
|
||||
|
||||
from oswin_tempest_plugin import config
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
Server_tuple = collections.namedtuple(
|
||||
'Server_tuple',
|
||||
['server', 'floating_ip', 'keypair', 'security_groups'])
|
||||
|
||||
|
||||
class TestBase(tempest.scenario.manager.ScenarioTest):
|
||||
"""Base class for tests."""
|
||||
|
||||
credentials = ['primary', 'admin']
|
||||
|
||||
# Inheriting TestCases should change this version if needed.
|
||||
_MIN_HYPERV_VERSION = 6002
|
||||
|
||||
# Inheriting TestCases should change this image ref if needed.
|
||||
_IMAGE_REF = CONF.compute.image_ref
|
||||
|
||||
# Inheriting TestCases should change this flavor ref if needed.
|
||||
_FLAVOR_REF = CONF.compute.flavor_ref
|
||||
|
||||
# Inheriting TestCases should change this ssh User if needed.
|
||||
_IMAGE_SSH_USER = CONF.validation.image_ssh_user
|
||||
|
||||
# suffix to use for the newly created flavors.
|
||||
_FLAVOR_SUFFIX = ''
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(TestBase, cls).skip_checks()
|
||||
# check if the configured hypervisor_version is higher than
|
||||
# the test's required minimum Hyper-V version.
|
||||
|
||||
# TODO(claudiub): instead of expecting a config option specifying
|
||||
# the hypervisor version, we could check nova's compute nodes for
|
||||
# their hypervisor versions.
|
||||
config_vers = CONF.hyperv.hypervisor_version
|
||||
if config_vers < cls._MIN_HYPERV_VERSION:
|
||||
msg = ('Configured hypervisor_version (%(config_vers)s) is not '
|
||||
'supported. It must be higher than %(req_vers)s.' % {
|
||||
'config_vers': config_vers,
|
||||
'req_vers': cls._MIN_HYPERV_VERSION})
|
||||
raise cls.skipException(msg)
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(TestBase, cls).setup_clients()
|
||||
# Compute client
|
||||
cls.compute_fips_client = (
|
||||
cls.os_primary.compute_floating_ips_client)
|
||||
cls.keypairs_client = cls.os_primary.keypairs_client
|
||||
cls.servers_client = cls.os_primary.servers_client
|
||||
cls.admin_servers_client = cls.os_admin.servers_client
|
||||
cls.admin_flavors_client = cls.os_admin.flavors_client
|
||||
cls.admin_migrations_client = cls.os_admin.migrations_client
|
||||
cls.admin_hypervisor_client = cls.os_admin.hypervisor_client
|
||||
|
||||
# Neutron network client
|
||||
cls.security_groups_client = (
|
||||
cls.os_primary.security_groups_client)
|
||||
cls.security_group_rules_client = (
|
||||
cls.os_primary.security_group_rules_client)
|
||||
|
||||
def create_floating_ip(self, server):
|
||||
"""Create a floating IP and associates to a server on Nova"""
|
||||
|
||||
pool_name = CONF.network.floating_network_name
|
||||
floating_ip = (
|
||||
self.compute_fips_client.create_floating_ip(pool=pool_name))
|
||||
floating_ip = floating_ip['floating_ip']
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.compute_fips_client.delete_floating_ip,
|
||||
floating_ip['id'])
|
||||
self.compute_fips_client.associate_floating_ip_to_server(
|
||||
floating_ip['ip'], server['id'])
|
||||
return floating_ip
|
||||
|
||||
def _get_image_ref(self):
|
||||
return self._IMAGE_REF
|
||||
|
||||
def _flavor_cleanup(self, flavor_id):
|
||||
try:
|
||||
self.admin_flavors_client.delete_flavor(flavor_id)
|
||||
self.admin_flavors_client.wait_for_resource_deletion(flavor_id)
|
||||
except exceptions.NotFound:
|
||||
pass
|
||||
|
||||
def _create_new_flavor(self, flavor_ref, flavor_updates):
|
||||
"""Creates a new flavor based on the given flavor and flavor updates.
|
||||
|
||||
:returns: the newly created flavor's ID.
|
||||
"""
|
||||
flavor = self.admin_flavors_client.show_flavor(flavor_ref)['flavor']
|
||||
|
||||
flavor_name = 'test_resize'
|
||||
if self._FLAVOR_SUFFIX:
|
||||
flavor_name += '_%s' % self._FLAVOR_SUFFIX
|
||||
|
||||
new_flavor = self.admin_flavors_client.create_flavor(
|
||||
name=data_utils.rand_name(flavor_name),
|
||||
ram=flavor['ram'] + flavor_updates.get('ram', 0),
|
||||
disk=flavor['disk'] + flavor_updates.get('disk', 0),
|
||||
vcpus=flavor['vcpus'] + flavor_updates.get('vcpus', 0),
|
||||
)['flavor']
|
||||
|
||||
self.addCleanup(self._flavor_cleanup, new_flavor['id'])
|
||||
|
||||
# Add flavor extra_specs, if needed.
|
||||
extra_specs = flavor_updates.get('extra_specs')
|
||||
if extra_specs:
|
||||
self.admin_flavors_client.set_flavor_extra_spec(
|
||||
new_flavor['id'], **extra_specs)
|
||||
|
||||
return new_flavor
|
||||
|
||||
def _get_flavor_ref(self):
|
||||
return self._FLAVOR_REF
|
||||
|
||||
def _create_server(self, flavor=None):
|
||||
"""Wrapper utility that returns a test server.
|
||||
|
||||
This wrapper utility calls the common create test server and
|
||||
returns a test server.
|
||||
"""
|
||||
clients = self.os_primary
|
||||
name = data_utils.rand_name(self.__class__.__name__ + "-server")
|
||||
image_id = self._get_image_ref()
|
||||
flavor = flavor or self._get_flavor_ref()
|
||||
keypair = self.create_keypair()
|
||||
tenant_network = self.get_tenant_network()
|
||||
security_group = self._create_security_group()
|
||||
# we need to pass the security group's name to the instance.
|
||||
sg_group_names = [{'name': security_group['name']}]
|
||||
|
||||
body, _ = compute.create_test_server(
|
||||
clients, name=name,
|
||||
flavor=flavor,
|
||||
image_id=image_id,
|
||||
key_name=keypair['name'],
|
||||
tenant_network=tenant_network,
|
||||
security_groups=sg_group_names,
|
||||
wait_until='ACTIVE')
|
||||
|
||||
self.addCleanup(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'])
|
||||
server = clients.servers_client.show_server(body['id'])['server']
|
||||
|
||||
floating_ip = self.create_floating_ip(server)
|
||||
server_tuple = Server_tuple(
|
||||
server=server,
|
||||
keypair=keypair,
|
||||
floating_ip=floating_ip,
|
||||
security_groups=[security_group])
|
||||
|
||||
return server_tuple
|
||||
|
||||
def _get_server_as_admin(self, server):
|
||||
# only admins have access to certain instance properties.
|
||||
return self.admin_servers_client.show_server(
|
||||
server['id'])['server']
|
||||
|
||||
def _create_security_group(self):
|
||||
sg_name = data_utils.rand_name(self.__class__.__name__)
|
||||
sg_desc = sg_name + " description"
|
||||
secgroup = self.security_groups_client.create_security_group(
|
||||
name=sg_name, description=sg_desc)['security_group']
|
||||
self.addCleanup(
|
||||
test_utils.call_and_ignore_notfound_exc,
|
||||
self.security_groups_client.delete_security_group,
|
||||
secgroup['id'])
|
||||
|
||||
# Add rules to the security group
|
||||
self._create_loginable_secgroup_rule(secgroup)
|
||||
return secgroup
|
||||
|
||||
def _create_loginable_secgroup_rule(self, secgroup):
|
||||
"""Create loginable security group rule
|
||||
|
||||
This function will create:
|
||||
1. egress and ingress tcp port 22 allow rule in order to allow ssh
|
||||
access for ipv4.
|
||||
3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
|
||||
"""
|
||||
|
||||
rulesets = [
|
||||
# ssh
|
||||
dict(protocol='tcp',
|
||||
port_range_min=22,
|
||||
port_range_max=22),
|
||||
# ping
|
||||
dict(protocol='icmp'),
|
||||
]
|
||||
for ruleset in rulesets:
|
||||
for r_direction in ['ingress', 'egress']:
|
||||
ruleset['direction'] = r_direction
|
||||
self._create_security_group_rule(
|
||||
secgroup, **ruleset)
|
||||
|
||||
def _create_security_group_rule(self, secgroup, **kwargs):
|
||||
"""Create a rule from a dictionary of rule parameters.
|
||||
|
||||
Creates a rule in a secgroup.
|
||||
|
||||
:param secgroup: the security group.
|
||||
:param kwargs: a dictionary containing rule parameters:
|
||||
for example, to allow incoming ssh:
|
||||
rule = {
|
||||
direction: 'ingress'
|
||||
protocol:'tcp',
|
||||
port_range_min: 22,
|
||||
port_range_max: 22
|
||||
}
|
||||
"""
|
||||
ruleset = dict(security_group_id=secgroup['id'],
|
||||
tenant_id=secgroup['tenant_id'])
|
||||
ruleset.update(kwargs)
|
||||
|
||||
sec_group_rules_client = self.security_group_rules_client
|
||||
sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
|
||||
sg_rule = sg_rule['security_group_rule']
|
||||
|
||||
return sg_rule
|
||||
|
||||
def _wait_for_server_status(self, server, status='ACTIVE'):
|
||||
waiters.wait_for_server_status(self.servers_client, server['id'],
|
||||
status)
|
||||
|
||||
def _get_server_client(self, server_tuple):
|
||||
"""Get a SSH client to a remote server
|
||||
|
||||
:returns: RemoteClient object
|
||||
"""
|
||||
server = server_tuple.server
|
||||
ip_address = server_tuple.floating_ip['ip']
|
||||
private_key = server_tuple.keypair['private_key']
|
||||
|
||||
# ssh into the VM
|
||||
username = self._IMAGE_SSH_USER
|
||||
linux_client = remote_client.RemoteClient(
|
||||
ip_address, username, pkey=private_key, password=None,
|
||||
server=server, servers_client=self.servers_client)
|
||||
linux_client.validate_authentication()
|
||||
|
||||
return linux_client
|
||||
|
||||
def _check_server_connectivity(self, server_tuple):
|
||||
# if server connectivity works, an SSH client can be opened.
|
||||
self._get_server_client(server_tuple)
|
||||
|
||||
def _check_scenario(self, server_tuple):
|
||||
# NOTE(claudiub): This method is to be used when verifying a
|
||||
# particular scenario. If a scenario test case needs to perform
|
||||
# different validation steps (e.g.: metrics collection), it should
|
||||
# overwrite this method.
|
||||
self._check_server_connectivity(server_tuple)
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Python 2.7 support has been dropped. Last release of oswin-tempest-plugin
|
||||
to support py2.7 is OpenStack Train. The minimum version of Python now
|
||||
supported by oswin-tempest-plugin is Python 3.5.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Python 3.6 & 3.7 support has been dropped. The minimum version of Python now
|
||||
supported is Python 3.8.
|
@ -1,11 +0,0 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
|
||||
oslo.config>=5.1.0 # Apache-2.0
|
||||
oslo.log>=3.36.0 # Apache-2.0
|
||||
oslo.utils>=3.33.0 # Apache-2.0
|
||||
tempest>=17.1.0 # Apache-2.0
|
||||
pywinrm>=0.2.2 # MIT
|
27
setup.cfg
27
setup.cfg
@ -1,27 +0,0 @@
|
||||
[metadata]
|
||||
name = oswin-tempest-plugin
|
||||
summary = This project contains Tempest tests to cover the os_win project, as well as a plugin to automatically load these tests into Tempest.
|
||||
description_file =
|
||||
README.rst
|
||||
author = Cloudbase Solutions
|
||||
author_email = info@cloudbasesolutions.com
|
||||
home_page = https://opendev.org/openstack/oswin-tempest-plugin
|
||||
python_requires = >=3.8
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Operating System :: Microsoft :: Windows
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.8
|
||||
|
||||
[files]
|
||||
packages =
|
||||
oswin_tempest_plugin
|
||||
|
||||
[entry_points]
|
||||
tempest.test_plugins =
|
||||
oswin_tempest_plugin = oswin_tempest_plugin.plugin:OSWinTempestPlugin
|
29
setup.py
29
setup.py
@ -1,29 +0,0 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||
# setuptools if some other modules registered functions in `atexit`.
|
||||
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||
try:
|
||||
import multiprocessing # noqa
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr>=2.0.0'],
|
||||
pbr=True)
|
@ -1,13 +0,0 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking>=3.0.1,<3.1.0 # Apache-2.0
|
||||
|
||||
coverage!=4.4,>=4.0 # Apache-2.0
|
||||
python-subunit>=1.0.0 # Apache-2.0/BSD
|
||||
stestr>=2.0.0 # Apache-2.0
|
||||
oslotest>=3.2.0 # Apache-2.0
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=2.2.0 # MIT
|
||||
|
43
tox.ini
43
tox.ini
@ -1,43 +0,0 @@
|
||||
[tox]
|
||||
minversion = 3.1.1
|
||||
envlist = py3,pypy,pep8
|
||||
skipsdist = True
|
||||
ignore_basepython_conflict = True
|
||||
|
||||
[testenv]
|
||||
basepython = python3
|
||||
usedevelop = True
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
PYTHONWARNINGS=default::DeprecationWarning
|
||||
deps =
|
||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
-r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = stestr run --slowest {posargs}
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8 {posargs}
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py test --coverage --testr-args='{posargs}'
|
||||
|
||||
[testenv:docs]
|
||||
deps =
|
||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
-r{toxinidir}/doc/requirements.txt
|
||||
commands = sphinx-build -W -b html doc/source doc/build/html
|
||||
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
# W503 line break before binary operator
|
||||
show-source = True
|
||||
ignore = E123,E125,W503
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
Loading…
Reference in New Issue
Block a user