diff --git a/.gitignore b/.gitignore index 6075d49..21adf3c 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ doc/build/ *.log *.sql *.sqlite +logs/* # OS generated files # ###################### @@ -61,6 +62,10 @@ releasenotes/build # Test temp files tests/plugins +tests/playbooks +tests/test.retry + +# Vagrant artifacts +.vagrant + -# Files created by releasenotes build -releasenotes/build diff --git a/manual-test.rc b/manual-test.rc new file mode 100644 index 0000000..f7e7771 --- /dev/null +++ b/manual-test.rc @@ -0,0 +1,33 @@ +export VIRTUAL_ENV=$(pwd) +export ANSIBLE_HOST_KEY_CHECKING=False +export ANSIBLE_SSH_CONTROL_PATH=/tmp/%%h-%%r + +# TODO (odyssey4me) These are only here as they are non-standard folder +# names for Ansible 1.9.x. We are using the standard folder names for +# Ansible v2.x. We can remove this when we move to Ansible 2.x. +export ANSIBLE_ACTION_PLUGINS=${HOME}/.ansible/plugins/action +export ANSIBLE_CALLBACK_PLUGINS=${HOME}/.ansible/plugins/callback +export ANSIBLE_FILTER_PLUGINS=${HOME}/.ansible/plugins/filter +export ANSIBLE_LOOKUP_PLUGINS=${HOME}/.ansible/plugins/lookup + +# This is required as the default is the current path or a path specified +# in ansible.cfg +export ANSIBLE_LIBRARY=${HOME}/.ansible/plugins/library + +# This is required as the default is '/etc/ansible/roles' or a path +# specified in ansible.cfg +export ANSIBLE_ROLES_PATH=${HOME}/.ansible/roles:$(pwd)/.. + +export ANSIBLE_SSH_ARGS="-o ControlMaster=no \ + -o UserKnownHostsFile=/dev/null \ + -o StrictHostKeyChecking=no \ + -o ServerAliveInterval=64 \ + -o ServerAliveCountMax=1024 \ + -o Compression=no \ + -o TCPKeepAlive=yes \ + -o VerifyHostKeyDNS=no \ + -o ForwardX11=no \ + -o ForwardAgent=yes" + +echo "Run manual functional tests by executing the following:" +echo "# ./.tox/functional/bin/ansible-playbook -i tests/inventory tests/test.yml -e \"rolename=$(pwd)\"" diff --git a/run_tests.sh b/run_tests.sh index 0a49aa3..482a389 100644 --- a/run_tests.sh +++ b/run_tests.sh @@ -24,23 +24,23 @@ if [ ! "$(which pip)" ]; then fi # Install bindep and tox -pip install bindep tox +sudo pip install bindep tox # CentOS 7 requires two additional packages: # redhat-lsb-core - for bindep profile support # epel-release - required to install python-ndg_httpsclient/python2-pyasn1 if [ "$(which yum)" ]; then - yum -y install redhat-lsb-core epel-release + sudo yum -y install redhat-lsb-core epel-release fi # Install OS packages using bindep if apt-get -v >/dev/null 2>&1 ; then - apt-get update + sudo apt-get update DEBIAN_FRONTEND=noninteractive \ - apt-get -q --option "Dpkg::Options::=--force-confold" \ + sudo apt-get -q --option "Dpkg::Options::=--force-confold" \ --assume-yes install `bindep -b -f bindep.txt test` else - yum install -y `bindep -b -f bindep.txt test` + sudo yum install -y `bindep -b -f bindep.txt test` fi # run through each tox env and execute the test diff --git a/tests/group_vars/all_containers.yml b/tests/group_vars/all_containers.yml new file mode 100644 index 0000000..f37df47 --- /dev/null +++ b/tests/group_vars/all_containers.yml @@ -0,0 +1,26 @@ +--- +# Copyright 2016, Rackspace US, Inc. +# +# 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. + +container_name: "{{ inventory_hostname }}" +container_networks: + management_address: + address: "{{ ansible_host }}" + bridge: "br-mgmt" + interface: "eth1" + netmask: "255.255.255.0" + type: "veth" +physical_host: localhost +properties: + service_name: "{{ inventory_hostname }}" diff --git a/tests/host_vars/localhost.yml b/tests/host_vars/localhost.yml new file mode 100644 index 0000000..65ddeaa --- /dev/null +++ b/tests/host_vars/localhost.yml @@ -0,0 +1,19 @@ +--- +# Copyright 2016, Rackspace US, Inc. +# +# 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. + +bridges: + - "br-mgmt" + +ansible_python_interpreter: "/usr/bin/python2" diff --git a/tests/inventory b/tests/inventory index 6c0833a..35885c4 100644 --- a/tests/inventory +++ b/tests/inventory @@ -1,2 +1,43 @@ [all] -localhost ansible_connection=local ansible_become=True +localhost ansible_become=True +service1 ansible_host=10.100.100.2 ansible_become=True ansible_user=root +openstack1 ansible_host=10.100.100.3 ansible_become=True ansible_user=root + +[all_containers] +service1 +openstack1 + +[rabbitmq_all] +service1 + +[galera_all] +service1 + +[memcached_all] +service1 + +[service_all:children] +rabbitmq_all +galera_all +memcached_all + +[keystone_all] +openstack1 + +[cloudkitty_api] +openstack1 + +[cloudkitty_engine] +openstack1 + +[cloudkitty_engine_container] +openstack1 + +[cloudkitty_apis_container] +openstack1 + +[cloudkitty_all:children] +cloudkitty_api +cloudkitty_apis_container +cloudkitty_engine +cloudkitty_engine_container diff --git a/tests/test-container-create.yml b/tests/test-container-create.yml deleted file mode 100644 index efca943..0000000 --- a/tests/test-container-create.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- -# Copyright 2015, Rackspace US, Inc. -# -# 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. - -- name: Create test containers - hosts: all_containers - connection: local - gather_facts: false - pre_tasks: - - name: Destroy test containers - lxc_container: - name: "{{ container_name }}" - state: "absent" - delegate_to: "{{ physical_host }}" - tags: - - container-destroy - - name: Destroy container service directories - file: - path: "{{ item }}" - state: "absent" - with_items: - - "/openstack/{{ container_name }}" - - "/openstack/backup/{{ container_name }}" - - "/openstack/log/{{ container_name }}" - - "/var/lib/lxc/{{ container_name }}" - - "{{ lxc_container_directory|default('/var/lib/lxc') }}/{{ container_name }}" - delegate_to: "{{ physical_host }}" - tags: - - container-directories - roles: - - role: "lxc_container_create" - lxc_container_release: trusty - lxc_container_backing_store: dir - global_environment_variables: - PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - post_tasks: - - name: Wait for ssh to be available - local_action: - module: wait_for - port: "{{ ansible_ssh_port | default('22') }}" - host: "{{ ansible_ssh_host | default(inventory_hostname) }}" - search_regex: OpenSSH - delay: 1 diff --git a/tests/test-install-cloudkitty.yml b/tests/test-install-cloudkitty.yml new file mode 100644 index 0000000..f6645bd --- /dev/null +++ b/tests/test-install-cloudkitty.yml @@ -0,0 +1,40 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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. + +- name: Playbook for role testing + hosts: cloudkitty_all + user: root + gather_facts: true + pre_tasks: + - name: Ensure Rabbitmq vhost + rabbitmq_vhost: + name: "{{ cloudkitty_rabbitmq_vhost }}" + state: "present" + delegate_to: "{{ hostvars[groups['rabbitmq_all'][0]]['ansible_host'] }}" + - name: Ensure rabbitmq user + rabbitmq_user: + user: "{{ cloudkitty_rabbitmq_userid }}" + password: "{{ cloudkitty_rabbitmq_password }}" + vhost: "{{ cloudkitty_rabbitmq_vhost }}" + configure_priv: ".*" + read_priv: ".*" + write_priv: ".*" + state: "present" + delegate_to: "{{ hostvars[groups['rabbitmq_all'][0]]['ansible_host'] }}" + roles: + - role: "os_cloudkitty" + vars_files: + - playbooks/test-vars.yml + - test-vars.yml \ No newline at end of file diff --git a/tests/test-prep.yml b/tests/test-prep.yml deleted file mode 100644 index b007dda..0000000 --- a/tests/test-prep.yml +++ /dev/null @@ -1,86 +0,0 @@ ---- -# Copyright 2015, Rackspace US, Inc. -# -# 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. - -- name: Create ssh key pairs for use with containers - hosts: 127.0.0.1 - connection: local - become: false - pre_tasks: - - name: Create ssh key pair for root - user: - name: "{{ ansible_ssh_user }}" - generate_ssh_key: "yes" - ssh_key_bits: 2048 - ssh_key_file: ".ssh/id_rsa" - - name: get the calling users key - command: cat ~/.ssh/id_rsa.pub - register: key_get - - set_fact: - lxc_container_ssh_key: "{{ key_get.stdout }}" - -- name: Perform basic LXC host setup - hosts: localhost - connection: local - become: yes - pre_tasks: - # Make sure OS does not have a stale package cache. - - name: Update apt cache. - apt: - update_cache: yes - when: ansible_os_family == 'Debian' - - name: Ensure root's new public ssh key is in authorized_keys - authorized_key: - user: root - key: "{{ hostvars['127.0.0.1']['lxc_container_ssh_key'] }}" - manage_dir: no - - set_fact: - lxc_container_ssh_key: "{{ hostvars['127.0.0.1']['lxc_container_ssh_key'] }}" - roles: - - role: "lxc_hosts" - lxc_net_address: 10.100.100.1 - lxc_net_dhcp_range: 10.100.100.2,10.100.100.253 - lxc_net_bridge: lxcbr0 - lxc_kernel_options: - - { key: 'fs.inotify.max_user_instances', value: 1024 } - lxc_container_caches: - - url: "https://rpc-repo.rackspace.com/container_images/rpc-trusty-container.tgz" - name: "trusty.tgz" - sha256sum: "56c6a6e132ea7d10be2f3e8104f47136ccf408b30e362133f0dc4a0a9adb4d0c" - chroot_path: trusty/rootfs-amd64 - post_tasks: - # Inventory is being pre-loaded using a post tasks instead of through a dynamic - # inventory system. While this is not a usual method for deployment it's being - # done for functional testing. - - name: Create container hosts - add_host: - groups: "{{ item.groups }}" - hostname: "{{ item.name }}" - inventory_hostname: "{{ item.name }}" - ansible_ssh_host: "{{ item.address }}" - ansible_become: true - properties: - service_name: "{{ item.service }}" - container_networks: - management_address: - address: "{{ item.address }}" - bridge: "lxcbr0" - interface: "eth1" - netmask: "255.255.252.0" - type: "veth" - physical_host: localhost - container_name: "{{ item.name }}" - with_items: - - { name: "service1", service: "service1", address: "10.100.100.101", groups: "all,all_containers,rabbitmq_all,galera_all,service_all" } - - { name: "openstack1", service: "openstack1", address: "10.100.100.102", groups: "all,all_containers,cloudkitty_all,cloudkitty_api,cloudkitty_engine,cloudkitty_engine_container,cloudkitty_apis_container,keystone_all" } diff --git a/tests/test-vars.yml b/tests/test-vars.yml new file mode 100644 index 0000000..eccd943 --- /dev/null +++ b/tests/test-vars.yml @@ -0,0 +1,25 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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. + +cloudkitty_venv_tag: "testing" +cloudkitty_developer_mode: true +cloudkitty_git_install_branch: master +cloudkitty_requirements_git_install_branch: master +cloudkitty_galera_address: "{{ hostvars[groups['galera_all'][0]]['ansible_host'] }}" +cloudkitty_galera_password: "SuperSecrete" +cloudkitty_user_password: "secrete" +cloudkitty_rabbitmq_password: "secrete" +cloudkitty_rabbitmq_userid: cloudkitty +cloudkitty_rabbitmq_vhost: /cloudkitty diff --git a/tests/test.yml b/tests/test.yml index 98db5fc..73ad239 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -13,145 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Run basic prep -- include: test-prep.yml +# Setup the host +- include: playbooks/test-setup-host.yml -# Run container clean up and build -- include: test-container-create.yml +# Install RabbitMQ/MariaDB +- include: playbooks/test-install-infra.yml -- name: Playbook for deploying infra services - hosts: service_all - user: root - gather_facts: true - roles: - - role: "rabbitmq_server" - rabbitmq_cookie_token: secrete - - role: "galera_server" - galera_root_password: secrete - galera_root_user: root - galera_innodb_buffer_pool_size: 512M - galera_innodb_log_buffer_size: 32M - galera_server_id: "{{ inventory_hostname | string_2_int }}" - galera_wsrep_node_name: "{{ inventory_hostname }}" - galera_wsrep_provider_options: - - { option: "gcache.size", value: "32M" } - galera_server_id: "{{ inventory_hostname | string_2_int }}" +# Install Keystone +- include: playbooks/test-install-keystone.yml -- name: Playbook for deploying keystone - hosts: keystone_all - user: root - gather_facts: true - pre_tasks: - - name: Ensure Rabbitmq vhost - rabbitmq_vhost: - name: "{{ keystone_rabbitmq_vhost }}" - state: "present" - delegate_to: "10.100.100.101" - - name: Ensure rabbitmq user - rabbitmq_user: - user: "{{ keystone_rabbitmq_userid }}" - password: "{{ keystone_rabbitmq_password }}" - vhost: "{{ keystone_rabbitmq_vhost }}" - configure_priv: ".*" - read_priv: ".*" - write_priv: ".*" - state: "present" - delegate_to: "10.100.100.101" - - name: Create DB for service - mysql_db: - login_user: "root" - login_password: "secrete" - login_host: "localhost" - name: "{{ keystone_galera_database }}" - state: "present" - delegate_to: "10.100.100.101" - - name: Grant access to the DB for the service - mysql_user: - login_user: "root" - login_password: "secrete" - login_host: "localhost" - name: "{{ keystone_galera_database }}" - password: "{{ keystone_container_mysql_password }}" - host: "{{ item }}" - state: "present" - priv: "{{ keystone_galera_database }}.*:ALL" - with_items: - - "localhost" - - "%" - delegate_to: "10.100.100.101" - roles: - - role: os_keystone - vars: - external_lb_vip_address: 10.100.100.102 - internal_lb_vip_address: 10.100.100.102 - keystone_galera_address: 10.100.100.101 - keystone_galera_database: keystone - keystone_venv_tag: "testing" - keystone_developer_mode: true - keystone_git_install_branch: master - keystone_requirements_git_install_branch: master - keystone_auth_admin_token: "SuperSecreteTestToken" - keystone_auth_admin_password: "SuperSecretePassword" - keystone_service_password: "secrete" - keystone_rabbitmq_password: "secrete" - keystone_container_mysql_password: "SuperSecrete" - keystone_rabbitmq_port: 5671 - keystone_rabbitmq_userid: keystone - keystone_rabbitmq_vhost: /keystone - keystone_rabbitmq_servers: 10.100.100.101 - keystone_rabbitmq_use_ssl: false - galera_client_drop_config_file: false - -- name: Playbook for role testing - hosts: cloudkitty_all - user: root - gather_facts: true - pre_tasks: - - name: Ensure Rabbitmq vhost - rabbitmq_vhost: - name: "{{ cloudkitty_rabbitmq_vhost }}" - state: "present" - delegate_to: "10.100.100.101" - - name: Ensure rabbitmq user - rabbitmq_user: - user: "{{ cloudkitty_rabbitmq_userid }}" - password: "{{ cloudkitty_rabbitmq_password }}" - vhost: "{{ cloudkitty_rabbitmq_vhost }}" - configure_priv: ".*" - read_priv: ".*" - write_priv: ".*" - state: "present" - delegate_to: "10.100.100.101" - roles: - - role: "{{ rolename | basename }}" - vars: - external_lb_vip_address: 10.100.100.102 - internal_lb_vip_address: 10.100.100.102 - cloudkitty_venv_tag: "testing" - cloudkitty_developer_mode: true - cloudkitty_git_install_branch: master - cloudkitty_requirements_git_install_branch: master - cloudkitty_galera_address: 10.100.100.101 - galera_client_drop_config_file: false - galera_root_password: "secrete" - cloudkitty_galera_password: "SuperSecrete" - cloudkitty_user_password: "secrete" - cloudkitty_rabbitmq_password: "secrete" - cloudkitty_rabbitmq_userid: cloudkitty - cloudkitty_rabbitmq_vhost: /cloudkitty - rabbitmq_servers: 10.100.100.101 - rabbitmq_use_ssl: false - rabbitmq_port: 5671 - keystone_auth_admin_password: "SuperSecretePassword" - keystone_admin_user_name: admin - keystone_admin_tenant_name: admin - keystone_service_adminuri_insecure: false - keystone_service_internaluri_insecure: false - keystone_service_internaluri: "http://{{ internal_lb_vip_address }}:5000" - keystone_service_internalurl: "{{ keystone_service_internaluri }}/v3" - keystone_service_adminuri: "http://{{ internal_lb_vip_address }}:35357" - keystone_service_adminurl: "{{ keystone_service_adminuri }}/v3" - openrc_os_password: "{{ keystone_auth_admin_password }}" - openrc_os_domain_name: "Default" - memcached_servers: 127.0.0.1 - memcached_encryption_key: "secrete" +- include: test-install-cloudkitty.yml \ No newline at end of file diff --git a/tox.ini b/tox.ini index 55a5f11..a55c5bb 100644 --- a/tox.ini +++ b/tox.ini @@ -94,7 +94,7 @@ commands = [testenv:ansible] deps = {[testenv]deps} - ansible==1.9.4 + ansible==2.1.1 ansible-lint>=2.7.0,<3.0.0 setenv = {[testenv]setenv} @@ -113,6 +113,7 @@ setenv = # This is required as the default is '/etc/ansible/roles' or a path # specified in ansible.cfg ANSIBLE_ROLES_PATH = {homedir}/.ansible/roles:{toxinidir}/.. + ANSIBLE_TRANSPORT = "ssh" commands = rm -rf {homedir}/.ansible/plugins git clone https://git.openstack.org/openstack/openstack-ansible-plugins \ @@ -121,7 +122,11 @@ commands = ansible-galaxy install \ --role-file={toxinidir}/tests/ansible-role-requirements.yml \ --force - + rm -rf {homedir}/.ansible/roles/os_cloudkitty + bash -c "ln -s {toxinidir} {homedir}/.ansible/roles/os_cloudkitty" + rm -rf {toxinidir}/tests/playbooks + git clone https://git.openstack.org/openstack/openstack-ansible-tests \ + {toxinidir}/tests/playbooks [testenv:ansible-syntax] deps = @@ -133,7 +138,6 @@ commands = ansible-playbook -i {toxinidir}/tests/inventory \ --syntax-check \ --list-tasks \ - -e "rolename={toxinidir}" \ {toxinidir}/tests/test.yml @@ -145,6 +149,22 @@ commands = ansible-lint {toxinidir} +[testenv:func_base] +# NOTE(odyssey4me): this target does not use constraints because +# it doesn't work in OpenStack-CI yet. Once that's fixed, we can +# drop the install_command. +install_command = + pip install -U --force-reinstall {opts} {packages} + + +[testenv:func_logs] +commands = + bash -c 'mkdir -p {toxinidir}/logs' + bash -c 'rsync --archive --verbose --ignore-errors /var/log/ /openstack/log/ {toxinidir}/logs/ || true' + bash -c 'find "{toxinidir}/logs/" -type f | sed "p;s|$|.txt|" | xargs -n2 mv' + bash -c 'command gzip --best --recursive "{toxinidir}/logs/"' + + [testenv:functional] # Ignore_errors is set to true so that the logs are collected at the # end of the run. This will not produce a false positive. Any @@ -155,7 +175,7 @@ ignore_errors = True # it doesn't work in OpenStack-CI yet. Once that's fixed, we can # drop the install_command. install_command = - pip install -U --force-reinstall {opts} {packages} + {[testenv:func_base]install_command} deps = {[testenv:ansible]deps} setenv = @@ -163,13 +183,9 @@ setenv = commands = {[testenv:ansible]commands} ansible-playbook -i {toxinidir}/tests/inventory \ - -e "rolename={toxinidir}" \ -e "install_test_packages=True" \ {toxinidir}/tests/test.yml -vvvv - bash -c 'mkdir -p {toxinidir}/logs' - bash -c 'rsync --archive --verbose --ignore-errors /var/log/ /openstack/log/ {toxinidir}/logs/ || true' - bash -c 'find "{toxinidir}/logs/" -type f | sed "p;s|$|.txt|" | xargs -n2 mv' - bash -c 'command gzip --best --recursive "{toxinidir}/logs/"' + {[testenv:func_logs]commands} [testenv:linters]