Merge "Proposed EC2 OpenStack extension"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index e1196f0..43277d6 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -107,9 +107,6 @@
# Level to log Compute API request/response details.
log_level = ERROR
-# Whitebox options for compute. Whitebox options enable the
-# whitebox test cases, which look at internal Nova database state,
-# SSH into VMs to check instance state, etc.
# Run live migration tests (requires 2 hosts)
live_migration_available = false
@@ -123,6 +120,12 @@
# are forced to skip, regardless of the extension status
disk_config_enabled_override = true
+
+[whitebox]
+# Whitebox options for compute. Whitebox options enable the
+# whitebox test cases, which look at internal Nova database state,
+# SSH into VMs to check instance state, etc.
+
# Should we run whitebox tests for Compute?
whitebox_enabled = true
diff --git a/openstack-common.conf b/openstack-common.conf
index a75279f..0c9e43e 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -1,7 +1,7 @@
[DEFAULT]
# The list of modules to copy from openstack-common
-modules=setup,cfg,iniparser
+modules=setup,cfg,iniparser,install_venv_common
# The base module to hold the copy of openstack.common
base=tempest
diff --git a/setup.cfg b/setup.cfg
index c28d129..b522f3a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,7 +1,5 @@
[nosetests]
# NOTE(jkoelker) To run the test suite under nose install the following
# coverage http://pypi.python.org/pypi/coverage
-# tissue http://pypi.python.org/pypi/tissue (pep8 checker)
# openstack-nose https://github.com/openstack-dev/openstack-nose
verbosity=2
-detailed-errors=1
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index cff038d..824198f 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -344,7 +344,9 @@
"""
Subclasses override with specific deletion detection.
"""
- return False
+ message = ('"%s" does not implement is_resource_deleted'
+ % self.__class__.__name__)
+ raise NotImplementedError(message)
class RestClientXML(RestClient):
diff --git a/tempest/config.py b/tempest/config.py
index 89fa2d9..9458ce8 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -171,22 +171,6 @@
default=True,
help="If false, skip config tests regardless of the "
"extension status"),
- cfg.BoolOpt('whitebox_enabled',
- default=False,
- help="Does the test environment support whitebox tests for "
- "Compute?"),
- cfg.StrOpt('db_uri',
- default=None,
- help="Connection string to the database of Compute service"),
- cfg.StrOpt('source_dir',
- default="/opt/stack/nova",
- help="Path of nova source directory"),
- cfg.StrOpt('config_path',
- default='/etc/nova/nova.conf',
- help="Path of nova configuration file"),
- cfg.StrOpt('bin_dir',
- default="/usr/local/bin/",
- help="Directory containing nova binaries such as nova-manage"),
]
@@ -219,6 +203,35 @@
conf.register_opt(opt, group='compute-admin')
+whitebox_group = cfg.OptGroup(name='whitebox',
+ title="Whitebox Options")
+
+WhiteboxGroup = [
+ cfg.BoolOpt('whitebox_enabled',
+ default=False,
+ help="Does the test environment support whitebox tests for "
+ "Compute?"),
+ cfg.StrOpt('db_uri',
+ default=None,
+ help="Connection string to the database of Compute service"),
+ cfg.StrOpt('source_dir',
+ default="/opt/stack/nova",
+ help="Path of nova source directory"),
+ cfg.StrOpt('config_path',
+ default='/etc/nova/nova.conf',
+ help="Path of nova configuration file"),
+ cfg.StrOpt('bin_dir',
+ default="/usr/local/bin/",
+ help="Directory containing nova binaries such as nova-manage"),
+]
+
+
+def register_whitebox_opts(conf):
+ conf.register_group(whitebox_group)
+ for opt in WhiteboxGroup:
+ conf.register_opt(opt, group='whitebox')
+
+
image_group = cfg.OptGroup(name='image',
title="Image Service Options")
@@ -418,6 +431,7 @@
register_compute_opts(cfg.CONF)
register_identity_opts(cfg.CONF)
+ register_whitebox_opts(cfg.CONF)
register_image_opts(cfg.CONF)
register_network_opts(cfg.CONF)
register_volume_opts(cfg.CONF)
@@ -425,6 +439,7 @@
register_boto_opts(cfg.CONF)
register_compute_admin_opts(cfg.CONF)
self.compute = cfg.CONF.compute
+ self.whitebox = cfg.CONF.whitebox
self.identity = cfg.CONF.identity
self.images = cfg.CONF.image
self.network = cfg.CONF.network
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index 9cc30d9..403a3ac 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -197,6 +197,12 @@
body = json.loads(body)
return resp, body['OS-KSADM:service']
+ def list_services(self):
+ """List Service - Returns Services."""
+ resp, body = self.get('/OS-KSADM/services/')
+ body = json.loads(body)
+ return resp, body['OS-KSADM:services']
+
def delete_service(self, service_id):
"""Delete Service."""
url = '/OS-KSADM/services/%s' % service_id
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
index 02be91e..f79c3d5 100644
--- a/tempest/services/identity/xml/identity_client.py
+++ b/tempest/services/identity/xml/identity_client.py
@@ -226,6 +226,12 @@
body = self._parse_body(etree.fromstring(body))
return resp, body
+ def list_services(self):
+ """Returns services."""
+ resp, body = self.get('OS-KSADM/services', self.headers)
+ body = self._parse_array(etree.fromstring(body))
+ return resp, body
+
def get_service(self, service_id):
"""Get Service."""
url = '/OS-KSADM/services/%s' % service_id
diff --git a/tempest/tests/compute/__init__.py b/tempest/tests/compute/__init__.py
index 08e5091..5b59a70 100644
--- a/tempest/tests/compute/__init__.py
+++ b/tempest/tests/compute/__init__.py
@@ -29,7 +29,7 @@
CREATE_IMAGE_ENABLED = CONFIG.compute.create_image_enabled
RESIZE_AVAILABLE = CONFIG.compute.resize_available
CHANGE_PASSWORD_AVAILABLE = CONFIG.compute.change_password_available
-WHITEBOX_ENABLED = CONFIG.compute.whitebox_enabled
+WHITEBOX_ENABLED = CONFIG.whitebox.whitebox_enabled
DISK_CONFIG_ENABLED = False
DISK_CONFIG_ENABLED_OVERRIDE = CONFIG.compute.disk_config_enabled_override
FLAVOR_EXTRA_DATA_ENABLED = False
diff --git a/tempest/tests/compute/servers/test_server_addresses.py b/tempest/tests/compute/servers/test_server_addresses.py
index 6e819a2..6b0f7ae 100644
--- a/tempest/tests/compute/servers/test_server_addresses.py
+++ b/tempest/tests/compute/servers/test_server_addresses.py
@@ -74,9 +74,9 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
- self.assertGreaterEqual(len(addresses), 1)
+ self.assertTrue(len(addresses) >= 1)
for network_name, network_addresses in addresses.iteritems():
- self.assertGreaterEqual(len(network_addresses), 1)
+ self.assertTrue(len(network_addresses) >= 1)
for address in network_addresses:
self.assertTrue(address['addr'])
self.assertTrue(address['version'])
diff --git a/tempest/tests/identity/admin/test_services.py b/tempest/tests/identity/admin/test_services.py
index 5261b9d..73f4a90 100644
--- a/tempest/tests/identity/admin/test_services.py
+++ b/tempest/tests/identity/admin/test_services.py
@@ -16,6 +16,9 @@
# under the License.
+from nose.plugins.attrib import attr
+import unittest2 as unittest
+
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
from tempest.tests.identity import base
@@ -30,8 +33,8 @@
name = rand_name('service-')
type = rand_name('type--')
description = rand_name('description-')
- resp, service_data = \
- self.client.create_service(name, type, description=description)
+ resp, service_data = self.client.create_service(
+ name, type, description=description)
self.assertTrue(resp['status'].startswith('2'))
#Verifying response body of create service
self.assertTrue('id' in service_data)
@@ -63,6 +66,32 @@
self.assertRaises(exceptions.NotFound, self.client.get_service,
service_data['id'])
+ def test_list_services(self):
+ # Create, List, Verify and Delete Services
+ services = []
+ for _ in xrange(3):
+ name = rand_name('service-')
+ type = rand_name('type--')
+ description = rand_name('description-')
+ resp, service = self.client.create_service(
+ name, type, description=description)
+ services.append(service)
+ service_ids = map(lambda x: x['id'], services)
+
+ # List and Verify Services
+ resp, body = self.client.list_services()
+ self.assertTrue(resp['status'].startswith('2'))
+ found = [service for service in body if service['id'] in service_ids]
+ self.assertEqual(len(found), len(services), 'Services not found')
+
+ # Delete Services
+ for service in services:
+ resp, body = self.client.delete_service(service['id'])
+ self.assertTrue(resp['status'].startswith('2'))
+ resp, body = self.client.list_services()
+ found = [service for service in body if service['id'] in service_ids]
+ self.assertFalse(any(found), 'Services failed to delete')
+
class ServicesTestJSON(base.BaseIdentityAdminTestJSON, ServicesTestBase):
@classmethod
diff --git a/tempest/tests/network/test_network_basic_ops.py b/tempest/tests/network/test_network_basic_ops.py
index bdebced..d297c98 100644
--- a/tempest/tests/network/test_network_basic_ops.py
+++ b/tempest/tests/network/test_network_basic_ops.py
@@ -186,9 +186,9 @@
cls.check_preconditions()
cfg = cls.config.network
cls.tenant_id = cls.manager._get_identity_client(
- cfg.username,
- cfg.password,
- cfg.tenant_name).tenant_id
+ cls.config.identity.username,
+ cls.config.identity.password,
+ cls.config.identity.tenant_name).tenant_id
# TODO(mnewby) Consider looking up entities as needed instead
# of storing them as collections on the class.
cls.keypairs = {}
diff --git a/tempest/tests/object_storage/test_container_sync.py b/tempest/tests/object_storage/test_container_sync.py
index 597fd86..d612880 100644
--- a/tempest/tests/object_storage/test_container_sync.py
+++ b/tempest/tests/object_storage/test_container_sync.py
@@ -103,7 +103,7 @@
self.assertEqual(resp['status'], '200',
'Error listing the destination container`s'
' "%s" contents' % (self.containers[0]))
- object_list_0 = {obj['name']: obj for obj in object_list_0}
+ object_list_0 = dict((obj['name'], obj) for obj in object_list_0)
# get second container content
resp, object_list_1 = \
cont_client[1].\
@@ -111,7 +111,7 @@
self.assertEqual(resp['status'], '200',
'Error listing the destination container`s'
' "%s" contents' % (self.containers[1]))
- object_list_1 = {obj['name']: obj for obj in object_list_1}
+ object_list_1 = dict((obj['name'], obj) for obj in object_list_1)
# check that containers is not empty and has equal keys()
# or wait for next attepmt
if not object_list_0 or not object_list_1 or \
diff --git a/tempest/whitebox.py b/tempest/whitebox.py
index 03ad63b..b7a1e68 100644
--- a/tempest/whitebox.py
+++ b/tempest/whitebox.py
@@ -63,9 +63,9 @@
super(ComputeWhiteboxTest, cls).setUpClass()
# Add some convenience attributes that tests use...
- cls.nova_dir = cls.config.compute.source_dir
- cls.compute_bin_dir = cls.config.compute.bin_dir
- cls.compute_config_path = cls.config.compute.config_path
+ cls.nova_dir = cls.config.whitebox.source_dir
+ cls.compute_bin_dir = cls.config.whitebox.bin_dir
+ cls.compute_config_path = cls.config.whitebox.config_path
cls.servers_client = cls.manager.servers_client
cls.images_client = cls.manager.images_client
cls.flavors_client = cls.manager.flavors_client
@@ -126,7 +126,7 @@
}
try:
- engine = create_engine(cls.config.compute.db_uri, **engine_args)
+ engine = create_engine(cls.config.whitebox.db_uri, **engine_args)
connection = engine.connect()
meta = MetaData()
meta.reflect(bind=engine)
diff --git a/tools/install_venv.py b/tools/install_venv.py
index 28275ba..52dbe39 100644
--- a/tools/install_venv.py
+++ b/tools/install_venv.py
@@ -5,6 +5,7 @@
# All Rights Reserved.
#
# Copyright 2010 OpenStack, LLC
+# 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
@@ -25,123 +26,10 @@
import subprocess
import sys
-
-ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-VENV = os.path.join(ROOT, '.venv')
-PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
-TEST_REQUIRES = os.path.join(ROOT, 'tools', 'test-requires')
-PY_VERSION = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
+import install_venv_common as install_venv
-def die(message, *args):
- print >> sys.stderr, message % args
- sys.exit(1)
-
-
-def check_python_version():
- if sys.version_info < (2, 6):
- die("Need Python Version >= 2.6")
-
-
-def run_command_with_code(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 ROOT.
- """
- if redirect_output:
- stdout = subprocess.PIPE
- else:
- stdout = None
-
- proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout)
- output = proc.communicate()[0]
- if check_exit_code and proc.returncode != 0:
- die('Command "%s" failed.\n%s', ' '.join(cmd), output)
- return (output, proc.returncode)
-
-
-def run_command(cmd, redirect_output=True, check_exit_code=True):
- return run_command_with_code(cmd, redirect_output, check_exit_code)[0]
-
-
-class Distro(object):
-
- def check_cmd(self, cmd):
- return bool(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...',
- if run_command(['easy_install', 'virtualenv']):
- print 'Succeeded'
- return
- else:
- print 'Failed'
-
- die('ERROR: virtualenv not found.\n\nTempest development'
- ' requires virtualenv, please install it using your'
- ' favorite package management tool')
-
- def post_process(self):
- """Any distribution-specific post-processing gets done here.
-
- In particular, this is useful for applying patches to code inside
- the venv.
- """
- pass
-
-
-class Fedora(Distro):
- """This covers Fedora-based distributions.
-
- Includes: Fedora, RHEL, Scientific Linux"""
-
- def check_pkg(self, pkg):
- return run_command_with_code(['rpm', '-q', pkg],
- check_exit_code=False)[1] == 0
-
- def yum_install(self, pkg, **kwargs):
- print "Attempting to install '%s' via yum" % pkg
- run_command(['sudo', 'yum', 'install', '-y', pkg], **kwargs)
-
- def apply_patch(self, originalfile, patchfile):
- run_command(['patch', originalfile, patchfile])
-
- def install_virtualenv(self):
- if self.check_cmd('virtualenv'):
- return
-
- if not self.check_pkg('python-virtualenv'):
- self.yum_install('python-virtualenv', check_exit_code=False)
-
- super(Fedora, self).install_virtualenv()
-
- def post_process(self):
- """Workaround for a bug in eventlet.
-
- This currently affects RHEL6.1, but the fix can safely be
- applied to all RHEL and Fedora distributions.
-
- This can be removed when the fix is applied upstream.
-
- Nova: https://bugs.launchpad.net/nova/+bug/884915
- Upstream: https://bitbucket.org/which_linden/eventlet/issue/89
- """
-
- # Install "patch" program if it's not there
- if not self.check_pkg('patch'):
- self.yum_install('patch')
-
- # Apply the eventlet patch
- self.apply_patch(os.path.join(VENV, 'lib', PY_VERSION, 'site-packages',
- 'eventlet/green/subprocess.py'),
- 'contrib/redhat-eventlet.patch')
-
-
-class CentOS(Fedora):
+class CentOS(install_venv.Fedora):
"""This covers CentOS."""
def post_process(self):
@@ -149,73 +37,6 @@
self.yum.install('openssl-devel', check_exit_code=False)
-def get_distro():
- if os.path.exists('/etc/redhat-release'):
- with open('/etc/redhat-release') as rh_release:
- if 'CentOS' in rh_release.read():
- return CentOS()
- return Fedora()
-
- if os.path.exists('/etc/fedora-release'):
- return Fedora()
-
- return Distro()
-
-
-def check_dependencies():
- get_distro().install_virtualenv()
-
-
-def create_virtualenv(venv=VENV, no_site_packages=True):
- """Creates the virtual environment and installs PIP.
-
- Creates the virtual environment and installs PIP only into the
- virtual environment.
- """
- print 'Creating venv...',
- if no_site_packages:
- run_command(['virtualenv', '-q', '--no-site-packages', VENV])
- else:
- run_command(['virtualenv', '-q', VENV])
- print 'done.'
- print 'Installing pip in virtualenv...',
- if not run_command(['tools/with_venv.sh', 'easy_install',
- 'pip>1.0']).strip():
- die("Failed to install pip.")
- print 'done.'
-
-
-def pip_install(*args):
- run_command(['tools/with_venv.sh',
- 'pip', 'install', '--upgrade'] + list(args),
- redirect_output=False)
-
-
-def install_dependencies(venv=VENV):
- print 'Installing dependencies with pip (this can take a while)...'
-
- # First things first, make sure our venv has the latest pip and distribute.
- # NOTE: we keep pip at version 1.1 since the most recent version causes
- # the .venv creation to fail. See:
- # https://bugs.launchpad.net/nova/+bug/1047120
- pip_install('pip==1.1')
- pip_install('distribute')
-
- # Install greenlet by hand - just listing it in the requires file does not
- # get it in stalled in the right order
- pip_install('greenlet')
-
- pip_install('-r', PIP_REQUIRES)
- pip_install('-r', TEST_REQUIRES)
-
- # Install tempest into the virtual_env. No more path munging!
- run_command([os.path.join(venv, 'bin/python'), 'setup.py', 'develop'])
-
-
-def post_process():
- get_distro().post_process()
-
-
def print_help():
help = """
Tempest development environment setup is complete.
@@ -238,23 +59,25 @@
print help
-def parse_args():
- """Parses command-line arguments."""
- parser = optparse.OptionParser()
- parser.add_option("-n", "--no-site-packages", dest="no_site_packages",
- default=False, action="store_true",
- help="Do not inherit packages from global Python"
- " install")
- return parser.parse_args()
-
-
def main(argv):
- (options, args) = parse_args()
- check_python_version()
- check_dependencies()
- create_virtualenv(no_site_packages=options.no_site_packages)
- install_dependencies()
- post_process()
+ root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+ venv = os.path.join(root, '.venv')
+ pip_requires = os.path.join(root, 'tools', 'pip-requires')
+ test_requires = os.path.join(root, 'tools', 'test-requires')
+ py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
+ project = 'Tempest'
+ install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
+ py_version, project)
+ if os.path.exists('/etc/redhat-release'):
+ with open('/etc/redhat-release') as rh_release:
+ if 'CentOS' in rh_release.read():
+ install_venv.Fedora = CentOS
+ 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()
+ install.post_process()
print_help()
if __name__ == '__main__':
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
new file mode 100644
index 0000000..3dbcafe
--- /dev/null
+++ b/tools/install_venv_common.py
@@ -0,0 +1,225 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack, LLC
+# 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.
+
+Synced in from openstack-common
+"""
+
+import os
+import subprocess
+import sys
+
+from tempest.openstack.common import cfg
+
+
+class InstallVenv(object):
+
+ def __init__(self, root, venv, pip_requires, test_requires, py_version,
+ project):
+ self.root = root
+ self.venv = venv
+ self.pip_requires = pip_requires
+ self.test_requires = test_requires
+ self.py_version = py_version
+ self.project = project
+
+ def die(self, message, *args):
+ print >> sys.stderr, message % args
+ 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 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.pip_requires,
+ self.test_requires, self.py_version, self.project)
+ else:
+ return Distro(self.root, self.venv, self.pip_requires,
+ self.test_requires, 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...',
+ if no_site_packages:
+ self.run_command(['virtualenv', '-q', '--no-site-packages',
+ self.venv])
+ else:
+ self.run_command(['virtualenv', '-q', self.venv])
+ print 'done.'
+ print 'Installing pip in virtualenv...',
+ if not self.run_command(['tools/with_venv.sh', 'easy_install',
+ 'pip>1.0']).strip():
+ self.die("Failed to install pip.")
+ 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
+ # distribute.
+ # NOTE: we keep pip at version 1.1 since the most recent version causes
+ # the .venv creation to fail. See:
+ # https://bugs.launchpad.net/nova/+bug/1047120
+ self.pip_install('pip==1.1')
+ self.pip_install('distribute')
+
+ # Install greenlet by hand - just listing it in the requires file does
+ # not
+ # get it installed in the right order
+ self.pip_install('greenlet')
+
+ self.pip_install('-r', self.pip_requires)
+ self.pip_install('-r', self.test_requires)
+
+ def post_process(self):
+ self.get_distro().post_process()
+
+ def parse_args(self, argv):
+ """Parses command-line arguments."""
+ cli_opts = [
+ cfg.BoolOpt('no-site-packages',
+ default=False,
+ short='n',
+ help="Do not inherit packages from global Python"
+ "install"),
+ ]
+ CLI = cfg.ConfigOpts()
+ CLI.register_cli_opts(cli_opts)
+ CLI(argv[1:])
+ return CLI
+
+
+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...',
+ 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)
+
+ def post_process(self):
+ """Any distribution-specific post-processing gets done here.
+
+ In particular, this is useful for applying patches to code inside
+ the venv.
+ """
+ pass
+
+
+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 yum_install(self, pkg, **kwargs):
+ print "Attempting to install '%s' via yum" % pkg
+ self.run_command(['sudo', 'yum', 'install', '-y', pkg], **kwargs)
+
+ def apply_patch(self, originalfile, patchfile):
+ self.run_command(['patch', originalfile, patchfile])
+
+ def install_virtualenv(self):
+ if self.check_cmd('virtualenv'):
+ return
+
+ if not self.check_pkg('python-virtualenv'):
+ self.yum_install('python-virtualenv', check_exit_code=False)
+
+ super(Fedora, self).install_virtualenv()
+
+ def post_process(self):
+ """Workaround for a bug in eventlet.
+
+ This currently affects RHEL6.1, but the fix can safely be
+ applied to all RHEL and Fedora distributions.
+
+ This can be removed when the fix is applied upstream.
+
+ Nova: https://bugs.launchpad.net/nova/+bug/884915
+ Upstream: https://bitbucket.org/which_linden/eventlet/issue/89
+ """
+
+ # Install "patch" program if it's not there
+ if not self.check_pkg('patch'):
+ self.yum_install('patch')
+
+ # Apply the eventlet patch
+ self.apply_patch(os.path.join(self.venv, 'lib', self.py_version,
+ 'site-packages',
+ 'eventlet/green/subprocess.py'),
+ 'contrib/redhat-eventlet.patch')