1. Many HA test cases try to kill special processes with their name.
2. Then they check corresponding openstack services and
the status of processes' recovery.
3. For different SUTs, the names of the processes and the hosts' names
may be different.
4. So there is a requirement for Dovetail tool to provide one way to
allow users to specify all the infos about process name and its host name.
5. All process infos can be added into file DOVETAIL_HOME/user_config/pod.yaml
6. The infos include 'attack_process' and 'attack_host' for each HA test cases.
7. If not given in this file, will use Yardtsick default values.
JIRA: DOVETAIL-627
Change-Id: I83cee991f72a8685080ed562597c70d73002623a
Signed-off-by: xudan <xudan16@huawei.com>
# http://www.apache.org/licenses/LICENSE-2.0
#
-import os
import json
-import utils.dovetail_utils as dt_utils
-import utils.dovetail_logger as dt_logger
-from utils.dovetail_config import DovetailConfig as dt_cfg
+import os
+
+import jinja2
+import jinja2.meta
+import yaml
from container import Container
+from dovetail import constants
+from utils.dovetail_config import DovetailConfig as dt_cfg
+import utils.dovetail_utils as dt_utils
+import utils.dovetail_logger as dt_logger
class DockerRunner(object):
class YardstickRunner(DockerRunner):
+ config_file_name = 'yardstick_config.yml'
+
def __init__(self, testcase):
self.type = 'yardstick'
super(YardstickRunner, self).__init__(testcase)
+ self._update_yardstick_config(testcase)
+
+ @staticmethod
+ def _render(task_template, **kwargs):
+ return jinja2.Template(task_template).render(**kwargs)
+
+ @staticmethod
+ def _add_testcase_info(testcase, config_item=None):
+ if not config_item:
+ config_item = {}
+ config_item['validate_testcase'] = testcase.validate_testcase()
+ config_item['testcase'] = testcase.name()
+ return config_item
+
+ def _update_yardstick_config(self, testcase):
+ config_item = None
+ pod_file = os.path.join(dt_cfg.dovetail_config['config_dir'],
+ dt_cfg.dovetail_config['pod_file'])
+ config_file = os.path.join(constants.CONF_PATH, self.config_file_name)
+ pod_info = dt_utils.read_yaml_file(pod_file, self.logger)
+ task_template = dt_utils.read_plain_file(config_file, self.logger)
+ if not (pod_info and task_template):
+ return None
+ try:
+ process_info = pod_info['process_info']
+ except KeyError as e:
+ process_info = None
+ if process_info:
+ for item in process_info:
+ try:
+ if item['testcase_name'] == testcase.name():
+ config_item = self._add_testcase_info(testcase, item)
+ break
+ except KeyError as e:
+ self.logger.error('Need key {} in {}'.format(e, item))
+ if not config_item:
+ config_item = self._add_testcase_info(testcase)
+ full_task = self._render(task_template, **config_item)
+ full_task_yaml = yaml.load(full_task)
+ dt_cfg.dovetail_config.update(full_task_yaml)
+ return dt_cfg.dovetail_config
class BottlenecksRunner(DockerRunner):
cls.dovetail_config = yaml.safe_load(f)
for extra_config_file in cls.dovetail_config['include_config']:
- with open(os.path.join(conf_path, extra_config_file)) as f:
- extra_config = yaml.safe_load(f)
- cls.dovetail_config.update(extra_config)
+
+ # The yardstick config file needs to be parsed later.
+ # Because it's related to the exact test case.
+ if extra_config_file.startswith("yardstick"):
+ continue
+ else:
+ file_path = os.path.join(conf_path, extra_config_file)
+ with open(file_path) as f:
+ extra_config = yaml.safe_load(f)
+ cls.dovetail_config.update(extra_config)
path = os.path.join(conf_path, cls.dovetail_config['cli_file_name'])
with open(path) as f:
logger.error("There is no key {} in file {}"
.format(e, hosts_config_file))
return hosts_config
+
+
+def read_yaml_file(file_path, logger=None):
+ if not os.path.isfile(file_path):
+ logger.error("File {} doesn't exist.".format(file_path))
+ return None
+ try:
+ with open(file_path, 'r') as f:
+ content = yaml.safe_load(f)
+ return content
+ except Exception as e:
+ logger.exception("Failed to read file {}, exception: {}"
+ .format(file_path, e))
+ return None
+
+
+def read_plain_file(file_path, logger=None):
+ if not os.path.isfile(file_path):
+ logger.error("File {} doesn't exist.".format(file_path))
+ return None
+ try:
+ with open(file_path, 'r') as f:
+ content = f.read()
+ return content
+ except Exception as e:
+ logger.exception("Failed to read file {}, exception: {}"
+ .format(file_path, e))
+ return None
---
+
+{% set attack_host = attack_host or '' %}
+{% set attack_process = attack_process or '' %}
+{% set validate_testcase = validate_testcase or '' %}
+{% set testcase = testcase or '' %}
+
yardstick:
image_name: opnfv/yardstick
docker_tag: opnfv-5.1.0
- "cd /home/opnfv/repos/yardstick && source /etc/yardstick/openstack.creds &&
yardstick task start tests/opnfv/test_cases/{{validate_testcase}}.yaml
--output-file /home/opnfv/yardstick/results/{{testcase}}.out
- --task-args '{'file': '/home/opnfv/userconfig/pre_config/pod.yaml'}'"
+ --task-args '{'file': '/home/opnfv/userconfig/pre_config/pod.yaml',
+ 'attack_host': {{attack_host}},
+ 'attack_process': {{attack_process}}}'"
post_condition:
- 'echo this is post_condition'
result:
ip: 10.1.0.54
user: root
key_filename: /root/.ssh/id_rsa
+
+# The options of this section include:
+# testcase_name: the name of test case
+# attack_process: the name of the process this test case attempt to kill
+# attack_host: one of the hosts given in section 'nodes' which is the primary host of attack_process
+#
+# if not set, it will use the default value of yardstick test case config
+# the default attack_host of all test cases is 'node1'
+# the default attack_process of all test cases are
+# dovetail.ha.tc001: nova-api
+# dovetail.ha.tc002: neutron-server
+# dovetail.ha.tc003: keystone
+# dovetail.ha.tc004: glance-api
+# dovetail.ha.tc005: cinder-api
+# dovetail.ha.tc008: haproxy
+# dovetail.ha.tc010: rabbitmq-server
+# dovetail.ha.tc011: neutron-l3-agent
+
+# process_info:
+# -
+# testcase_name: dovetail.ha.tc008
+# attack_host: node2
+#
+# -
+# testcase_name: dovetail.ha.tc010
+# attack_process: rabbitmq