diff --git a/manual-test.rc b/manual-test.rc
index f7e77710..7016c453 100644
--- a/manual-test.rc
+++ b/manual-test.rc
@@ -30,4 +30,4 @@ export ANSIBLE_SSH_ARGS="-o ControlMaster=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)\""
+echo "# ./.tox/functional/bin/ansible-playbook -i tests/inventory tests/test.yml"
diff --git a/tests/test.yml b/tests/test.yml
index cbd33f89..32011abc 100644
--- a/tests/test.yml
+++ b/tests/test.yml
@@ -37,7 +37,7 @@
     - set_fact:
         lxc_container_ssh_key: key_get.stdout
   roles:
-    - role: "{{ rolename | basename }}"
+    - role: "lxc_hosts"
       lxc_net_address: 10.100.100.1
       lxc_net_bridge: lxcbr0
       lxc_kernel_options:
diff --git a/tox.ini b/tox.ini
index 94c9c1f1..c3abca57 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,12 +22,11 @@ passenv =
     NO_PROXY
 whitelist_externals =
     bash
-    git
-    rm
-    wget
 setenv =
-    VIRTUAL_ENV={envdir}
     PYTHONUNBUFFERED=1
+    ROLE_NAME=lxc_hosts
+    VIRTUAL_ENV={envdir}
+    WORKING_DIR={toxinidir}
 
 
 [testenv:docs]
@@ -53,17 +52,17 @@ commands =
     {posargs}
 
 
+[testenv:tests_clone]
+commands =
+    bash -c "if [ ! -d "{toxinidir}/tests/common" ]; then \
+               git clone https://git.openstack.org/openstack/openstack-ansible-tests {toxinidir}/tests/common; \
+             fi"
+
+
 [testenv:pep8]
 commands =
-    # Run hacking/flake8 check for all python files
-    bash -c "grep --recursive --binary-files=without-match \
-        --files-with-match '^.!.*python$' \
-        --exclude-dir .eggs \
-        --exclude-dir .git \
-        --exclude-dir .tox \
-        --exclude-dir *.egg-info \
-        --exclude-dir doc \
-        {toxinidir} | xargs flake8 --verbose"
+    {[testenv:tests_clone]commands}
+    bash -c "{toxinidir}/tests/common/test-pep8.sh"
 
 
 [flake8]
@@ -76,70 +75,27 @@ ignore=F403,H303
 
 [testenv:bashate]
 commands =
-    # Run bashate check for all bash scripts
-    # Ignores the following rules:
-    #     E003: Indent not multiple of 4 (we prefer to use multiples of 2)
-    #     E006: Line longer than 79 columns (as many scripts use jinja
-    #           templating, this is very difficult)
-    #     E040: Syntax error determined using `bash -n` (as many scripts
-    #           use jinja templating, this will often fail and the syntax
-    #           error will be discovered in execution anyway)
-    bash -c "grep --recursive --binary-files=without-match \
-        --files-with-match '^.!.*\(ba\)\?sh$' \
-        --exclude-dir .tox \
-        --exclude-dir .git \
-        {toxinidir} | xargs bashate --error . --verbose --ignore=E003,E006,E040"
+    {[testenv:tests_clone]commands}
+    bash -c "{toxinidir}/tests/common/test-bashate.sh"
 
 
 [testenv:ansible]
 deps =
     {[testenv]deps}
-    ansible==2.1.1
-    ansible-lint>=2.7.0,<3.0.0
-setenv =
-    {[testenv]setenv}
-    ANSIBLE_HOST_KEY_CHECKING = False
-    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.
-    ANSIBLE_ACTION_PLUGINS = {homedir}/.ansible/plugins/action
-    ANSIBLE_CALLBACK_PLUGINS = {homedir}/.ansible/plugins/callback
-    ANSIBLE_FILTER_PLUGINS = {homedir}/.ansible/plugins/filter
-    ANSIBLE_LOOKUP_PLUGINS = {homedir}/.ansible/plugins/lookup
-    # This is required as the default is the current path or a path specified
-    # in ansible.cfg
-    ANSIBLE_LIBRARY = {homedir}/.ansible/plugins/library
-    # 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"
+    -rhttp://git.openstack.org/cgit/openstack/openstack-ansible-tests/plain/test-ansible-deps.txt
 commands =
-    rm -rf {homedir}/.ansible/plugins
-    git clone https://git.openstack.org/openstack/openstack-ansible-plugins \
-              {homedir}/.ansible/plugins
-    rm -rf {homedir}/.ansible/roles
-    ansible-galaxy install \
-                   --role-file={toxinidir}/tests/ansible-role-requirements.yml \
-                   --force
-    rm -rf {homedir}/.ansible/roles/lxc_hosts
-    bash -c "ln -s {toxinidir} {homedir}/.ansible/roles/lxc_hosts"
-    rm -rf {toxinidir}/tests/playbooks
-    git clone https://git.openstack.org/openstack/openstack-ansible-tests \
-              {toxinidir}/tests/playbooks
+    {[testenv:tests_clone]commands}
+    bash -c "{toxinidir}/tests/common/test-ansible-env-prep.sh"
 
 
 [testenv:ansible-syntax]
 deps =
     {[testenv:ansible]deps}
-setenv =
-    {[testenv:ansible]setenv}
 commands =
     {[testenv:ansible]commands}
     ansible-playbook -i {toxinidir}/tests/inventory \
                      --syntax-check \
                      --list-tasks \
-                     -e "rolename={toxinidir}" \
                      {toxinidir}/tests/test.yml
 
 
@@ -161,10 +117,7 @@ install_command =
 
 [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/"'
+    bash -c "{toxinidir}/tests/common/test-log-collect.sh"
 
 
 [testenv:functional]
@@ -180,12 +133,9 @@ install_command =
     {[testenv:func_base]install_command}
 deps =
     {[testenv:ansible]deps}
-setenv =
-    {[testenv:ansible]setenv}
 commands =
     {[testenv:ansible]commands}
     ansible-playbook -i {toxinidir}/tests/inventory \
-                     -e "rolename={toxinidir}" \
                      -e "install_test_packages=True" \
                      {toxinidir}/tests/test.yml -vvvv
     {[testenv:func_logs]commands}
@@ -194,8 +144,6 @@ commands =
 [testenv:linters]
 deps =
     {[testenv:ansible]deps}
-setenv =
-    {[testenv:ansible]setenv}
 commands =
     {[testenv:pep8]commands}
     {[testenv:bashate]commands}