Add functional tests and some tactical non-package fixes

This commit is contained in:
Liam Young 2019-02-19 16:01:16 +00:00
parent b0ad40223c
commit 4ae04efb83
15 changed files with 1335 additions and 328 deletions

View File

@ -22,10 +22,17 @@ class MasakariCharm(charms_openstack.charm.HAOpenStackCharm):
service_name = name = 'masakari'
# First release supported
release = 'mitaka'
release = 'rocky'
# List of packages to install for this charm
packages = ['libapache2-mod-wsgi', 'apache2', 'python-apt', 'cinder-common']
packages = ['apache2', 'python-apt',
'cinder-common', 'python3-oslo.policy', 'python3-pymysql',
'python3-keystoneauth1', 'python3-oslo.db',
'python3-oslo.service', 'python3-oslo.middleware',
'python3-oslo.messaging', 'python3-oslo.versionedobjects',
'python3-novaclient', 'python3-keystonemiddleware',
'python3-taskflow', 'libapache2-mod-wsgi-py3',
'python3-microversion-parse']
api_ports = {
'masakari': {
@ -59,7 +66,8 @@ class MasakariCharm(charms_openstack.charm.HAOpenStackCharm):
}
sync_cmd = ['masakari-manage', '--config-file', '/etc/masakari/masakari.conf', 'db', 'sync']
sync_cmd = ['masakari-manage', '--config-file',
'/etc/masakari/masakari.conf', 'db', 'sync']
def get_amqp_credentials(self):
return ('masakari', 'masakari')
@ -92,8 +100,10 @@ class MasakariCharm(charms_openstack.charm.HAOpenStackCharm):
'git', 'clone', '-b', 'stable/{}'.format(os_release),
'https://github.com/openstack/masakari.git', git_dir])
subprocess.check_call([
'sudo', 'python', 'setup.py', 'install'], cwd=git_dir)
'sudo', 'python3', 'setup.py', 'install'], cwd=git_dir)
subprocess.check_call(['mkdir', '-p', '/var/lock/masakari', '/var/log/masakari', '/var/lib/masakari'])
subprocess.check_call(['cp', 'templates/masakari-engine.service', '/lib/systemd/system'])
subprocess.check_call(['cp', 'templates/wsgi.py', '/usr/local/lib/python3.6/dist-packages/masakari/api/openstack/wsgi.py'])
subprocess.check_call(['systemctl', 'daemon-reload'])
subprocess.check_call(['systemctl', 'start', 'masakari-engine'])
subprocess.check_call(['cp', 'templates/api-paste.ini', '/etc/masakari/'])

View File

@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import subprocess
import charms_openstack.charm as charm
import charms.reactive as reactive
@ -39,6 +40,7 @@ def render_config(*args):
# charm_class.upgrade_if_available(args)
charm_class.render_with_interfaces(args)
charm_class.assess_status()
subprocess.check_call(['chgrp', '-R', 'ubuntu', '/etc/masakari'])
reactive.set_state('config.rendered')
# db_sync checks if sync has been done so rerunning is a noop

View File

@ -0,0 +1,45 @@
[composite:masakari_api]
use = call:masakari.api.urlmap:urlmap_factory
/: apiversions
/v1: masakari_api_v1
[composite:masakari_api_v1]
use = call:masakari.api.auth:pipeline_factory_v1
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit authtoken keystonecontext osapi_masakari_app_v1
# filters
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = masakari
[filter:http_proxy_to_wsgi]
paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory
[filter:faultwrap]
paste.filter_factory = masakari.api.openstack:FaultWrapper.factory
[filter:sizelimit]
paste.filter_factory = oslo_middleware:RequestBodySizeLimiter.factory
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
[filter:keystonecontext]
paste.filter_factory = masakari.api.auth:MasakariKeystoneContext.factory
[filter:noauth2]
paste.filter_factory = masakari.api.auth:NoAuthMiddleware.factory
# apps
[app:osapi_masakari_app_v1]
paste.app_factory = masakari.api.openstack.ha:APIRouterV1.factory
[pipeline:apiversions]
pipeline = faultwrap http_proxy_to_wsgi apiversionsapp
[app:apiversionsapp]
paste.app_factory = masakari.api.openstack.ha.versions:Versions.factory

View File

@ -5,9 +5,10 @@ Listen {{ options.service_listen_info.masakari.public_port }}
WSGIProcessGroup masakari-api
WSGIScriptAlias / /usr/local/bin/masakari-wsgi
WSGIApplicationGroup %{GLOBAL}
<IfVersion >= 2.4>
ErrorLogFormat "%{cu}t %M"
</IfVersion>
<Directory /usr/local/bin>
Require all granted
</Directory>
ErrorLogFormat "%{cu}t %M"
ErrorLog /var/log/apache2/masakari_error.log
CustomLog /var/log/apache2/masakari_access.log combined
</VirtualHost>

1085
src/templates/wsgi.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,2 @@
# charm-proof
charm-tools>=2.0.0
# amulet deployment helpers
bzr+lp:charm-helpers#egg=charmhelpers
# BEGIN: Amulet OpenStack Charm Helper Requirements
# Liberty client lower constraints
amulet>=1.14.3,<2.0
bundletester>=0.6.1,<1.0
python-keystoneclient>=1.7.1,<2.0
python-designateclient>=1.5,<2.0
python-cinderclient>=1.4.0,<2.0
python-glanceclient>=1.1.0,<2.0
python-heatclient>=0.8.0,<1.0
python-neutronclient>=3.1.0,<4.0
python-novaclient>=2.30.1,<3.0
python-openstackclient>=1.7.0,<2.0
python-swiftclient>=2.6.0,<3.0
pika>=0.10.0,<1.0
distro-info
# END: Amulet OpenStack Charm Helper Requirements
# zaza
git+https://github.com/openstack-charmers/zaza.git#egg=zaza

View File

@ -1,9 +0,0 @@
# Overview
This directory provides Amulet tests to verify basic deployment functionality
from the perspective of this charm, its requirements and its features, as
exercised in a subset of the full OpenStack deployment test bundle topology.
For full details on functional testing of OpenStack charms please refer to
the [functional testing](http://docs.openstack.org/developer/charm-guide/testing.html#functional-testing)
section of the OpenStack Charm Guide.

View File

@ -1,147 +0,0 @@
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import amulet
import json
import subprocess
import time
import charmhelpers.contrib.openstack.amulet.deployment as amulet_deployment
import charmhelpers.contrib.openstack.amulet.utils as os_amulet_utils
# Use DEBUG to turn on debug logging
u = os_amulet_utils.OpenStackAmuletUtils(os_amulet_utils.DEBUG)
class MasakariCharmDeployment(amulet_deployment.OpenStackAmuletDeployment):
"""Amulet tests on a basic masakari deployment."""
def __init__(self, series, openstack=None, source=None, stable=False):
"""Deploy the entire test environment."""
super(MasakariCharmDeployment, self).__init__(series, openstack,
source, stable)
self._add_services()
self._add_relations()
self._configure_services()
self._deploy()
u.log.info('Waiting on extended status checks...')
exclude_services = ['mysql', 'mongodb']
self._auto_wait_for_status(exclude_services=exclude_services)
self._initialize_tests()
def _add_services(self):
"""Add services
Add the services that we're testing, where masakari is local,
and the rest of the service are from lp branches that are
compatible with the local charm (e.g. stable or next).
"""
this_service = {'name': 'masakari'}
other_services = [
{'name': 'mysql'},
{'name': 'rabbitmq-server'},
{'name': 'keystone'},
]
super(MasakariCharmDeployment, self)._add_services(this_service,
other_services)
def _add_relations(self):
"""Add all of the relations for the services."""
relations = {
'keystone:shared-db': 'mysql:shared-db',
'masakari:amqp': 'rabbitmq-server:amqp',
'masakari:identity-service': 'keystone:identity-service',
'masakari:shared-db': 'mysql:shared-db',
}
super(MasakariCharmDeployment, self)._add_relations(relations)
def _configure_services(self):
"""Configure all of the services."""
keystone_config = {'admin-password': 'openstack',
'admin-token': 'ubuntutesting'}
configs = {'keystone': keystone_config}
super(MasakariCharmDeployment, self)._configure_services(configs)
def _get_token(self):
return self.keystone.service_catalog.catalog['token']['id']
def _initialize_tests(self):
"""Perform final initialization before tests get run."""
# Access the sentries for inspecting service units
self.masakari_sentry = self.d.sentry['masakari'][0]
self.mysql_sentry = self.d.sentry['mysql'][0]
self.keystone_sentry = self.d.sentry['keystone'][0]
self.rabbitmq_sentry = self.d.sentry['rabbitmq-server'][0]
self.masakari_svcs = ['haproxy', 'masakari']
# Authenticate admin with keystone endpoint
self.keystone = u.authenticate_keystone_admin(self.keystone_sentry,
user='admin',
password='openstack',
tenant='admin')
def check_and_wait(self, check_command, interval=2, max_wait=200,
desc=None):
waited = 0
while not check_command() or waited > max_wait:
if desc:
u.log.debug(desc)
time.sleep(interval)
waited = waited + interval
if waited > max_wait:
raise Exception('cmd failed {}'.format(check_command))
def _run_action(self, unit_id, action, *args):
command = ["juju", "action", "do", "--format=json", unit_id, action]
command.extend(args)
output = subprocess.check_output(command)
output_json = output.decode(encoding="UTF-8")
data = json.loads(output_json)
action_id = data[u'Action queued with id']
return action_id
def _wait_on_action(self, action_id):
command = ["juju", "action", "fetch", "--format=json", action_id]
while True:
try:
output = subprocess.check_output(command)
except Exception as e:
print(e)
return False
output_json = output.decode(encoding="UTF-8")
data = json.loads(output_json)
if data[u"status"] == "completed":
return True
elif data[u"status"] == "failed":
return False
time.sleep(2)
def test_100_services(self):
"""Verify the expected services are running on the corresponding
service units."""
u.log.debug('Checking system services on units...')
service_names = {
self.masakari_sentry: self.masakari_svcs,
}
ret = u.validate_services_by_name(service_names)
if ret:
amulet.raise_status(amulet.FAIL, msg=ret)
u.log.debug('OK')

View File

@ -0,0 +1,156 @@
series: bionic
relations:
- - nova-compute:amqp
- rabbitmq-server:amqp
- - neutron-gateway:amqp
- rabbitmq-server:amqp
- - neutron-gateway:amqp-nova
- rabbitmq-server:amqp
- - keystone:shared-db
- mysql:shared-db
- - cinder:identity-service
- keystone:identity-service
- - nova-cloud-controller:identity-service
- keystone:identity-service
- - glance:identity-service
- keystone:identity-service
- - neutron-api:identity-service
- keystone:identity-service
- - neutron-openvswitch:neutron-plugin-api
- neutron-api:neutron-plugin-api
- - cinder:shared-db
- mysql:shared-db
- - neutron-api:shared-db
- mysql:shared-db
- - cinder:amqp
- rabbitmq-server:amqp
- - neutron-api:amqp
- rabbitmq-server:amqp
- - neutron-gateway:neutron-plugin-api
- neutron-api:neutron-plugin-api
- - glance:shared-db
- mysql:shared-db
- - glance:amqp
- rabbitmq-server:amqp
- - nova-cloud-controller:image-service
- glance:image-service
- - nova-compute:image-service
- glance:image-service
- - nova-cloud-controller:amqp
- rabbitmq-server:amqp
- - nova-cloud-controller:quantum-network-service
- neutron-gateway:quantum-network-service
- - nova-compute:neutron-plugin
- neutron-openvswitch:neutron-plugin
- - neutron-openvswitch:amqp
- rabbitmq-server:amqp
- - nova-cloud-controller:shared-db
- mysql:shared-db
- - nova-cloud-controller:neutron-api
- neutron-api:neutron-api
- - nova-cloud-controller:cloud-compute
- nova-compute:cloud-compute
- - masakari:shared-db
- mysql:shared-db
- - masakari:amqp
- rabbitmq-server:amqp
- - masakari:identity-service
- keystone:identity-service
- - glance:ceph
- ceph-mon:client
- - ceph-mon:osd
- ceph-osd:mon
- - cinder:storage-backend
- cinder-ceph:storage-backend
- - cinder-ceph:ceph
- ceph-mon:client
- - cinder-ceph:ceph-access
- nova-compute:ceph-access
applications:
glance:
charm: cs:~openstack-charmers-next/glance
num_units: 1
options:
openstack-origin: cloud:bionic-rocky
worker-multiplier: 0.25
cinder:
charm: cs:~openstack-charmers-next/cinder
num_units: 1
options:
block-device: "None"
glance-api-version: 2
keystone:
charm: cs:~openstack-charmers-next/keystone
num_units: 1
options:
admin-password: openstack
openstack-origin: cloud:bionic-rocky
worker-multiplier: 0.25
mysql:
charm: cs:~openstack-charmers-next/percona-cluster
num_units: 1
options:
innodb-buffer-pool-size: 256M
max-connections: 1000
neutron-api:
charm: cs:~openstack-charmers-next/neutron-api
num_units: 1
options:
flat-network-providers: physnet1
neutron-security-groups: true
openstack-origin: cloud:bionic-rocky
worker-multiplier: 0.25
neutron-gateway:
charm: cs:~openstack-charmers-next/neutron-gateway
num_units: 1
options:
bridge-mappings: physnet1:br-ex
openstack-origin: cloud:bionic-rocky
worker-multiplier: 0.25
neutron-openvswitch:
charm: cs:~openstack-charmers-next/neutron-openvswitch
num_units: 0
nova-cloud-controller:
charm: cs:~openstack-charmers-next/nova-cloud-controller
num_units: 1
options:
network-manager: Neutron
openstack-origin: cloud:bionic-rocky
worker-multiplier: 0.25
debug: true
nova-compute:
charm: cs:~openstack-charmers-next/nova-compute
num_units: 3
constraints: mem=4G
options:
config-flags: default_ephemeral_format=ext4
enable-live-migration: true
enable-resize: true
migration-auth-type: ssh
openstack-origin: cloud:bionic-rocky
debug: true
cpu-model: kvm64
cpu-mode: custom
rabbitmq-server:
charm: cs:~openstack-charmers-next/rabbitmq-server
num_units: 1
masakari:
charm: masakari
series: bionic
num_units: 1
options:
openstack-origin: cloud:bionic-rocky
ceph-mon:
charm: ceph-mon
num_units: 3
options:
expected-osd-count: 3
ceph-osd:
charm: ceph-osd
constraints: mem=1G
num_units: 3
storage:
osd-devices: cinder,40G
cinder-ceph:
charm: cinder-ceph

View File

@ -1,23 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Amulet tests on a basic SDN Charm deployment on trusty-icehouse."""
from basic_deployment import MasakariCharmDeployment
if __name__ == '__main__':
deployment = MasakariCharmDeployment(series='trusty')
deployment.run_tests()

View File

@ -1,25 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Amulet tests on a basic SDN Charm deployment on trusty-liberty."""
from basic_deployment import MasakariCharmDeployment
if __name__ == '__main__':
deployment = MasakariCharmDeployment(series='trusty',
openstack='cloud:trusty-liberty',
source='cloud:trusty-updates/liberty')
deployment.run_tests()

View File

@ -1,25 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Amulet tests on a basic SDN Charm deployment on trusty-mitaka."""
from basic_deployment import MasakariCharmDeployment
if __name__ == '__main__':
deployment = MasakariCharmDeployment(series='trusty',
openstack='cloud:trusty-mitaka',
source='cloud:trusty-updates/mitaka')
deployment.run_tests()

View File

@ -1,23 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Amulet tests on a basic SDN Charm deployment on xenial-mitaka."""
from basic_deployment import MasakariCharmDeployment
if __name__ == '__main__':
deployment = MasakariCharmDeployment(series='xenial')
deployment.run_tests()

View File

@ -1,17 +1,13 @@
# Bootstrap the model if necessary.
bootstrap: True
# Re-use bootstrap node instead of destroying/re-bootstrapping.
reset: True
# Use tox/requirements to drive the venv instead of bundletester's venv feature.
virtualenv: False
# Leave makefile empty, otherwise unit/lint tests will rerun ahead of amulet.
makefile: []
# Do not specify juju PPA sources. Juju is presumed to be pre-installed
# and configured in all test runner environments.
#sources:
# Do not specify or rely on system packages.
#packages:
# Do not specify python packages here. Use test-requirements.txt
# and tox instead. ie. The venv is constructed before bundletester
# is invoked.
#python-packages:
charm_name: masakari
tests:
- zaza.charm_tests.nova.tests.CirrosGuestCreateTest
configure:
- zaza.charm_tests.glance.setup.add_cirros_image
- zaza.charm_tests.glance.setup.add_lts_image
- zaza.charm_tests.neutron.setup.basic_overcloud_network
- zaza.charm_tests.nova.setup.create_flavors
- zaza.charm_tests.nova.setup.manage_ssh_key
gate_bundles:
- bionic-rocky
smoke_bundles:
- bionic-rocky

View File

@ -1,6 +1,3 @@
# Source charm: ./src/tox.ini
# This file is managed centrally by release-tools and should not be modified
# within individual charm repos.
[tox]
envlist = pep8
skipsdist = True
@ -8,46 +5,31 @@ skipsdist = True
[testenv]
setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0
AMULET_SETUP_TIMEOUT=2700
whitelist_externals = juju
passenv = HOME TERM AMULET_*
passenv = HOME TERM CS_API_* OS_* AMULET_*
deps = -r{toxinidir}/test-requirements.txt
install_command =
pip install --allow-unverified python-apt {opts} {packages}
pip install {opts} {packages}
[testenv:pep8]
basepython = python2.7
basepython = python3
deps=charm-tools
commands = charm-proof
[testenv:func27-noop]
# DRY RUN - For Debug
basepython = python2.7
[testenv:func-noop]
basepython = python3
commands =
bundletester -vl DEBUG -r json -o func-results.json --test-pattern "gate-*" -n --no-destroy
true
[testenv:func27]
# Run all gate tests which are +x (expected to always pass)
basepython = python2.7
[testenv:func]
basepython = python3
commands =
bundletester -vl DEBUG -r json -o func-results.json --test-pattern "gate-*" --no-destroy
functest-run-suite --keep-model
[testenv:func27-smoke]
# Run a specific test as an Amulet smoke test (expected to always pass)
basepython = python2.7
[testenv:func-smoke]
basepython = python3
commands =
bundletester -vl DEBUG -r json -o func-results.json gate-basic-xenial-mitaka --no-destroy
[testenv:func27-dfs]
# Run all deploy-from-source tests which are +x (may not always pass!)
basepython = python2.7
commands =
bundletester -vl DEBUG -r json -o func-results.json --test-pattern "dfs-*" --no-destroy
[testenv:func27-dev]
# Run all development test targets which are +x (may not always pass!)
basepython = python2.7
commands =
bundletester -vl DEBUG -r json -o func-results.json --test-pattern "dev-*" --no-destroy
functest-run-suite --keep-model --smoke
[testenv:venv]
commands = {posargs}
commands = {posargs}