diff options
Diffstat (limited to 'tests')
38 files changed, 8 insertions, 2456 deletions
diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tests/__init__.py diff --git a/tests/alarm.py b/tests/alarm.py deleted file mode 100644 index 916f4405..00000000 --- a/tests/alarm.py +++ /dev/null @@ -1,93 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 oslo_config import cfg - -from identity_auth import get_identity_auth -from identity_auth import get_session -from os_clients import aodh_client -from os_clients import nova_client - -OPTS = [ - cfg.StrOpt('alarm_basename', - default='doctor_alarm', - help='the base name of alarm', - required=True), -] - - -class Alarm(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - self.auth = get_identity_auth(project=self.conf.doctor_project) - self.aodh = \ - aodh_client(conf.aodh_version, - get_session(auth=self.auth)) - self.nova = \ - nova_client(conf.nova_version, - get_session(auth=self.auth)) - self._init_alarm_name() - - def _init_alarm_name(self): - self.alarm_names = [] - for i in range(0, self.conf.instance_count): - alarm_name = '%s%d' % (self.conf.alarm_basename, i) - self.alarm_names.append(alarm_name) - - def create(self): - self.log.info('alarm create start......') - - alarms = {alarm['name']: alarm for alarm in self.aodh.alarm.list()} - servers = \ - {getattr(server, 'name'): server - for server in self.nova.servers.list()} - - for i in range(0, self.conf.instance_count): - alarm_name = self.alarm_names[i] - if alarm_name in alarms: - continue; - vm_name = '%s%d' % (self.conf.instance_basename, i) - vm_id = getattr(servers[vm_name], 'id') - alarm_request = dict( - name=alarm_name, - description=u'VM failure', - enabled=True, - alarm_actions=[u'http://%s:%d/failure' - % (self.conf.consumer.ip, - self.conf.consumer.port)], - repeat_actions=False, - severity=u'moderate', - type=u'event', - event_rule=dict( - event_type=u'compute.instance.update', - query=[ - dict(field=u'traits.instance_id', - type='', - op=u'eq', - value=vm_id), - dict(field=u'traits.state', - type='', - op=u'eq', - value=u'error')])) - self.aodh.alarm.create(alarm_request) - - self.log.info('alarm create end......') - - def delete(self): - self.log.info('alarm delete start.......') - - alarms = {alarm['name']: alarm for alarm in self.aodh.alarm.list()} - for alarm_name in self.alarm_names: - if alarm_name in alarms: - self.aodh.alarm.delete(alarms[alarm_name]['alarm_id']) - - del self.alarm_names[:] - - self.log.info('alarm delete end.......') diff --git a/tests/common/__init__.py b/tests/common/__init__.py deleted file mode 100644 index e68a3070..00000000 --- a/tests/common/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -##############################################################################
\ No newline at end of file diff --git a/tests/common/constants.py b/tests/common/constants.py deleted file mode 100644 index 72d037af..00000000 --- a/tests/common/constants.py +++ /dev/null @@ -1,12 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 - - -Host = namedtuple('Host', ['name', 'ip']) diff --git a/tests/common/utils.py b/tests/common/utils.py deleted file mode 100644 index 2e823acb..00000000 --- a/tests/common/utils.py +++ /dev/null @@ -1,105 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import json -import os -import paramiko -import re - - -def load_json_file(full_path): - """Loads JSON from file - :param target_filename: - :return: - """ - if not os.path.isfile(full_path): - raise Exception('File(%s) does not exist' % full_path) - - with open(full_path, 'r') as file: - return json.load(file) - - -def write_json_file(full_path, data): - """write JSON from file - :param target_filename: - :return: - """ - - with open(full_path, 'w+') as file: - file.write(json.dumps(data)) - - -def match_rep_in_file(regex, full_path): - if not os.path.isfile(full_path): - raise Exception('File(%s) does not exist' % full_path) - - with open(full_path, 'r') as file: - for line in file: - result = re.search(regex, line) - if result: - return result - - return None - - -class SSHClient(object): - def __init__(self, ip, username, password=None, pkey=None, - key_filename=None, log=None, look_for_keys=False, - allow_agent=False): - self.client = paramiko.SSHClient() - self.client.load_system_host_keys() - self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.client.connect(ip, username=username, password=password, - pkey=pkey, key_filename=key_filename, - look_for_keys=look_for_keys, - allow_agent=allow_agent) - self.log = log - - def __del__(self): - self.client.close() - - def ssh(self, command): - if self.log: - self.log.info("Executing: %s" % command) - stdin, stdout, stderr = self.client.exec_command(command) - ret = stdout.channel.recv_exit_status() - output = list() - for line in stdout.read().splitlines(): - output.append(line.decode('utf-8')) - if ret: - if self.log: - self.log.info("*** FAILED to run command %s (%s)" % (command, ret)) - raise Exception( - "Unable to run \ncommand: %s\nret: %s" - % (command, ret)) - if self.log: - self.log.info("*** SUCCESSFULLY run command %s" % command) - return ret, output - - def scp(self, source, dest, method='put'): - if self.log: - self.log.info("Copy %s -> %s" % (source, dest)) - ftp = self.client.open_sftp() - if method == 'put': - ftp.put(source, dest) - elif method == 'get': - ftp.get(source, dest) - ftp.close() - - -def run_async(func): - from threading import Thread - from functools import wraps - - @wraps(func) - def async_func(*args, **kwargs): - thread = Thread(target=func, args=args, kwargs=kwargs) - thread.start() - return thread - - return async_func diff --git a/tests/config.py b/tests/config.py deleted file mode 100644 index c71d5ad7..00000000 --- a/tests/config.py +++ /dev/null @@ -1,54 +0,0 @@ -##############################################################################
-# Copyright (c) 2017 ZTE Corporation 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
-##############################################################################
-import itertools
-
-from oslo_config import cfg
-
-import alarm
-import consumer
-import image
-import instance
-import installer
-import network
-import inspector
-import monitor
-import os_clients
-import profiler_poc
-import user
-
-
-def list_opts():
- return [
- ('installer', installer.OPTS),
- ('monitor', monitor.OPTS),
- ('inspector', inspector.OPTS),
- ('consumer', consumer.OPTS),
- ('DEFAULT', itertools.chain(
- os_clients.OPTS,
- image.OPTS,
- user.OPTS,
- network.OPTS,
- instance.OPTS,
- alarm.OPTS,
- profiler_poc.OPTS))
- ]
-
-
-def prepare_conf(args=None, conf=None, config_files=None):
- if conf is None:
- conf = cfg.ConfigOpts()
-
- for group, options in list_opts():
- conf.register_opts(list(options),
- group=None if group == 'DEFAULT' else group)
-
- conf(args, project='doctor', validate_default_values=True,
- default_config_files=config_files)
-
- return conf
diff --git a/tests/consumer/__init__.py b/tests/consumer/__init__.py deleted file mode 100644 index ccec8644..00000000 --- a/tests/consumer/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 oslo_config import cfg -from oslo_utils import importutils - - -OPTS = [ - cfg.StrOpt('type', - default='sample', - choices=['sample'], - help='the component of doctor consumer', - required=True), - cfg.StrOpt('ip', - default='127.0.0.1', - help='the ip of consumer', - required=True), - cfg.IntOpt('port', - default='12346', - help='the port of doctor consumer', - required=True), -] - - -_consumer_name_class_mapping = { - 'sample': 'consumer.sample.SampleConsumer' -} - - -def get_consumer(conf, log): - consumer_class = _consumer_name_class_mapping.get(conf.consumer.type) - return importutils.import_object(consumer_class, conf, log)
\ No newline at end of file diff --git a/tests/consumer/base.py b/tests/consumer/base.py deleted file mode 100644 index 35170748..00000000 --- a/tests/consumer/base.py +++ /dev/null @@ -1,26 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import abc -import six - - -@six.add_metaclass(abc.ABCMeta) -class BaseConsumer(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - - @abc.abstractmethod - def start(self): - pass - - @abc.abstractmethod - def stop(self): - pass
\ No newline at end of file diff --git a/tests/consumer/sample.py b/tests/consumer/sample.py deleted file mode 100644 index 20ad9d57..00000000 --- a/tests/consumer/sample.py +++ /dev/null @@ -1,71 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 flask import Flask -from flask import request -import json -import time -from threading import Thread -import requests - -from consumer.base import BaseConsumer - - -class SampleConsumer(BaseConsumer): - - def __init__(self, conf, log): - super(SampleConsumer, self).__init__(conf, log) - self.app = None - - def start(self): - self.log.info('sample consumer start......') - self.app = ConsumerApp(self.conf.consumer.port, self, self.log) - self.app.start() - - def stop(self): - self.log.info('sample consumer stop......') - if not self.app: - return - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - } - url = 'http://%s:%d/shutdown'\ - % (self.conf.consumer.ip, - self.conf.consumer.port) - requests.post(url, data='', headers=headers) - - -class ConsumerApp(Thread): - - def __init__(self, port, consumer, log): - Thread.__init__(self) - self.port = port - self.consumer = consumer - self.log = log - - def run(self): - app = Flask('consumer') - - @app.route('/failure', methods=['POST']) - def event_posted(): - self.log.info('doctor consumer notified at %s' % time.time()) - self.log.info('sample consumer received data = %s' % request.data) - data = json.loads(request.data.decode('utf8')) - return 'OK' - - @app.route('/shutdown', methods=['POST']) - def shutdown(): - self.log.info('shutdown consumer app server at %s' % time.time()) - func = request.environ.get('werkzeug.server.shutdown') - if func is None: - raise RuntimeError('Not running with the Werkzeug Server') - func() - return 'consumer app shutting down...' - - app.run(host="0.0.0.0", port=self.port)
\ No newline at end of file diff --git a/tests/identity_auth.py b/tests/identity_auth.py deleted file mode 100644 index c94893f4..00000000 --- a/tests/identity_auth.py +++ /dev/null @@ -1,44 +0,0 @@ -############################################################################## -# Copyright (c) 2017 NEC Corporation 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 -############################################################################## - -import os - -from keystoneauth1 import loading -from keystoneauth1 import session - - -def get_identity_auth(username=None, password=None, project=None): - auth_url = os.environ['OS_AUTH_URL'] - username = username or os.environ['OS_USERNAME'] - password = password or os.environ['OS_PASSWORD'] - user_domain_name = os.environ.get('OS_USER_DOMAIN_NAME') or 'default' - user_domain_id = os.environ.get('OS_USER_DOMAIN_ID') or 'default' - project_name = project or os.environ.get('OS_PROJECT_NAME') \ - or os.environ.get('OS_TENANT_NAME') - project_domain_name = os.environ.get('OS_PROJECT_DOMAIN_NAME') or 'default' - project_domain_id = os.environ.get('OS_PROJECT_DOMAIN_ID') or 'default' - - loader = loading.get_plugin_loader('password') - return loader.load_from_options( - auth_url=auth_url, - username=username, - password=password, - user_domain_name=user_domain_name, - user_domain_id=user_domain_id, - project_name=project_name, - tenant_name=project_name, - project_domain_name=project_domain_name, - project_domain_id=project_domain_id) - - -def get_session(auth=None): - """Get a user credentials auth session.""" - if auth is None: - auth = get_identity_auth() - return session.Session(auth=auth) diff --git a/tests/image.py b/tests/image.py deleted file mode 100644 index 453322b8..00000000 --- a/tests/image.py +++ /dev/null @@ -1,74 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os -import urllib.request - -from oslo_config import cfg - -from identity_auth import get_session -from os_clients import glance_client - -OPTS = [ - cfg.StrOpt('image_name', - default=os.environ.get('IMAGE_NAME', 'cirros'), - help='the name of test image', - required=True), - cfg.StrOpt('image_format', - default='qcow2', - help='the format of test image', - required=True), - cfg.StrOpt('image_filename', - default='cirros.img', - help='the name of image file', - required=True), - cfg.StrOpt('image_download_url', - default='https://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-disk.img', - help='the url where to get the image', - required=True), -] - - -class Image(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - self.glance = \ - glance_client(conf.glance_version, get_session()) - self.use_existing_image = False - self.image = None - - def create(self): - self.log.info('image create start......') - - images = {image.name: image for image in self.glance.images.list()} - if self.conf.image_name not in images: - if not os.path.exists(self.conf.image_filename): - resp = urllib.request.urlopen(self.conf.image_download_url) - with open(self.conf.image_filename, "wb") as file: - file.write(resp.read()) - self.image = self.glance.images.create(name=self.conf.image_name, - disk_format=self.conf.image_format, - container_format="bare", - visibility="public") - self.glance.images.upload(self.image['id'], - open(self.conf.image_filename, 'rb')) - else: - self.use_existing_image = True - self.image = images[self.conf.image_name] - - self.log.info('image create end......') - - def delete(self): - self.log.info('image delete start.......') - - if not self.use_existing_image and self.image: - self.glance.images.delete(self.image['id']) - - self.log.info('image delete end.......') diff --git a/tests/inspector.py b/tests/inspector.py index 82ffc338..0046b999 100644 --- a/tests/inspector.py +++ b/tests/inspector.py @@ -19,7 +19,7 @@ import time from keystoneauth1 import session import novaclient.client as novaclient -import identity_auth +import doctor_tests.identity_auth LOG = doctor_log.Logger('doctor_inspector').getLogger() diff --git a/tests/inspector/__init__.py b/tests/inspector/__init__.py deleted file mode 100644 index afba4800..00000000 --- a/tests/inspector/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -############################################################################# -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os - -from oslo_config import cfg -from oslo_utils import importutils - - -OPTS = [ - cfg.StrOpt('type', - default=os.environ.get('INSPECTOR_TYPE', 'sample'), - choices=['sample', 'congress', 'vitrage'], - help='the component of doctor inspector', - required=True), - cfg.StrOpt('ip', - default='127.0.0.1', - help='the host ip of inspector', - required=False), - cfg.StrOpt('port', - default='12345', - help='the port of default for inspector', - required=False), -] - - -_inspector_name_class_mapping = { - 'sample': 'inspector.sample.SampleInspector', - 'congress': 'inspector.congress.CongressInspector', -} - - -def get_inspector(conf, log): - inspector_class = _inspector_name_class_mapping[conf.inspector.type] - return importutils.import_object(inspector_class, conf, log) diff --git a/tests/inspector/base.py b/tests/inspector/base.py deleted file mode 100644 index 854f0695..00000000 --- a/tests/inspector/base.py +++ /dev/null @@ -1,30 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import abc -import six - - -@six.add_metaclass(abc.ABCMeta) -class BaseInspector(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - - @abc.abstractmethod - def get_inspector_url(self): - pass - - @abc.abstractmethod - def start(self): - pass - - @abc.abstractmethod - def stop(self): - pass
\ No newline at end of file diff --git a/tests/inspector/congress.py b/tests/inspector/congress.py deleted file mode 100644 index ae295852..00000000 --- a/tests/inspector/congress.py +++ /dev/null @@ -1,94 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 identity_auth import get_identity_auth -from identity_auth import get_session -from os_clients import congress_client - -from inspector.base import BaseInspector - - -class CongressInspector(BaseInspector): - nova_api_min_version = '2.11' - doctor_driver = 'doctor' - doctor_datasource = 'doctor' - policy = 'classification' - rules = { - 'host_down': - 'host_down(host) :- doctor:events(hostname=host, type="compute.host.down", status="down")', - 'active_instance_in_host': - 'active_instance_in_host(vmid, host) :- nova:servers(id=vmid, host_name=host, status="ACTIVE")', - 'host_force_down': - 'execute[nova:services.force_down(host, "nova-compute", "True")] :- host_down(host)', - 'error_vm_states': - 'execute[nova:servers.reset_state(vmid, "error")] :- host_down(host), active_instance_in_host(vmid, host)' - } - - def __init__(self, conf, log): - super(CongressInspector, self).__init__(conf, log) - self.auth = get_identity_auth() - self.congress = congress_client(get_session(auth=self.auth)) - self._init_driver_and_ds() - self.inspector_url = self.get_inspector_url() - - def _init_driver_and_ds(self): - datasources = \ - {ds['name']: ds for ds in self.congress.list_datasources()['results']} - - # check nova_api version - nova_api_version = datasources['nova']['config'].get('api_version') - if nova_api_version and nova_api_version < self.nova_api_min_version: - raise Exception('Congress Nova datasource API version < nova_api_min_version(%s)' - % self.nova_api_min_version) - - # create doctor datasource if it's not exist - if self.doctor_datasource not in datasources: - self.congress.create_datasource( - body={'driver': self.doctor_driver, - 'name': self.doctor_datasource}) - - # check whether doctor driver exist - drivers = \ - {driver['id']: driver for driver in self.congress.list_drivers()['results']} - if self.doctor_driver not in drivers: - raise Exception('Do not support doctor driver in congress') - - self.policy_rules = \ - {rule['name']: rule for rule in - self.congress.list_policy_rules(self.policy)['results']} - - def get_inspector_url(self): - ds = self.congress.list_datasources()['results'] - doctor_ds = next((item for item in ds if item['driver'] == 'doctor'), - None) - congress_endpoint = self.congress.httpclient.get_endpoint(auth=self.auth) - return ('%s/v1/data-sources/%s/tables/events/rows' % - (congress_endpoint, doctor_ds['id'])) - - def start(self): - self.log.info('congress inspector start......') - - for rule_name, rule in self.rules.items(): - self._add_rule(rule_name, rule) - - def stop(self): - self.log.info('congress inspector stop......') - - for rule_name in self.rules.keys(): - self._del_rule(rule_name) - - def _add_rule(self, rule_name, rule): - if rule_name not in self.policy_rules: - self.congress.create_policy_rule(self.policy, - body={'name': rule_name, - 'rule': rule}) - - def _del_rule(self, rule_name): - if rule_name in self.policy_rules: - rule_id = self.policy_rules[rule_name]['id'] - self.congress.delete_policy_rule(self.policy, rule_id) diff --git a/tests/inspector/sample.py b/tests/inspector/sample.py deleted file mode 100644 index 1c05cede..00000000 --- a/tests/inspector/sample.py +++ /dev/null @@ -1,169 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import collections -from flask import Flask -from flask import request -import json -import time -from threading import Thread -import requests - -from common import utils -from identity_auth import get_identity_auth -from identity_auth import get_session -from os_clients import nova_client -from os_clients import neutron_client -from inspector.base import BaseInspector - - -class SampleInspector(BaseInspector): - event_type = 'compute.host.down' - - def __init__(self, conf, log): - super(SampleInspector, self).__init__(conf, log) - self.inspector_url = self.get_inspector_url() - self.novaclients = list() - self._init_novaclients() - # Normally we use this client for non redundant API calls - self.nova = self.novaclients[0] - - auth = get_identity_auth(project=self.conf.doctor_project) - session = get_session(auth=auth) - self.neutron = neutron_client(session) - - self.servers = collections.defaultdict(list) - self.hostnames = list() - self.app = None - - def _init_novaclients(self): - self.NUMBER_OF_CLIENTS = self.conf.instance_count - auth = get_identity_auth(project=self.conf.doctor_project) - session = get_session(auth=auth) - for i in range(self.NUMBER_OF_CLIENTS): - self.novaclients.append( - nova_client(self.conf.nova_version, session)) - - def _init_servers_list(self): - self.servers.clear() - opts = {'all_tenants': True} - servers = self.nova.servers.list(search_opts=opts) - for server in servers: - try: - host = server.__dict__.get('OS-EXT-SRV-ATTR:host') - self.servers[host].append(server) - self.log.debug('get hostname=%s from server=%s' % (host, server)) - except Exception as e: - self.log.info('can not get hostname from server=%s' % server) - - def get_inspector_url(self): - return 'http://%s:%s' % (self.conf.inspector.ip, self.conf.inspector.port) - - def start(self): - self.log.info('sample inspector start......') - self._init_servers_list() - self.app = InspectorApp(self.conf.inspector.port, self, self.log) - self.app.start() - - def stop(self): - self.log.info('sample inspector stop......') - if not self.app: - return - for hostname in self.hostnames: - self.nova.services.force_down(hostname, 'nova-compute', False) - - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - } - url = '%s%s' % (self.inspector_url, 'shutdown') \ - if self.inspector_url.endswith('/') else \ - '%s%s' % (self.inspector_url, '/shutdown') - requests.post(url, data='', headers=headers) - - def handle_events(self, events): - for event in events: - hostname = event['details']['hostname'] - event_type = event['type'] - if event_type == self.event_type: - self.hostnames.append(hostname) - thr1 = self._disable_compute_host(hostname) - thr2 = self._vms_reset_state('error', hostname) - thr3 = self._set_ports_data_plane_status('DOWN', hostname) - thr1.join() - thr2.join() - thr3.join() - - @utils.run_async - def _disable_compute_host(self, hostname): - self.nova.services.force_down(hostname, 'nova-compute', True) - self.log.info('doctor mark host(%s) down at %s' % (hostname, time.time())) - - @utils.run_async - def _vms_reset_state(self, state, hostname): - - @utils.run_async - def _vm_reset_state(nova, server, state): - nova.servers.reset_state(server, state) - self.log.info('doctor mark vm(%s) error at %s' % (server, time.time())) - - thrs = [] - for nova, server in zip(self.novaclients, self.servers[hostname]): - t = _vm_reset_state(nova, server, state) - thrs.append(t) - for t in thrs: - t.join() - - @utils.run_async - def _set_ports_data_plane_status(self, status, hostname): - body = {'data_plane_status': status} - - @utils.run_async - def _set_port_data_plane_status(port_id): - self.neutron.update_port(port_id, body) - self.log.info('doctor set data plane status %s on port %s' % (status, port_id)) - - thrs = [] - params = {'binding:host_id': hostname} - for port_id in self.neutron.list_ports(**params): - t = _set_port_data_plane_status(port_id) - thrs.append(t) - for t in thrs: - t.join() - - -class InspectorApp(Thread): - - def __init__(self, port, inspector, log): - Thread.__init__(self) - self.port = port - self.inspector = inspector - self.log = log - - def run(self): - app = Flask('inspector') - - @app.route('/events', methods=['PUT']) - def event_posted(): - self.log.info('event posted in sample inspector at %s' % time.time()) - self.log.info('sample inspector = %s' % self.inspector) - self.log.info('sample inspector received data = %s' % request.data) - events = json.loads(request.data.decode('utf8')) - self.inspector.handle_events(events) - return "OK" - - @app.route('/shutdown', methods=['POST']) - def shutdown(): - self.log.info('shutdown inspector app server at %s' % time.time()) - func = request.environ.get('werkzeug.server.shutdown') - if func is None: - raise RuntimeError('Not running with the Werkzeug Server') - func() - return 'inspector app shutting down...' - - app.run(host="0.0.0.0", port=self.port) diff --git a/tests/installer/__init__.py b/tests/installer/__init__.py deleted file mode 100644 index bb0e452d..00000000 --- a/tests/installer/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os - -from oslo_config import cfg -from oslo_utils import importutils - -OPTS = [ - cfg.StrOpt('type', - default=os.environ.get('INSTALLER_TYPE', 'local'), - choices=['local', 'apex'], - help='the type of installer', - required=True), - cfg.StrOpt('ip', - default=os.environ.get('INSTALLER_IP', '127.0.0.1'), - help='the ip of installer'), - cfg.StrOpt('username', - default='root', - help='the user name for login installer server', - required=True), -] - - -_installer_name_class_mapping = { - 'local': 'installer.local.LocalInstaller', - 'apex': 'installer.apex.ApexInstaller' -} - - -def get_installer(conf, log): - installer_class = _installer_name_class_mapping[conf.installer.type] - return importutils.import_object(installer_class, conf, log)
\ No newline at end of file diff --git a/tests/installer/apex.py b/tests/installer/apex.py deleted file mode 100644 index 98eb6c9c..00000000 --- a/tests/installer/apex.py +++ /dev/null @@ -1,127 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import getpass -import grp -import os -import pwd -import stat -import subprocess -import sys - -from common.utils import SSHClient -from installer.base import BaseInstaller - - -class ApexInstaller(BaseInstaller): - node_user_name = 'heat-admin' - cm_set_script = 'set_ceilometer.py' - cm_restore_script = 'restore_ceilometer.py' - - def __init__(self, conf, log): - super(ApexInstaller, self).__init__(conf, log) - self.client = SSHClient(self.conf.installer.ip, - self.conf.installer.username, - look_for_keys=True) - self.key_file = None - self.controllers = list() - self.controller_clients = list() - self.servers = list() - - def setup(self): - self.log.info('Setup Apex installer start......') - - self.get_ssh_key_from_installer() - self.get_controller_ips() - self.set_apply_patches() - self.setup_stunnel() - - def cleanup(self): - self.restore_apply_patches() - for server in self.servers: - server.terminate() - - def get_ssh_key_from_installer(self): - self.log.info('Get SSH keys from Apex installer......') - - if self.key_file is not None: - self.log.info('Already have SSH keys from Apex installer......') - return self.key_file - - self.client.scp('/home/stack/.ssh/id_rsa', './instack_key', method='get') - user = getpass.getuser() - uid = pwd.getpwnam(user).pw_uid - gid = grp.getgrnam(user).gr_gid - os.chown('./instack_key', uid, gid) - os.chmod('./instack_key', stat.S_IREAD) - current_dir = sys.path[0] - self.key_file = '{0}/{1}'.format(current_dir, 'instack_key') - return self.key_file - - def get_controller_ips(self): - self.log.info('Get controller ips from Apex installer......') - - command = "source stackrc; " \ - "nova list | grep ' overcloud-controller-[0-9] ' " \ - "| sed -e 's/^.*ctlplane=//' |awk '{print $1}'" - ret, controllers = self.client.ssh(command) - if ret: - raise Exception('Exec command to get controller ips in Apex installer failed' - 'ret=%s, output=%s' % (ret, controllers)) - self.log.info('Get controller_ips:%s from Apex installer' % controllers) - self.controllers = controllers - - def get_host_ip_from_hostname(self, hostname): - self.log.info('Get host ip from host name in Apex installer......') - - hostname_in_undercloud = hostname.split('.')[0] - - command = "source stackrc; nova show %s | awk '/ ctlplane network /{print $5}'" % (hostname_in_undercloud) - ret, host_ip = self.client.ssh(command) - if ret: - raise Exception('Exec command to get host ip from hostname(%s) in Apex installer failed' - 'ret=%s, output=%s' % (hostname, ret, host_ip)) - self.log.info('Get host_ip:%s from host_name:%s in Apex installer' % (host_ip, hostname)) - return host_ip[0] - - def setup_stunnel(self): - self.log.info('Setup ssh stunnel in controller nodes in Apex installer......') - for node_ip in self.controllers: - cmd = "sudo ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i %s %s@%s -R %s:localhost:%s sleep 600 > ssh_tunnel.%s.log 2>&1 < /dev/null &" \ - % (self.key_file, self.node_user_name, node_ip, - self.conf.consumer.port, self.conf.consumer.port, node_ip) - server = subprocess.Popen(cmd, shell=True) - self.servers.append(server) - server.communicate() - - def set_apply_patches(self): - self.log.info('Set apply patches start......') - - for node_ip in self.controllers: - client = SSHClient(node_ip, self.node_user_name, key_filename=self.key_file) - self.controller_clients.append(client) - self._ceilometer_apply_patches(client, self.cm_set_script) - - def restore_apply_patches(self): - self.log.info('restore apply patches start......') - - for client in self.controller_clients: - self._ceilometer_apply_patches(client, self.cm_restore_script) - - def _ceilometer_apply_patches(self, ssh_client, script_name): - installer_dir = os.path.dirname(os.path.realpath(__file__)) - script_abs_path = '{0}/{1}/{2}'.format(installer_dir, 'common', script_name) - - ssh_client.scp(script_abs_path, script_name) - cmd = 'sudo python %s' % script_name - ret, output = ssh_client.ssh(cmd) - if ret: - raise Exception('Do the ceilometer command in controller node failed....' - 'ret=%s, cmd=%s, output=%s' % (ret, cmd, output)) - ssh_client.ssh('sudo systemctl restart openstack-ceilometer-notification.service') - diff --git a/tests/installer/base.py b/tests/installer/base.py deleted file mode 100644 index fa39816a..00000000 --- a/tests/installer/base.py +++ /dev/null @@ -1,36 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import abc -import six - -@six.add_metaclass(abc.ABCMeta) -class BaseInstaller(object): - def __init__(self, conf, log): - self.conf = conf - self.log = log - - @abc.abstractproperty - def node_user_name(self): - """user name for login to cloud node""" - - @abc.abstractmethod - def get_ssh_key_from_installer(self): - pass - - @abc.abstractmethod - def get_host_ip_from_hostname(self, hostname): - pass - - @abc.abstractmethod - def setup(self): - pass - - @abc.abstractmethod - def cleanup(self): - pass diff --git a/tests/installer/common/congress.py b/tests/installer/common/congress.py deleted file mode 100644 index db882de2..00000000 --- a/tests/installer/common/congress.py +++ /dev/null @@ -1,47 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -def set_doctor_driver_conf(ssh_client, restart_cmd): - cg_set_cmd = '''#!/bin/bash -co_conf=/etc/congress/congress.conf -co_conf_bak=/etc/congress/congress.conf.bak -co_entry="congress.datasources.doctor_driver.DoctorDriver" -if sudo grep -e "^drivers.*$co_entry" $co_conf; then - echo "NOTE: congress is configured as we needed" -else - echo "modify the congress config" - sudo cp $co_conf $co_conf_bak - sudo sed -i -e "/^drivers/s/$/,$co_entry/" $co_conf - %s -fi - ''' % (restart_cmd) - - ret, output = ssh_client.ssh(cg_set_cmd) - if ret: - raise Exception('Do the congress command in controller node failed....' - 'ret=%s, cmd=%s, output=%s' % (ret, cg_set_cmd, output)) - - -def restore_doctor_driver_conf(ssh_client, restart_cmd): - cg_restore_cmd = '''#!/bin/bash -co_conf=/etc/congress/congress.conf -co_conf_bak=/etc/congress/congress.conf.bak -if [ -e $co_conf_bak ]; then - echo "restore the congress config" - sudo cp $co_conf_bak $co_conf - sudo rm $co_conf_bak - %s -else - echo "Do not need to restore the congress config" -fi - ''' % (restart_cmd) - - ret, output = ssh_client.ssh(cg_restore_cmd) - if ret: - raise Exception('Do the congress command in controller node failed....' - 'ret=%s, cmd=%s, output=%s' % (ret, cg_restore_cmd, output)) diff --git a/tests/installer/common/restore_ceilometer.py b/tests/installer/common/restore_ceilometer.py deleted file mode 100644 index d25b9ede..00000000 --- a/tests/installer/common/restore_ceilometer.py +++ /dev/null @@ -1,27 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os -import shutil - -ep_file = '/etc/ceilometer/event_pipeline.yaml' -ep_file_bak = '/etc/ceilometer/event_pipeline.yaml.bak' - - -def restore_ep_config(): - - if not os.path.isfile(ep_file_bak): - print('Bak_file:%s does not exist.' % ep_file_bak) - else: - print('restore') - shutil.copyfile(ep_file_bak, ep_file) - os.remove(ep_file_bak) - return - - -restore_ep_config() diff --git a/tests/installer/common/set_ceilometer.py b/tests/installer/common/set_ceilometer.py deleted file mode 100644 index f5946cb2..00000000 --- a/tests/installer/common/set_ceilometer.py +++ /dev/null @@ -1,44 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os -import shutil -import yaml - -ep_file = '/etc/ceilometer/event_pipeline.yaml' -ep_file_bak = '/etc/ceilometer/event_pipeline.yaml.bak' -event_notifier_topic = 'notifier://?topic=alarm.all' - - -def set_notifier_topic(): - config_modified = False - - if not os.path.isfile(ep_file): - raise Exception("File doesn't exist: %s." % ep_file) - - with open(ep_file, 'r') as file: - config = yaml.safe_load(file) - - sinks = config['sinks'] - for sink in sinks: - if sink['name'] == 'event_sink': - publishers = sink['publishers'] - if event_notifier_topic not in publishers: - print('Add event notifier in ceilometer') - publishers.append(event_notifier_topic) - config_modified = True - else: - print('NOTE: event notifier is configured in ceilometer as we needed') - - if config_modified: - shutil.copyfile(ep_file, ep_file_bak) - with open(ep_file, 'w+') as file: - file.write(yaml.safe_dump(config)) - - -set_notifier_topic() diff --git a/tests/installer/local.py b/tests/installer/local.py deleted file mode 100644 index dcdf41e3..00000000 --- a/tests/installer/local.py +++ /dev/null @@ -1,109 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os -import shutil -import subprocess - -from installer.base import BaseInstaller -from common.utils import load_json_file -from common.utils import write_json_file - - -class LocalInstaller(BaseInstaller): - node_user_name = 'root' - - nova_policy_file = '/etc/nova/policy.json' - nova_policy_file_backup = '%s%s' % (nova_policy_file, '.bak') - - def __init__(self, conf, log): - super(LocalInstaller, self).__init__(conf, log) - self.policy_modified = False - self.add_policy_file = False - - def setup(self): - self.get_ssh_key_from_installer() - self.set_apply_patches() - - def cleanup(self): - self.restore_apply_patches() - - def get_ssh_key_from_installer(self): - self.log.info('Assuming SSH keys already exchanged with computer for local installer type') - return None - - def get_host_ip_from_hostname(self, hostname): - self.log.info('Get host ip from host name in local installer......') - - cmd = "getent hosts %s | awk '{ print $1 }'" % (hostname) - server = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) - stdout, stderr = server.communicate() - host_ip = stdout.strip() - - self.log.info('Get host_ip:%s from host_name:%s in local installer' % (host_ip, hostname)) - return host_ip - - def set_apply_patches(self): - self._set_nova_policy() - - def restore_apply_patches(self): - self._restore_nova_policy() - - def _set_nova_policy(self): - host_status_policy = 'os_compute_api:servers:show:host_status' - host_status_rule = 'rule:admin_or_owner' - policy_data = { - 'context_is_admin': 'role:admin', - 'owner': 'user_id:%(user_id)s', - 'admin_or_owner': 'rule:context_is_admin or rule:owner', - host_status_policy: host_status_rule - } - - if os.path.isfile(self.nova_policy_file): - data = load_json_file(self.nova_policy_file) - if host_status_policy in data: - rule_origion = data[host_status_policy] - if host_status_rule == rule_origion: - self.log.info('Do not need to modify nova policy.') - self.policy_modified = False - else: - # update the host_status_policy - data[host_status_policy] = host_status_rule - self.policy_modified = True - else: - # add the host_status_policy, if the admin_or_owner is not - # defined, add it also - for policy, rule in policy_data.items(): - if policy not in data: - data[policy] = rule - self.policy_modified = True - if self.policy_modified: - self.log.info('Nova policy is Modified.') - shutil.copyfile(self.nova_policy_file, - self.nova_policy_file_backup) - else: - # file does not exit, create a new one and add the policy - self.log.info('Nova policy file not exist. Creating a new one') - data = policy_data - self.add_policy_file = True - - if self.policy_modified or self.add_policy_file: - write_json_file(self.nova_policy_file, data) - os.system('screen -S stack -p n-api -X stuff "^C^M^[[A^M"') - - def _restore_nova_policy(self): - if self.policy_modified: - shutil.copyfile(self.nova_policy_file_backup, self.nova_policy_file) - os.remove(self.nova_policy_file_backup) - elif self.add_policy_file: - os.remove(self.nova_policy_file) - - if self.add_policy_file or self.policy_modified: - os.system('screen -S stack -p n-api -X stuff "^C^M^[[A^M"') - self.add_policy_file = False - self.policy_modified = False diff --git a/tests/instance.py b/tests/instance.py deleted file mode 100644 index c6acbc3d..00000000 --- a/tests/instance.py +++ /dev/null @@ -1,114 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os -import time - -from oslo_config import cfg - -from identity_auth import get_identity_auth -from identity_auth import get_session -from os_clients import neutron_client -from os_clients import nova_client - -OPTS = [ - cfg.StrOpt('flavor', - default='m1.tiny', - help='the name of flavor', - required=True), - cfg.IntOpt('instance_count', - default=os.environ.get('VM_COUNT', 1), - help='the count of instance', - required=True), - cfg.StrOpt('instance_basename', - default='doctor_vm', - help='the base name of instance', - required=True), -] - - -class Instance(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - self.auth = get_identity_auth(username=self.conf.doctor_user, - password=self.conf.doctor_passwd, - project=self.conf.doctor_project) - self.nova = \ - nova_client(conf.nova_version, - get_session(auth=self.auth)) - self.neutron = neutron_client(get_session(auth=self.auth)) - self.servers = {} - self.vm_names = [] - - def create(self): - self.log.info('instance create start......') - - # get flavor, image and network for vm boot - flavors = {flavor.name: flavor for flavor in self.nova.flavors.list()} - flavor = flavors.get(self.conf.flavor) - image = self.nova.glance.find_image(self.conf.image_name) - network = self.neutron.list_networks(name=self.conf.net_name)['networks'][0] - nics = {'net-id': network['id']} - - self.servers = \ - {getattr(server, 'name'): server - for server in self.nova.servers.list()} - for i in range(0, self.conf.instance_count): - vm_name = "%s%d"%(self.conf.instance_basename, i) - self.vm_names.append(vm_name) - if vm_name not in self.servers: - server = self.nova.servers.create(vm_name, image, - flavor, nics=[nics]) - self.servers[vm_name] = server - time.sleep(0.1) - - self.log.info('instance create end......') - - def delete(self): - self.log.info('instance delete start.......') - - for vm_name in self.vm_names: - if vm_name in self.servers: - self.nova.servers.delete(self.servers[vm_name]) - time.sleep(0.1) - - # check that all vms are deleted - while self.nova.servers.list(): - time.sleep(0.1) - self.servers.clear() - del self.vm_names[:] - - self.log.info('instance delete end.......') - - def wait_for_vm_launch(self): - self.log.info('wait for vm launch start......') - - wait_time = 60 - count = 0 - while count < wait_time: - active_count = 0 - for vm_name in self.vm_names: - server = self.nova.servers.get(self.servers[vm_name]) - server_status = getattr(server, 'status').lower() - if 'active' == server_status: - active_count += 1 - elif 'error' == server_status: - raise Exception('vm launched with error state') - else: - time.sleep(2) - count += 1 - continue - if active_count == self.conf.instance_count: - self.log.info('wait for vm launch end......') - return - count += 1 - time.sleep(2) - raise Exception('time out for vm launch') - diff --git a/tests/logger.py b/tests/logger.py deleted file mode 100644 index b7a49fdb..00000000 --- a/tests/logger.py +++ /dev/null @@ -1,46 +0,0 @@ -############################################################################## -# Copyright (c) 2016 ZTE Corporation 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 -############################################################################## -# Usage: -# import doctor_logger -# logger = doctor_logger.Logger("script_name").getLogger() -# logger.info("message to be shown with - INFO - ") -# logger.debug("message to be shown with - DEBUG -") - -import logging -import os - - -class Logger(object): - def __init__(self, logger_name): - - CI_DEBUG = os.getenv('CI_DEBUG') - - self.logger = logging.getLogger(logger_name) - self.logger.propagate = 0 - self.logger.setLevel(logging.DEBUG) - - formatter = logging.Formatter('%(asctime)s %(filename)s %(lineno)d ' - '%(levelname)-6s %(message)s') - - ch = logging.StreamHandler() - ch.setFormatter(formatter) - if CI_DEBUG is not None and CI_DEBUG.lower() == "true": - ch.setLevel(logging.DEBUG) - else: - ch.setLevel(logging.INFO) - self.logger.addHandler(ch) - - filename = '%s.log' % logger_name - file_handler = logging.FileHandler(filename, mode='w') - file_handler.setFormatter(formatter) - file_handler.setLevel(logging.DEBUG) - self.logger.addHandler(file_handler) - - def getLogger(self): - return self.logger diff --git a/tests/main.py b/tests/main.py deleted file mode 100644 index df7e95f3..00000000 --- a/tests/main.py +++ /dev/null @@ -1,217 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os -from os.path import isfile, join -import random -import sys -import time - -from alarm import Alarm -from common.constants import Host -from common.utils import match_rep_in_file -import config -from consumer import get_consumer -from identity_auth import get_identity_auth -from identity_auth import get_session -from image import Image -from instance import Instance -from inspector import get_inspector -from installer import get_installer -import logger as doctor_log -from network import Network -from monitor import get_monitor -from os_clients import nova_client -from profiler_poc import main as profiler_main -from scenario.common import calculate_notification_time -from scenario.network_failure import NetworkFault -from user import User - - -LOG = doctor_log.Logger('doctor').getLogger() - - -class DoctorTest(object): - - def __init__(self, conf): - self.conf = conf - self.image = Image(self.conf, LOG) - self.user = User(self.conf, LOG) - self.network = Network(self.conf, LOG) - self.instance = Instance(self.conf, LOG) - self.alarm = Alarm(self.conf, LOG) - self.installer = get_installer(self.conf, LOG) - self.inspector = get_inspector(self.conf, LOG) - self.monitor = get_monitor(self.conf, - self.inspector.get_inspector_url(), - LOG) - self.consumer = get_consumer(self.conf, LOG) - self.fault = NetworkFault(self.conf, self.installer, LOG) - auth = get_identity_auth(project=self.conf.doctor_project) - self.nova = nova_client(self.conf.nova_version, - get_session(auth=auth)) - self.down_host = None - - def setup(self): - # prepare the cloud env - self.installer.setup() - - # preparing VM image... - self.image.create() - - # creating test user... - self.user.create() - self.user.update_quota() - - # creating VM... - self.network.create() - self.instance.create() - self.instance.wait_for_vm_launch() - - # creating alarm... - self.alarm.create() - - # starting doctor sample components... - self.inspector.start() - - self.down_host = self.get_host_info_for_random_vm() - self.monitor.start(self.down_host) - - self.consumer.start() - - def run(self): - """run doctor test""" - try: - LOG.info('doctor test starting.......') - - # prepare test env - self.setup() - - # wait for aodh alarms are updated in caches for event evaluator, - # sleep time should be larger than event_alarm_cache_ttl(default 60) - time.sleep(60) - - # injecting host failure... - # NOTE (umar) add INTERFACE_NAME logic to host injection - - self.fault.start(self.down_host) - time.sleep(10) - - # verify the test results - # NOTE (umar) copy remote monitor.log file when monitor=collectd - self.check_host_status(self.down_host.name, 'down') - - notification_time = calculate_notification_time() - if notification_time < 1 and notification_time > 0: - LOG.info('doctor test successfully, notification_time=%s' % notification_time) - else: - LOG.error('doctor test failed, notification_time=%s' % notification_time) - sys.exit(1) - - if self.conf.profiler_type: - LOG.info('doctor test begin to run profile.......') - self.collect_logs() - self.run_profiler() - except Exception as e: - LOG.error('doctor test failed, Exception=%s' % e) - sys.exit(1) - finally: - self.cleanup() - - def get_host_info_for_random_vm(self): - num = random.randint(0, self.conf.instance_count - 1) - vm_name = "%s%d" % (self.conf.instance_basename, num) - - servers = \ - {getattr(server, 'name'): server - for server in self.nova.servers.list()} - server = servers.get(vm_name) - if not server: - raise \ - Exception('Can not find instance: vm_name(%s)' % vm_name) - host_name = server.__dict__.get('OS-EXT-SRV-ATTR:hypervisor_hostname') - host_ip = self.installer.get_host_ip_from_hostname(host_name) - - LOG.info('Get host info(name:%s, ip:%s) which vm(%s) launched at' - % (host_name, host_ip, vm_name)) - return Host(host_name, host_ip) - - def check_host_status(self, hostname, state): - service = self.nova.services.list(host=hostname, binary='nova-compute') - host_state = service[0].__dict__.get('state') - assert host_state == state - - def unset_forced_down_hosts(self): - if self.down_host: - self.nova.services.force_down(self.down_host.name, 'nova-compute', False) - time.sleep(2) - self.check_host_status(self.down_host.name, 'up') - - def collect_logs(self): - self.fault.get_disable_network_log() - - def run_profiler(self): - - log_file = '{0}/{1}'.format(sys.path[0], 'disable_network.log') - reg = '(?<=doctor set link down at )\d+.\d+' - linkdown = float(match_rep_in_file(reg, log_file).group(0)) - - log_file = '{0}/{1}'.format(sys.path[0], 'doctor.log') - reg = '(.* doctor mark vm.* error at )(\d+.\d+)' - vmdown = float(match_rep_in_file(reg, log_file).group(2)) - - reg = '(?<=doctor mark host.* down at )\d+.\d+' - hostdown = float(match_rep_in_file(reg, log_file).group(2)) - - reg = '(?<=doctor monitor detected at )\d+.\d+' - detected = float(match_rep_in_file(reg, log_file).group(0)) - - reg = '(?<=doctor consumer notified at )\d+.\d+' - notified = float(match_rep_in_file(reg, log_file).group(0)) - - # TODO(yujunz) check the actual delay to verify time sync status - # expected ~1s delay from $trigger to $linkdown - relative_start = linkdown - os.environ['DOCTOR_PROFILER_T00'] = str(int((linkdown - relative_start)*1000)) - os.environ['DOCTOR_PROFILER_T01'] = str(int((detected - relative_start) * 1000)) - os.environ['DOCTOR_PROFILER_T03'] = str(int((vmdown - relative_start) * 1000)) - os.environ['DOCTOR_PROFILER_T04'] = str(int((hostdown - relative_start) * 1000)) - os.environ['DOCTOR_PROFILER_T09'] = str(int((notified - relative_start) * 1000)) - - profiler_main(log=LOG) - - def cleanup(self): - self.unset_forced_down_hosts() - self.inspector.stop() - self.monitor.stop() - self.consumer.stop() - self.installer.cleanup() - self.alarm.delete() - self.instance.delete() - self.network.delete() - self.image.delete() - self.fault.cleanup() - self.user.delete() - - -def main(): - """doctor main""" - doctor_root_dir = os.path.dirname(sys.path[0]) - config_file_dir = '{0}/{1}'.format(doctor_root_dir, 'etc/') - config_files = [join(config_file_dir, f) for f in os.listdir(config_file_dir) - if isfile(join(config_file_dir, f))] - - conf = config.prepare_conf(args=sys.argv[1:], - config_files=config_files) - - doctor = DoctorTest(conf) - doctor.run() - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tests/monitor/__init__.py b/tests/monitor/__init__.py deleted file mode 100644 index e268907f..00000000 --- a/tests/monitor/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 oslo_config import cfg -from oslo_utils import importutils - -OPTS = [ - cfg.StrOpt('type', - default='sample', - choices=['sample', 'collectd'], - help='the type of doctor monitor component', - required=True), -] - - -_monitor_name_class_mapping = { - 'sample': 'monitor.sample.SampleMonitor', - 'collectd': 'monitor.collectd.CollectdMonitor' -} - -def get_monitor(conf, inspector_url, log): - monitor_class = _monitor_name_class_mapping.get(conf.monitor.type) - return importutils.import_object(monitor_class, conf, - inspector_url, log) diff --git a/tests/monitor/base.py b/tests/monitor/base.py deleted file mode 100644 index 119c8a1c..00000000 --- a/tests/monitor/base.py +++ /dev/null @@ -1,27 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import abc -import six - - -@six.add_metaclass(abc.ABCMeta) -class BaseMonitor(object): - """Monitor computer fault and report error to the inspector""" - def __init__(self, conf, inspector_url, log): - self.conf = conf - self.log = log - self.inspector_url = inspector_url - - @abc.abstractmethod - def start(self, host): - pass - - @abc.abstractmethod - def stop(self): - pass diff --git a/tests/monitor/collectd.py b/tests/monitor/collectd.py deleted file mode 100644 index e2a800ea..00000000 --- a/tests/monitor/collectd.py +++ /dev/null @@ -1,138 +0,0 @@ -############################################################################## -# Copyright (c) 2017 NEC Corporation 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 -############################################################################## - -import os -import socket -import getpass -import sys - -from monitor.base import BaseMonitor - - -class CollectdMonitor(BaseMonitor): - def __init__(self, conf, inspector_url, log): - super(CollectdMonitor, self).__init__(conf, inspector_url, log) - self.top_dir = os.path.dirname(sys.path[0]) - tmp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - tmp_sock.connect(("8.8.8.8", 80)) - - ## control_ip is the IP of primary interface of control node i.e. - ## eth0, eno1. It is used by collectd monitor to communicate with - ## sample inspector. - ## TODO (umar) see if mgmt IP of control is a better option. Also - ## primary interface may not be the right option - self.control_ip = tmp_sock.getsockname()[0] - self.compute_user = getpass.getuser() - self.interface_name = os.environ.get('INTERFACE_NAME') or '' - self.inspector_type = os.environ.get('INSPECTOR_TYPE', 'sample') - self.auth_url = os.environ.get('OS_AUTH_URL') - self.username = os.environ.get('OS_USERNAME') - self.password = os.environ.get('OS_PASSWORD') - self.project_name = os.environ.get('OS_PROJECT_NAME') - self.user_domain_name = os.environ.get('OS_USER_DOMAIN_NAME') or 'default' - self.user_domain_id = os.environ.get('OS_USER_DOMAIN_ID') - self.project_domain_name = os.environ.get('OS_PROJECT_DOMAIN_NAME') or 'default' - self.project_domain_id = os.environ.get('OS_PROJECT_DOMAIN_ID') - self.ssh_opts_cpu = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' - - def start(self, host): - self.log.info("Collectd monitor start.........") - self.compute_host = host.name - self.compute_ip = host.ip - f = open("%s/tests/collectd.conf" % self.top_dir, 'w') - collectd_conf_file = """ -Hostname %s -FQDNLookup false -Interval 1 -MaxReadInterval 2 - -<LoadPlugin python> -Globals true -</LoadPlugin> -LoadPlugin ovs_events -LoadPlugin logfile - -<Plugin logfile> - File \"/var/log/collectd.log\" - Timestamp true - LogLevel \"info\" -</Plugin> - -<Plugin python> - ModulePath \"/home/%s\" - LogTraces true - Interactive false - Import \"collectd_plugin\" - <Module \"collectd_plugin\"> - control_ip \"%s\" - compute_ip \"%s\" - compute_host \"%s\" - compute_user \"%s\" - inspector_type \"%s\" - os_auth_url \"%s\" - os_username \"%s\" - os_password \"%s\" - os_project_name \"%s\" - os_user_domain_name \"%s\" - os_user_domain_id \"%s\" - os_project_domain_name \"%s\" - os_project_domain_id \"%s\" - </Module> -</Plugin> - -<Plugin ovs_events> - Port 6640 - Socket \"/var/run/openvswitch/db.sock\" - Interfaces \"@INTERFACE_NAME@\" - SendNotification true - DispatchValues false -</Plugin> - """ % (self.compute_host, self.compute_user, self.control_ip, self.compute_ip, self.compute_host, self.compute_user, - self.inspector_type, self.auth_url, self.username, self.password, self.project_name, self.user_domain_name, - self.user_domain_id, self.project_domain_name, self.project_domain_id) - f.write(collectd_conf_file) - f.close() - - os.system(" scp %s %s/tests/collectd.conf %s@%s: " % (self.ssh_opts_cpu, self.top_dir, self.compute_user, self.compute_ip)) - self.log.info("after first scp") - ## @TODO (umar) Always assuming that the interface is assigned an IP if - ## interface name is not provided. See if there is a better approach - os.system(""" ssh %s %s@%s \"if [ -n \"%s\" ]; then - dev=%s - else - dev=\$(sudo ip a | awk '/ %s\//{print \$NF}') - fi - sed -i -e \"s/@INTERFACE_NAME@/\$dev/\" collectd.conf - collectd_conf=/opt/collectd/etc/collectd.conf - if [ -e \$collectd_conf ]; then - sudo cp \$collectd_conf \${collectd_conf}-doctor-saved - else - sudo touch \${collectd_conf}-doctor-created - fi - sudo mv collectd.conf /opt/collectd/etc/collectd.conf\" """ % (self.ssh_opts_cpu, self.compute_user, self.compute_ip, self.interface_name, self.interface_name, self.compute_ip)) - self.log.info("after first ssh") - os.system(" scp %s %s/tests/lib/monitors/collectd/collectd_plugin.py %s@%s:collectd_plugin.py " % (self.ssh_opts_cpu, self.top_dir, self.compute_user, self.compute_ip)) - self.log.info("after sec scp") - os.system(" ssh %s %s@%s \"sudo pkill collectd; sudo /opt/collectd/sbin/collectd\" " % (self.ssh_opts_cpu, self.compute_user, self.compute_ip)) - self.log.info("after sec ssh") - - def stop(self): - os.system(" ssh %s %s@%s \"sudo pkill collectd\" " % (self.ssh_opts_cpu, self.compute_user, self.compute_ip)) - - def cleanup(self): - os.system(""" ssh %s %s@%s \" - collectd_conf=/opt/collectd/etc/collectd.conf - if [ -e \"\${collectd_conf}-doctor-created\" ]; then - sudo rm \"\${collectd_conf}-doctor-created\" - sudo rm \$collectd_conf - elif [ -e \"\${collectd_conf}-doctor-saved\" ]; then - sudo cp -f \"\${collectd_conf}-doctor-saved\" \$collectd_conf - sudo rm \"\${collectd_conf}-doctor-saved\" - fi\" """ % (self.ssh_opts_cpu, self.compute_user, self.compute_ip)) - os.remove("%s/tests/collectd.conf" % self.top_dir) diff --git a/tests/monitor/sample.py b/tests/monitor/sample.py deleted file mode 100644 index 9ac1bccf..00000000 --- a/tests/monitor/sample.py +++ /dev/null @@ -1,106 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 datetime import datetime -import json -import requests -import socket -from threading import Thread -import time - -from identity_auth import get_session -from monitor.base import BaseMonitor - - -class SampleMonitor(BaseMonitor): - event_type = "compute.host.down" - - def __init__(self, conf, inspector_url, log): - super(SampleMonitor, self).__init__(conf, inspector_url, log) - self.session = get_session() - self.pinger = None - - def start(self, host): - self.log.info('sample monitor start......') - self.pinger = Pinger(host.name, host.ip, self, self.log) - self.pinger.start() - - def stop(self): - self.log.info('sample monitor stop......') - if self.pinger is not None: - self.pinger.stop() - self.pinger.join() - - def report_error(self, hostname): - self.log.info('sample monitor report error......') - data = [ - { - 'id': 'monitor_sample_id1', - 'time': datetime.now().isoformat(), - 'type': self.event_type, - 'details': { - 'hostname': hostname, - 'status': 'down', - 'monitor': 'monitor_sample', - 'monitor_event_id': 'monitor_sample_event1' - }, - }, - ] - - auth_token = self.session.get_token() if \ - self.conf.inspector.type != 'sample' else None - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-Auth-Token': auth_token, - } - - url = '%s%s' % (self.inspector_url, 'events') \ - if self.inspector_url.endswith('/') else \ - '%s%s' % (self.inspector_url, '/events') - requests.put(url, data=json.dumps(data), headers=headers) - - -class Pinger(Thread): - interval = 0.1 # second - timeout = 0.1 # second - ICMP_ECHO_MESSAGE = bytes([0x08, 0x00, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00]) - - def __init__(self, host_name, host_ip, monitor, log): - Thread.__init__(self) - self.monitor = monitor - self.hostname = host_name - self.ip_addr = host_ip or socket.gethostbyname(self.hostname) - self.log = log - self._stopped = False - - def run(self): - self.log.info("Starting Pinger host_name(%s), host_ip(%s)" - % (self.hostname, self.ip_addr)) - - sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, - socket.IPPROTO_ICMP) - sock.settimeout(self.timeout) - while True: - if self._stopped: - return - try: - sock.sendto(self.ICMP_ECHO_MESSAGE, (self.ip_addr, 0)) - sock.recv(4096) - except socket.timeout: - self.log.info("doctor monitor detected at %s" % time.time()) - self.monitor.report_error(self.hostname) - self.log.info("ping timeout, quit monitoring...") - self._stopped = True - return - time.sleep(self.interval) - - def stop(self): - self.log.info("Stopping Pinger host_name(%s), host_ip(%s)" - % (self.hostname, self.ip_addr)) - self._stopped = True diff --git a/tests/network.py b/tests/network.py deleted file mode 100644 index da7ad09d..00000000 --- a/tests/network.py +++ /dev/null @@ -1,68 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 oslo_config import cfg - -from identity_auth import get_identity_auth -from identity_auth import get_session -from os_clients import neutron_client - - -OPTS = [ - cfg.StrOpt('net_name', - default='doctor_net', - help='the name of test net', - required=True), - cfg.StrOpt('net_cidr', - default='192.168.168.0/24', - help='the cidr of test subnet', - required=True), -] - - -class Network(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - self.auth = get_identity_auth(username=self.conf.doctor_user, - password=self.conf.doctor_passwd, - project=self.conf.doctor_project) - self.neutron = neutron_client(get_session(auth=self.auth)) - self.net = None - self.subnet = None - - def create(self): - self.log.info('network create start.......') - net_name = self.conf.net_name - networks = self.neutron.list_networks(name=net_name)['networks'] - self.net = networks[0] if networks \ - else self.neutron.create_network( - {'network': {'name': net_name}})['network'] - self.log.info('network create end.......') - - self.log.info('subnet create start.......') - subnets = self.neutron.list_subnets(network_id=self.net['id'])['subnets'] - subnet_param = {'name': net_name, 'network_id': self.net['id'], - 'cidr': self.conf.net_cidr, 'ip_version': 4, - 'enable_dhcp': False} - self.subnet = subnets[0] if subnets \ - else self.neutron.create_subnet( - {'subnet': subnet_param})['subnet'] - self.log.info('subnet create end.......') - - def delete(self): - self.log.info('subnet delete start.......') - if self.subnet: - self.neutron.delete_subnet(self.subnet['id']) - self.log.info('subnet delete end.......') - - self.log.info('network delete start.......') - if self.net: - self.neutron.delete_network(self.net['id']) - self.log.info('network delete end.......') diff --git a/tests/os_clients.py b/tests/os_clients.py deleted file mode 100644 index 44fa3aad..00000000 --- a/tests/os_clients.py +++ /dev/null @@ -1,50 +0,0 @@ -##############################################################################
-# Copyright (c) 2017 ZTE Corporation 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 oslo_config import cfg
-
-import aodhclient.client as aodhclient
-from congressclient.v1 import client as congressclient
-import glanceclient.client as glanceclient
-from keystoneclient.v2_0 import client as ks_client
-from neutronclient.v2_0 import client as neutronclient
-import novaclient.client as novaclient
-
-
-OPTS = [
- cfg.StrOpt('glance_version', default='2', help='glance version'),
- cfg.StrOpt('nova_version', default='2.34', help='Nova version'),
- cfg.StrOpt('aodh_version', default='2', help='aodh version'),
-]
-
-
-def glance_client(version, session):
- return glanceclient.Client(version=version,
- session=session)
-
-
-def keystone_client(session):
- return ks_client.Client(session=session)
-
-
-def nova_client(version, session):
- return novaclient.Client(version=version,
- session=session)
-
-
-def neutron_client(session):
- return neutronclient.Client(session=session)
-
-
-def aodh_client(version, session):
- return aodhclient.Client(version, session=session)
-
-
-def congress_client(session):
- return congressclient.Client(session=session,
- service_type='policy')
diff --git a/tests/profiler_poc.py b/tests/profiler_poc.py deleted file mode 100644 index ea36eaeb..00000000 --- a/tests/profiler_poc.py +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################## -# Copyright (c) 2016 ZTE Corporation 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 -############################################################################## - -""" -PoC of performance profiler for OPNFV doctor project - -Usage: - -Export environment variables to set timestamp at each checkpoint in millisecond. -Valid check points are: DOCTOR_PROFILER_T{00-09} - -See also: https://goo.gl/98Osig -""" - -import json -import os - -from oslo_config import cfg - - -OPTS = [ - cfg.StrOpt('profiler_type', - default=os.environ.get('PROFILER_TYPE', 'poc'), - help='the type of installer'), -] - - -OUTPUT = 'doctor_profiling_output' -PREFIX = 'DOCTOR_PROFILER' -TOTAL_CHECK_POINTS = 10 -MODULE_CHECK_POINTS = ['T00', 'T01', 'T04', 'T05', 'T06', 'T09'] -TAG_FORMAT = "{:<5}" -# Inspired by https://github.com/reorx/httpstat -TEMPLATE = """ -Total time cost: {total}(ms) -==============================================================================> - |Monitor|Inspector |Controller|Notifier|Evaluator | - |{M00} |{M01} |{M02} |{M03} |{M04} | - | | | | | | | | | | -link down:{T00}| | | | | | | | | - raw failure:{T01}| | | | | | | | - found affected:{T02}| | | | | | | - set VM error:{T03}| | | | | | - marked host down:{T04}| | | | | - notified VM error:{T05} | | | | - transformed event:{T06}| | | - evaluated event:{T07}| | - fired alarm:{T08}| - received alarm:{T09} -""" - - -def main(log=None): - check_points = ["T{:02d}".format(i) for i in range(TOTAL_CHECK_POINTS)] - module_map = {"M{:02d}".format(i): - (MODULE_CHECK_POINTS[i], MODULE_CHECK_POINTS[i + 1]) - for i in range(len(MODULE_CHECK_POINTS) - 1)} - - # check point tags - elapsed_ms = {cp: os.getenv("{}_{}".format(PREFIX, cp)) - for cp in check_points} - - def format_tag(tag): - return TAG_FORMAT.format(tag or '?') - - tags = {cp: format_tag(ms) for cp, ms in elapsed_ms.items()} - - def time_cost(cp): - if elapsed_ms[cp[0]] and elapsed_ms[cp[1]]: - return int(elapsed_ms[cp[1]]) - int(elapsed_ms[cp[0]]) - else: - return None - - # module time cost tags - modules_cost_ms = {module: time_cost(cp) - for module, cp in module_map.items()} - - tags.update({module: format_tag(cost) - for module, cost in modules_cost_ms.items()}) - - tags.update({'total': time_cost((check_points[0], check_points[-1]))}) - - profile = TEMPLATE.format(**tags) - - logfile = open('{}.json'.format(OUTPUT), 'w') - logfile.write(json.dumps(tags)) - - print(profile) - if log: - log.info('%s' % profile) - - -if __name__ == '__main__': - main() diff --git a/tests/run.sh b/tests/run.sh index e1875e09..b5c56872 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -42,6 +42,8 @@ ceilometer="ceilometer $as_doctor_user" as_admin_user="--os-username admin --os-project-name $DOCTOR_PROJECT --os-tenant-name $DOCTOR_PROJECT" +upper_constraints="https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/ocata" +pip_install="pip install -c${upper_constraints}" # Functions @@ -477,16 +479,16 @@ cleanup() { } setup_python_packages() { - sudo pip install flask==0.10.1 - command -v openstack || sudo pip install python-openstackclient==2.3.0 - command -v ceilometer || sudo pip install python-ceilometerclient==2.6.2 - command -v congress || sudo pip install python-congressclient==1.5.0 + pip freeze |grep -i flask\= > /dev/null || sudo ${pip_install} flask + command -v openstack || sudo ${pip_install} python-openstackclient + command -v ceilometer || sudo ${pip_install} python-ceilometerclient + command -v congress || sudo ${pip_install} python-congressclient } # Main process if [[ $PYTHON_ENABLE == [Tt]rue ]]; then - which tox || sudo pip install tox + which tox || sudo ${pip_install} tox if [ -f /usr/bin/apt-get ]; then sudo apt-get install -y python3-dev elif [ -f /usr/bin/yum ] ; then diff --git a/tests/scenario/__init__.py b/tests/scenario/__init__.py deleted file mode 100644 index 48893ae6..00000000 --- a/tests/scenario/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## diff --git a/tests/scenario/common.py b/tests/scenario/common.py deleted file mode 100644 index a33c50ff..00000000 --- a/tests/scenario/common.py +++ /dev/null @@ -1,28 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import sys -from common.utils import match_rep_in_file - - -def calculate_notification_time(): - log_file = '{0}/{1}'.format(sys.path[0], 'doctor.log') - - reg = '(?<=doctor monitor detected at )\d+.\d+' - result = match_rep_in_file(reg, log_file) - if not result: - raise Exception('Can not match detected time') - detected = result.group(0) - - reg = '(?<=doctor consumer notified at )\d+.\d+' - result = match_rep_in_file(reg, log_file) - if not result: - raise Exception('Can not match notified time') - notified = result.group(0) - - return float(notified) - float(detected)
\ No newline at end of file diff --git a/tests/scenario/network_failure.py b/tests/scenario/network_failure.py deleted file mode 100644 index e9a239db..00000000 --- a/tests/scenario/network_failure.py +++ /dev/null @@ -1,71 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 identity_auth import get_session -from os_clients import nova_client -from common.utils import SSHClient - -LINK_DOWN_SCRIPT = """ -#!/bin/bash -x -dev=$(sudo ip a | awk '/ {compute_ip}\//{{print $NF}}') -sleep 1 -sudo ip link set $dev down -echo "doctor set link down at" $(date "+%s.%N") -sleep 10 -sudo ip link set $dev up -sleep 1 -""" - - -class NetworkFault(object): - - def __init__(self, conf, installer, log): - self.conf = conf - self.log = log - self.installer = installer - self.nova = nova_client(self.conf.nova_version, get_session()) - self.host = None - self.GetLog = False - - def start(self, host): - self.log.info('fault inject start......') - self._set_link_down(host.ip) - self.host = host - self.log.info('fault inject end......') - - def cleanup(self): - self.log.info('fault inject cleanup......') - self.get_disable_network_log() - - def get_disable_network_log(self): - if self.GetLog: - self.log.info('Already get the disable_netork.log from down_host......') - return - if self.host is not None: - client = SSHClient(self.host.ip, - self.installer.node_user_name, - key_filename=self.installer.get_ssh_key_from_installer(), - look_for_keys=True, - log=self.log) - client.scp('disable_network.log', './disable_network.log', method='get') - self.log.info('Get the disable_netork.log from down_host(host_name:%s, host_ip:%s)' - % (self.host.name, self.host.ip)) - self.GetLog = True - - def _set_link_down(self, compute_ip): - file_name = './disable_network.sh' - with open(file_name, 'w') as file: - file.write(LINK_DOWN_SCRIPT.format(compute_ip=compute_ip)) - client = SSHClient(compute_ip, - self.installer.node_user_name, - key_filename=self.installer.get_ssh_key_from_installer(), - look_for_keys=True, - log=self.log) - client.scp('./disable_network.sh', 'disable_network.sh') - command = 'bash disable_network.sh > disable_network.log 2>&1 &' - client.ssh(command) diff --git a/tests/user.py b/tests/user.py deleted file mode 100644 index b21bd1a8..00000000 --- a/tests/user.py +++ /dev/null @@ -1,163 +0,0 @@ -############################################################################## -# Copyright (c) 2017 ZTE Corporation 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 -############################################################################## -import os - -from oslo_config import cfg - -from identity_auth import get_session -from os_clients import keystone_client -from os_clients import nova_client - - -OPTS = [ - cfg.StrOpt('doctor_user', - default='doctor', - help='the name of test user', - required=True), - cfg.StrOpt('doctor_passwd', - default='doctor', - help='the password of test user', - required=True), - cfg.StrOpt('doctor_project', - default='doctor', - help='the name of test project', - required=True), - cfg.StrOpt('doctor_role', - default='_member_', - help='the role of test user', - required=True), - cfg.IntOpt('quota_instances', - default=os.environ.get('VM_COUNT', 1), - help='the quota of instances in test user', - required=True), - cfg.IntOpt('quota_cores', - default=os.environ.get('VM_COUNT', 1), - help='the quota of cores in test user', - required=True), -] - - -class User(object): - - def __init__(self, conf, log): - self.conf = conf - self.log = log - self.keystone = \ - keystone_client(get_session()) - self.nova = \ - nova_client(conf.nova_version, get_session()) - self.users = {} - self.projects = {} - self.roles = {} - self.roles_for_user = {} - self.roles_for_admin = {} - - def create(self): - """create test user, project and etc""" - self.log.info('user create start......') - - self._create_project() - self._create_user() - self._create_role() - self._add_user_role_in_project(is_admin=False) - self._add_user_role_in_project(is_admin=True) - - self.log.info('user create end......') - - def _create_project(self): - """create test project""" - self.projects = {project.name: project - for project in self.keystone.tenants.list()} - if self.conf.doctor_project not in self.projects: - test_project = \ - self.keystone.tenants.create(self.conf.doctor_project) - self.projects[test_project.name] = test_project - - def _create_user(self): - """create test user""" - project = self.projects.get(self.conf.doctor_project) - self.users = {user.name: user for user in self.keystone.users.list()} - if self.conf.doctor_user not in self.users: - test_user = self.keystone.users.create( - self.conf.doctor_user, - password=self.conf.doctor_passwd, - tenant_id=project.id) - self.users[test_user.name] = test_user - - def _create_role(self): - """create test role""" - self.roles = {role.name: role for role in self.keystone.roles.list()} - if self.conf.doctor_role not in self.roles: - test_role = self.keystone.roles.create(self.conf.doctor_role) - self.roles[test_role.name] = test_role - - def _add_user_role_in_project(self, is_admin=False): - """add test user with test role in test project""" - project = self.projects.get(self.conf.doctor_project) - - user_name = 'admin' if is_admin else self.conf.doctor_user - user = self.users.get(user_name) - - role_name = 'admin' if is_admin else self.conf.doctor_role - role = self.roles.get(role_name) - - roles_for_user = self.roles_for_admin \ - if is_admin else self.roles_for_user - - roles_for_user = \ - {role.name: role for role in - self.keystone.roles.roles_for_user(user, tenant=project)} - if role_name not in roles_for_user: - self.keystone.roles.add_user_role(user, role, tenant=project) - roles_for_user[role_name] = role - - def delete(self): - """delete the test user, project and role""" - self.log.info('user delete start......') - - project = self.projects.get(self.conf.doctor_project) - user = self.users.get(self.conf.doctor_user) - role = self.roles.get(self.conf.doctor_role) - - if project: - if 'admin' in self.roles_for_admin: - self.keystone.roles.remove_user_role( - self.users['admin'], - self.roles['admin'], - tenant=project) - - if user: - if role and self.conf.doctor_role in self.roles_for_user: - self.keystone.roles.remove_user_role( - user, role, tenant=project) - self.keystone.roles.delete(role) - self.keystone.users.delete(user) - - self.keystone.tenants.delete(project) - self.log.info('user delete end......') - - def update_quota(self): - self.log.info('user quota update start......') - project = self.projects.get(self.conf.doctor_project) - user = self.users.get(self.conf.doctor_user) - - if project and user: - self.quota = self.nova.quotas.get(project.id, - user_id=user.id) - if self.conf.quota_instances > self.quota.instances: - self.nova.quotas.update(project.id, - instances=self.conf.quota_instances, - user_id=user.id) - if self.conf.quota_cores > self.quota.cores: - self.nova.quotas.update(project.id, - cores=self.conf.quota_cores, - user_id=user.id) - self.log.info('user quota update end......') - else: - raise Exception('No project or role for update quota') |