summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--devstack/README.rst27
-rw-r--r--devstack/plugin.sh92
-rw-r--r--devstack/settings3
-rw-r--r--tests/config.py8
-rw-r--r--tests/consumer.py1
-rw-r--r--tests/identity_auth.py10
-rw-r--r--tests/image.py45
-rw-r--r--tests/inspector.py1
-rw-r--r--tests/main.py33
-rw-r--r--tests/monitor.py7
-rw-r--r--tests/os_clients.py13
-rwxr-xr-xtests/run.sh11
-rw-r--r--tests/user.py163
13 files changed, 363 insertions, 51 deletions
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/tests/config.py b/tests/config.py
index 2288d36e..7a0bef2d 100644
--- a/tests/config.py
+++ b/tests/config.py
@@ -6,16 +6,20 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
+import itertools
from oslo_config import cfg
import image
import os_clients
+import user
def list_opts():
return [
- ('os_clients', os_clients.OPTS),
- ('image', image.IMAGE_OPTS),
+ ('DEFAULT', itertools.chain(
+ os_clients.OPTS,
+ image.OPTS,
+ user.OPTS))
]
diff --git a/tests/consumer.py b/tests/consumer.py
index 3c012b4f..042cf20a 100644
--- a/tests/consumer.py
+++ b/tests/consumer.py
@@ -12,7 +12,6 @@ from flask import Flask
from flask import request
import json
import logger as doctor_log
-import os
import time
LOG = doctor_log.Logger('doctor_consumer').getLogger()
diff --git a/tests/identity_auth.py b/tests/identity_auth.py
index a40c41cf..ffecc68a 100644
--- a/tests/identity_auth.py
+++ b/tests/identity_auth.py
@@ -17,9 +17,11 @@ 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')
+ 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(
@@ -27,9 +29,11 @@ def get_identity_auth():
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_name=project_domain_name,
+ project_domain_id=project_domain_id)
def get_session(auth=None):
diff --git a/tests/image.py b/tests/image.py
index 0b4a3d72..453322b8 100644
--- a/tests/image.py
+++ b/tests/image.py
@@ -7,71 +7,68 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
import os
-import urllib2
+import urllib.request
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',
+OPTS = [
+ cfg.StrOpt('image_name',
default=os.environ.get('IMAGE_NAME', 'cirros'),
help='the name of test image',
required=True),
- cfg.StrOpt('format',
+ cfg.StrOpt('image_format',
default='qcow2',
help='the format of test image',
required=True),
- cfg.StrOpt('file_name',
+ cfg.StrOpt('image_filename',
default='cirros.img',
help='the name of image file',
required=True),
- cfg.StrOpt('url',
+ 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),
]
-LOG = doctor_log.Logger('doctor').getLogger()
-
class Image(object):
- def __init__(self, conf):
+ def __init__(self, conf, log):
self.conf = conf
+ self.log = log
self.glance = \
- glance_client(conf.os_clients.glance_version,
- get_session())
+ glance_client(conf.glance_version, get_session())
self.use_existing_image = False
self.image = None
def create(self):
- LOG.info('image create start......')
+ 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:
+ 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,
+ 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'))
+ open(self.conf.image_filename, 'rb'))
else:
self.use_existing_image = True
- self.image = images[self.conf.image.name]
+ self.image = images[self.conf.image_name]
- LOG.info('image create end......')
+ self.log.info('image create end......')
def delete(self):
- LOG.info('image delete start.......')
+ 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.......')
+ self.log.info('image delete end.......')
diff --git a/tests/inspector.py b/tests/inspector.py
index ba00f40e..d11da299 100644
--- a/tests/inspector.py
+++ b/tests/inspector.py
@@ -13,7 +13,6 @@ from flask import Flask
from flask import request
import json
import logger as doctor_log
-import os
import threading
import time
diff --git a/tests/main.py b/tests/main.py
index 50e0821b..46f0c894 100644
--- a/tests/main.py
+++ b/tests/main.py
@@ -11,6 +11,7 @@ import sys
import config
from image import Image
import logger as doctor_log
+from user import User
LOG = doctor_log.Logger('doctor').getLogger()
@@ -20,33 +21,39 @@ class DoctorTest(object):
def __init__(self, conf):
self.conf = conf
- self.image = Image(self.conf)
+ self.image = Image(self.conf, LOG)
+ self.user = User(self.conf, LOG)
+
+ def setup(self):
+ # prepare the cloud env
+
+ # preparing VM image...
+ self.image.create()
+
+ # creating test user...
+ self.user.create()
+ self.user.update_quota()
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...
+ self.setup()
# 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()
+ self.cleanup()
+
+ def cleanup(self):
+ self.image.delete()
+ self.user.delete()
def main():
diff --git a/tests/monitor.py b/tests/monitor.py
index 8e8aa7a5..7450c534 100644
--- a/tests/monitor.py
+++ b/tests/monitor.py
@@ -11,12 +11,11 @@ import argparse
from datetime import datetime
import json
import logger as doctor_log
-import os
import requests
import socket
-import sys
import time
+from keystoneauth1 import session
from congressclient.v1 import client
import identity_auth
@@ -48,8 +47,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
index 2eb406e0..c9eb0b1d 100644
--- a/tests/os_clients.py
+++ b/tests/os_clients.py
@@ -9,13 +9,24 @@
from oslo_config import cfg
import glanceclient.client as glanceclient
-
+from keystoneclient.v2_0 import client as ks_client
+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'),
]
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)
diff --git a/tests/run.sh b/tests/run.sh
index c21c3fd7..fda1e753 100755
--- a/tests/run.sh
+++ b/tests/run.sh
@@ -30,6 +30,7 @@ DOCTOR_PW=doctor
DOCTOR_PROJECT=doctor
DOCTOR_ROLE=_member_
PROFILER_TYPE=${PROFILER_TYPE:-none}
+PYTHON_ENABLE=${PYTHON_ENABLE:-false}
TOP_DIR=$(cd $(dirname "$0") && pwd)
@@ -293,8 +294,7 @@ inject_failure() {
echo "disabling network of compute host [$COMPUTE_HOST] for 3 mins..."
cat > disable_network.sh << 'END_TXT'
#!/bin/bash -x
-dev=$(sudo ip a | awk '/ @COMPUTE_IP@\//{print $7}')
-[[ -n "$dev" ]] || dev=$(sudo ip a | awk '/ @COMPUTE_IP@\//{print $5}')
+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")
@@ -480,6 +480,13 @@ cleanup() {
# Main process
+if $PYTHON_ENABLE; then
+ cd $TOP_DIR
+ echo "executing tox..."
+ tox
+ exit $?
+fi
+
echo "Note: doctor/tests/run.sh has been executed."
git log --oneline -1 || true # ignore even you don't have git installed
diff --git a/tests/user.py b/tests/user.py
new file mode 100644
index 00000000..b21bd1a8
--- /dev/null
+++ b/tests/user.py
@@ -0,0 +1,163 @@
+##############################################################################
+# 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')