[Verify] New command to install Tempest plugins
This command allows us to install a Tempest plugin from a repository. E.g. $ rally verify installplugin --source https://github.com/MBonell/hello-world-tempest-plugin $ rally verify installplugin --source /home/ubuntu/my-plugin Implements Blueprint: install-tempest-plugins Change-Id: I03ac6063b6b9d7f860379b99f3b524adedba6df9
This commit is contained in:
parent
31d738a125
commit
f6a02afcda
@ -52,6 +52,7 @@ _rally()
|
||||
OPTS["verify_genconfig"]="--deployment --tempest-config --override"
|
||||
OPTS["verify_import"]="--deployment --set --file --no-use"
|
||||
OPTS["verify_install"]="--deployment --source --version --system-wide"
|
||||
OPTS["verify_installplugin"]="--deployment --source --version --system-wide"
|
||||
OPTS["verify_list"]=""
|
||||
OPTS["verify_reinstall"]="--deployment --source --version --system-wide"
|
||||
OPTS["verify_results"]="--uuid --html --json --output-file"
|
||||
@ -88,4 +89,4 @@ _rally()
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -o filenames -F _rally rally
|
||||
complete -o filenames -F _rally rally
|
22
rally/api.py
22
rally/api.py
@ -486,6 +486,28 @@ class Verification(object):
|
||||
verifier.uninstall()
|
||||
verifier.install()
|
||||
|
||||
@classmethod
|
||||
def install_tempest_plugin(cls, deployment, source=None, version=None,
|
||||
system_wide=False):
|
||||
"""Install Tempest plugin.
|
||||
|
||||
:param deployment: UUID or name of a deployment
|
||||
:param source: Path/URL to repo to clone Tempest plugin from
|
||||
:param version: Branch, commit ID or tag to checkout before Tempest
|
||||
plugin installation
|
||||
:param system_wide: Whether or not to install plugin in Tempest
|
||||
virtual env
|
||||
"""
|
||||
deployment_uuid = objects.Deployment.get(deployment)["uuid"]
|
||||
verifier = tempest.Tempest(deployment_uuid,
|
||||
plugin_source=source,
|
||||
plugin_version=version,
|
||||
system_wide=system_wide)
|
||||
|
||||
cls._check_tempest_tree_existence(verifier)
|
||||
|
||||
verifier.install_plugin()
|
||||
|
||||
@classmethod
|
||||
def discover_tests(cls, deployment, pattern=""):
|
||||
"""Get a list of discovered tests.
|
||||
|
@ -467,6 +467,34 @@ class VerifyCommands(object):
|
||||
api.Verification.reinstall_tempest(deployment, source,
|
||||
version, system_wide)
|
||||
|
||||
@cliutils.args("--deployment", type=str, dest="deployment",
|
||||
required=False, help="UUID or name of a deployment")
|
||||
@cliutils.args("--source", type=str, dest="source", required=True,
|
||||
help="Path/URL to repo to clone Tempest plugin from")
|
||||
@envutils.with_default_deployment(cli_arg_name="deployment")
|
||||
@cliutils.args("--version", type=str, dest="version", required=False,
|
||||
help="Branch, commit ID or tag to checkout before Tempest "
|
||||
"plugin installation")
|
||||
@cliutils.args("--system-wide", dest="system_wide",
|
||||
help="Don't install plugin in Tempest virtual env. "
|
||||
"Note that all Tempest plugin requirements have "
|
||||
"to be already installed in the local env!",
|
||||
required=False, action="store_true")
|
||||
@envutils.with_default_deployment(cli_arg_name="deployment")
|
||||
def installplugin(self, deployment=None, source=None, version=None,
|
||||
system_wide=False):
|
||||
"""Install Tempest plugin.
|
||||
|
||||
:param deployment: UUID or name of a deployment
|
||||
:param source: Path/URL to repo to clone Tempest plugin from
|
||||
:param version: Branch, commit ID or tag to checkout before Tempest
|
||||
plugin installation
|
||||
:param system_wide: Whether or not to install plugin in Tempest
|
||||
virtual env
|
||||
"""
|
||||
api.Verification.install_tempest_plugin(deployment, source,
|
||||
version, system_wide)
|
||||
|
||||
@cliutils.args("--deployment", dest="deployment", type=str, required=False,
|
||||
metavar="<uuid>", help="UUID or name of a deployment")
|
||||
@cliutils.args("--pattern", dest="pattern", type=str,
|
||||
|
@ -61,6 +61,10 @@
|
||||
<a href="{{ reinstall.stdout_file }}">Tempest re-installation</a>
|
||||
<code>$ {{ reinstall.cmd }}</code>
|
||||
|
||||
<span class="{{ installplugin.status }}">[{{ installplugin.status }}]</span>
|
||||
<a href="{{ installplugin.stdout_file }}">Tempest plugin installation</a>
|
||||
<code>$ {{ installplugin.cmd }}</code>
|
||||
|
||||
<span class="{{ genconfig.status }}">[{{ genconfig.status }}]</span>
|
||||
<a href="{{ genconfig.stdout_file }}">Tempest config generation</a>
|
||||
<code>$ {{ genconfig.cmd }}</code>
|
||||
|
@ -58,16 +58,20 @@ class Tempest(object):
|
||||
".rally/tempest/base")
|
||||
|
||||
def __init__(self, deployment, verification=None, tempest_config=None,
|
||||
source=None, version=None, system_wide=False):
|
||||
self.tempest_source = source or TEMPEST_SOURCE
|
||||
self.version = version
|
||||
source=None, version=None, plugin_source=None,
|
||||
plugin_version=None, system_wide=False):
|
||||
self.deployment = deployment
|
||||
self.verification = verification
|
||||
self._path = os.path.join(os.path.expanduser("~"),
|
||||
".rally/tempest",
|
||||
"for-deployment-%s" % deployment)
|
||||
self.config_file = tempest_config or self.path("tempest.conf")
|
||||
self.tempest_source = source or TEMPEST_SOURCE
|
||||
self.version = version
|
||||
self.plugin_source = plugin_source
|
||||
self.plugin_version = plugin_version
|
||||
self.log_file_raw = self.path("subunit.stream")
|
||||
self.verification = verification
|
||||
|
||||
self._env = None
|
||||
self._base_repo = None
|
||||
self._system_wide = system_wide
|
||||
@ -290,6 +294,17 @@ class Tempest(object):
|
||||
if os.path.exists(self.path()):
|
||||
shutil.rmtree(self.path())
|
||||
|
||||
def install_plugin(self):
|
||||
"""Install Tempest plugin for local Tempest repo."""
|
||||
LOG.info(_("Installing Tempest plugin from %s for "
|
||||
"deployment: %s") % (self.plugin_source, self.deployment))
|
||||
egg = os.path.basename(self.plugin_source.strip("/"))
|
||||
version = self.plugin_version or "master"
|
||||
cmd = [self.venv_wrapper, "pip", "install", "-e",
|
||||
"git+{0}@{1}#egg={2}".format(self.plugin_source, version, egg)]
|
||||
check_output(cmd, cwd=self.path())
|
||||
LOG.info(_("Tempest plugin has been successfully installed!"))
|
||||
|
||||
@logging.log_verification_wrapper(LOG.info, _("Run verification."))
|
||||
def _prepare_and_run(self, set_name, regex, tests_file, concur, failing):
|
||||
if not self.is_configured():
|
||||
|
@ -46,6 +46,8 @@ EXPECTED_FAILURES = {
|
||||
"This test fails because 'novnc' console type is unavailable."
|
||||
}
|
||||
|
||||
TEMPEST_PLUGIN = "https://github.com/MBonell/hello-world-tempest-plugin"
|
||||
|
||||
# NOTE(andreykurilin): this variable is used to generate output file names
|
||||
# with prefix ${CALL_COUNT}_ .
|
||||
_call_count = 0
|
||||
@ -62,10 +64,10 @@ def call_rally(cmd, print_output=False, output_type=None):
|
||||
data = {"cmd": "rally --rally-debug %s" % cmd}
|
||||
stdout_file = "{base}/{prefix}_{cmd}.txt.gz"
|
||||
|
||||
if "--xfails-file" in cmd:
|
||||
if "--xfails-file" in cmd or "--source" in cmd:
|
||||
cmd_items = cmd.split()
|
||||
for num, item in enumerate(cmd_items):
|
||||
if EXPECTED_FAILURES_FILE in item:
|
||||
if EXPECTED_FAILURES_FILE in item or TEMPEST_PLUGIN in item:
|
||||
cmd_items[num] = os.path.basename(item)
|
||||
break
|
||||
cmd = " ".join(cmd_items)
|
||||
@ -233,15 +235,9 @@ def main():
|
||||
|
||||
render_vars = {"verifications": []}
|
||||
|
||||
# Install Tempest
|
||||
# Install the latest Tempest version
|
||||
render_vars["install"] = call_rally("verify install")
|
||||
|
||||
# Discover tests depending on Tempest suite
|
||||
discover_cmd = "verify discover"
|
||||
if args.mode == "light":
|
||||
discover_cmd += " --pattern smoke"
|
||||
render_vars["discover"] = call_rally(discover_cmd)
|
||||
|
||||
# Get Rally deployment ID
|
||||
rally_deployment_id = subprocess.check_output(
|
||||
"rally deployment list | awk '/devstack/ {print $2}'",
|
||||
@ -251,10 +247,21 @@ def main():
|
||||
"cd /home/jenkins/.rally/tempest/for-deployment-%s "
|
||||
"git log --skip 1 -n 1 | awk '/commit/ {print $2}' | head -1"
|
||||
% rally_deployment_id, shell=True, stderr=subprocess.STDOUT).strip()
|
||||
# Reinstall Tempest with providing the --version arg to the command
|
||||
# Install the penultimate Tempest version
|
||||
render_vars["reinstall"] = call_rally(
|
||||
"verify reinstall --version %s" % tempest_commit_id)
|
||||
|
||||
# Install a simple Tempest plugin
|
||||
render_vars["installplugin"] = call_rally(
|
||||
"verify installplugin --source %s" % TEMPEST_PLUGIN)
|
||||
|
||||
# Discover tests depending on Tempest suite
|
||||
discover_cmd = "verify discover"
|
||||
if args.mode == "light":
|
||||
discover_cmd += " --pattern smoke"
|
||||
render_vars["discover"] = call_rally(discover_cmd)
|
||||
|
||||
# Generate and show Tempest config file
|
||||
render_vars["genconfig"] = call_rally("verify genconfig")
|
||||
render_vars["showconfig"] = call_rally("verify showconfig")
|
||||
|
||||
|
@ -482,6 +482,24 @@ class VerifyCommandsTestCase(test.TestCase):
|
||||
mock_verification_reinstall_tempest.assert_called_once_with(
|
||||
deployment_uuid, None, version, False)
|
||||
|
||||
@mock.patch("rally.api.Verification.install_tempest_plugin")
|
||||
def test_install_plugin_from_url(
|
||||
self, mock_verification_install_tempest_plugin):
|
||||
deployment_uuid = "83514de2-a770-4e28-82dd-2826b725e733"
|
||||
url = "https://github.com/fake/plugin"
|
||||
self.verify.installplugin(deployment_uuid, url)
|
||||
mock_verification_install_tempest_plugin.assert_called_once_with(
|
||||
deployment_uuid, url, None, False)
|
||||
|
||||
@mock.patch("rally.api.Verification.install_tempest_plugin")
|
||||
def test_install_plugin_from_path(
|
||||
self, mock_verification_install_tempest_plugin):
|
||||
deployment_uuid = "83514de2-a770-4e28-82dd-2826b725e733"
|
||||
path = "/tmp/fake/plugin"
|
||||
self.verify.installplugin(deployment_uuid, path)
|
||||
mock_verification_install_tempest_plugin.assert_called_once_with(
|
||||
deployment_uuid, path, None, False)
|
||||
|
||||
@mock.patch("rally.api.Verification.discover_tests")
|
||||
def test_discover(self, mock_verification_discover_tests):
|
||||
deployment_uuid = "97725f22-1cd2-46a5-8c62-3cdc36ed6d2a"
|
||||
|
@ -495,6 +495,26 @@ class VerificationAPITestCase(BaseDeploymentTestCase):
|
||||
self.tempest.uninstall.assert_called_once_with()
|
||||
self.tempest.install.assert_called_once_with()
|
||||
|
||||
@mock.patch("os.path.exists", return_value=True)
|
||||
@mock.patch("rally.common.objects.Deployment.get")
|
||||
@mock.patch("rally.verification.tempest.tempest.Tempest")
|
||||
def test_install_tempest_plugin_from_url(
|
||||
self, mock_tempest, mock_deployment_get, mock_exists):
|
||||
mock_tempest.return_value = self.tempest
|
||||
api.Verification.install_tempest_plugin(self.deployment_uuid,
|
||||
"https://fake/plugin")
|
||||
self.tempest.install_plugin.assert_called_once_with()
|
||||
|
||||
@mock.patch("os.path.exists", return_value=True)
|
||||
@mock.patch("rally.common.objects.Deployment.get")
|
||||
@mock.patch("rally.verification.tempest.tempest.Tempest")
|
||||
def test_install_tempest_plugin_from_path(
|
||||
self, mock_tempest, mock_deployment_get, mock_exists):
|
||||
mock_tempest.return_value = self.tempest
|
||||
api.Verification.install_tempest_plugin(self.deployment_uuid,
|
||||
"/tmp/fake/plugin")
|
||||
self.tempest.install_plugin.assert_called_once_with()
|
||||
|
||||
@mock.patch("os.path.exists", return_value=True)
|
||||
@mock.patch("rally.common.objects.Deployment.get")
|
||||
@mock.patch("rally.verification.tempest.tempest.Tempest")
|
||||
|
@ -17,6 +17,7 @@ import copy
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from rally import exceptions
|
||||
@ -326,6 +327,21 @@ class TempestInstallAndUninstallTestCase(BaseTestCase):
|
||||
mock_move.assert_called_once_with(source, dest)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TempestInstallPluginsTestCase(BaseTestCase):
|
||||
|
||||
@mock.patch(TEMPEST_PATH + ".tempest.check_output")
|
||||
@ddt.data("https://github.com/fake-plugin", "/tmp/fake-plugin")
|
||||
def test_install_plugin(self, plugin_source, mock_tempest_check_output):
|
||||
self.verifier.plugin_source = plugin_source
|
||||
self.verifier.install_plugin()
|
||||
|
||||
cmd = [self.verifier.venv_wrapper, "pip", "install", "-e",
|
||||
"git+{0}@master#egg={1}".format(plugin_source, "fake-plugin")]
|
||||
mock_tempest_check_output.assert_called_with(cmd,
|
||||
cwd=self.verifier.path())
|
||||
|
||||
|
||||
class TempestVerifyTestCase(BaseTestCase):
|
||||
def _get_fake_call(self, testr_args,
|
||||
concur_args="--parallel --concurrency 0"):
|
||||
|
Loading…
x
Reference in New Issue
Block a user