Merge pull request #126 from markgoddard/molecule-kolla-openstack

Molecule tests for kolla-openstack role
This commit is contained in:
Mark Goddard 2018-02-22 15:19:49 +00:00 committed by GitHub
commit e0578cf907
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 768 additions and 27 deletions

29
.gitignore vendored
View File

@ -50,29 +50,18 @@ ansible/*.retry
ansible/roles/*/tests/*.retry
# Ansible Galaxy roles
ansible/roles/ahuffman.resolv/
ansible/roles/singleplatform-eng.users/
ansible/roles/jriguera.configdrive/
ansible/roles/mrlesmithjr.manage-lvm/
ansible/roles/MichaelRigart.interfaces/
ansible/roles/stackhpc.drac/
ansible/roles/stackhpc.drac-facts/
ansible/roles/stackhpc.grafana-conf/
ansible/roles/stackhpc.libvirt-host/
ansible/roles/stackhpc.libvirt-vm/
ansible/roles/stackhpc.os-flavors/
ansible/roles/stackhpc.os-images/
ansible/roles/stackhpc.os-ironic-state/
ansible/roles/stackhpc.os-openstackclient/
ansible/roles/stackhpc.os-networks/
ansible/roles/stackhpc.os-projects/
ansible/roles/stackhpc.os-shade/
ansible/roles/stackhpc.parted-1-1/
ansible/roles/resmo.ntp/
ansible/roles/yatesr.timezone/
ansible/roles/*\.*/
# Virtualenv
ansible/kolla-venv/
# Vagrant
.vagrant
# Molecule
.molecule/
# Pytest
.cache/
.pytest_cache/
pytestdebug.log

View File

@ -27,6 +27,8 @@ env:
- TOX_ENV=ansible-syntax
# Run ansible tests.
- TOX_ENV=ansible
# Run molecule tests.
- TOX_ENV=molecule
install:
# Install tox in a virtualenv to ensure we have an up to date version.

View File

@ -0,0 +1,13 @@
extends: default
rules:
braces:
max-spaces-inside: 1
level: error
brackets:
max-spaces-inside: 1
level: error
line-length: disable
# NOTE(retr0h): Templates no longer fail this lint rule.
# Uncomment if running old Molecule templates.
# truthy: disable

View File

@ -3,7 +3,7 @@
kolla_extra_config_path:
# Directory where Kolla custom configuration files will be installed.
kolla_node_custom_config_path:
kolla_node_custom_config_path: /etc/kolla/config
###############################################################################
# ceph configuration.
@ -48,6 +48,9 @@ kolla_extra_glance:
# Whether to enable Grafana.
kolla_enable_grafana:
# Name of the admin user for Grafana.
grafana_local_admin_user_name:
# Free form extra configuration to append to grafana.ini.
kolla_extra_grafana:
@ -60,6 +63,12 @@ kolla_enable_heat:
# Free form extra configuration to append to heat.conf.
kolla_extra_heat:
###############################################################################
# Horizon configuration.
# Whether to enable Horizon.
kolla_enable_horizon:
###############################################################################
# Ironic configuration.
@ -194,7 +203,7 @@ kolla_inspector_enable_discovery:
kolla_inspector_discovery_enroll_node_driver:
# List of extra kernel parameters for the inspector default PXE configuration.
kolla_inspector_extra_kernel_options:
kolla_inspector_extra_kernel_options: []
# URL of Ironic Python Agent (IPA) kernel image for Ironic Inspector.
# Mutually exclusive with kolla_inspector_ipa_kernel_path.
@ -246,6 +255,12 @@ kolla_enable_magnum:
# Free form extra configuration to append to magnum.conf.
kolla_extra_magnum:
###############################################################################
# Manila configuration.
# Whether to enable Manila.
kolla_enable_manila:
###############################################################################
# Monasca configuration.

View File

@ -0,0 +1,9 @@
# Molecule managed
FROM {{ item.image }}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python2-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; fi

View File

@ -0,0 +1,16 @@
*******
Install
*******
Requirements
============
* Docker Engine
* docker-py
Install
=======
.. code-block:: bash
$ sudo pip install docker-py

View File

@ -0,0 +1,60 @@
---
- name: Create
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
vars:
molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}"
molecule_ephemeral_directory: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}"
molecule_scenario_directory: "{{ lookup('env', 'MOLECULE_SCENARIO_DIRECTORY') }}"
molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}"
tasks:
- name: Create Dockerfiles from image names
template:
src: "{{ molecule_scenario_directory }}/Dockerfile.j2"
dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.image | regex_replace('[^a-zA-Z0-9_]', '_') }}"
with_items: "{{ molecule_yml.platforms }}"
register: platforms
- name: Discover local Docker images
docker_image_facts:
name: "molecule_local/{{ item.item.name }}"
with_items: "{{ platforms.results }}"
register: docker_images
- name: Build an Ansible compatible image
docker_image:
path: "{{ molecule_ephemeral_directory }}"
name: "molecule_local/{{ item.item.image }}"
dockerfile: "{{ item.item.dockerfile | default(item.invocation.module_args.dest) }}"
force: "{{ item.item.force | default(true) }}"
with_items: "{{ platforms.results }}"
when: platforms.changed or docker_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0
- name: Create molecule instance(s)
docker_container:
name: "{{ item.name }}"
hostname: "{{ item.name }}"
image: "molecule_local/{{ item.image }}"
state: started
recreate: false
log_driver: json-file
command: "{{ item.command | default('bash -c \"while true; do sleep 10000; done\"') }}"
privileged: "{{ item.privileged | default(omit) }}"
volumes: "{{ item.volumes | default(omit) }}"
capabilities: "{{ item.capabilities | default(omit) }}"
ports: "{{ item.exposed_ports | default(omit) }}"
ulimits: "{{ item.ulimits | default(omit) }}"
register: server
with_items: "{{ molecule_yml.platforms }}"
async: 7200
poll: 0
- name: Wait for instance(s) creation to complete
async_status:
jid: "{{ item.ansible_job_id }}"
register: docker_jobs
until: docker_jobs.finished
retries: 300
with_items: "{{ server.results }}"

View File

@ -0,0 +1,27 @@
---
- name: Destroy
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
vars:
molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}"
molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}"
tasks:
- name: Destroy molecule instance(s)
docker_container:
name: "{{ item.name }}"
state: absent
force_kill: "{{ item.force_kill | default(true) }}"
register: server
with_items: "{{ molecule_yml.platforms }}"
async: 7200
poll: 0
- name: Wait for instance(s) deletion to complete
async_status:
jid: "{{ item.ansible_job_id }}"
register: docker_jobs
until: docker_jobs.finished
retries: 300
with_items: "{{ server.results }}"

View File

@ -0,0 +1,22 @@
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
platforms:
- name: centos-7
image: centos:7
- name: ubuntu-1604
image: ubuntu:16.04
provisioner:
name: ansible
lint:
name: ansible-lint
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8

View File

@ -0,0 +1,5 @@
---
- name: Converge
hosts: all
roles:
- role: kolla-openstack

View File

@ -0,0 +1,5 @@
---
- name: Prepare
hosts: all
gather_facts: false
tasks: []

View File

@ -0,0 +1,57 @@
# Copyright (c) 2018 StackHPC 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 os
import os.path
from kayobe.tests.molecule import utils
import pytest
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
@pytest.mark.parametrize(
'path',
['fluentd/filter',
'fluentd/output',
'keystone'])
def test_service_config_directory(host, path):
path = os.path.join('/etc/kolla/config', path)
utils.test_directory(host, path)
@pytest.mark.parametrize(
'path',
['ceph',
'cinder',
'designate',
'glance',
'grafana',
'heat',
'horizon',
'ironic',
'magnum',
'manila',
'murano',
'neutron',
'nova',
'sahara',
'swift'])
def test_service_config_directory_absent(host, path):
path = os.path.join('/etc/kolla/config', path)
utils.test_path_absent(host, path)

View File

@ -0,0 +1,9 @@
# Molecule managed
FROM {{ item.image }}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python2-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; fi

View File

@ -0,0 +1,16 @@
*******
Install
*******
Requirements
============
* Docker Engine
* docker-py
Install
=======
.. code-block:: bash
$ sudo pip install docker-py

View File

@ -0,0 +1,60 @@
---
- name: Create
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
vars:
molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}"
molecule_ephemeral_directory: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}"
molecule_scenario_directory: "{{ lookup('env', 'MOLECULE_SCENARIO_DIRECTORY') }}"
molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}"
tasks:
- name: Create Dockerfiles from image names
template:
src: "{{ molecule_scenario_directory }}/Dockerfile.j2"
dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.image | regex_replace('[^a-zA-Z0-9_]', '_') }}"
with_items: "{{ molecule_yml.platforms }}"
register: platforms
- name: Discover local Docker images
docker_image_facts:
name: "molecule_local/{{ item.item.name }}"
with_items: "{{ platforms.results }}"
register: docker_images
- name: Build an Ansible compatible image
docker_image:
path: "{{ molecule_ephemeral_directory }}"
name: "molecule_local/{{ item.item.image }}"
dockerfile: "{{ item.item.dockerfile | default(item.invocation.module_args.dest) }}"
force: "{{ item.item.force | default(true) }}"
with_items: "{{ platforms.results }}"
when: platforms.changed or docker_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0
- name: Create molecule instance(s)
docker_container:
name: "{{ item.name }}"
hostname: "{{ item.name }}"
image: "molecule_local/{{ item.image }}"
state: started
recreate: false
log_driver: json-file
command: "{{ item.command | default('bash -c \"while true; do sleep 10000; done\"') }}"
privileged: "{{ item.privileged | default(omit) }}"
volumes: "{{ item.volumes | default(omit) }}"
capabilities: "{{ item.capabilities | default(omit) }}"
ports: "{{ item.exposed_ports | default(omit) }}"
ulimits: "{{ item.ulimits | default(omit) }}"
register: server
with_items: "{{ molecule_yml.platforms }}"
async: 7200
poll: 0
- name: Wait for instance(s) creation to complete
async_status:
jid: "{{ item.ansible_job_id }}"
register: docker_jobs
until: docker_jobs.finished
retries: 300
with_items: "{{ server.results }}"

View File

@ -0,0 +1,27 @@
---
- name: Destroy
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
vars:
molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}"
molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}"
tasks:
- name: Destroy molecule instance(s)
docker_container:
name: "{{ item.name }}"
state: absent
force_kill: "{{ item.force_kill | default(true) }}"
register: server
with_items: "{{ molecule_yml.platforms }}"
async: 7200
poll: 0
- name: Wait for instance(s) deletion to complete
async_status:
jid: "{{ item.ansible_job_id }}"
register: docker_jobs
until: docker_jobs.finished
retries: 300
with_items: "{{ server.results }}"

View File

@ -0,0 +1,88 @@
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
platforms:
- name: centos-7
image: centos:7
- name: ubuntu-1604
image: ubuntu:16.04
provisioner:
name: ansible
inventory:
group_vars:
all:
kolla_extra_config_path:
kolla_enable_ceph: True
kolla_extra_ceph: |
[extra-ceph.conf]
foo=bar
kolla_enable_cinder: True
kolla_extra_cinder: |
[extra-cinder.conf]
foo=bar
kolla_enable_designate: True
kolla_extra_designate: |
[extra-designate.conf]
foo=bar
kolla_enable_glance: True
kolla_extra_glance: |
[extra-glance.conf]
foo=bar
kolla_enable_grafana: True
kolla_extra_grafana: |
[extra-grafana.ini]
foo=bar
kolla_enable_heat: True
kolla_extra_heat: |
[extra-heat.conf]
foo=bar
kolla_enable_horizon: True
kolla_enable_ironic: True
kolla_extra_ironic: |
[extra-ironic.conf]
foo=bar
kolla_extra_inspector: |
[extra-ironic-inspector.conf]
foo=bar
kolla_inspector_ipa_kernel_path: ${MOLECULE_TEMP_PATH:-/tmp}/ironic-agent.kernel
kolla_inspector_ipa_ramdisk_path: ${MOLECULE_TEMP_PATH:-/tmp}/ironic-agent.initramfs
kolla_extra_ironic_dnsmasq: |
extra=bar
kolla_enable_magnum: True
kolla_extra_magnum: |
[extra-magnum.conf]
foo=bar
kolla_enable_manila: True
kolla_enable_murano: True
kolla_enable_monasca: True
kolla_extra_murano: |
[extra-murano.conf]
foo=bar
kolla_enable_neutron: True
kolla_extra_neutron: |
[extra-neutron.conf]
foo=bar
kolla_extra_neutron_ml2: |
[extra-ml2_conf.ini]
foo=bar
kolla_enable_nova: True
kolla_extra_nova: |
[extra-nova.conf]
foo=bar
kolla_enable_sahara: True
kolla_extra_sahara: |
[extra-sahara.conf]
foo=bar
kolla_enable_swift: True
lint:
name: ansible-lint
scenario:
name: enable-everything
verifier:
name: testinfra
lint:
name: flake8

View File

@ -0,0 +1,5 @@
---
- name: Converge
hosts: all
roles:
- role: kolla-openstack

View File

@ -0,0 +1,23 @@
---
- name: Prepare
hosts: all
gather_facts: false
tasks:
- name: Ensure ironic inspector kernel and ramdisk image directory exists
local_action:
module: file
path: "{{ item | dirname }}"
state: directory
recurse: True
with_items:
- "{{ kolla_inspector_ipa_kernel_path }}"
- "{{ kolla_inspector_ipa_ramdisk_path }}"
- name: Ensure ironic inspector kernel and ramdisk images exist
local_action:
module: file
path: "{{ item }}"
state: touch
with_items:
- "{{ kolla_inspector_ipa_kernel_path }}"
- "{{ kolla_inspector_ipa_ramdisk_path }}"

View File

@ -0,0 +1,86 @@
# Copyright (c) 2018 StackHPC 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 os
import os.path
from kayobe.tests.molecule import utils
import pytest
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
@pytest.mark.parametrize(
'path',
['ceph',
'cinder',
'designate',
'fluentd/filter',
'fluentd/output',
'glance',
'grafana',
'heat',
'horizon',
'ironic',
'keystone',
'magnum',
'manila',
'murano',
'neutron',
'nova',
'sahara',
'swift'])
def test_service_config_directory(host, path):
path = os.path.join('/etc/kolla/config', path)
utils.test_directory(host, path)
@pytest.mark.parametrize(
'path',
['ceph.conf',
'cinder.conf',
'designate.conf',
'glance.conf',
'grafana.ini',
'heat.conf',
'ironic.conf',
'ironic-inspector.conf',
'magnum.conf',
'neutron/ml2_conf.ini',
'murano.conf',
'neutron.conf',
'nova.conf',
'sahara.conf'])
def test_service_ini_file(host, path):
# TODO(mgoddard): Check more of config file contents.
path = os.path.join('/etc/kolla/config', path)
extra_section = 'extra-%s' % os.path.basename(path)
expected = {extra_section: {'foo': 'bar'}}
utils.test_ini_file(host, path, expected=expected)
@pytest.mark.parametrize(
'path',
['ironic/ironic-agent.initramfs',
'ironic/ironic-agent.kernel',
'ironic/ironic-dnsmasq.conf',
'ironic/pxelinux.default'])
def test_service_non_ini_file(host, path):
# TODO(mgoddard): Check config file contents.
path = os.path.join('/etc/kolla/config', path)
utils.test_file(host, path)

View File

@ -13,7 +13,7 @@ kolla_openstack_custom_config:
- src: "{{ kolla_extra_config_path }}/ceph"
dest: "{{ kolla_node_custom_config_path }}/ceph"
patterns: "*"
enabled: "{{ kolla_enable_ceph }}"
enabled: "{{ kolla_enable_ceph }}"
# Cinder.
- src: "{{ kolla_extra_config_path }}/cinder"
dest: "{{ kolla_node_custom_config_path }}/cinder"

View File

@ -8,4 +8,5 @@ Kayobe Development Guide
vagrant
manual
automated
testing
contributing

View File

@ -0,0 +1,93 @@
=======
Testing
=======
Kayobe has a number of test suites covering different areas of code. Many tests
are run in virtual environments using ``tox``.
Preparation
===========
System Prerequisites
--------------------
The following packages should be installed on the development system prior to
running kayobe's tests.
* Ubuntu/Debian::
sudo apt-get install build-essential python-dev libssl-dev python-pip git
* Fedora 21/RHEL7/CentOS7::
sudo yum install python-devel openssl-devel python-pip git gcc
* Fedora 22 or higher::
sudo dnf install python-devel openssl-devel python-pip git gcc
* OpenSUSE/SLE 12::
sudo zypper install python-devel python-pip libopenssl-devel git
Python Prerequisites
--------------------
If your distro has at least ``tox 1.8``, use your system package manager to
install the ``python-tox`` package. Otherwise install this on all distros::
sudo pip install -U tox
You may need to explicitly upgrade ``virtualenv`` if youve installed the one from
your OS distribution and it is too old (tox will complain). You can upgrade it
individually, if you need to::
sudo pip install -U virtualenv
Running Unit Tests Locally
==========================
If you havent already, the kayobe source code should be pulled directly from
git::
# from your home or source directory
cd ~
git clone https://github.com/stackhpc/kayobe
cd kayobe
Running Unit and Style Tests
----------------------------
Kayobe defines a number of different tox environments in ``tox.ini``. The
default environments may be displayed::
tox -list
To run all default environments::
tox
To run one or more specific environments, including any of the non-default
environments::
tox -e <environment>[,<environment>]
Environments
------------
The following tox environments are provided:
alint
Run Ansible linter.
ansible
Run Ansible tests for some ansible roles using Ansible playbooks.
ansible-syntax
Run a syntax check for all Ansible files.
docs
Build Sphinx documentation.
molecule
Run Ansible tests for some Ansible roles using the molecule test framework.
pep8
Run style checks for all shell, python and documentation files.
py27,py34
Run python unit tests for kayobe python module.

View File

View File

@ -0,0 +1,78 @@
# Copyright (c) 2018 StackHPC 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 six
from six.moves import configparser
from six import StringIO
def test_file(host, path, owner='root', group='root'):
"""Test an expected file.
Validate that the file exists and has the correct ownership.
"""
f = host.file(path)
assert f.exists
assert f.is_file
assert owner == f.user
assert group == f.group
def test_ini_file(host, path, owner='root', group='root', expected=None):
"""Test an expected INI file.
Validate that the file exists, has the correct ownership, format and
expected contents.
:param expected: a dict of dicts providing config that should be present.
"""
test_file(host, path, owner, group)
sio = StringIO(host.file(path).content_string)
parser = configparser.RawConfigParser()
if six.PY3:
parser.read_file(sio)
else:
parser.readfp(sio)
if expected is None:
return
for exp_section_name, exp_section in expected.items():
assert parser.has_section(exp_section_name)
for exp_key, exp_value in exp_section.items():
assert parser.has_option(exp_section_name, exp_key)
assert parser.get(exp_section_name, exp_key) == exp_value
def test_directory(host, path, owner='root', group='root'):
"""Test an expected directory.
Validate that the directory exists and has the correct ownership.
"""
d = host.file(path)
assert d.exists
assert d.is_directory
assert owner == d.user
assert group == d.group
def test_path_absent(host, path):
"""Test a path expected to not exist."""
p = host.file(path)
assert not p.exists

View File

@ -2,11 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking>=0.12.0,<0.13 # Apache-2.0
ansible-lint>=3.0.0 # MIT
bashate>=0.2 # Apache-2.0
coverage>=4.0 # Apache-2.0
doc8 # Apache-2.0
sphinx>=1.5.1 # BSD
docker<3 # Apache-2.0
hacking>=0.12.0,<0.13 # Apache-2.0
molecule<3 # MIT
oslotest>=1.10.0 # Apache-2.0
ansible-lint>=3.0.0 # MIT
sphinx>=1.5.1 # BSD

25
tools/test-molecule.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
# Run molecule tests. Any arguments passed to this script will be passed onto
# molecule.
set -e
molecules="$(find ansible/roles/ -name molecule -type d)"
failed=0
ran=0
for molecule in $molecules; do
pushd $(dirname $molecule)
if ! molecule test --all $*; then
failed=$((failed + 1))
fi
ran=$((ran + 1))
popd
done
if [[ $failed -ne 0 ]]; then
echo "Failed $failed / $ran molecule tests"
exit 1
fi
echo "Ran $ran molecule tests successfully"

View File

@ -48,6 +48,15 @@ commands =
-p {toxinidir}/ansible/roles
{toxinidir}/tools/test-ansible.sh {posargs}
[testenv:molecule]
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/pike} {opts} {packages}
commands =
# Install ansible role dependencies from Galaxy.
ansible-galaxy install \
-r {toxinidir}/requirements.yml \
-p {toxinidir}/ansible/roles
{toxinidir}/tools/test-molecule.sh {posargs}
[testenv:alint]
commands = ansible-lint ansible/*.yaml