summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--devstack/README.rst27
-rw-r--r--devstack/plugin.sh92
-rw-r--r--devstack/settings3
-rw-r--r--test-requirements.txt13
-rw-r--r--tests/config.py30
-rw-r--r--tests/identity_auth.py41
-rw-r--r--tests/image.py77
-rw-r--r--tests/lib/installers/fuel38
-rw-r--r--tests/logger.py2
-rw-r--r--tests/main.py61
-rw-r--r--tests/monitor.py5
-rw-r--r--tests/os_clients.py21
-rwxr-xr-xtests/run.sh51
-rw-r--r--tox.ini26
15 files changed, 457 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore
index d2ded272..65b51a69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,6 @@
/docs_output/
/releng/
/tests/*.img
+
+#Build results
+.tox
diff --git a/devstack/README.rst b/devstack/README.rst
new file mode 100644
index 00000000..cd836f13
--- /dev/null
+++ b/devstack/README.rst
@@ -0,0 +1,27 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. (c) 2017 OPNFV.
+
+====================================
+Enabling OPNFV Doctor using DevStack
+====================================
+
+This directory contains the files necessary to run OpenStack with enabled
+OPNFV Doctor in DevStack.
+
+To configure DevStack to enable OPNFV Doctor edit
+``${DEVSTACK_DIR}/local.conf`` file and add::
+
+ enable_plugin aodh http://git.openstack.org/openstack/aodh
+ enable_plugin panko https://git.openstack.org/openstack/panko
+ enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
+ enable_plugin osprofiler https://git.openstack.org/openstack/osprofiler
+ enable_plugin doctor https://git.opnfv.org/doctor
+
+to the ``[[local|localrc]]`` section.
+
+.. note:: The order of enabling plugins matters.
+
+Run DevStack as normal::
+
+ $ ./stack.sh
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
new file mode 100644
index 00000000..a7f6a63b
--- /dev/null
+++ b/devstack/plugin.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+
+##############################################################################
+# 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
+##############################################################################
+
+# Defaults
+# --------
+
+CONF_FILES=(
+ $CINDER_CONF
+ $HEAT_CONF
+ $KEYSTONE_CONF
+ $NOVA_CONF
+ $NEUTRON_CONF
+ $GLANCE_API_CONF
+ $GLANCE_REGISTRY_CONF
+# Supported by osprofiler but not used in doctor at the moment
+# $TROVE_CONF
+# $TROVE_CONDUCTOR_CONF
+# $TROVE_GUESTAGENT_CONF
+# $TROVE_TASKMANAGER_CONF
+# $SENLIN_CONF
+# $MAGNUM_CONF
+# $ZUN_CONF
+)
+
+function install_doctor {
+ # no-op
+ :
+}
+
+function configure_doctor {
+ for conf in ${CONF_FILES[@]}; do
+ if [ -f $conf ]
+ then
+ iniset $conf profiler enabled true
+ iniset $conf profiler trace_sqlalchemy true
+ iniset $conf profiler hmac_keys $(iniget $conf profiler hmac_keys),${DOCTOR_HMAC_KEYS:=doctor}
+ iniset $conf profiler connection_string ${OSPROFILER_CONNECTION_STRING:=redis://127.0.0.1:6379}
+ fi
+ done
+}
+
+function init_doctor {
+ # no-op
+ :
+}
+
+# check for service enabled
+if is_service_enabled doctor; then
+
+ if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
+ # Set up system services
+ echo_summary "Configuring system services Doctor"
+ # install_package cowsay
+
+ elif [[ "$1" == "stack" && "$2" == "install" ]]; then
+ # Perform installation of service source
+ echo_summary "Installing Doctor"
+ install_doctor
+
+ elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
+ # Configure after the other layer 1 and 2 services have been configured
+ echo_summary "Configuring Doctor"
+ configure_doctor
+
+ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
+ # Initialize and start the doctor service
+ echo_summary "Initializing Doctor"
+ init_doctor
+ fi
+
+ if [[ "$1" == "unstack" ]]; then
+ # Shut down doctor services
+ # no-op
+ :
+ fi
+
+ if [[ "$1" == "clean" ]]; then
+ # Remove state and transient data
+ # Remember clean.sh first calls unstack.sh
+ # no-op
+ :
+ fi
+fi
+
diff --git a/devstack/settings b/devstack/settings
new file mode 100644
index 00000000..83e02e35
--- /dev/null
+++ b/devstack/settings
@@ -0,0 +1,3 @@
+# setting file for doctor
+
+enable_service doctor
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 00000000..2928e0f7
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,13 @@
+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
+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/config.py b/tests/config.py
new file mode 100644
index 00000000..2288d36e
--- /dev/null
+++ b/tests/config.py
@@ -0,0 +1,30 @@
+##############################################################################
+# 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 image
+import os_clients
+
+
+def list_opts():
+ return [
+ ('os_clients', os_clients.OPTS),
+ ('image', image.IMAGE_OPTS),
+ ]
+
+
+def prepare_conf(conf=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)
+
+ return conf
diff --git a/tests/identity_auth.py b/tests/identity_auth.py
index 4726ca37..ffecc68a 100644
--- a/tests/identity_auth.py
+++ b/tests/identity_auth.py
@@ -9,26 +9,35 @@
import os
-from keystoneauth1.identity import v2
-from keystoneauth1.identity import v3
+from keystoneauth1 import loading
+from keystoneauth1 import session
def get_identity_auth():
auth_url = os.environ['OS_AUTH_URL']
username = os.environ['OS_USERNAME']
password = os.environ['OS_PASSWORD']
- user_domain_name = os.environ.get('OS_USER_DOMAIN_NAME')
+ 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 = os.environ.get('OS_PROJECT_NAME') or os.environ.get('OS_TENANT_NAME')
- project_domain_name = os.environ.get('OS_PROJECT_DOMAIN_NAME')
- if auth_url.endswith('v3'):
- return v3.Password(auth_url=auth_url,
- username=username,
- password=password,
- user_domain_name=user_domain_name,
- project_name=project_name,
- project_domain_name=project_domain_name)
- else:
- return v2.Password(auth_url=auth_url,
- username=username,
- password=password,
- tenant_name=project_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
new file mode 100644
index 00000000..0b4a3d72
--- /dev/null
+++ b/tests/image.py
@@ -0,0 +1,77 @@
+##############################################################################
+# 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 urllib2
+
+from oslo_config import cfg
+
+from identity_auth import get_session
+from os_clients import glance_client
+import logger as doctor_log
+
+IMAGE_OPTS = [
+ cfg.StrOpt('name',
+ default=os.environ.get('IMAGE_NAME', 'cirros'),
+ help='the name of test image',
+ required=True),
+ cfg.StrOpt('format',
+ default='qcow2',
+ help='the format of test image',
+ required=True),
+ cfg.StrOpt('file_name',
+ default='cirros.img',
+ help='the name of image file',
+ required=True),
+ cfg.StrOpt('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),
+]
+
+LOG = doctor_log.Logger('doctor').getLogger()
+
+
+class Image(object):
+
+ def __init__(self, conf):
+ self.conf = conf
+ self.glance = \
+ glance_client(conf.os_clients.glance_version,
+ get_session())
+ self.use_existing_image = False
+ self.image = None
+
+ def create(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.file_name):
+ resp = urllib2.urlopen(self.conf.image.url)
+ with open(self.conf.image.file_name, "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.file_name, 'rb'))
+ else:
+ self.use_existing_image = True
+ self.image = images[self.conf.image.name]
+
+ LOG.info('image create end......')
+
+ def delete(self):
+ LOG.info('image delete start.......')
+
+ if not self.use_existing_image and self.image:
+ self.glance.images.delete(self.image['id'])
+
+ LOG.info('image delete end.......')
diff --git a/tests/lib/installers/fuel b/tests/lib/installers/fuel
index da0de34b..0c56963c 100644
--- a/tests/lib/installers/fuel
+++ b/tests/lib/installers/fuel
@@ -74,6 +74,31 @@ function installer_apply_patches {
ip netns exec haproxy /usr/lib/ocf/resource.d/fuel/ns_haproxy restart
fi
fi
+
+ np_conf=/etc/nova/policy.json
+ if [ -e $np_conf ]; then
+ entry="os_compute_api:servers:show:host_status"
+ new="rule:admin_or_owner"
+ np_backup="${np_conf}-doctor-saved"
+ if grep -q "${entry}.*${new}" $np_conf; then
+ echo "Not modifying nova policy"
+ elif grep -q "${entry}" $np_conf; then
+ echo "modify nova policy"
+ cp $np_conf $np_backup
+ oldline=$(grep "$entry" $np_conf)
+ newline=$(echo "$oldline" | sed "s/rule.*\"/$new\"/")
+ sed -i "s/$oldline/$newline/" $np_conf
+ service nova-api restart
+ else
+ echo "add nova policy"
+ cp $np_conf $np_backup
+ sed -i "/{/a \ \"${entry}\": \"$new\"" $np_conf
+ service nova-api restart
+ fi
+ else
+ # TODO(tojuvone) policy.json might not exists in Ocata.
+ echo "$np_conf does not exist!!!"
+ fi
' > installer_apply_patches_$node.log 2>&1
done
}
@@ -83,6 +108,8 @@ function setup_installer {
installer_get_ssh_keys
get_controller_ips
installer_apply_patches
+ #Might take a moment for nova-api to restart
+ sleep 20
if ! openstack flavor show $VM_FLAVOR ; then
openstack flavor create --ram 512 --disk 1 $VM_FLAVOR \
&& touch created_doctor_flavor
@@ -138,6 +165,17 @@ function installer_revert_patches {
sed -ie "/# added by doctor script/d" $ep_conf
service ceilometer-agent-notification restart
fi
+
+ np_conf=/etc/nova/policy.json
+ entry="os_compute_api:servers:show:host_status"
+ if [ -e $np_conf ]; then
+ np_backup="${np_conf}-doctor-saved"
+ if [ -e $np_backup ]; then
+ cp -f $np_backup $np_conf
+ rm $np_backup
+ service nova-api restart
+ fi
+ fi
' >> installer_apply_patches_$node.log 2>&1
done
}
diff --git a/tests/logger.py b/tests/logger.py
index a4f33234..72043ab3 100644
--- a/tests/logger.py
+++ b/tests/logger.py
@@ -16,7 +16,7 @@ import logging
import os
-class Logger:
+class Logger(object):
def __init__(self, logger_name):
CI_DEBUG = os.getenv('CI_DEBUG')
diff --git a/tests/main.py b/tests/main.py
new file mode 100644
index 00000000..50e0821b
--- /dev/null
+++ b/tests/main.py
@@ -0,0 +1,61 @@
+##############################################################################
+# 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
+
+import config
+from image import Image
+import logger as doctor_log
+
+
+LOG = doctor_log.Logger('doctor').getLogger()
+
+
+class DoctorTest(object):
+
+ def __init__(self, conf):
+ self.conf = conf
+ self.image = Image(self.conf)
+
+ def run(self):
+ """run doctor test"""
+ try:
+ LOG.info('doctor test starting.......')
+ # prepare the cloud env
+
+ # preparing VM image...
+ self.image.create()
+
+ # creating test user...
+
+ # creating VM...
+
+ # creating alarm...
+
+ # starting doctor sample components...
+
+ # injecting host failure...
+
+ # verify the test results
+ except Exception as e:
+ LOG.error('doctor test failed, Exception=%s' % e)
+ sys.exit(1)
+ finally:
+ self.image.delete()
+
+
+def main():
+ """doctor main"""
+ conf = config.prepare_conf()
+
+ doctor = DoctorTest(conf)
+ doctor.run()
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tests/monitor.py b/tests/monitor.py
index 8e8aa7a5..8244dc88 100644
--- a/tests/monitor.py
+++ b/tests/monitor.py
@@ -17,6 +17,7 @@ import socket
import sys
import time
+from keystoneauth1 import session
from congressclient.v1 import client
import identity_auth
@@ -48,8 +49,8 @@ class DoctorMonitorSample(object):
self.inspector_url = 'http://127.0.0.1:12345/events'
elif self.inspector_type == 'congress':
auth=identity_auth.get_identity_auth()
- sess=session.Session(auth=auth)
- congress = client.Client(session=sess, service_type='policy')
+ self.session=session.Session(auth=auth)
+ congress = client.Client(session=self.session, service_type='policy')
ds = congress.list_datasources()['results']
doctor_ds = next((item for item in ds if item['driver'] == 'doctor'),
None)
diff --git a/tests/os_clients.py b/tests/os_clients.py
new file mode 100644
index 00000000..2eb406e0
--- /dev/null
+++ b/tests/os_clients.py
@@ -0,0 +1,21 @@
+##############################################################################
+# 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 glanceclient.client as glanceclient
+
+
+OPTS = [
+ cfg.StrOpt('glance_version', default='2', help='glance version'),
+]
+
+
+def glance_client(version, session):
+ return glanceclient.Client(version=version,
+ session=session)
diff --git a/tests/run.sh b/tests/run.sh
index 7f95a8a4..daf23946 100755
--- a/tests/run.sh
+++ b/tests/run.sh
@@ -28,8 +28,7 @@ CONSUMER_PORT=12346
DOCTOR_USER=doctor
DOCTOR_PW=doctor
DOCTOR_PROJECT=doctor
-#TODO: change back to `_member_` when JIRA DOCTOR-55 is done
-DOCTOR_ROLE=admin
+DOCTOR_ROLE=_member_
PROFILER_TYPE=${PROFILER_TYPE:-none}
PYTHON_ENABLE=${PYTHON_ENABLE:-false}
@@ -40,13 +39,15 @@ as_doctor_user="--os-username $DOCTOR_USER --os-password $DOCTOR_PW
# NOTE: ceilometer command still requires '--os-tenant-name'.
#ceilometer="ceilometer ${as_doctor_user/--os-project-name/--os-tenant-name}"
ceilometer="ceilometer $as_doctor_user"
+as_admin_user="--os-username admin --os-project-name $DOCTOR_PROJECT
+ --os-tenant-name $DOCTOR_PROJECT"
# Functions
get_compute_host_info() {
- # get computer host info which first VM boot in
- COMPUTE_HOST=$(openstack $as_doctor_user server show ${VM_BASENAME}1 |
+ # get computer host info which first VM boot in as admin user
+ COMPUTE_HOST=$(openstack $as_admin_user server show ${VM_BASENAME}1 |
grep "OS-EXT-SRV-ATTR:host" | awk '{ print $4 }')
compute_host_in_undercloud=${COMPUTE_HOST%%.*}
die_if_not_set $LINENO COMPUTE_HOST "Failed to get compute hostname"
@@ -109,17 +110,25 @@ register_image() {
create_test_user() {
openstack project list | grep -q " $DOCTOR_PROJECT " || {
- openstack project create "$DOCTOR_PROJECT"
+ openstack project create --description "Doctor Project" \
+ "$DOCTOR_PROJECT"
}
openstack user list | grep -q " $DOCTOR_USER " || {
openstack user create "$DOCTOR_USER" --password "$DOCTOR_PW" \
--project "$DOCTOR_PROJECT"
}
- openstack role show "$DOCTOR_ROLE" || {
+ openstack role show "$DOCTOR_ROLE" | grep -q " $DOCTOR_ROLE " || {
openstack role create "$DOCTOR_ROLE"
}
- openstack role add "$DOCTOR_ROLE" --user "$DOCTOR_USER" \
- --project "$DOCTOR_PROJECT"
+ openstack role assignment list --user "$DOCTOR_USER" \
+ --project "$DOCTOR_PROJECT" --names | grep -q " $DOCTOR_ROLE " || {
+ openstack role add "$DOCTOR_ROLE" --user "$DOCTOR_USER" \
+ --project "$DOCTOR_PROJECT"
+ }
+ openstack role assignment list --user admin --project "$DOCTOR_PROJECT" \
+ --names | grep -q " admin " || {
+ openstack role add admin --user admin --project "$DOCTOR_PROJECT"
+ }
# tojuvone: openstack quota show is broken and have to use nova
# https://bugs.launchpad.net/manila/+bug/1652118
# Note! while it is encouraged to use openstack client it has proven
@@ -141,6 +150,24 @@ create_test_user() {
fi
}
+remove_test_user() {
+ openstack project list | grep -q " $DOCTOR_PROJECT " && {
+ openstack role assignment list --user admin \
+ --project "$DOCTOR_PROJECT" --names | grep -q " admin " && {
+ openstack role remove admin --user admin --project "$DOCTOR_PROJECT"
+ }
+ openstack user list | grep -q " $DOCTOR_USER " && {
+ openstack role assignment list --user "$DOCTOR_USER" \
+ --project "$DOCTOR_PROJECT" --names | grep -q " $DOCTOR_ROLE " && {
+ openstack role remove "$DOCTOR_ROLE" --user "$DOCTOR_USER" \
+ --project "$DOCTOR_PROJECT"
+ }
+ openstack user delete "$DOCTOR_USER"
+ }
+ openstack project delete "$DOCTOR_PROJECT"
+ }
+}
+
boot_vm() {
# test VM done with test user, so can test non-admin
@@ -436,12 +463,8 @@ cleanup() {
if [[ "$use_existing_image" == false ]] ; then
[ -n "$image_id" ] && openstack image delete "$image_id"
fi
- openstack role remove "$DOCTOR_ROLE" --user "$DOCTOR_USER" \
- --project "$DOCTOR_PROJECT"
- openstack project delete "$DOCTOR_PROJECT"
- openstack user delete "$DOCTOR_USER"
- # NOTE: remove role only for doctor test.
- #openstack role delete "$DOCTOR_ROLE"
+
+ remove_test_user
cleanup_installer
cleanup_inspector
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..2f74083f
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,26 @@
+[tox]
+minversion = 2.3.1
+envlist = verify
+skipsdist = True
+
+[testenv]
+install_command = pip install -U {opts} {packages}
+setenv = VIRTUAL_ENV={envdir}
+deps = -r{toxinidir}/test-requirements.txt
+passenv =
+ OS_AUTH_URL
+ OS_USERNAME
+ OS_PASSWORD
+ OS_USER_DOMAIN_NAME
+ OS_PROJECT_NAME
+ OS_TENANT_NAME
+ OS_PROJECT_DOMAIN_NAME
+ IMAGE_NAME
+ VM_COUNT
+ PROFILER_TYPE
+ PYTHON_ENABLE
+ CI_DEBUG
+
+[testenv:verify]
+changedir = {toxinidir}/tests
+commands = python main.py