diff --git a/doc/source/devref/development.environment.rst b/doc/source/devref/development.environment.rst
index 71553434bde..faaeaf83027 100644
--- a/doc/source/devref/development.environment.rst
+++ b/doc/source/devref/development.environment.rst
@@ -106,29 +106,33 @@ See :doc:`testing` for more details.
 Manually installing and using the virtualenv
 --------------------------------------------
 
-You can manually install the virtual environment instead of having
-``run_tests.sh`` do it for you::
+You can also manually install the virtual environment::
 
-  python tools/install_venv.py
+  tox -e py27 --notest
+
+or::
+
+  tox -e py35 --notest
 
 This will install all of the Python packages listed in the
-``requirements.txt`` file into your virtualenv. There will also be some
-additional packages (pip, setuptools) that are installed
-by the ``tools/install_venv.py`` file into the virtualenv.
+``requirements.txt`` file into your virtualenv.
 
-If all goes well, you should get a message something like this::
+To activate the Cinder virtualenv you can run::
 
-  Cinder development environment setup is complete.
+     $ source .tox/py27/bin/activate
 
-To activate the Cinder virtualenv for the extent of your current shell session
-you can run::
+or::
 
-     $ source .venv/bin/activate
+     $ source .tox/py35/bin/activate
+
+To exit your virtualenv, just type::
+
+     $ deactivate
 
 Or, if you prefer, you can run commands in the virtualenv on a case by case
 basis by running::
 
-     $ tools/with_venv.sh <your command>
+     $ tox -e venv -- <your command>
 
 Contributing Your Work
 ----------------------
diff --git a/run_tests.sh b/run_tests.sh
deleted file mode 100755
index 6b308a32f4f..00000000000
--- a/run_tests.sh
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-function usage {
-  echo "Usage: $0 [OPTION]..."
-  echo "Run Cinder's test suite(s)"
-  echo ""
-  echo "  -V, --virtual-env           Always use virtualenv.  Install automatically if not present"
-  echo "  -N, --no-virtual-env        Don't use virtualenv.  Run tests in local environment"
-  echo "  -s, --no-site-packages      Isolate the virtualenv from the global Python environment"
-  echo "  -r, --recreate-db           Recreate the test database (deprecated, as this is now the default)."
-  echo "  -n, --no-recreate-db        Don't recreate the test database."
-  echo "  -f, --force                 Force a clean re-build of the virtual environment. Useful when dependencies have been added."
-  echo "  -u, --update                Update the virtual environment with any newer package versions"
-  echo "  -p, --pep8                  Just run PEP8 and HACKING compliance check"
-  echo "  -8, --pep8-only-changed Just run PEP8 and HACKING compliance check on files changed since HEAD~1"
-  echo "  -P, --no-pep8               Don't run static code checks"
-  echo "  -c, --coverage              Generate coverage report"
-  echo "  -d, --debug                 Run tests with testtools instead of testr. This allows you to use the debugger."
-  echo "  -h, --help                  Print this usage message"
-  echo "  --hide-elapsed              Don't print the elapsed time for each test along with slow test list"
-  echo "  --virtual-env-path <path>   Location of the virtualenv directory"
-  echo "                               Default: \$(pwd)"
-  echo "  --virtual-env-name <name>   Name of the virtualenv directory"
-  echo "                               Default: .venv"
-  echo "  --tools-path <dir>          Location of the tools directory"
-  echo "                               Default: \$(pwd)"
-  echo "  --concurrency <concurrency> How many processes to use when running the tests. A value of 0 autodetects concurrency from your CPU count"
-  echo "                               Default: 1"
-  echo ""
-  echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
-  echo "      If no virtualenv is found, the script will ask if you would like to create one.  If you "
-  echo "      prefer to run tests NOT in a virtual environment, simply pass the -N option."
-  exit
-}
-
-function process_options {
-  i=1
-  while [ $i -le $# ]; do
-    case "${!i}" in
-      -h|--help) usage;;
-      -V|--virtual-env) always_venv=1; never_venv=0;;
-      -N|--no-virtual-env) always_venv=0; never_venv=1;;
-      -s|--no-site-packages) no_site_packages=1;;
-      -r|--recreate-db) recreate_db=1;;
-      -n|--no-recreate-db) recreate_db=0;;
-      -f|--force) force=1;;
-      -u|--update) update=1;;
-      -p|--pep8) just_pep8=1;;
-      -8|--pep8-only-changed) just_pep8_changed=1;;
-      -P|--no-pep8) no_pep8=1;;
-      -c|--coverage) coverage=1;;
-      -d|--debug) debug=1;;
-      --virtual-env-path)
-        (( i++ ))
-        venv_path=${!i}
-        ;;
-      --virtual-env-name)
-        (( i++ ))
-        venv_dir=${!i}
-        ;;
-      --tools-path)
-        (( i++ ))
-        tools_path=${!i}
-        ;;
-      --concurrency)
-        (( i++ ))
-        concurrency=${!i}
-        ;;
-      -*) testropts="$testropts ${!i}";;
-      *) testrargs="$testrargs ${!i}"
-    esac
-    (( i++ ))
-  done
-}
-
-tool_path=${tools_path:-$(pwd)}
-venv_path=${venv_path:-$(pwd)}
-venv_dir=${venv_name:-.venv}
-with_venv=tools/with_venv.sh
-always_venv=0
-never_venv=0
-force=0
-no_site_packages=0
-installvenvopts=
-testrargs=
-testropts=
-wrapper=""
-just_pep8=0
-just_pep8_changed=0
-no_pep8=0
-coverage=0
-debug=0
-recreate_db=1
-update=0
-concurrency=1
-
-LANG=en_US.UTF-8
-LANGUAGE=en_US:en
-LC_ALL=C
-
-process_options $@
-# Make our paths available to other scripts we call
-export venv_path
-export venv_dir
-export venv_name
-export tools_dir
-export venv=${venv_path}/${venv_dir}
-
-if [ $no_site_packages -eq 1 ]; then
-  installvenvopts="--no-site-packages"
-fi
-
-function run_tests {
-  # Cleanup *pyc
-  ${wrapper} find . -type f -name "*.pyc" -delete
-
-  if [ $debug -eq 1 ]; then
-    if [ "$testropts" = "" ] && [ "$testrargs" = "" ]; then
-      # Default to running all tests if specific test is not
-      # provided.
-      testrargs="discover ./cinder/tests"
-    fi
-    ${wrapper} python -m testtools.run $testropts $testrargs
-
-    # Short circuit because all of the testr and coverage stuff
-    # below does not make sense when running testtools.run for
-    # debugging purposes.
-    return $?
-  fi
-
-  if [ $coverage -eq 1 ]; then
-    TESTRTESTS="$TESTRTESTS --coverage"
-    if [ -z "${PYTHONPATH:-}" ]; then
-        export PYTHONPATH=./
-    else
-        export PYTHONPATH=$PYTHONPATH:./
-    fi
-  else
-    TESTRTESTS="$TESTRTESTS"
-  fi
-
-  # Just run the test suites in current environment
-  set +e
-  testrargs=`echo "$testrargs" | sed -e's/^\s*\(.*\)\s*$/\1/'`
-  TESTRTESTS="$TESTRTESTS --testr-args='--subunit --concurrency $concurrency $testropts $testrargs'"
-  if [ setup.cfg -nt cinder.egg-info/entry_points.txt ]
-  then
-    ${wrapper} python setup.py egg_info
-  fi
-  echo "Running \`${wrapper} $TESTRTESTS\`"
-  bash -c "${wrapper} $TESTRTESTS | ${wrapper} subunit-trace"
-  RESULT=$?
-  set -e
-
-  copy_subunit_log
-
-  if [ $coverage -eq 1 ]; then
-    echo "Generating coverage report in covhtml/"
-    # Don't compute coverage for common code, which is tested elsewhere
-    ${wrapper} coverage combine
-    ${wrapper} coverage html --include='cinder/*' -d covhtml -i
-  fi
-
-  return $RESULT
-}
-
-function copy_subunit_log {
-  LOGNAME=`cat .testrepository/next-stream`
-  LOGNAME=$(($LOGNAME - 1))
-  LOGNAME=".testrepository/${LOGNAME}"
-  cp $LOGNAME subunit.log
-}
-
-function warn_on_flake8_without_venv {
-  if [ $never_venv -eq 1 ]; then
-    echo "**WARNING**:"
-    echo "Running flake8 without virtual env may miss OpenStack HACKING detection"
-  fi
-}
-
-function run_pep8 {
-  echo "Running flake8 ..."
-  warn_on_flake8_without_venv
-  bash -c "${wrapper} flake8"
-  ${wrapper} bash tools/config/check_uptodate.sh --checkonly
-  ${wrapper} tools/check_exec.py cinder || exit 1
-}
-
-
-TESTRTESTS="python setup.py testr"
-
-if [ $never_venv -eq 0 ]
-then
-  # Remove the virtual environment if --force used
-  if [ $force -eq 1 ]; then
-    echo "Cleaning virtualenv..."
-    rm -rf ${venv}
-  fi
-  if [ $update -eq 1 ]; then
-      echo "Updating virtualenv..."
-      python tools/install_venv.py $installvenvopts
-  fi
-  if [ -e ${venv} ]; then
-    wrapper="${with_venv}"
-  else
-    if [ $always_venv -eq 1 ]; then
-      # Automatically install the virtualenv
-      python tools/install_venv.py $installvenvopts
-      wrapper="${with_venv}"
-    else
-      echo -e "No virtual environment found...create one? (Y/n) \c"
-      read use_ve
-      if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
-        # Install the virtualenv and run the test suite in it
-        python tools/install_venv.py $installvenvopts
-        wrapper=${with_venv}
-      fi
-    fi
-  fi
-fi
-
-# Delete old coverage data from previous runs
-if [ $coverage -eq 1 ]; then
-    ${wrapper} coverage erase
-fi
-
-if [ $just_pep8 -eq 1 ]; then
-    run_pep8
-    exit
-fi
-
-if [ $recreate_db -eq 1 ]; then
-    rm -f tests.sqlite
-fi
-
-if [ $just_pep8_changed -eq 1 ]; then
-    # NOTE(gilliard) We want to use flake8 to check the
-    # entirety of every file that has a change in it.
-    # Unfortunately the --filenames argument to flake8 only accepts
-    # file *names* and there are no files named (eg) "nova/compute/manager.py". The
-    # --diff argument behaves surprisingly as well, because although you feed it a
-    # diff, it actually checks the file on disk anyway.
-    files=$(git diff --name-only HEAD~1 | tr '\n' ' ')
-    echo "Running flake8 on ${files}"
-    warn_on_flake8_without_venv
-    bash -c "diff -u --from-file /dev/null ${files} | ${wrapper} flake8 --diff"
-    exit
-fi
-
-run_tests
-
-# NOTE(sirp): we only want to run pep8 when we're running the full-test suite,
-# not when we're running tests individually. To handle this, we need to
-# distinguish between options (testropts), which begin with a '-', and
-# arguments (testrargs).
-if [ -z "$testrargs" ]; then
-  if [ $no_pep8 -eq 0 ]; then
-    run_pep8
-  fi
-fi
diff --git a/tools/enable-pre-commit-hook.sh b/tools/enable-pre-commit-hook.sh
index d4f1ba3f523..4c4a20dd9a4 100755
--- a/tools/enable-pre-commit-hook.sh
+++ b/tools/enable-pre-commit-hook.sh
@@ -17,7 +17,7 @@
 PRE_COMMIT_SCRIPT=.git/hooks/pre-commit
 
 make_hook() {
-    echo "exec ./run_tests.sh -N -p" >> $PRE_COMMIT_SCRIPT
+    echo "exec tox -e fast8" >> $PRE_COMMIT_SCRIPT
     chmod +x $PRE_COMMIT_SCRIPT
 
     if [ -w $PRE_COMMIT_SCRIPT -a -x $PRE_COMMIT_SCRIPT ]; then
diff --git a/tools/install_venv.py b/tools/install_venv.py
deleted file mode 100644
index 8cf250ab743..00000000000
--- a/tools/install_venv.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2010 OpenStack Foundation
-# Copyright 2013 IBM Corp.
-#
-#    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.
-
-"""Installation script for Cinder's development virtualenv."""
-
-from __future__ import print_function
-
-import optparse
-import os
-import subprocess
-import sys
-
-import install_venv_common as install_venv
-
-
-def print_help():
-    help = """
-    Cinder development environment setup is complete.
-
-    Cinder development uses virtualenv to track and manage Python dependencies
-    while in development and testing.
-
-    To activate the Cinder virtualenv for the extent of your current shell
-    session you can run:
-
-    $ source .venv/bin/activate
-
-    Or, if you prefer, you can run commands in the virtualenv on a case by case
-    basis by running:
-
-    $ tools/with_venv.sh <your command>
-
-    Also, make test will automatically use the virtualenv.
-    """
-    print(help)
-
-
-def main(argv):
-    root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-    venv = os.path.join(root, '.venv')
-    if os.environ.get('venv'):
-        venv = os.environ['venv']
-    pip_requires = os.path.join(root, 'requirements.txt')
-    test_requires = os.path.join(root, 'test-requirements.txt')
-    project = 'Cinder'
-    py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
-    install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
-                                       py_version, project)
-    options = install.parse_args(argv)
-    install.check_python_version()
-    install.check_dependencies()
-    install.create_virtualenv(no_site_packages=options.no_site_packages)
-    install.install_dependencies()
-    print_help()
-
-
-if __name__ == '__main__':
-    main(sys.argv)
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
deleted file mode 100644
index e279159abbc..00000000000
--- a/tools/install_venv_common.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# Copyright 2013 IBM Corp.
-#
-#    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.
-
-"""Provides methods needed by installation script for OpenStack development
-virtual environments.
-
-Since this script is used to bootstrap a virtualenv from the system's Python
-environment, it should be kept strictly compatible with Python 2.6.
-
-Synced in from openstack-common
-"""
-
-from __future__ import print_function
-
-import optparse
-import os
-import subprocess
-import sys
-
-
-class InstallVenv(object):
-
-    def __init__(self, root, venv, requirements,
-                 test_requirements, py_version,
-                 project):
-        self.root = root
-        self.venv = venv
-        self.requirements = requirements
-        self.test_requirements = test_requirements
-        self.py_version = py_version
-        self.project = project
-
-    def die(self, message, *args):
-        print(message % args, file=sys.stderr)
-        sys.exit(1)
-
-    def check_python_version(self):
-        if sys.version_info < (2, 6):
-            self.die("Need Python Version >= 2.6")
-
-    def run_command_with_code(self, cmd, redirect_output=True,
-                              check_exit_code=True):
-        """Runs a command in an out-of-process shell.
-
-        Returns the output of that command. Working directory is self.root.
-        """
-        if redirect_output:
-            stdout = subprocess.PIPE
-        else:
-            stdout = None
-
-        proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
-        output = proc.communicate()[0]
-        if check_exit_code and proc.returncode != 0:
-            self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
-        return (output, proc.returncode)
-
-    def run_command(self, cmd, redirect_output=True, check_exit_code=True):
-        return self.run_command_with_code(cmd, redirect_output,
-                                          check_exit_code)[0]
-
-    def get_distro(self):
-        if (os.path.exists('/etc/fedora-release') or
-                os.path.exists('/etc/redhat-release')):
-            return Fedora(
-                self.root, self.venv, self.requirements,
-                self.test_requirements, self.py_version, self.project)
-        else:
-            return Distro(
-                self.root, self.venv, self.requirements,
-                self.test_requirements, self.py_version, self.project)
-
-    def check_dependencies(self):
-        self.get_distro().install_virtualenv()
-
-    def create_virtualenv(self, no_site_packages=True):
-        """Creates the virtual environment and installs PIP.
-
-        Creates the virtual environment and installs PIP only into the
-        virtual environment.
-        """
-        if not os.path.isdir(self.venv):
-            print('Creating venv...', end=' ')
-            if no_site_packages:
-                self.run_command(['virtualenv', '-q', '--no-site-packages',
-                                 self.venv])
-            else:
-                self.run_command(['virtualenv', '-q', self.venv])
-            print('done.')
-        else:
-            print("venv already exists...")
-            pass
-
-    def pip_install(self, *args):
-        self.run_command(['tools/with_venv.sh',
-                         'pip', 'install', '--upgrade'] + list(args),
-                         redirect_output=False)
-
-    def install_dependencies(self):
-        print('Installing dependencies with pip (this can take a while)...')
-
-        # First things first, make sure our venv has the latest pip and
-        # setuptools and pbr
-        self.pip_install('pip>=1.4')
-        self.pip_install('setuptools')
-        self.pip_install('pbr')
-
-        self.pip_install('-r', self.requirements, '-r', self.test_requirements)
-
-    def parse_args(self, argv):
-        """Parses command-line arguments."""
-        parser = optparse.OptionParser()
-        parser.add_option('-n', '--no-site-packages',
-                          action='store_true',
-                          help="Do not inherit packages from global Python "
-                               "install.")
-        return parser.parse_args(argv[1:])[0]
-
-
-class Distro(InstallVenv):
-
-    def check_cmd(self, cmd):
-        return bool(self.run_command(['which', cmd],
-                    check_exit_code=False).strip())
-
-    def install_virtualenv(self):
-        if self.check_cmd('virtualenv'):
-            return
-
-        if self.check_cmd('easy_install'):
-            print('Installing virtualenv via easy_install...', end=' ')
-            if self.run_command(['easy_install', 'virtualenv']):
-                print('Succeeded')
-                return
-            else:
-                print('Failed')
-
-        self.die('ERROR: virtualenv not found.\n\n%s development'
-                 ' requires virtualenv, please install it using your'
-                 ' favorite package management tool' % self.project)
-
-
-class Fedora(Distro):
-    """This covers all Fedora-based distributions.
-
-    Includes: Fedora, RHEL, CentOS, Scientific Linux
-    """
-
-    def check_pkg(self, pkg):
-        return self.run_command_with_code(['rpm', '-q', pkg],
-                                          check_exit_code=False)[1] == 0
-
-    def install_virtualenv(self):
-        if self.check_cmd('virtualenv'):
-            return
-
-        if not self.check_pkg('python-virtualenv'):
-            self.die("Please install 'python-virtualenv'.")
-
-        super(Fedora, self).install_virtualenv()