avocado.core.remoter keep environment variables

Add options --env-keep to run command so users can make
available in remote executions of Avocado some environment
variables that are available locally.

Reference: https://trello.com/c/Ddcly0oGSigned-off-by: NAmador Pahim <apahim@redhat.com>
上级 c44c1819
...@@ -89,7 +89,8 @@ class RemoteTestRunner(TestRunner): ...@@ -89,7 +89,8 @@ class RemoteTestRunner(TestRunner):
password=self.job.args.remote_password, password=self.job.args.remote_password,
key_filename=self.job.args.remote_key_file, key_filename=self.job.args.remote_key_file,
port=self.job.args.remote_port, 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): def check_remote_avocado(self):
""" """
......
...@@ -18,6 +18,7 @@ Module to provide remote operations. ...@@ -18,6 +18,7 @@ Module to provide remote operations.
import getpass import getpass
import logging import logging
import os
import time import time
from .settings import settings from .settings import settings
...@@ -30,6 +31,7 @@ try: ...@@ -30,6 +31,7 @@ try:
import fabric.network import fabric.network
import fabric.operations import fabric.operations
import fabric.tasks import fabric.tasks
from fabric.context_managers import shell_env
except ImportError: except ImportError:
REMOTE_CAPABLE = False REMOTE_CAPABLE = False
LOG.info('Remote module is disabled: could not import fabric') LOG.info('Remote module is disabled: could not import fabric')
...@@ -46,6 +48,21 @@ class ConnectionError(RemoterError): ...@@ -46,6 +48,21 @@ class ConnectionError(RemoterError):
pass 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): def run(command, ignore_status=False, quiet=True, timeout=60):
""" """
Executes a command on the defined fabric hosts. Executes a command on the defined fabric hosts.
...@@ -166,7 +183,8 @@ class Remote(object): ...@@ -166,7 +183,8 @@ class Remote(object):
""" """
def __init__(self, hostname, username=None, password=None, 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`. Creates an instance of :class:`Remote`.
...@@ -194,6 +212,10 @@ class Remote(object): ...@@ -194,6 +212,10 @@ class Remote(object):
'disable_known_hosts', 'disable_known_hosts',
key_type=bool, key_type=bool,
default=False) 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, fabric.api.env.update(host_string=hostname,
user=username, user=username,
password=password, password=password,
...@@ -222,10 +244,12 @@ class Remote(object): ...@@ -222,10 +244,12 @@ class Remote(object):
:rtype: :class:`avocado.utils.process.CmdResult`. :rtype: :class:`avocado.utils.process.CmdResult`.
:raise fabric.exceptions.CommandTimeout: When timeout exhausted. :raise fabric.exceptions.CommandTimeout: When timeout exhausted.
""" """
return_dict = fabric.tasks.execute(run, command, ignore_status,
quiet, timeout, with shell_env(**self.env_vars):
hosts=[self.hostname]) return_dict = fabric.tasks.execute(run, command, ignore_status,
return return_dict[self.hostname] quiet, timeout,
hosts=[self.hostname])
return return_dict[self.hostname]
@staticmethod @staticmethod
def _run(command, ignore_status=False, quiet=True, timeout=60): def _run(command, ignore_status=False, quiet=True, timeout=60):
......
# 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 <apahim@redhat.com>
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
...@@ -146,3 +146,17 @@ As you can see, Avocado will copy the tests you have to your libvirt domain and ...@@ -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, 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 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. 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.
...@@ -39,7 +39,8 @@ class RemoteTestRunnerTest(unittest.TestCase): ...@@ -39,7 +39,8 @@ class RemoteTestRunnerTest(unittest.TestCase):
remote_timeout=60, remote_timeout=60,
show_job_log=False, show_job_log=False,
multiplex_files=['foo.yaml', 'bar/baz.yaml'], multiplex_files=['foo.yaml', 'bar/baz.yaml'],
dry_run=True) dry_run=True,
env_keep=None)
log = flexmock() log = flexmock()
log.should_receive("info") log.should_receive("info")
job = flexmock(args=Args, log=log, job = flexmock(args=Args, log=log,
...@@ -156,7 +157,8 @@ class RemoteTestRunnerSetup(unittest.TestCase): ...@@ -156,7 +157,8 @@ class RemoteTestRunnerSetup(unittest.TestCase):
remote_remote = flexmock(remoter) remote_remote = flexmock(remoter)
(remote_remote.should_receive('Remote') (remote_remote.should_receive('Remote')
.with_args(hostname='hostname', username='username', .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() .once().ordered()
.and_return(Remote)) .and_return(Remote))
Args = flexmock(test_result_total=1, Args = flexmock(test_result_total=1,
...@@ -169,7 +171,8 @@ class RemoteTestRunnerSetup(unittest.TestCase): ...@@ -169,7 +171,8 @@ class RemoteTestRunnerSetup(unittest.TestCase):
remote_key_file=None, remote_key_file=None,
remote_no_copy=False, remote_no_copy=False,
remote_timeout=60, remote_timeout=60,
show_job_log=False) show_job_log=False,
env_keep=None)
log = flexmock() log = flexmock()
log.should_receive("info") log.should_receive("info")
job = flexmock(args=Args, log=log) job = flexmock(args=Args, log=log)
......
...@@ -39,7 +39,8 @@ class VMTestRunnerSetup(unittest.TestCase): ...@@ -39,7 +39,8 @@ class VMTestRunnerSetup(unittest.TestCase):
vm_cleanup=True, vm_cleanup=True,
vm_no_copy=False, vm_no_copy=False,
vm_timeout=120, vm_timeout=120,
vm_hypervisor_uri='my_hypervisor_uri') vm_hypervisor_uri='my_hypervisor_uri',
env_keep=None)
log = flexmock() log = flexmock()
log.should_receive("info") log.should_receive("info")
job = flexmock(args=Args, log=log) job = flexmock(args=Args, log=log)
......
...@@ -128,6 +128,7 @@ if __name__ == '__main__': ...@@ -128,6 +128,7 @@ if __name__ == '__main__':
'scripts/avocado-rest-client'], 'scripts/avocado-rest-client'],
entry_points={ entry_points={
'avocado.plugins.cli': [ 'avocado.plugins.cli': [
'envkeep = avocado.plugins.envkeep:EnvKeep',
'gdb = avocado.plugins.gdb:GDB', 'gdb = avocado.plugins.gdb:GDB',
'wrapper = avocado.plugins.wrapper:Wrapper', 'wrapper = avocado.plugins.wrapper:Wrapper',
'xunit = avocado.plugins.xunit:XUnit', 'xunit = avocado.plugins.xunit:XUnit',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册