From b8b2d5e8de33f314a76e7a2ff2385befeafd4cc3 Mon Sep 17 00:00:00 2001 From: "wu.zhihui" Date: Sat, 4 Mar 2017 20:33:22 +0800 Subject: Implement ansible driver - According to inputs parameters, setup test environment. If failed during setupping, qtip will exited. If successful, execute metric tests. - Parameters(optional): * keypair: the keypair to login/execute commands to the remote hosts. They can be automatically generated. * hostfile: a inventory file. If not give, it can be automatically generated via installer. * args: the parameters passed to playbook - Use ansible python api to trigger ansible-playbook. Unit test will be in a new patch. Change-Id: I7470d348308f7cb6cb669bcc49063cf0f4da2111 Signed-off-by: wu.zhihui --- qtip/driver/ansible.py | 14 ------- qtip/driver/ansible_api.py | 58 +++++++++++++++++++++++++++++ qtip/driver/ansible_driver.py | 85 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 14 deletions(-) delete mode 100644 qtip/driver/ansible.py create mode 100644 qtip/driver/ansible_api.py create mode 100644 qtip/driver/ansible_driver.py (limited to 'qtip') diff --git a/qtip/driver/ansible.py b/qtip/driver/ansible.py deleted file mode 100644 index cd17625d..00000000 --- a/qtip/driver/ansible.py +++ /dev/null @@ -1,14 +0,0 @@ -############################################################################## -# Copyright (c) 2016 ZTE Corp and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -from qtip.driver.base import BaseDriver - - -class AnsibleDriver(BaseDriver): - """driver for running performance tests with Ansible""" diff --git a/qtip/driver/ansible_api.py b/qtip/driver/ansible_api.py new file mode 100644 index 00000000..5c5baffc --- /dev/null +++ b/qtip/driver/ansible_api.py @@ -0,0 +1,58 @@ +############################################################################## +# Copyright (c) 2017 ZTE Corp and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from collections import namedtuple + +from ansible.executor.playbook_executor import PlaybookExecutor +from ansible.inventory import Inventory +from ansible.parsing.dataloader import DataLoader +from ansible.vars import VariableManager + + +class AnsibleApi(object): + + def __init__(self): + self.variable_manager = VariableManager() + self.loader = DataLoader() + self.passwords = {} + self.playbook_executor = None + + def execute_playbook(self, playbook_path, hosts_file=None, + key_file=None, extra_vars=None): + inventory = Inventory(loader=self.loader, + variable_manager=self.variable_manager, + host_list=hosts_file) + Options = namedtuple('Options', + ['listtags', 'listtasks', 'listhosts', 'syntax', + 'connection', 'module_path', 'forks', 'remote_user', + 'private_key_file', 'ssh_common_args', 'ssh_extra_args', + 'sftp_extra_args', 'scp_extra_args', 'become', + 'become_method', 'become_user', 'verbosity', 'check']) + options = Options(listtags=False, listtasks=False, listhosts=False, + syntax=False, connection='ssh', module_path=None, + forks=100, remote_user='root', private_key_file=key_file, + ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, + scp_extra_args=None, become=None, become_method=None, + become_user='root', verbosity=None, check=False) + self.variable_manager.extra_vars = extra_vars + + self.playbook_executor = PlaybookExecutor(playbooks=[playbook_path], + inventory=inventory, + variable_manager=self.variable_manager, + loader=self.loader, + options=options, + passwords=self.passwords) + return self.playbook_executor.run() + + def get_detail_playbook_stats(self): + if self.playbook_executor: + stats = self.playbook_executor._tqm._stats + return map(lambda x: (x, stats.summarize(x)), stats.processed.keys()) + else: + return None diff --git a/qtip/driver/ansible_driver.py b/qtip/driver/ansible_driver.py new file mode 100644 index 00000000..1cd7918d --- /dev/null +++ b/qtip/driver/ansible_driver.py @@ -0,0 +1,85 @@ +############################################################################## +# Copyright (c) 2017 ZTE Corp and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from collections import defaultdict +from os import path + +from qtip.driver.ansible_api import AnsibleApi +from qtip.util.env import AnsibleEnvSetup +from qtip.util.logger import QtipLogger + +logger = QtipLogger('ansible_driver').get +PLAYBOOK_DIR = path.join(path.dirname(__file__), 'playbook') + + +class AnsibleDriver(object): + """driver for running performance tests with Ansible""" + + def __init__(self, config={}): + self.config = config + self.env = AnsibleEnvSetup() + self.env_setup_flag = False + + @staticmethod + def merge_two_dicts(x, y): + ''' + It is from http://stackoverflow.com/questions/38987/ + how-can-i-merge-two-python-dictionaries-in-a-single-expression + ''' + z = x.copy() + z.update(y) + return z + + def pre_run(self): + if self.env_setup_flag: + logger.info("Already setup environment......") + else: + logger.info("Starting to setup test environment...") + self.env.setup(self.config) + self.env_setup_flag = True + logger("Done!") + + def run(self, metric_list, **kwargs): + if 'args' in self.config: + extra_vars = self.merge_two_dicts(kwargs, self.config['args']) + else: + extra_vars = kwargs + logger.info("extra_var: {0}".format(extra_vars)) + + # TODO zhihui: will add a new property named "tool" for metrics, hardcode it now. + tool_to_metrics = defaultdict(list) + for metric in metric_list: + if metric in ['dhrystone', 'whetstone']: + tool_to_metrics['unixbench'].append(metric) + extra_vars[metric] = True + elif metric == 'ssl': + tool_to_metrics['openssl'].append(metric) + else: + tool_to_metrics[metric].append(metric) + + ansible_api = AnsibleApi() + map(lambda tool: self._run_metric(ansible_api, tool, + tool_to_metrics[tool], extra_vars), + tool_to_metrics) + + def _run_metric(self, ansible_api, tool, metrics, extra_vars): + logger.info('Using {0} to measure metrics {1}'.format(tool, metrics)) + + for metric in metrics: + extra_vars[metric] = True + + logger.debug("extra_vars: {0}".format(extra_vars)) + + for item in ['setup', 'run', 'clean']: + pbook = "{0}/{1}/{2}.yaml".format(PLAYBOOK_DIR, tool, item) + logger.debug("Start to run {0}".format(pbook)) + ansible_api.execute_playbook(pbook, self.env.hostfile, + self.env.keypair['private'], extra_vars) + playbook_stat = ansible_api.get_detail_playbook_stats() + logger.debug("playbook_stat: {0}".format(playbook_stat)) -- cgit 1.2.3-korg