diff --git a/avocado/core/remote/runner.py b/avocado/core/remote/runner.py index 9ef821fdac29875203df4f80967d682dbe691e3c..7b4cd845f42475c92763bcfe7de2cc3d862f833c 100644 --- a/avocado/core/remote/runner.py +++ b/avocado/core/remote/runner.py @@ -89,7 +89,8 @@ class RemoteTestRunner(TestRunner): password=self.job.args.remote_password, key_filename=self.job.args.remote_key_file, port=self.job.args.remote_port, - timeout=self.job.args.remote_timeout) + timeout=self.job.args.remote_timeout, + env_keep=self.job.args.env_keep) def check_remote_avocado(self): """ diff --git a/avocado/core/remoter.py b/avocado/core/remoter.py index 367ad8e7a9ff027b8a2f725e4f0a2143f2cbada6..f1e5080bef32eafab9409d920c41d6e69d330618 100644 --- a/avocado/core/remoter.py +++ b/avocado/core/remoter.py @@ -18,6 +18,7 @@ Module to provide remote operations. import getpass import logging +import os import time from .settings import settings @@ -30,6 +31,7 @@ try: import fabric.network import fabric.operations import fabric.tasks + from fabric.context_managers import shell_env except ImportError: REMOTE_CAPABLE = False LOG.info('Remote module is disabled: could not import fabric') @@ -46,6 +48,21 @@ class ConnectionError(RemoterError): pass +def _get_env_vars(env_vars): + """ + Gets environment variables. + + :param variables: A list of variables to get. + :return: A dictionary with variables names and values. + """ + env_vars_map = {} + for var in env_vars: + value = os.environ.get(var) + if value is not None: + env_vars_map[var] = value + return env_vars_map + + def run(command, ignore_status=False, quiet=True, timeout=60): """ Executes a command on the defined fabric hosts. @@ -166,7 +183,8 @@ class Remote(object): """ def __init__(self, hostname, username=None, password=None, - key_filename=None, port=22, timeout=60, attempts=10): + key_filename=None, port=22, timeout=60, attempts=10, + env_keep=None): """ Creates an instance of :class:`Remote`. @@ -194,6 +212,10 @@ class Remote(object): 'disable_known_hosts', key_type=bool, default=False) + if env_keep is None: + self.env_vars = {} + else: + self.env_vars = _get_env_vars(env_keep) fabric.api.env.update(host_string=hostname, user=username, password=password, @@ -222,10 +244,12 @@ class Remote(object): :rtype: :class:`avocado.utils.process.CmdResult`. :raise fabric.exceptions.CommandTimeout: When timeout exhausted. """ - return_dict = fabric.tasks.execute(run, command, ignore_status, - quiet, timeout, - hosts=[self.hostname]) - return return_dict[self.hostname] + + with shell_env(**self.env_vars): + return_dict = fabric.tasks.execute(run, command, ignore_status, + quiet, timeout, + hosts=[self.hostname]) + return return_dict[self.hostname] @staticmethod def _run(command, ignore_status=False, quiet=True, timeout=60): diff --git a/avocado/plugins/envkeep.py b/avocado/plugins/envkeep.py new file mode 100644 index 0000000000000000000000000000000000000000..d47ac6c24f198832046a6b0500d30d4b4849e63e --- /dev/null +++ b/avocado/plugins/envkeep.py @@ -0,0 +1,44 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: Red Hat Inc. 2016 +# Author: Amador Pahim + +from avocado.core.plugin_interfaces import CLI + + +class EnvKeep(CLI): + + """ + Keep environment variables on remote executions + """ + + name = 'envkeep' + description = "Keep variables in remote environment" + + def configure(self, parser): + run_subcommand_parser = parser.subcommands.choices.get('run', None) + if run_subcommand_parser is None: + return + + msg = 'keep environment variables' + env_keep_parser = run_subcommand_parser.add_argument_group(msg) + env_keep_parser.add_argument('--env-keep', dest='env_keep', + default=None, + type=self._parse_env_keep, + help='Keep environment variables in ' + 'remote executions') + + def _parse_env_keep(self, string): + return string.split(',') + + def run(self, args): + pass diff --git a/docs/source/RunningTestsRemotely.rst b/docs/source/RunningTestsRemotely.rst index d7780fd9e73440429a8996d17f523b1303054080..243accc11ddc32acd952ecf8a7ae06061930408c 100644 --- a/docs/source/RunningTestsRemotely.rst +++ b/docs/source/RunningTestsRemotely.rst @@ -146,3 +146,17 @@ As you can see, Avocado will copy the tests you have to your libvirt domain and execute them. A bit of extra logging information is added to your job summary, mainly to distinguish the regular execution from the remote one. Note here that we did not need `--vm-password` because the SSH key is already setup. + +Environment Variables +===================== + +Running remote instances os Avocado, for example using `remote` or `vm` +plugins, the remote environment has a diferent set of environment variables. If +you want to make available remotely variables that are available in the local +environment, you can use the `run` option `--env-keep`. See the example below:: + + $ export MYVAR1=foobar + $ env MYVAR2=foobar2 avocado run passtest.py --env-keep MYVAR1,MYVAR2 --remote-hostname 192.168.122.30 --remote-username fedora + +By doing that, both `MYVAR1` and `MYVAR2` will be available in remote +environment. diff --git a/selftests/unit/test_remote.py b/selftests/unit/test_remote.py index 2ce267340de84809223b51e016e9493e4179dada..4c2d9cad1105159db99d835da5296526d0867d63 100644 --- a/selftests/unit/test_remote.py +++ b/selftests/unit/test_remote.py @@ -39,7 +39,8 @@ class RemoteTestRunnerTest(unittest.TestCase): remote_timeout=60, show_job_log=False, multiplex_files=['foo.yaml', 'bar/baz.yaml'], - dry_run=True) + dry_run=True, + env_keep=None) log = flexmock() log.should_receive("info") job = flexmock(args=Args, log=log, @@ -156,7 +157,8 @@ class RemoteTestRunnerSetup(unittest.TestCase): remote_remote = flexmock(remoter) (remote_remote.should_receive('Remote') .with_args(hostname='hostname', username='username', - password='password', key_filename=None, port=22, timeout=60) + password='password', key_filename=None, port=22, + timeout=60, env_keep=None) .once().ordered() .and_return(Remote)) Args = flexmock(test_result_total=1, @@ -169,7 +171,8 @@ class RemoteTestRunnerSetup(unittest.TestCase): remote_key_file=None, remote_no_copy=False, remote_timeout=60, - show_job_log=False) + show_job_log=False, + env_keep=None) log = flexmock() log.should_receive("info") job = flexmock(args=Args, log=log) diff --git a/selftests/unit/test_vm.py b/selftests/unit/test_vm.py index 6dedeedf94c74775fb13b8e2b5937ca04a4e6569..29e102c5eb97a0b1ba2315729bacd70b3b232cef 100644 --- a/selftests/unit/test_vm.py +++ b/selftests/unit/test_vm.py @@ -39,7 +39,8 @@ class VMTestRunnerSetup(unittest.TestCase): vm_cleanup=True, vm_no_copy=False, vm_timeout=120, - vm_hypervisor_uri='my_hypervisor_uri') + vm_hypervisor_uri='my_hypervisor_uri', + env_keep=None) log = flexmock() log.should_receive("info") job = flexmock(args=Args, log=log) diff --git a/setup.py b/setup.py index 022c79c19060b6924ad2095982b4802c0ce9aea6..4a7c6211a7ec3abc07323c2e8a6b4128ca1d5fa0 100755 --- a/setup.py +++ b/setup.py @@ -128,6 +128,7 @@ if __name__ == '__main__': 'scripts/avocado-rest-client'], entry_points={ 'avocado.plugins.cli': [ + 'envkeep = avocado.plugins.envkeep:EnvKeep', 'gdb = avocado.plugins.gdb:GDB', 'wrapper = avocado.plugins.wrapper:Wrapper', 'xunit = avocado.plugins.xunit:XUnit',