Merge "Add parallel execution and shortcut notification to inspector design guideline"
authorRyota Mibu <r-mibu@cq.jp.nec.com>
Fri, 22 Sep 2017 11:25:35 +0000 (11:25 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Fri, 22 Sep 2017 11:25:35 +0000 (11:25 +0000)
47 files changed:
.gitignore
docs/development/overview/testing.rst
doctor_tests/__init__.py [moved from tests/scenario/__init__.py with 100% similarity]
doctor_tests/alarm.py [moved from tests/alarm.py with 94% similarity]
doctor_tests/common/__init__.py [moved from tests/common/__init__.py with 100% similarity]
doctor_tests/common/constants.py [moved from tests/common/constants.py with 100% similarity]
doctor_tests/common/utils.py [moved from tests/common/utils.py with 100% similarity]
doctor_tests/config.py [moved from tests/config.py with 75% similarity]
doctor_tests/consumer/__init__.py [moved from tests/consumer/__init__.py with 89% similarity]
doctor_tests/consumer/base.py [moved from tests/consumer/base.py with 100% similarity]
doctor_tests/consumer/sample.py [moved from tests/consumer/sample.py with 95% similarity]
doctor_tests/identity_auth.py [moved from tests/identity_auth.py with 99% similarity]
doctor_tests/image.py [moved from tests/image.py with 96% similarity]
doctor_tests/inspector/__init__.py [moved from tests/inspector/__init__.py with 90% similarity]
doctor_tests/inspector/base.py [moved from tests/inspector/base.py with 100% similarity]
doctor_tests/inspector/congress.py [moved from tests/inspector/congress.py with 94% similarity]
doctor_tests/inspector/sample.py [moved from tests/inspector/sample.py with 95% similarity]
doctor_tests/installer/__init__.py [moved from tests/installer/__init__.py with 91% similarity]
doctor_tests/installer/apex.py [moved from tests/installer/apex.py with 97% similarity]
doctor_tests/installer/base.py [moved from tests/installer/base.py with 100% similarity]
doctor_tests/installer/common/congress.py [moved from tests/installer/common/congress.py with 100% similarity]
doctor_tests/installer/common/restore_ceilometer.py [moved from tests/installer/common/restore_ceilometer.py with 100% similarity]
doctor_tests/installer/common/set_ceilometer.py [moved from tests/installer/common/set_ceilometer.py with 100% similarity]
doctor_tests/installer/local.py [moved from tests/installer/local.py with 96% similarity]
doctor_tests/instance.py [moved from tests/instance.py with 95% similarity]
doctor_tests/logger.py [moved from tests/logger.py with 100% similarity]
doctor_tests/main.py [moved from tests/main.py with 87% similarity]
doctor_tests/monitor/__init__.py [moved from tests/monitor/__init__.py with 88% similarity]
doctor_tests/monitor/base.py [moved from tests/monitor/base.py with 100% similarity]
doctor_tests/monitor/collectd.py [moved from tests/monitor/collectd.py with 90% similarity]
doctor_tests/monitor/collectd_plugin.py [new file with mode: 0644]
doctor_tests/monitor/sample.py [moved from tests/monitor/sample.py with 97% similarity]
doctor_tests/network.py [moved from tests/network.py with 94% similarity]
doctor_tests/os_clients.py [moved from tests/os_clients.py with 100% similarity]
doctor_tests/profiler_poc.py [moved from tests/profiler_poc.py with 100% similarity]
doctor_tests/scenario/__init__.py [new file with mode: 0644]
doctor_tests/scenario/common.py [moved from tests/scenario/common.py with 90% similarity]
doctor_tests/scenario/network_failure.py [moved from tests/scenario/network_failure.py with 94% similarity]
doctor_tests/user.py [moved from tests/user.py with 97% similarity]
requirements.txt [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]
test-requirements.txt [deleted file]
tests/__init__.py [new file with mode: 0644]
tests/inspector.py
tests/run.sh
tox.ini

index c671eee..7e89386 100644 (file)
@@ -2,6 +2,9 @@
 *.pyc
 .*.sw?
 **.log
+*.pyc
+/*.egg-info/
+/build/
 /docs_build/
 /docs_output/
 /releng/
index cd39ee0..08a4d93 100644 (file)
@@ -29,7 +29,10 @@ OpenStack services.
 
 .. _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
 
@@ -46,6 +49,24 @@ INSPECTOR_TYPE can be specified either 'sample'(default) or 'congress'.
 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
 ==================
 
@@ -60,10 +81,14 @@ Functest container. You can run the Doctor test with the following steps:
         -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
similarity index 94%
rename from tests/alarm.py
rename to doctor_tests/alarm.py
index 916f440..3b1aaf3 100644 (file)
@@ -8,10 +8,10 @@
 ##############################################################################
 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',
similarity index 75%
rename from tests/config.py
rename to doctor_tests/config.py
index c71d5ad..273e84d 100644 (file)
@@ -10,17 +10,17 @@ import itertools
 \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
similarity index 89%
rename from tests/consumer/__init__.py
rename to doctor_tests/consumer/__init__.py
index ccec864..2c66a54 100644 (file)
@@ -28,10 +28,10 @@ OPTS = [
 
 
 _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)
similarity index 95%
rename from tests/consumer/sample.py
rename to doctor_tests/consumer/sample.py
index 20ad9d5..d76a764 100644 (file)
@@ -13,7 +13,7 @@ import time
 from threading import Thread
 import requests
 
-from consumer.base import BaseConsumer
+from doctor_tests.consumer.base import BaseConsumer
 
 
 class SampleConsumer(BaseConsumer):
@@ -68,4 +68,4 @@ class ConsumerApp(Thread):
             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)
similarity index 99%
rename from tests/identity_auth.py
rename to doctor_tests/identity_auth.py
index c94893f..2586720 100644 (file)
@@ -6,7 +6,6 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-
 import os
 
 from keystoneauth1 import loading
similarity index 96%
rename from tests/image.py
rename to doctor_tests/image.py
index 453322b..2e313e1 100644 (file)
@@ -11,8 +11,8 @@ import urllib.request
 
 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',
similarity index 90%
rename from tests/inspector/__init__.py
rename to doctor_tests/inspector/__init__.py
index afba480..3be79e5 100644 (file)
@@ -30,8 +30,8 @@ OPTS = [
 
 
 _inspector_name_class_mapping = {
-    'sample': 'inspector.sample.SampleInspector',
-    'congress': 'inspector.congress.CongressInspector',
+    'sample': 'doctor_tests.inspector.sample.SampleInspector',
+    'congress': 'doctor_tests.inspector.congress.CongressInspector',
 }
 
 
similarity index 94%
rename from tests/inspector/congress.py
rename to doctor_tests/inspector/congress.py
index ae29585..c89a41b 100644 (file)
@@ -6,11 +6,11 @@
 # 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):
similarity index 95%
rename from tests/inspector/sample.py
rename to doctor_tests/inspector/sample.py
index 1c05ced..114e4eb 100644 (file)
@@ -14,12 +14,12 @@ 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
+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):
similarity index 91%
rename from tests/installer/__init__.py
rename to doctor_tests/installer/__init__.py
index bb0e452..02735b1 100644 (file)
@@ -28,11 +28,11 @@ OPTS = [
 
 
 _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)
similarity index 97%
rename from tests/installer/apex.py
rename to doctor_tests/installer/apex.py
index 98eb6c9..2a1ce94 100644 (file)
@@ -12,10 +12,9 @@ import os
 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):
@@ -59,7 +58,7 @@ 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
 
similarity index 96%
rename from tests/installer/local.py
rename to doctor_tests/installer/local.py
index dcdf41e..7d0ae54 100644 (file)
@@ -10,9 +10,9 @@ 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
+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):
similarity index 95%
rename from tests/instance.py
rename to doctor_tests/instance.py
index c6acbc3..27f412e 100644 (file)
@@ -11,10 +11,10 @@ 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
+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',
similarity index 100%
rename from tests/logger.py
rename to doctor_tests/logger.py
similarity index 87%
rename from tests/main.py
rename to doctor_tests/main.py
index df7e95f..006aac9 100644 (file)
@@ -12,25 +12,25 @@ 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
+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()
@@ -201,7 +201,9 @@ class DoctorTest(object):
 
 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))]
@@ -211,7 +213,3 @@ def main():
 
     doctor = DoctorTest(conf)
     doctor.run()
-
-
-if __name__ == '__main__':
-    sys.exit(main())
similarity index 88%
rename from tests/monitor/__init__.py
rename to doctor_tests/monitor/__init__.py
index e268907..7e30c9f 100644 (file)
@@ -19,8 +19,8 @@ OPTS = [
 
 
 _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):
similarity index 90%
rename from tests/monitor/collectd.py
rename to doctor_tests/monitor/collectd.py
index e2a800e..4e9329c 100644 (file)
@@ -6,19 +6,19 @@
 # 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))
 
@@ -45,7 +45,7 @@ class CollectdMonitor(BaseMonitor):
         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
@@ -99,7 +99,7 @@ LoadPlugin logfile
         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
@@ -117,7 +117,7 @@ LoadPlugin logfile
         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")
@@ -135,4 +135,4 @@ LoadPlugin logfile
                 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)
diff --git a/doctor_tests/monitor/collectd_plugin.py b/doctor_tests/monitor/collectd_plugin.py
new file mode 100644 (file)
index 0000000..57105f3
--- /dev/null
@@ -0,0 +1,166 @@
+##############################################################################
+# 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)
similarity index 97%
rename from tests/monitor/sample.py
rename to doctor_tests/monitor/sample.py
index 9ac1bcc..7a46304 100644 (file)
@@ -13,8 +13,8 @@ import socket
 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):
similarity index 94%
rename from tests/network.py
rename to doctor_tests/network.py
index da7ad09..ee153e6 100644 (file)
@@ -8,9 +8,9 @@
 ##############################################################################
 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 = [
diff --git a/doctor_tests/scenario/__init__.py b/doctor_tests/scenario/__init__.py
new file mode 100644 (file)
index 0000000..48893ae
--- /dev/null
@@ -0,0 +1,8 @@
+##############################################################################
+# 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
+##############################################################################
similarity index 90%
rename from tests/scenario/common.py
rename to doctor_tests/scenario/common.py
index a33c50f..a5cbe48 100644 (file)
@@ -7,7 +7,8 @@
 # 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():
@@ -25,4 +26,4 @@ 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)
similarity index 94%
rename from tests/scenario/network_failure.py
rename to doctor_tests/scenario/network_failure.py
index e9a239d..b94a622 100644 (file)
@@ -6,9 +6,9 @@
 # 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
similarity index 97%
rename from tests/user.py
rename to doctor_tests/user.py
index b21bd1a..33f995e 100644 (file)
@@ -10,9 +10,9 @@ 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
+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 = [
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..4623289
--- /dev/null
@@ -0,0 +1,14 @@
+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
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..a9e8144
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,11 @@
+[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
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..a1e9b3b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,22 @@
+#!/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)
diff --git a/test-requirements.txt b/test-requirements.txt
deleted file mode 100644 (file)
index 070caa4..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-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
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index 82ffc33..0046b99 100644 (file)
@@ -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()
 
index e1875e0..b5c5687 100755 (executable)
@@ -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/tox.ini b/tox.ini
index d4babeb..748241e 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -4,9 +4,12 @@ envlist = py34
 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
@@ -23,6 +26,5 @@ passenv =
     INSTALLER_TYPE
     INSTALLER_IP
     PROFILER_TYPE
-changedir = {toxinidir}/tests
-commands = python main.py
-
+changedir = {toxinidir}/doctor_tests
+commands = doctor-test