*.pyc
.*.sw?
**.log
+*.pyc
+/*.egg-info/
+/build/
/docs_build/
/docs_output/
/releng/
.. _OpenStack CLI manual: https://docs.openstack.org/user-guide/common/cli-set-environment-variables-using-openstack-rc.html
-Then, you can run the script as follows:
+Run Bash Test Script
+~~~~~~~~~~~~~~~~~~~~
+
+You can run the bash script as follows:
.. code-block:: bash
For testing with stable version, checkout stable branch of doctor repo before
'./run.sh'.
+The bash test script will be deprecated(only bug fixes) after E Release.
+
+Run Python Test Script
+~~~~~~~~~~~~~~~~~~~~~~
+
+You can run the python script as follows:
+
+.. code-block:: bash
+
+ git clone https://gerrit.opnfv.org/gerrit/doctor
+ cd doctor && tox
+
+You can see all the configurations with default values in sample configuration
+file `doctor.sample.conf`_. And you can also modify the file to meet your
+environment and then run the test.
+
+.. _doctor.sample.conf: https://git.opnfv.org/doctor/tree/etc/doctor.sample.conf
+
Run Functest Suite
==================
-e INSTALLER_TYPE=${INSTALLER_TYPE} \
-e INSTALLER_IP=${INSTALLER_IP} \
-e INSPECTOR_TYPE=sample \
+ -e PYTHON_ENABLE=True \
opnfv/functest:${DOCKER_TAG} /bin/bash
docker exec <container_id> python /home/opnfv/repos/functest/functest/ci/prepare_env.py start
docker exec <container_id> functest testcase run doctor
+Add an environment variable *PYTHON_ENABLE* to indicate that using Python or
+Bash to run the test when start the docker container.
+
See `Functest Userguide`_ for more information.
.. _Functest Userguide: http://artifacts.opnfv.org/functest/docs/userguide/index.html
##############################################################################
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
+from doctor_tests.identity_auth import get_identity_auth
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import aodh_client
+from doctor_tests.os_clients import nova_client
OPTS = [
cfg.StrOpt('alarm_basename',
\r
from oslo_config import cfg\r
\r
-import alarm\r
-import consumer\r
-import image\r
-import instance\r
-import installer\r
-import network\r
-import inspector\r
-import monitor\r
-import os_clients\r
-import profiler_poc\r
-import user\r
+from doctor_tests import alarm\r
+from doctor_tests import consumer\r
+from doctor_tests import image\r
+from doctor_tests import instance\r
+from doctor_tests import installer\r
+from doctor_tests import network\r
+from doctor_tests import inspector\r
+from doctor_tests import monitor\r
+from doctor_tests import os_clients\r
+from doctor_tests import profiler_poc\r
+from doctor_tests import user\r
\r
\r
def list_opts():\r
_consumer_name_class_mapping = {
- 'sample': 'consumer.sample.SampleConsumer'
+ 'sample': 'doctor_tests.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
+ return importutils.import_object(consumer_class, conf, log)
from threading import Thread
import requests
-from consumer.base import BaseConsumer
+from doctor_tests.consumer.base import BaseConsumer
class SampleConsumer(BaseConsumer):
func()
return 'consumer app shutting down...'
- app.run(host="0.0.0.0", port=self.port)
\ No newline at end of file
+ app.run(host="0.0.0.0", port=self.port)
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-
import os
from keystoneauth1 import loading
from oslo_config import cfg
-from identity_auth import get_session
-from os_clients import glance_client
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import glance_client
OPTS = [
cfg.StrOpt('image_name',
_inspector_name_class_mapping = {
- 'sample': 'inspector.sample.SampleInspector',
- 'congress': 'inspector.congress.CongressInspector',
+ 'sample': 'doctor_tests.inspector.sample.SampleInspector',
+ 'congress': 'doctor_tests.inspector.congress.CongressInspector',
}
# 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 doctor_tests.identity_auth import get_identity_auth
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import congress_client
-from inspector.base import BaseInspector
+from doctor_tests.inspector.base import BaseInspector
class CongressInspector(BaseInspector):
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
+from doctor_tests.common import utils
+from doctor_tests.identity_auth import get_identity_auth
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import nova_client
+from doctor_tests.os_clients import neutron_client
+from doctor_tests.inspector.base import BaseInspector
class SampleInspector(BaseInspector):
_installer_name_class_mapping = {
- 'local': 'installer.local.LocalInstaller',
- 'apex': 'installer.apex.ApexInstaller'
+ 'local': 'doctor_tests.installer.local.LocalInstaller',
+ 'apex': 'doctor_tests.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
+ return importutils.import_object(installer_class, conf, log)
import pwd
import stat
import subprocess
-import sys
-from common.utils import SSHClient
-from installer.base import BaseInstaller
+from doctor_tests.common.utils import SSHClient
+from doctor_tests.installer.base import BaseInstaller
class ApexInstaller(BaseInstaller):
gid = grp.getgrnam(user).gr_gid
os.chown('./instack_key', uid, gid)
os.chmod('./instack_key', stat.S_IREAD)
- current_dir = sys.path[0]
+ current_dir = os.curdir
self.key_file = '{0}/{1}'.format(current_dir, 'instack_key')
return self.key_file
import shutil
import subprocess
-from installer.base import BaseInstaller
-from common.utils import load_json_file
-from common.utils import write_json_file
+from doctor_tests.installer.base import BaseInstaller
+from doctor_tests.common.utils import load_json_file
+from doctor_tests.common.utils import write_json_file
class LocalInstaller(BaseInstaller):
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
+from doctor_tests.identity_auth import get_identity_auth
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import neutron_client
+from doctor_tests.os_clients import nova_client
OPTS = [
cfg.StrOpt('flavor',
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
+from doctor_tests.alarm import Alarm
+from doctor_tests.common.constants import Host
+from doctor_tests.common.utils import match_rep_in_file
+from doctor_tests import config
+from doctor_tests.consumer import get_consumer
+from doctor_tests.identity_auth import get_identity_auth
+from doctor_tests.identity_auth import get_session
+from doctor_tests.image import Image
+from doctor_tests.instance import Instance
+from doctor_tests.inspector import get_inspector
+from doctor_tests.installer import get_installer
+import doctor_tests.logger as doctor_log
+from doctor_tests.network import Network
+from doctor_tests.monitor import get_monitor
+from doctor_tests.os_clients import nova_client
+from doctor_tests.profiler_poc import main as profiler_main
+from doctor_tests.scenario.common import calculate_notification_time
+from doctor_tests.scenario.network_failure import NetworkFault
+from doctor_tests.user import User
LOG = doctor_log.Logger('doctor').getLogger()
def main():
"""doctor main"""
- doctor_root_dir = os.path.dirname(sys.path[0])
+ test_dir = os.path.split(os.path.realpath(__file__))[0]
+ doctor_root_dir = os.path.dirname(test_dir)
+
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))]
doctor = DoctorTest(conf)
doctor.run()
-
-
-if __name__ == '__main__':
- sys.exit(main())
_monitor_name_class_mapping = {
- 'sample': 'monitor.sample.SampleMonitor',
- 'collectd': 'monitor.collectd.CollectdMonitor'
+ 'sample': 'doctor_tests.monitor.sample.SampleMonitor',
+ 'collectd': 'doctor_tests.monitor.collectd.CollectdMonitor'
}
def get_monitor(conf, inspector_url, log):
# 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
+from doctor_tests.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])
+ monitor_dir = os.path.split(os.path.realpath(__file__))[0]
+ self.top_dir = os.path.dirname(monitor_dir)
tmp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
tmp_sock.connect(("8.8.8.8", 80))
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')
+ f = open("%s/collectd.conf" % self.top_dir, 'w')
collectd_conf_file = """
Hostname %s
FQDNLookup false
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))
+ os.system(" scp %s %s/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
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))
+ os.system(" scp %s %s/monitor/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")
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)
+ os.remove("%s/collectd.conf" % self.top_dir)
--- /dev/null
+##############################################################################
+# 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 collectd
+import sys
+from datetime import datetime
+import json
+import requests
+import time
+from requests.exceptions import ConnectionError
+
+from keystoneauth1 import loading
+from keystoneauth1 import session
+from congressclient.v1 import client
+
+
+def write_debug(str_write, write_type, compute_user):
+ file_name = ('/home/%s/monitor.log' % compute_user)
+ file_tmp = open(file_name, write_type)
+ file_tmp.write( "%s" % str_write)
+ file_tmp.close()
+
+
+class DoctorMonitorCollectd(object):
+ def __init__(self):
+ self.control_ip = ''
+ self.compute_user = ''
+ self.compute_ip = ''
+ self.host_name = ''
+ self.inspector_type = ''
+ self.inspector_url = ''
+ self.os_auth_url = ''
+ self.os_username = ''
+ self.os_password = ''
+ self.os_project_name = ''
+ self.os_user_domain_name = ''
+ self.os_user_domain_id = ''
+ self.os_project_domain_name = ''
+ self.os_project_domain_id = ''
+ self.sess = ''
+ self.auth = ''
+ self.inspector_notified = 0
+ self.start_notifications = 0
+ self.monitor_type = 'sample'
+
+ def config_func(self, config):
+ for node in config.children:
+ key = node.key.lower()
+ val = node.values[0]
+
+ if key == 'compute_host':
+ self.host_name = val
+ elif key == 'control_ip':
+ self.control_ip = val
+ elif key == 'compute_ip':
+ self.compute_ip = val
+ elif key == 'compute_user':
+ self.compute_user = val
+ elif key == 'inspector_type':
+ self.inspector_type = val
+ elif key == 'os_auth_url':
+ self.os_auth_url = val
+ elif key == 'os_username':
+ self.os_username = val
+ elif key == 'os_password':
+ self.os_password = val
+ elif key == 'os_project_name':
+ self.os_project_name = val
+ elif key == 'os_user_domain_name':
+ self.os_user_domain_name = val
+ elif key == 'os_user_domain_id':
+ self.os_user_domain_id = val
+ elif key == 'os_project_domain_name':
+ self.os_project_domain_name = val
+ elif key == 'os_project_domain_id':
+ self.os_project_domain_id = val
+ else:
+ collectd.info('Unknown config key "%s"' % key)
+
+ def init_collectd(self):
+ write_debug("Compute node collectd monitor start at %s\n\n" % datetime.now().isoformat(), "w", self.compute_user)
+
+ if self.inspector_type == 'sample':
+ self.inspector_url = ('http://%s:12345/events' % self.control_ip)
+ elif self.inspector_type == 'congress':
+ loader = loading.get_plugin_loader('password')
+ self.auth = loader.load_from_options(auth_url=self.os_auth_url,
+ username=self.os_username,
+ password=self.os_password,
+ project_name=self.os_project_name,
+ user_domain_name=self.os_user_domain_name,
+ user_domain_id=self.os_user_domain_id,
+ project_domain_name=self.os_project_domain_name,
+ project_domain_id=self.os_project_domain_id)
+ self.sess=session.Session(auth=self.auth)
+ congress = client.Client(session=self.sess, service_type='policy')
+ ds = congress.list_datasources()['results']
+ doctor_ds = next((item for item in ds if item['driver'] == 'doctor'),
+ None)
+
+ congress_endpoint = congress.httpclient.get_endpoint(auth=self.auth)
+ self.inspector_url = ('%s/v1/data-sources/%s/tables/events/rows' %
+ (congress_endpoint, doctor_ds['id']))
+ else:
+ sys.exit()
+ self.start_notifications = 1
+
+
+ def notify_inspector(self):
+ event_type = "compute.host.down"
+ payload = [
+ {
+ 'id': ("monitor_%s_id1" % self.monitor_type),
+ 'time': datetime.now().isoformat(),
+ 'type': event_type,
+ 'details': {
+ 'hostname': self.host_name,
+ 'status': 'down',
+ 'monitor': ("monitor_%s" % self.monitor_type),
+ 'monitor_event_id': ("monitor_%s_event1" % self.monitor_type)
+ },
+ },
+ ]
+ data = json.dumps(payload)
+ self.inspector_notified = 1
+
+ if self.inspector_type == 'sample':
+ headers = {'content-type': 'application/json'}
+ try:
+ requests.post(self.inspector_url, data=data, headers=headers)
+ except ConnectionError as err:
+ print err
+ elif self.inspector_type == 'congress':
+ # TODO(umar) enhance for token expiry case
+ headers = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ 'X-Auth-Token': self.sess.get_token()
+ }
+ requests.put(self.inspector_url, data=data, headers=headers)
+
+
+ def handle_notif(self, notification, data=None):
+ if (notification.severity == collectd.NOTIF_FAILURE or
+ notification.severity == collectd.NOTIF_WARNING):
+ if (self.start_notifications == 1 and self.inspector_notified == 0):
+ write_debug("Received down notification: doctor monitor detected at %s\n" % time.time(), "a", self.compute_user)
+ self.notify_inspector()
+
+ elif notification.severity == collectd.NOTIF_OKAY:
+ collectd.info("Interface status: UP again %s\n" % time.time())
+ else:
+ collectd.info("Unknown notification severity %s\n" % notification.severity)
+
+
+monitor = DoctorMonitorCollectd()
+
+collectd.register_config(monitor.config_func)
+collectd.register_init(monitor.init_collectd)
+collectd.register_notification(monitor.handle_notif)
from threading import Thread
import time
-from identity_auth import get_session
-from monitor.base import BaseMonitor
+from doctor_tests.identity_auth import get_session
+from doctor_tests.monitor.base import BaseMonitor
class SampleMonitor(BaseMonitor):
##############################################################################
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 doctor_tests.identity_auth import get_identity_auth
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import neutron_client
OPTS = [
--- /dev/null
+##############################################################################
+# 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
+##############################################################################
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
import sys
-from common.utils import match_rep_in_file
+
+from doctor_tests.common.utils import match_rep_in_file
def calculate_notification_time():
raise Exception('Can not match notified time')
notified = result.group(0)
- return float(notified) - float(detected)
\ No newline at end of file
+ return float(notified) - float(detected)
# 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
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import nova_client
+from doctor_tests.common.utils import SSHClient
LINK_DOWN_SCRIPT = """
#!/bin/bash -x
from oslo_config import cfg
-from identity_auth import get_session
-from os_clients import keystone_client
-from os_clients import nova_client
+from doctor_tests.identity_auth import get_session
+from doctor_tests.os_clients import keystone_client
+from doctor_tests.os_clients import nova_client
OPTS = [
--- /dev/null
+Flask!=0.11,<1.0,>=0.10 # BSD
+paramiko>=2.0 # LGPLv2.1+
+scp
+requests!=2.12.2,>=2.10.0 # Apache-2.0
+oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
+python-openstackclient>=3.3.0 # Apache-2.0
+python-ceilometerclient>=2.5.0 # Apache-2.0
+aodhclient>=0.7.0 # Apache-2.0
+python-keystoneclient>=3.8.0 # Apache-2.0
+python-neutronclient>=5.1.0 # Apache-2.0
+python-novaclient!=7.0.0,>=6.0.0 # Apache-2.0
+python-congressclient<2000,>=1.3.0 # Apache-2.0
+python-glanceclient>=2.5.0 # Apache-2.0
+virtualenv>=13.1.0 # MIT
--- /dev/null
+[metadata]
+name = doctor-tests
+version = 2017.9.0
+home-page = https://wiki.opnfv.org/display/doctor/Doctor+Home
+
+[files]
+packages = doctor_tests
+
+[entry_points]
+console_scripts =
+ doctor-test = doctor_tests.main:main
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2017 Orange 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 setuptools
+
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+ import multiprocessing # noqa
+except ImportError:
+ pass
+
+setuptools.setup(
+ setup_requires=['pbr>=1.8'],
+ pbr=True)
+++ /dev/null
-Flask==0.10.1
-paramiko==1.16.0
-scp==0.10.2
-requests>=2.8.0
-oslo.config==3.22.0 # Apache-2.0
-python-openstackclient==2.3.0
-python-ceilometerclient==2.6.2
-aodhclient==0.7.0
-python-keystoneclient==3.5.0
-python-neutronclient==6.0.0
-python-novaclient==6.0.0
-python-congressclient==1.5.0
-python-glanceclient==2.5.0
-virtualenv==15.1.0
from keystoneauth1 import session
import novaclient.client as novaclient
-import identity_auth
+import doctor_tests.identity_auth
LOG = doctor_log.Logger('doctor_inspector').getLogger()
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
}
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
skipsdist = True
[testenv]
-install_command = pip install -U {opts} {packages}
+usedevelop = True
+install_command = pip install \
+ -chttps://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/ocata \
+ {opts} {packages}
setenv = VIRTUAL_ENV={envdir}
-deps = -r{toxinidir}/test-requirements.txt
+deps = -r{toxinidir}/requirements.txt
passenv =
OS_AUTH_URL
OS_USERNAME
INSTALLER_TYPE
INSTALLER_IP
PROFILER_TYPE
-changedir = {toxinidir}/tests
-commands = python main.py
-
+changedir = {toxinidir}/doctor_tests
+commands = doctor-test