@ -0,0 +1,30 @@ | |||
# Compiled files | |||
*.py[co] | |||
*.a | |||
*.o | |||
*.so | |||
# Sphinx | |||
_build | |||
# Packages/installer info | |||
*.egg | |||
*.egg-info | |||
dist | |||
build | |||
eggs | |||
parts | |||
bin | |||
var | |||
sdist | |||
develop-eggs | |||
.installed.cfg | |||
# Other | |||
.testrepository | |||
.tox | |||
.*.swp | |||
.coverage | |||
cover | |||
AUTHORS | |||
ChangeLog |
@ -0,0 +1,4 @@ | |||
[gerrit] | |||
host=review.openstack.org | |||
port=29418 | |||
project=openstack/ironic.git |
@ -0,0 +1,17 @@ | |||
If you would like to contribute to the development of OpenStack, | |||
you must follow the steps in the "If you're a developer, start here" | |||
section of this page: | |||
http://wiki.openstack.org/HowToContribute | |||
Once those steps have been completed, changes to OpenStack | |||
should be submitted for review via the Gerrit tool, following | |||
the workflow documented at: | |||
http://wiki.openstack.org/GerritWorkflow | |||
Pull requests submitted through GitHub will be ignored. | |||
Bugs should be filed on Launchpad, not GitHub: | |||
https://bugs.launchpad.net/ironic |
@ -0,0 +1,176 @@ | |||
Apache License | |||
Version 2.0, January 2004 | |||
http://www.apache.org/licenses/ | |||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
1. Definitions. | |||
"License" shall mean the terms and conditions for use, reproduction, | |||
and distribution as defined by Sections 1 through 9 of this document. | |||
"Licensor" shall mean the copyright owner or entity authorized by | |||
the copyright owner that is granting the License. | |||
"Legal Entity" shall mean the union of the acting entity and all | |||
other entities that control, are controlled by, or are under common | |||
control with that entity. For the purposes of this definition, | |||
"control" means (i) the power, direct or indirect, to cause the | |||
direction or management of such entity, whether by contract or | |||
otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
outstanding shares, or (iii) beneficial ownership of such entity. | |||
"You" (or "Your") shall mean an individual or Legal Entity | |||
exercising permissions granted by this License. | |||
"Source" form shall mean the preferred form for making modifications, | |||
including but not limited to software source code, documentation | |||
source, and configuration files. | |||
"Object" form shall mean any form resulting from mechanical | |||
transformation or translation of a Source form, including but | |||
not limited to compiled object code, generated documentation, | |||
and conversions to other media types. | |||
"Work" shall mean the work of authorship, whether in Source or | |||
Object form, made available under the License, as indicated by a | |||
copyright notice that is included in or attached to the work | |||
(an example is provided in the Appendix below). | |||
"Derivative Works" shall mean any work, whether in Source or Object | |||
form, that is based on (or derived from) the Work and for which the | |||
editorial revisions, annotations, elaborations, or other modifications | |||
represent, as a whole, an original work of authorship. For the purposes | |||
of this License, Derivative Works shall not include works that remain | |||
separable from, or merely link (or bind by name) to the interfaces of, | |||
the Work and Derivative Works thereof. | |||
"Contribution" shall mean any work of authorship, including | |||
the original version of the Work and any modifications or additions | |||
to that Work or Derivative Works thereof, that is intentionally | |||
submitted to Licensor for inclusion in the Work by the copyright owner | |||
or by an individual or Legal Entity authorized to submit on behalf of | |||
the copyright owner. For the purposes of this definition, "submitted" | |||
means any form of electronic, verbal, or written communication sent | |||
to the Licensor or its representatives, including but not limited to | |||
communication on electronic mailing lists, source code control systems, | |||
and issue tracking systems that are managed by, or on behalf of, the | |||
Licensor for the purpose of discussing and improving the Work, but | |||
excluding communication that is conspicuously marked or otherwise | |||
designated in writing by the copyright owner as "Not a Contribution." | |||
"Contributor" shall mean Licensor and any individual or Legal Entity | |||
on behalf of whom a Contribution has been received by Licensor and | |||
subsequently incorporated within the Work. | |||
2. Grant of Copyright License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
copyright license to reproduce, prepare Derivative Works of, | |||
publicly display, publicly perform, sublicense, and distribute the | |||
Work and such Derivative Works in Source or Object form. | |||
3. Grant of Patent License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
(except as stated in this section) patent license to make, have made, | |||
use, offer to sell, sell, import, and otherwise transfer the Work, | |||
where such license applies only to those patent claims licensable | |||
by such Contributor that are necessarily infringed by their | |||
Contribution(s) alone or by combination of their Contribution(s) | |||
with the Work to which such Contribution(s) was submitted. If You | |||
institute patent litigation against any entity (including a | |||
cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
or a Contribution incorporated within the Work constitutes direct | |||
or contributory patent infringement, then any patent licenses | |||
granted to You under this License for that Work shall terminate | |||
as of the date such litigation is filed. | |||
4. Redistribution. You may reproduce and distribute copies of the | |||
Work or Derivative Works thereof in any medium, with or without | |||
modifications, and in Source or Object form, provided that You | |||
meet the following conditions: | |||
(a) You must give any other recipients of the Work or | |||
Derivative Works a copy of this License; and | |||
(b) You must cause any modified files to carry prominent notices | |||
stating that You changed the files; and | |||
(c) You must retain, in the Source form of any Derivative Works | |||
that You distribute, all copyright, patent, trademark, and | |||
attribution notices from the Source form of the Work, | |||
excluding those notices that do not pertain to any part of | |||
the Derivative Works; and | |||
(d) If the Work includes a "NOTICE" text file as part of its | |||
distribution, then any Derivative Works that You distribute must | |||
include a readable copy of the attribution notices contained | |||
within such NOTICE file, excluding those notices that do not | |||
pertain to any part of the Derivative Works, in at least one | |||
of the following places: within a NOTICE text file distributed | |||
as part of the Derivative Works; within the Source form or | |||
documentation, if provided along with the Derivative Works; or, | |||
within a display generated by the Derivative Works, if and | |||
wherever such third-party notices normally appear. The contents | |||
of the NOTICE file are for informational purposes only and | |||
do not modify the License. You may add Your own attribution | |||
notices within Derivative Works that You distribute, alongside | |||
or as an addendum to the NOTICE text from the Work, provided | |||
that such additional attribution notices cannot be construed | |||
as modifying the License. | |||
You may add Your own copyright statement to Your modifications and | |||
may provide additional or different license terms and conditions | |||
for use, reproduction, or distribution of Your modifications, or | |||
for any such Derivative Works as a whole, provided Your use, | |||
reproduction, and distribution of the Work otherwise complies with | |||
the conditions stated in this License. | |||
5. Submission of Contributions. Unless You explicitly state otherwise, | |||
any Contribution intentionally submitted for inclusion in the Work | |||
by You to the Licensor shall be under the terms and conditions of | |||
this License, without any additional terms or conditions. | |||
Notwithstanding the above, nothing herein shall supersede or modify | |||
the terms of any separate license agreement you may have executed | |||
with Licensor regarding such Contributions. | |||
6. Trademarks. This License does not grant permission to use the trade | |||
names, trademarks, service marks, or product names of the Licensor, | |||
except as required for reasonable and customary use in describing the | |||
origin of the Work and reproducing the content of the NOTICE file. | |||
7. Disclaimer of Warranty. Unless required by applicable law or | |||
agreed to in writing, Licensor provides the Work (and each | |||
Contributor provides its Contributions) on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
implied, including, without limitation, any warranties or conditions | |||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
PARTICULAR PURPOSE. You are solely responsible for determining the | |||
appropriateness of using or redistributing the Work and assume any | |||
risks associated with Your exercise of permissions under this License. | |||
8. Limitation of Liability. In no event and under no legal theory, | |||
whether in tort (including negligence), contract, or otherwise, | |||
unless required by applicable law (such as deliberate and grossly | |||
negligent acts) or agreed to in writing, shall any Contributor be | |||
liable to You for damages, including any direct, indirect, special, | |||
incidental, or consequential damages of any character arising as a | |||
result of this License or out of the use or inability to use the | |||
Work (including but not limited to damages for loss of goodwill, | |||
work stoppage, computer failure or malfunction, or any and all | |||
other commercial damages or losses), even if such Contributor | |||
has been advised of the possibility of such damages. | |||
9. Accepting Warranty or Additional Liability. While redistributing | |||
the Work or Derivative Works thereof, You may choose to offer, | |||
and charge a fee for, acceptance of support, warranty, indemnity, | |||
or other liability obligations and/or rights consistent with this | |||
License. However, in accepting such obligations, You may act only | |||
on Your own behalf and on Your sole responsibility, not on behalf | |||
of any other Contributor, and only if You agree to indemnify, | |||
defend, and hold each Contributor harmless for any liability | |||
incurred by, or claims asserted against, such Contributor by reason | |||
of your accepting any such warranty or additional liability. | |||
@ -0,0 +1,6 @@ | |||
include AUTHORS | |||
include ChangeLog | |||
exclude .gitignore | |||
exclude .gitreview | |||
global-exclude *.pyc |
@ -0,0 +1,4 @@ | |||
Ironic | |||
====== | |||
Provision Bare Metal machines with Nova. |
@ -0,0 +1,270 @@ | |||
# vim: tabstop=4 shiftwidth=4 softtabstop=4 | |||
# Copyright 2010 United States Government as represented by the | |||
# Administrator of the National Aeronautics and Space Administration. | |||
# All Rights Reserved. | |||
# | |||
# 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. | |||
"""Base classes for our unit tests. | |||
Allows overriding of flags for use of fakes, and some black magic for | |||
inline callbacks. | |||
""" | |||
import eventlet | |||
eventlet.monkey_patch(os=False) | |||
import os | |||
import shutil | |||
import sys | |||
import uuid | |||
import fixtures | |||
import mox | |||
from oslo.config import cfg | |||
import stubout | |||
import testtools | |||
from nova import context | |||
from nova import db | |||
from nova.db import migration | |||
from nova.network import manager as network_manager | |||
from nova.openstack.common.db.sqlalchemy import session | |||
from nova.openstack.common import log as logging | |||
from nova.openstack.common import timeutils | |||
from nova import paths | |||
from nova import service | |||
from nova.tests import conf_fixture | |||
from nova.tests import policy_fixture | |||
test_opts = [ | |||
cfg.StrOpt('sqlite_clean_db', | |||
default='clean.sqlite', | |||
help='File name of clean sqlite db'), | |||
] | |||
CONF = cfg.CONF | |||
CONF.register_opts(test_opts) | |||
CONF.import_opt('sql_connection', | |||
'nova.openstack.common.db.sqlalchemy.session') | |||
CONF.import_opt('sqlite_db', 'nova.openstack.common.db.sqlalchemy.session') | |||
CONF.set_override('use_stderr', False) | |||
logging.setup('nova') | |||
_DB_CACHE = None | |||
class Database(fixtures.Fixture): | |||
def __init__(self, db_session, db_migrate, sql_connection, | |||
sqlite_db, sqlite_clean_db): | |||
self.sql_connection = sql_connection | |||
self.sqlite_db = sqlite_db | |||
self.sqlite_clean_db = sqlite_clean_db | |||
self.engine = db_session.get_engine() | |||
self.engine.dispose() | |||
conn = self.engine.connect() | |||
if sql_connection == "sqlite://": | |||
if db_migrate.db_version() > db_migrate.INIT_VERSION: | |||
return | |||
else: | |||
testdb = paths.state_path_rel(sqlite_db) | |||
if os.path.exists(testdb): | |||
return | |||
db_migrate.db_sync() | |||
self.post_migrations() | |||
if sql_connection == "sqlite://": | |||
conn = self.engine.connect() | |||
self._DB = "".join(line for line in conn.connection.iterdump()) | |||
self.engine.dispose() | |||
else: | |||
cleandb = paths.state_path_rel(sqlite_clean_db) | |||
shutil.copyfile(testdb, cleandb) | |||
def setUp(self): | |||
super(Database, self).setUp() | |||
if self.sql_connection == "sqlite://": | |||
conn = self.engine.connect() | |||
conn.connection.executescript(self._DB) | |||
self.addCleanup(self.engine.dispose) | |||
else: | |||
shutil.copyfile(paths.state_path_rel(self.sqlite_clean_db), | |||
paths.state_path_rel(self.sqlite_db)) | |||
def post_migrations(self): | |||
"""Any addition steps that are needed outside of the migrations.""" | |||
ctxt = context.get_admin_context() | |||
network = network_manager.VlanManager() | |||
bridge_interface = CONF.flat_interface or CONF.vlan_interface | |||
network.create_networks(ctxt, | |||
label='test', | |||
cidr=CONF.fixed_range, | |||
multi_host=CONF.multi_host, | |||
num_networks=CONF.num_networks, | |||
network_size=CONF.network_size, | |||
cidr_v6=CONF.fixed_range_v6, | |||
gateway=CONF.gateway, | |||
gateway_v6=CONF.gateway_v6, | |||
bridge=CONF.flat_network_bridge, | |||
bridge_interface=bridge_interface, | |||
vpn_start=CONF.vpn_start, | |||
vlan_start=CONF.vlan_start, | |||
dns1=CONF.flat_network_dns) | |||
for net in db.network_get_all(ctxt): | |||
network.set_network_host(ctxt, net) | |||
class ReplaceModule(fixtures.Fixture): | |||
"""Replace a module with a fake module.""" | |||
def __init__(self, name, new_value): | |||
self.name = name | |||
self.new_value = new_value | |||
def _restore(self, old_value): | |||
sys.modules[self.name] = old_value | |||
def setUp(self): | |||
super(ReplaceModule, self).setUp() | |||
old_value = sys.modules.get(self.name) | |||
sys.modules[self.name] = self.new_value | |||
self.addCleanup(self._restore, old_value) | |||
class ServiceFixture(fixtures.Fixture): | |||
"""Run a service as a test fixture.""" | |||
def __init__(self, name, host=None, **kwargs): | |||
name = name | |||
host = host and host or uuid.uuid4().hex | |||
kwargs.setdefault('host', host) | |||
kwargs.setdefault('binary', 'nova-%s' % name) | |||
self.kwargs = kwargs | |||
def setUp(self): | |||
super(ServiceFixture, self).setUp() | |||
self.service = service.Service.create(**self.kwargs) | |||
self.service.start() | |||
self.addCleanup(self.service.kill) | |||
class MoxStubout(fixtures.Fixture): | |||
"""Deal with code around mox and stubout as a fixture.""" | |||
def setUp(self): | |||
super(MoxStubout, self).setUp() | |||
# emulate some of the mox stuff, we can't use the metaclass | |||
# because it screws with our generators | |||
self.mox = mox.Mox() | |||
self.stubs = stubout.StubOutForTesting() | |||
self.addCleanup(self.mox.UnsetStubs) | |||
self.addCleanup(self.stubs.UnsetAll) | |||
self.addCleanup(self.stubs.SmartUnsetAll) | |||
self.addCleanup(self.mox.VerifyAll) | |||
class TestingException(Exception): | |||
pass | |||
class TestCase(testtools.TestCase): | |||
"""Test case base class for all unit tests.""" | |||
def setUp(self): | |||
"""Run before each test method to initialize test environment.""" | |||
super(TestCase, self).setUp() | |||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) | |||
try: | |||
test_timeout = int(test_timeout) | |||
except ValueError: | |||
# If timeout value is invalid do not set a timeout. | |||
test_timeout = 0 | |||
if test_timeout > 0: | |||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) | |||
self.useFixture(fixtures.NestedTempfile()) | |||
self.useFixture(fixtures.TempHomeDir()) | |||
if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or | |||
os.environ.get('OS_STDOUT_CAPTURE') == '1'): | |||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream | |||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) | |||
if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or | |||
os.environ.get('OS_STDERR_CAPTURE') == '1'): | |||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream | |||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) | |||
self.log_fixture = self.useFixture(fixtures.FakeLogger()) | |||
self.useFixture(conf_fixture.ConfFixture(CONF)) | |||
global _DB_CACHE | |||
if not _DB_CACHE: | |||
_DB_CACHE = Database(session, migration, | |||
sql_connection=CONF.sql_connection, | |||
sqlite_db=CONF.sqlite_db, | |||
sqlite_clean_db=CONF.sqlite_clean_db) | |||
self.useFixture(_DB_CACHE) | |||
mox_fixture = self.useFixture(MoxStubout()) | |||
self.mox = mox_fixture.mox | |||
self.stubs = mox_fixture.stubs | |||
self.addCleanup(self._clear_attrs) | |||
self.useFixture(fixtures.EnvironmentVariable('http_proxy')) | |||
self.policy = self.useFixture(policy_fixture.PolicyFixture()) | |||
CONF.set_override('fatal_exception_format_errors', True) | |||
def _clear_attrs(self): | |||
# Delete attributes that don't start with _ so they don't pin | |||
# memory around unnecessarily for the duration of the test | |||
# suite | |||
for key in [k for k in self.__dict__.keys() if k[0] != '_']: | |||
del self.__dict__[key] | |||
def flags(self, **kw): | |||
"""Override flag variables for a test.""" | |||
group = kw.pop('group', None) | |||
for k, v in kw.iteritems(): | |||
CONF.set_override(k, v, group) | |||
def start_service(self, name, host=None, **kwargs): | |||
svc = self.useFixture(ServiceFixture(name, host, **kwargs)) | |||
return svc.service | |||
class APICoverage(object): | |||
cover_api = None | |||
def test_api_methods(self): | |||
self.assertTrue(self.cover_api is not None) | |||
api_methods = [x for x in dir(self.cover_api) | |||
if not x.startswith('_')] | |||
test_methods = [x[5:] for x in dir(self) | |||
if x.startswith('test_')] | |||
self.assertThat( | |||
test_methods, | |||
testtools.matchers.ContainsAll(api_methods)) | |||
class TimeOverride(fixtures.Fixture): | |||
"""Fixture to start and remove time override.""" | |||
def setUp(self): | |||
super(TimeOverride, self).setUp() | |||
timeutils.set_time_override() | |||
self.addCleanup(timeutils.clear_time_override) |
@ -0,0 +1,31 @@ | |||
d2to1>=0.2.10,<0.3 | |||
pbr>=0.5,<0.6 | |||
SQLAlchemy>=0.7.8,<0.7.99 | |||
Cheetah>=2.4.4 | |||
amqplib>=0.6.1 | |||
anyjson>=0.2.4 | |||
argparse | |||
boto | |||
eventlet>=0.9.17 | |||
kombu>=1.0.4 | |||
lxml>=2.3 | |||
routes>=1.12.3 | |||
WebOb==1.2.3 | |||
greenlet>=0.3.1 | |||
PasteDeploy>=1.5.0 | |||
paste | |||
sqlalchemy-migrate>=0.7.2 | |||
netaddr>=0.7.6 | |||
suds>=0.4 | |||
paramiko | |||
pyasn1 | |||
Babel>=0.9.6 | |||
iso8601>=0.1.4 | |||
httplib2 | |||
python-cinderclient>=1.0.1 | |||
python-quantumclient>=2.2.0,<3.0.0 | |||
python-glanceclient>=0.5.0,<2 | |||
python-keystoneclient>=0.2.0 | |||
stevedore>=0.7 | |||
websockify<0.4 | |||
oslo.config>=1.1.0 |
@ -0,0 +1,56 @@ | |||
[metadata] | |||
name = ironic | |||
version = 2013.2 | |||
summary = OpenStack Bare Metal Provisioning | |||
description-file = | |||
README.rst | |||
author = OpenStack | |||
author-email = openstack-dev@lists.openstack.org | |||
home-page = http://www.openstack.org/ | |||
classifier = | |||
Environment :: OpenStack | |||
Intended Audience :: Information Technology | |||
Intended Audience :: System Administrators | |||
License :: OSI Approved :: Apache Software License | |||
Operating System :: POSIX :: Linux | |||
Programming Language :: Python | |||
Programming Language :: Python :: 2 | |||
Programming Language :: Python :: 2.7 | |||
Programming Language :: Python :: 2.6 | |||
[global] | |||
setup-hooks = | |||
pbr.hooks.setup_hook | |||
[files] | |||
packages = | |||
ironic | |||
[entry_points] | |||
console_scripts = | |||
nova-baremetal-deploy-helper = nova.cmd.baremetal_deploy_helper:main | |||
nova-baremetal-manage = nova.cmd.baremetal_manage:main | |||
[build_sphinx] | |||
all_files = 1 | |||
build-dir = doc/build | |||
source-dir = doc/source | |||
[egg_info] | |||
tag_build = | |||
tag_date = 0 | |||
tag_svn_revision = 0 | |||
[compile_catalog] | |||
directory = ironic/locale | |||
domain = ironic | |||
[update_catalog] | |||
domain = ironic | |||
output_dir = ironic/locale | |||
input_file = ironic/locale/ironic.pot | |||
[extract_messages] | |||
keywords = _ gettext ngettext l_ lazy_gettext | |||
mapping_file = babel.cfg | |||
output_file = ironic/locale/nova.pot |
@ -0,0 +1,21 @@ | |||
#!/usr/bin/env python | |||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. | |||
# | |||
# 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 setuptools | |||
setuptools.setup( | |||
setup_requires=['d2to1>=0.2.10,<0.3', 'pbr>=0.5,<0.6'], | |||
d2to1=True) |
@ -0,0 +1,18 @@ | |||
# Packages needed for dev testing | |||
distribute>=0.6.24 | |||
# Install bounded pep8/pyflakes first, then let flake8 install | |||
pep8==1.4.5 | |||
pyflakes==0.7.2 | |||
flake8==2.0 | |||
hacking>=0.5.3,<0.6 | |||
coverage>=3.6 | |||
discover | |||
fixtures>=0.3.12 | |||
mox==0.5.3 | |||
MySQL-python | |||
python-subunit | |||
sphinx>=1.1.2 | |||
testrepository>=0.0.13 | |||
testtools>=0.9.27 |
@ -0,0 +1,216 @@ | |||
# vim: tabstop=4 shiftwidth=4 softtabstop=4 | |||
# 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. | |||
Synced in from openstack-common | |||
""" | |||
import argparse | |||
import os | |||
import subprocess | |||
import sys | |||
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 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.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 venv...', | |||
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.""" | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument('-n', '--no-site-packages', | |||
action='store_true', | |||
help="Do not inherit packages from global Python " | |||
"install") | |||
return parser.parse_args(argv[1:]) | |||
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 apply_patch(self, originalfile, patchfile): | |||
self.run_command(['patch', '-N', originalfile, patchfile], | |||
check_exit_code=False) | |||
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() | |||
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.die("Please 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') |
@ -0,0 +1,38 @@ | |||
# vim: tabstop=4 shiftwidth=4 softtabstop=4 | |||
# Copyright 2013 Red Hat, 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. | |||
import os | |||
import sys | |||
import tools.install_venv_common as install_venv | |||
def main(argv): | |||
root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) | |||
venv = os.environ['VIRTUAL_ENV'] | |||
pip_requires = os.path.join(root, 'requirements.txt') | |||
test_requires = os.path.join(root, 'test-requirements.txt') | |||
py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1]) | |||
project = 'Nova' | |||
install = install_venv.InstallVenv(root, venv, pip_requires, test_requires, | |||
py_version, project) | |||
#NOTE(dprince): For Tox we only run post_process (which patches files, etc) | |||
install.post_process() | |||
if __name__ == '__main__': | |||
main(sys.argv) |
@ -0,0 +1,34 @@ | |||
[tox] | |||
envlist = py26,py27,pep8 | |||
[testenv] | |||
setenv = VIRTUAL_ENV={envdir} | |||
LANG=en_US.UTF-8 | |||
LANGUAGE=en_US:en | |||
LC_ALL=C | |||
deps = -r{toxinidir}/requirements.txt | |||
-r{toxinidir}/test-requirements.txt | |||
commands = | |||
python tools/patch_tox_venv.py | |||
python setup.py testr --slowest --testr-args='{posargs}' | |||
[tox:jenkins] | |||
downloadcache = ~/cache/pip | |||
[testenv:pep8] | |||
commands = | |||
flake8 | |||
[testenv:cover] | |||
setenv = VIRTUAL_ENV={envdir} | |||
commands = | |||
python tools/patch_tox_venv.py | |||
python setup.py testr --coverage {posargs} | |||
[testenv:venv] | |||
commands = {posargs} | |||
[flake8] | |||
ignore = E12,E711,E721,E712,H302,H303,H403,H404,F | |||
builtins = _ | |||
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build |