Rename files and fix things.

This commit is contained in:
Devananda van der Veen 2013-05-03 14:01:05 -07:00
parent 1f276b1a4a
commit 6cbb3b5ccc
34 changed files with 1584 additions and 57 deletions

5
.gitignore vendored
View File

@ -21,6 +21,7 @@ develop-eggs
.installed.cfg
# Other
*.DS_Store
.testrepository
.tox
.*.swp
@ -28,3 +29,7 @@ develop-eggs
cover
AUTHORS
ChangeLog
.testrepository/
.tox
.venv

6
etc/ironic/policy.json Normal file
View File

@ -0,0 +1,6 @@
{
"admin_api": "is_admin:True",
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
"context_is_admin": "role:admin",
"default": "rule:admin_or_owner",
}

16
ironic/__init__.py Normal file
View File

@ -0,0 +1,16 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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.

27
ironic/cmd/__init__.py Normal file
View File

@ -0,0 +1,27 @@
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
# 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.
# TODO(mikal): move eventlet imports to ironic.__init__ once we move to PBR
import os
import sys
os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
import eventlet
eventlet.monkey_patch(os=False)
from ironic.openstack.common import gettextutils
gettextutils.install('ironic')

16
ironic/db/__init__.py Normal file
View File

@ -0,0 +1,16 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# All Rights Reserved.
# flake8: noqa
# 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.
from ironic.db.api import *

178
ironic/db/api.py Normal file
View File

@ -0,0 +1,178 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
# 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.
"""Defines interface for DB access.
The underlying driver is loaded as a :class:`LazyPluggable`.
Functions in this module are imported into the ironic.db
namespace. Call these functions from ironic.db namespace, not
the ironic.db.api namespace.
All functions in this module return objects that implement a dictionary-like
interface. Currently, many of these objects are sqlalchemy objects that
implement a dictionary interface. However, a future goal is to have all of
these objects be simple dictionaries.
**Related Flags**
:db_backend: string to lookup in the list of LazyPluggable backends.
`sqlalchemy` is the only supported backend right now.
:sql_connection: string specifying the sqlalchemy connection to
use, like: `sqlite:///var/lib/ironic/ironic.sqlite`.
"""
from oslo.config import cfg
from ironic import utils
db_opts = [
cfg.StrOpt('db_backend',
default='sqlalchemy',
help='The backend to use for the ironic database'),
]
CONF = cfg.CONF
CONF.register_opts(db_opts)
IMPL = utils.LazyPluggable(
'db_backend',
sqlalchemy='ironic.db.sqlalchemy.api')
def bm_node_get_all(context, service_host=None):
return IMPL.bm_node_get_all(context,
service_host=service_host)
def bm_node_get_associated(context, service_host=None):
return IMPL.bm_node_get_associated(context,
service_host=service_host)
def bm_node_get_unassociated(context, service_host=None):
return IMPL.bm_node_get_unassociated(context,
service_host=service_host)
def bm_node_find_free(context, service_host=None,
memory_mb=None, cpus=None, local_gb=None):
return IMPL.bm_node_find_free(context,
service_host=service_host,
memory_mb=memory_mb,
cpus=cpus,
local_gb=local_gb)
def bm_node_get(context, bm_node_id):
return IMPL.bm_node_get(context, bm_node_id)
def bm_node_get_by_instance_uuid(context, instance_uuid):
return IMPL.bm_node_get_by_instance_uuid(context,
instance_uuid)
def bm_node_get_by_node_uuid(context, node_uuid):
return IMPL.bm_node_get_by_node_uuid(context, node_uuid)
def bm_node_create(context, values):
return IMPL.bm_node_create(context, values)
def bm_node_destroy(context, bm_node_id):
return IMPL.bm_node_destroy(context, bm_node_id)
def bm_node_update(context, bm_node_id, values):
return IMPL.bm_node_update(context, bm_node_id, values)
def bm_node_associate_and_update(context, node_uuid, values):
return IMPL.bm_node_associate_and_update(context, node_uuid, values)
def bm_pxe_ip_create(context, address, server_address):
return IMPL.bm_pxe_ip_create(context, address, server_address)
def bm_pxe_ip_create_direct(context, bm_pxe_ip):
return IMPL.bm_pxe_ip_create_direct(context, bm_pxe_ip)
def bm_pxe_ip_destroy(context, ip_id):
return IMPL.bm_pxe_ip_destroy(context, ip_id)
def bm_pxe_ip_destroy_by_address(context, address):
return IMPL.bm_pxe_ip_destroy_by_address(context, address)
def bm_pxe_ip_get_all(context):
return IMPL.bm_pxe_ip_get_all(context)
def bm_pxe_ip_get(context, ip_id):
return IMPL.bm_pxe_ip_get(context, ip_id)
def bm_pxe_ip_get_by_bm_node_id(context, bm_node_id):
return IMPL.bm_pxe_ip_get_by_bm_node_id(context, bm_node_id)
def bm_pxe_ip_associate(context, bm_node_id):
return IMPL.bm_pxe_ip_associate(context, bm_node_id)
def bm_pxe_ip_disassociate(context, bm_node_id):
return IMPL.bm_pxe_ip_disassociate(context, bm_node_id)
def bm_interface_get(context, if_id):
return IMPL.bm_interface_get(context, if_id)
def bm_interface_get_all(context):
return IMPL.bm_interface_get_all(context)
def bm_interface_destroy(context, if_id):
return IMPL.bm_interface_destroy(context, if_id)
def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
return IMPL.bm_interface_create(context, bm_node_id, address,
datapath_id, port_no)
def bm_interface_set_vif_uuid(context, if_id, vif_uuid):
return IMPL.bm_interface_set_vif_uuid(context, if_id, vif_uuid)
def bm_interface_get_by_vif_uuid(context, vif_uuid):
return IMPL.bm_interface_get_by_vif_uuid(context, vif_uuid)
def bm_interface_get_all_by_bm_node_id(context, bm_node_id):
return IMPL.bm_interface_get_all_by_bm_node_id(context, bm_node_id)

38
ironic/db/migration.py Normal file
View File

@ -0,0 +1,38 @@
# 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.
"""Database setup and migration commands."""
from ironic import utils
IMPL = utils.LazyPluggable(
'db_backend',
sqlalchemy='ironic.db.sqlalchemy.migration')
INIT_VERSION = 0
def db_sync(version=None):
"""Migrate the database to `version` or the most recent version."""
return IMPL.db_sync(version=version)
def db_version():
"""Display the current database version."""
return IMPL.db_version()

View File

@ -0,0 +1,14 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.

433
ironic/db/sqlalchemy/api.py Normal file
View File

@ -0,0 +1,433 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
# 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.
"""Implementation of SQLAlchemy backend."""
import uuid
from sqlalchemy.sql.expression import asc
from sqlalchemy.sql.expression import literal_column
import nova.context
from nova.db.sqlalchemy import api as sqlalchemy_api
from nova import exception
from ironic.openstack.common.db import exception as db_exc
from ironic.openstack.common import timeutils
from ironic.openstack.common import uuidutils
from nova.virt.baremetal.db.sqlalchemy import models
from nova.virt.baremetal.db.sqlalchemy import session as db_session
def model_query(context, *args, **kwargs):
"""Query helper that accounts for context's `read_deleted` field.
:param context: context to query under
:param session: if present, the session to use
:param read_deleted: if present, overrides context's read_deleted field.
:param project_only: if present and context is user-type, then restrict
query to match the context's project_id.
"""
session = kwargs.get('session') or db_session.get_session()
read_deleted = kwargs.get('read_deleted') or context.read_deleted
project_only = kwargs.get('project_only')
query = session.query(*args)
if read_deleted == 'no':
query = query.filter_by(deleted=False)
elif read_deleted == 'yes':
pass # omit the filter to include deleted and active
elif read_deleted == 'only':
query = query.filter_by(deleted=True)
else:
raise Exception(
_("Unrecognized read_deleted value '%s'") % read_deleted)
if project_only and nova.context.is_user_context(context):
query = query.filter_by(project_id=context.project_id)
return query
def _save(ref, session=None):
if not session:
session = db_session.get_session()
# We must not call ref.save() with session=None, otherwise NovaBase
# uses nova-db's session, which cannot access bm-db.
ref.save(session=session)
def _build_node_order_by(query):
query = query.order_by(asc(models.BareMetalNode.memory_mb))
query = query.order_by(asc(models.BareMetalNode.cpus))
query = query.order_by(asc(models.BareMetalNode.local_gb))
return query
@sqlalchemy_api.require_admin_context
def bm_node_get_all(context, service_host=None):
query = model_query(context, models.BareMetalNode, read_deleted="no")
if service_host:
query = query.filter_by(service_host=service_host)
return query.all()
@sqlalchemy_api.require_admin_context
def bm_node_get_associated(context, service_host=None):
query = model_query(context, models.BareMetalNode, read_deleted="no").\
filter(models.BareMetalNode.instance_uuid is not None)
if service_host:
query = query.filter_by(service_host=service_host)
return query.all()
@sqlalchemy_api.require_admin_context
def bm_node_get_unassociated(context, service_host=None):
query = model_query(context, models.BareMetalNode, read_deleted="no").\
filter(models.BareMetalNode.instance_uuid is None)
if service_host:
query = query.filter_by(service_host=service_host)
return query.all()
@sqlalchemy_api.require_admin_context
def bm_node_find_free(context, service_host=None,
cpus=None, memory_mb=None, local_gb=None):
query = model_query(context, models.BareMetalNode, read_deleted="no")
query = query.filter(models.BareMetalNode.instance_uuid is None)
if service_host:
query = query.filter_by(service_host=service_host)
if cpus is not None:
query = query.filter(models.BareMetalNode.cpus >= cpus)
if memory_mb is not None:
query = query.filter(models.BareMetalNode.memory_mb >= memory_mb)
if local_gb is not None:
query = query.filter(models.BareMetalNode.local_gb >= local_gb)
query = _build_node_order_by(query)
return query.first()
@sqlalchemy_api.require_admin_context
def bm_node_get(context, bm_node_id):
# bm_node_id may be passed as a string. Convert to INT to improve DB perf.
bm_node_id = int(bm_node_id)
result = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(id=bm_node_id).\
first()
if not result:
raise exception.NodeNotFound(node_id=bm_node_id)
return result
@sqlalchemy_api.require_admin_context
def bm_node_get_by_instance_uuid(context, instance_uuid):
if not uuidutils.is_uuid_like(instance_uuid):
raise exception.InstanceNotFound(instance_id=instance_uuid)
result = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(instance_uuid=instance_uuid).\
first()
if not result:
raise exception.InstanceNotFound(instance_id=instance_uuid)
return result
@sqlalchemy_api.require_admin_context
def bm_node_get_by_node_uuid(context, bm_node_uuid):
result = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(uuid=bm_node_uuid).\
first()
if not result:
raise exception.NodeNotFoundByUUID(node_uuid=bm_node_uuid)
return result
@sqlalchemy_api.require_admin_context
def bm_node_create(context, values):
if not values.get('uuid'):
values['uuid'] = str(uuid.uuid4())
bm_node_ref = models.BareMetalNode()
bm_node_ref.update(values)
_save(bm_node_ref)
return bm_node_ref
@sqlalchemy_api.require_admin_context
def bm_node_update(context, bm_node_id, values):
rows = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(id=bm_node_id).\
update(values)
if not rows:
raise exception.NodeNotFound(node_id=bm_node_id)
@sqlalchemy_api.require_admin_context
def bm_node_associate_and_update(context, node_uuid, values):
"""Associate an instance to a node safely
Associate an instance to a node only if that node is not yet assocated.
Allow the caller to set any other fields they require in the same
operation. For example, this is used to set the node's task_state to
BUILDING at the beginning of driver.spawn().
"""
if 'instance_uuid' not in values:
raise exception.NovaException(_(
"instance_uuid must be supplied to bm_node_associate_and_update"))
session = db_session.get_session()
with session.begin():
query = model_query(context, models.BareMetalNode,
session=session, read_deleted="no").\
filter_by(uuid=node_uuid)
count = query.filter_by(instance_uuid=None).\
update(values, synchronize_session=False)
if count != 1:
raise exception.NovaException(_(
"Failed to associate instance %(i_uuid)s to baremetal node "
"%(n_uuid)s.") % {'i_uuid': values['instance_uuid'],
'n_uuid': node_uuid})
ref = query.first()
return ref
@sqlalchemy_api.require_admin_context
def bm_node_destroy(context, bm_node_id):
# First, delete all interfaces belonging to the node.
# Delete physically since these have unique columns.
session = db_session.get_session()
with session.begin():
model_query(context, models.BareMetalInterface, read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
delete()
rows = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(id=bm_node_id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
if not rows:
raise exception.NodeNotFound(node_id=bm_node_id)
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_get_all(context):
query = model_query(context, models.BareMetalPxeIp, read_deleted="no")
return query.all()
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_create(context, address, server_address):
ref = models.BareMetalPxeIp()
ref.address = address
ref.server_address = server_address
_save(ref)
return ref
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_create_direct(context, bm_pxe_ip):
ref = bm_pxe_ip_create(context,
address=bm_pxe_ip['address'],
server_address=bm_pxe_ip['server_address'])
return ref
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_destroy(context, ip_id):
# Delete physically since it has unique columns
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(id=ip_id).\
delete()
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_destroy_by_address(context, address):
# Delete physically since it has unique columns
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(address=address).\
delete()
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_get(context, ip_id):
result = model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(id=ip_id).\
first()
return result
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_get_by_bm_node_id(context, bm_node_id):
result = model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
first()
if not result:
raise exception.NodeNotFound(node_id=bm_node_id)
return result
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_associate(context, bm_node_id):
session = db_session.get_session()
with session.begin():
# Check if the node really exists
node_ref = model_query(context, models.BareMetalNode,
read_deleted="no", session=session).\
filter_by(id=bm_node_id).\
first()
if not node_ref:
raise exception.NodeNotFound(node_id=bm_node_id)
# Check if the node already has a pxe_ip
ip_ref = model_query(context, models.BareMetalPxeIp,
read_deleted="no", session=session).\
filter_by(bm_node_id=bm_node_id).\
first()
if ip_ref:
return ip_ref.id
# with_lockmode('update') and filter_by(bm_node_id=None) will lock all
# records. It may cause a performance problem in high-concurrency
# environment.
ip_ref = model_query(context, models.BareMetalPxeIp,
read_deleted="no", session=session).\
filter_by(bm_node_id=None).\
with_lockmode('update').\
first()
# this exception is not caught in nova/compute/manager
if not ip_ref:
raise exception.NovaException(_("No more PXE IPs available"))
ip_ref.bm_node_id = bm_node_id
session.add(ip_ref)
return ip_ref.id
@sqlalchemy_api.require_admin_context
def bm_pxe_ip_disassociate(context, bm_node_id):
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
update({'bm_node_id': None})
@sqlalchemy_api.require_admin_context
def bm_interface_get(context, if_id):
result = model_query(context, models.BareMetalInterface,
read_deleted="no").\
filter_by(id=if_id).\
first()
if not result:
raise exception.NovaException(_("Baremetal interface %s "
"not found") % if_id)
return result
@sqlalchemy_api.require_admin_context
def bm_interface_get_all(context):
query = model_query(context, models.BareMetalInterface,
read_deleted="no")
return query.all()
@sqlalchemy_api.require_admin_context
def bm_interface_destroy(context, if_id):
# Delete physically since it has unique columns
model_query(context, models.BareMetalInterface, read_deleted="no").\
filter_by(id=if_id).\
delete()
@sqlalchemy_api.require_admin_context
def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
ref = models.BareMetalInterface()
ref.bm_node_id = bm_node_id
ref.address = address
ref.datapath_id = datapath_id
ref.port_no = port_no
_save(ref)
return ref.id
@sqlalchemy_api.require_admin_context
def bm_interface_set_vif_uuid(context, if_id, vif_uuid):
session = db_session.get_session()
with session.begin():
bm_interface = model_query(context, models.BareMetalInterface,
read_deleted="no", session=session).\
filter_by(id=if_id).\
with_lockmode('update').\
first()
if not bm_interface:
raise exception.NovaException(_("Baremetal interface %s "
"not found") % if_id)
bm_interface.vif_uuid = vif_uuid
try:
session.add(bm_interface)
session.flush()
except db_exc.DBError as e:
# TODO(deva): clean up when db layer raises DuplicateKeyError
if str(e).find('IntegrityError') != -1:
raise exception.NovaException(_("Baremetal interface %s "
"already in use") % vif_uuid)
else:
raise e
@sqlalchemy_api.require_admin_context
def bm_interface_get_by_vif_uuid(context, vif_uuid):
result = model_query(context, models.BareMetalInterface,
read_deleted="no").\
filter_by(vif_uuid=vif_uuid).\
first()
if not result:
raise exception.NovaException(_("Baremetal virtual interface %s "
"not found") % vif_uuid)
return result
@sqlalchemy_api.require_admin_context
def bm_interface_get_all_by_bm_node_id(context, bm_node_id):
result = model_query(context, models.BareMetalInterface,
read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
all()
if not result:
raise exception.NodeNotFound(node_id=bm_node_id)
return result

View File

@ -0,0 +1,14 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.

View File

@ -0,0 +1,20 @@
[db_settings]
# Used to identify which repository this database is versioned under.
# You can use the name of your project.
repository_id=nova_bm
# The name of the database table used to track the schema version.
# This name shouldn't already be used by your project.
# If this is changed once a database is under version control, you'll need to
# change the table name in each database too.
version_table=migrate_version
# When committing a change script, Migrate will attempt to generate the
# sql for all supported databases; normally, if one of them fails - probably
# because you don't have that database installed - it is ignored and the
# commit continues, perhaps ending successfully.
# Databases in this list MUST compile successfully during a commit, or the
# entire commit will fail. List the databases your application will actually
# be using to ensure your updates to that database work properly.
# This must be a list; example: ['postgres','sqlite']
required_dbs=[]

View File

@ -0,0 +1,119 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.
from sqlalchemy import Boolean, Column, DateTime
from sqlalchemy import Index, Integer, MetaData, String, Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
bm_nodes = Table('bm_nodes', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('cpus', Integer),
Column('memory_mb', Integer),
Column('local_gb', Integer),
Column('pm_address', String(length=255)),
Column('pm_user', String(length=255)),
Column('pm_password', String(length=255)),
Column('service_host', String(length=255)),
Column('prov_mac_address', String(length=255)),
Column('instance_uuid', String(length=36)),
Column('registration_status', String(length=16)),
Column('task_state', String(length=255)),
Column('prov_vlan_id', Integer),
Column('terminal_port', Integer),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_interfaces = Table('bm_interfaces', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('bm_node_id', Integer),
Column('address', String(length=255), unique=True),
Column('datapath_id', String(length=255)),
Column('port_no', Integer),
Column('vif_uuid', String(length=36), unique=True),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_pxe_ips = Table('bm_pxe_ips', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('address', String(length=255), unique=True),
Column('bm_node_id', Integer),
Column('server_address', String(length=255), unique=True),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_deployments = Table('bm_deployments', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('bm_node_id', Integer),
Column('key', String(length=255)),
Column('image_path', String(length=255)),
Column('pxe_config_path', String(length=255)),
Column('root_mb', Integer),
Column('swap_mb', Integer),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_nodes.create()
bm_interfaces.create()
bm_pxe_ips.create()
bm_deployments.create()
Index('idx_bm_nodes_service_host_deleted',
bm_nodes.c.service_host, bm_nodes.c.deleted)\
.create(migrate_engine)
Index('idx_bm_nodes_instance_uuid_deleted',
bm_nodes.c.instance_uuid, bm_nodes.c.deleted)\
.create(migrate_engine)
Index('idx_bm_nodes_hmcld',
bm_nodes.c.service_host, bm_nodes.c.memory_mb, bm_nodes.c.cpus,
bm_nodes.c.local_gb, bm_nodes.c.deleted)\
.create(migrate_engine)
Index('idx_bm_interfaces_bm_node_id_deleted',
bm_interfaces.c.bm_node_id, bm_interfaces.c.deleted)\
.create(migrate_engine)
Index('idx_bm_pxe_ips_bm_node_id_deleted',
bm_pxe_ips.c.bm_node_id, bm_pxe_ips.c.deleted)\
.create(migrate_engine)
def downgrade(migrate_engine):
raise NotImplementedError('Downgrade from 001_init is unsupported.')

View File

@ -0,0 +1,68 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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.
from sqlalchemy import Column, Index, MetaData, Table
from sqlalchemy import Integer, String, DateTime, Boolean
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
bm_nodes = Table('bm_nodes', meta, autoload=True)
image_path = Column('image_path', String(length=255))
pxe_config_path = Column('pxe_config_path', String(length=255))
deploy_key = Column('deploy_key', String(length=255))
root_mb = Column('root_mb', Integer())
swap_mb = Column('swap_mb', Integer())
for c in [image_path, pxe_config_path, deploy_key, root_mb, swap_mb]:
bm_nodes.create_column(c)
deploy_key_idx = Index('deploy_key_idx', bm_nodes.c.deploy_key)
deploy_key_idx.create(migrate_engine)
bm_deployments = Table('bm_deployments', meta, autoload=True)
bm_deployments.drop()
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
bm_nodes = Table('bm_nodes', meta, autoload=True)
for c in ['image_path', 'pxe_config_path', 'deploy_key', 'root_mb',
'swap_mb']:
bm_nodes.drop_column(c)
bm_deployments = Table('bm_deployments', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('bm_node_id', Integer),
Column('key', String(length=255)),
Column('image_path', String(length=255)),
Column('pxe_config_path', String(length=255)),
Column('root_mb', Integer),
Column('swap_mb', Integer),
mysql_engine='InnoDB',
)
bm_deployments.create()

View File

@ -0,0 +1,39 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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.
from sqlalchemy import Column, MetaData, String, Table, Index
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
t = Table('bm_nodes', meta, autoload=True)
uuid_col = Column('uuid', String(36))
t.create_column(uuid_col)
uuid_ux = Index('uuid_ux', t.c.uuid, unique=True)
uuid_ux.create(migrate_engine)
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
t = Table('bm_nodes', meta, autoload=True)
t.drop_column('uuid')

View File

@ -0,0 +1,35 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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.
from sqlalchemy import Column, MetaData, String, Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
t = Table('bm_nodes', meta, autoload=True)
name_col = Column('instance_name', String(255))
t.create_column(name_col)
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
t = Table('bm_nodes', meta, autoload=True)
t.drop_column('instance_name')

View File

@ -0,0 +1,35 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2013 NTT DOCOMO, 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.
from sqlalchemy import Column, String, Integer, MetaData, Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
nodes = Table('bm_nodes', meta, autoload=True)
nodes.drop_column('prov_vlan_id')
nodes.drop_column('registration_status')
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
nodes = Table('bm_nodes', meta, autoload=True)
nodes.create_column(Column('prov_vlan_id', Integer))
nodes.create_column(Column('registration_status', String(length=16)))

View File

@ -0,0 +1,84 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2013 NTT DOCOMO, 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.
from ironic.openstack.common import log as logging
from sqlalchemy import and_, MetaData, select, Table, exists
from sqlalchemy import exc
LOG = logging.getLogger(__name__)
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
nodes = Table('bm_nodes', meta, autoload=True)
ifs = Table('bm_interfaces', meta, autoload=True)
q = select([nodes.c.id, nodes.c.prov_mac_address],
from_obj=nodes)
# Iterate all elements before starting insert since IntegrityError
# may disturb the iteration.
node_address = {}
for node_id, address in q.execute():
node_address[node_id] = address
i = ifs.insert()
for node_id, address in node_address.iteritems():
try:
i.execute({'bm_node_id': node_id, 'address': address})
except exc.IntegrityError:
# The address is registered in both bm_nodes and bm_interfaces.
# It is expected.
pass
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
nodes = Table('bm_nodes', meta, autoload=True)
ifs = Table('bm_interfaces', meta, autoload=True)
subq = exists().where(and_(ifs.c.bm_node_id == nodes.c.id,
ifs.c.address == nodes.c.prov_mac_address))
ifs.delete().where(subq).execute()
# NOTE(arata):
# In fact, this downgrade may not return the db to the previous state.
# It seems to be not so match a problem, so this is just for memo.
#
# Think these two state before upgrading:
#
# (A) address 'x' is duplicate
# bm_nodes.prov_mac_address='x'
# bm_interfaces.address=['x', 'y']
#
# (B) no address is duplicate
# bm_nodes.prov_mac_address='x'
# bm_interfaces.address=['y']
#
# Upgrading them results in the same state:
#
# bm_nodes.prov_mac_address='x'
# bm_interfaces.address=['x', 'y']
#
# Downgrading this results in B, even if the actual initial status was A
# Of course we can change it to downgrade to B, but then we cannot
# downgrade to A; it is an exclusive choice since we do not have
# information about the initial state.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.

View File

@ -0,0 +1,111 @@
# 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.
import distutils.version as dist_version
import migrate
from migrate.versioning import util as migrate_util
import os
import sqlalchemy
from ironic import exception
from ironic.db import migration
from ironic.db.sqlalchemy import session
@migrate_util.decorator
def patched_with_engine(f, *a, **kw):
url = a[0]
engine = migrate_util.construct_engine(url, **kw)
try:
kw['engine'] = engine
return f(*a, **kw)
finally:
if isinstance(engine, migrate_util.Engine) and engine is not url:
migrate_util.log.debug('Disposing SQLAlchemy engine %s', engine)
engine.dispose()
# TODO(jkoelker) When migrate 0.7.3 is released and nova depends
# on that version or higher, this can be removed
MIN_PKG_VERSION = dist_version.StrictVersion('0.7.3')
if (not hasattr(migrate, '__version__') or
dist_version.StrictVersion(migrate.__version__) < MIN_PKG_VERSION):
migrate_util.with_engine = patched_with_engine
# NOTE(jkoelker) Delay importing migrate until we are patched
from migrate import exceptions as versioning_exceptions
from migrate.versioning import api as versioning_api
from migrate.versioning.repository import Repository
_REPOSITORY = None
def db_sync(version=None):
if version is not None:
try:
version = int(version)
except ValueError:
raise exception.NovaException(_("version should be an integer"))
current_version = db_version()
repository = _find_migrate_repo()
if version is None or version > current_version:
return versioning_api.upgrade(session.get_engine(), repository,
version)
else:
return versioning_api.downgrade(session.get_engine(), repository,
version)
def db_version():
repository = _find_migrate_repo()
try:
return versioning_api.db_version(session.get_engine(), repository)
except versioning_exceptions.DatabaseNotControlledError:
meta = sqlalchemy.MetaData()
engine = session.get_engine()
meta.reflect(bind=engine)
tables = meta.tables
if len(tables) == 0:
db_version_control(migration.INIT_VERSION)
return versioning_api.db_version(session.get_engine(), repository)
else:
# Some pre-Essex DB's may not be version controlled.
# Require them to upgrade using Essex first.
raise exception.NovaException(
_("Upgrade DB using Essex release first."))
def db_version_control(version=None):
repository = _find_migrate_repo()
versioning_api.version_control(session.get_engine(), repository, version)
return version
def _find_migrate_repo():
"""Get the path for the migrate repository."""
global _REPOSITORY
path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'migrate_repo')
assert os.path.exists(path)
if _REPOSITORY is None:
_REPOSITORY = Repository(path)
return _REPOSITORY

View File

@ -0,0 +1,75 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.
"""
SQLAlchemy models for baremetal data.
"""
from sqlalchemy import Column, Boolean, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ForeignKey, Text
from nova.db.sqlalchemy import models
BASE = declarative_base()
class BareMetalNode(BASE, models.NovaBase):
"""Represents a bare metal node."""
__tablename__ = 'bm_nodes'
id = Column(Integer, primary_key=True)
deleted = Column(Boolean, default=False)
uuid = Column(String(36))
service_host = Column(String(255))
instance_uuid = Column(String(36), nullable=True)
instance_name = Column(String(255), nullable=True)
cpus = Column(Integer)
memory_mb = Column(Integer)
local_gb = Column(Integer)
pm_address = Column(Text)
pm_user = Column(Text)
pm_password = Column(Text)
prov_mac_address = Column(Text)
task_state = Column(String(255))
terminal_port = Column(Integer)
image_path = Column(String(255), nullable=True)
pxe_config_path = Column(String(255), nullable=True)
deploy_key = Column(String(255), nullable=True)
root_mb = Column(Integer)
swap_mb = Column(Integer)
class BareMetalPxeIp(BASE, models.NovaBase):
__tablename__ = 'bm_pxe_ips'
id = Column(Integer, primary_key=True)
deleted = Column(Boolean, default=False)
address = Column(String(255), unique=True)
server_address = Column(String(255), unique=True)
bm_node_id = Column(Integer, ForeignKey('bm_nodes.id'), nullable=True)
class BareMetalInterface(BASE, models.NovaBase):
__tablename__ = 'bm_interfaces'
id = Column(Integer, primary_key=True)
deleted = Column(Boolean, default=False)
bm_node_id = Column(Integer, ForeignKey('bm_nodes.id'), nullable=True)
address = Column(String(255), unique=True)
datapath_id = Column(String(255))
port_no = Column(Integer)
vif_uuid = Column(String(36), unique=True)

View File

@ -0,0 +1,65 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.
"""Session Handling for SQLAlchemy backend."""
from oslo.config import cfg
from ironic.openstack.common.db.sqlalchemy import session as nova_session
from nova import paths
opts = [
cfg.StrOpt('sql_connection',
default=('sqlite:///' +
paths.state_path_def('baremetal_$sqlite_db')),
help='The SQLAlchemy connection string used to connect to the '
'bare-metal database'),
]
baremetal_group = cfg.OptGroup(name='baremetal',
title='Baremetal Options')
CONF = cfg.CONF
CONF.register_group(baremetal_group)
CONF.register_opts(opts, baremetal_group)
CONF.import_opt('sqlite_db', 'ironic.openstack.common.db.sqlalchemy.session')
_ENGINE = None
_MAKER = None
def get_session(autocommit=True, expire_on_commit=False):
"""Return a SQLAlchemy session."""
global _MAKER
if _MAKER is None:
engine = get_engine()
_MAKER = nova_session.get_maker(engine, autocommit, expire_on_commit)
session = _MAKER()
return session
def get_engine():
"""Return a SQLAlchemy engine."""
global _ENGINE
if _ENGINE is None:
_ENGINE = nova_session.create_engine(CONF.baremetal.sql_connection)
return _ENGINE

View File

@ -0,0 +1,17 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.
from ironic.manager import driver
BareMetalDriver = driver.BareMetalDriver

View File

@ -297,11 +297,5 @@ def _get_impl():
"""Delay import of rpc_backend until configuration is loaded."""
global _RPCIMPL
if _RPCIMPL is None:
try:
_RPCIMPL = importutils.import_module(CONF.rpc_backend)
except ImportError:
# For backwards compatibility with older nova config.
impl = CONF.rpc_backend.replace('nova.rpc',
'nova.openstack.common.rpc')
_RPCIMPL = importutils.import_module(impl)
_RPCIMPL = importutils.import_module(CONF.rpc_backend)
return _RPCIMPL

38
ironic/tests/__init__.py Normal file
View File

@ -0,0 +1,38 @@
# 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.
"""
:mod:`Ironic.tests` -- ironic Unittests
=====================================================
.. automodule:: ironic.tests
:platform: Unix
"""
# TODO(mikal): move eventlet imports to ironic.__init__ once we move to PBR
import os
import sys
import eventlet
eventlet.monkey_patch(os=False)
# See http://code.google.com/p/python-nose/issues/detail?id=373
# The code below enables nosetests to work with i18n _() blocks
import __builtin__
setattr(__builtin__, '_', lambda x: x)

View File

@ -19,23 +19,13 @@
import fixtures
from oslo.config import cfg
from nova import config
from nova import ipv6
from nova import paths
from nova.tests import utils
from ironic import config
from ironic import paths
from ironic.tests import utils
CONF = cfg.CONF
CONF.import_opt('use_ipv6', 'nova.netconf')
CONF.import_opt('host', 'nova.netconf')
CONF.import_opt('scheduler_driver', 'nova.scheduler.manager')
CONF.import_opt('fake_network', 'nova.network.manager')
CONF.import_opt('network_size', 'nova.network.manager')
CONF.import_opt('num_networks', 'nova.network.manager')
CONF.import_opt('floating_ip_dns_manager', 'nova.network.floating_ips')
CONF.import_opt('instance_dns_manager', 'nova.network.floating_ips')
CONF.import_opt('policy_file', 'nova.policy')
CONF.import_opt('compute_driver', 'nova.virt.driver')
CONF.import_opt('api_paste_config', 'nova.wsgi')
CONF.import_opt('use_ipv6', 'ironic.netconf')
CONF.import_opt('host', 'ironic.netconf')
class ConfFixture(fixtures.Fixture):
@ -48,28 +38,16 @@ class ConfFixture(fixtures.Fixture):
super(ConfFixture, self).setUp()
self.conf.set_default('api_paste_config',
paths.state_path_def('etc/nova/api-paste.ini'))
paths.state_path_def('etc/ironic/api-paste.ini'))
self.conf.set_default('host', 'fake-mini')
self.conf.set_default('compute_driver', 'nova.virt.fake.FakeDriver')
self.conf.set_default('fake_network', True)
self.conf.set_default('fake_rabbit', True)
self.conf.set_default('flat_network_bridge', 'br100')
self.conf.set_default('floating_ip_dns_manager',
'nova.tests.utils.dns_manager')
self.conf.set_default('instance_dns_manager',
'nova.tests.utils.dns_manager')
self.conf.set_default('lock_path', None)
self.conf.set_default('network_size', 8)
self.conf.set_default('num_networks', 2)
self.conf.set_default('rpc_backend',
'nova.openstack.common.rpc.impl_fake')
'ironic.openstack.common.rpc.impl_fake')
self.conf.set_default('rpc_cast_timeout', 5)
self.conf.set_default('rpc_response_timeout', 5)
self.conf.set_default('sql_connection', "sqlite://")
self.conf.set_default('sqlite_synchronous', False)
self.conf.set_default('use_ipv6', True)
self.conf.set_default('verbose', True)
self.conf.set_default('vlan_interface', 'eth0')
config.parse_args([], default_config_files=[])
self.addCleanup(self.conf.reset)
self.addCleanup(utils.cleanup_dns_managers)

View File

@ -0,0 +1,16 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# All Rights Reserved.
# flake8: noqa
#
# 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.
from ironic.tests.db import *

50
ironic/tests/db/base.py Normal file
View File

@ -0,0 +1,50 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# 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.
"""Bare-metal DB test base class."""
from oslo.config import cfg
from ironic import context as ironic_context
from ironic import test
from ironic.db import migration as bm_migration
from ironic.db.sqlalchemy import session as bm_session
_DB_CACHE = None
CONF = cfg.CONF
CONF.import_opt('sql_connection',
'ironic.db.sqlalchemy.session')
class Database(test.Database):
def post_migrations(self):
pass
class BMDBTestCase(test.TestCase):
def setUp(self):
super(BMDBTestCase, self).setUp()
self.flags(sql_connection='sqlite://')
global _DB_CACHE
if not _DB_CACHE:
_DB_CACHE = Database(bm_session, bm_migration,
sql_connection=CONF.sql_connection,
sqlite_db=None,
sqlite_clean_db=None)
self.useFixture(_DB_CACHE)
self.context = nova_context.get_admin_context()

View File

@ -18,6 +18,8 @@
policy_data = """
{
"admin_api": "role:admin",
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
"context_is_admin": "role:admin or role:administrator",
"default": "rule:admin_or_owner"
}
"""

View File

@ -0,0 +1,15 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# All Rights Reserved.
# flake8: noqa
# 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.
from ironic.tests.manager import *

View File

@ -17,9 +17,9 @@ import os
import fixtures
from oslo.config import cfg
from nova.openstack.common import policy as common_policy
import nova.policy
from nova.tests import fake_policy
from ironic.openstack.common import policy as common_policy
import ironic.policy
from ironic.tests import fake_policy
CONF = cfg.CONF
@ -34,9 +34,9 @@ class PolicyFixture(fixtures.Fixture):
with open(self.policy_file_name, 'w') as policy_file:
policy_file.write(fake_policy.policy_data)
CONF.set_override('policy_file', self.policy_file_name)
nova.policy.reset()
nova.policy.init()
self.addCleanup(nova.policy.reset)
ironic.policy.reset()
ironic.policy.init()
self.addCleanup(ironic.policy.reset)
def set_rules(self, rules):
common_policy.set_rules(common_policy.Rules(

View File

View File

@ -24,8 +24,6 @@ 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
@ -44,7 +42,7 @@ class InstallVenv(object):
self.project = project
def die(self, message, *args):
print(message % args, file=sys.stderr)
print >> sys.stderr, message % args
sys.exit(1)
def check_python_version(self):
@ -91,20 +89,20 @@ class InstallVenv(object):
virtual environment.
"""
if not os.path.isdir(self.venv):
print('Creating venv...', end=' ')
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...', end=' ')
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.')
print 'done.'
else:
print("venv already exists...")
print "venv already exists..."
pass
def pip_install(self, *args):
@ -113,7 +111,7 @@ class InstallVenv(object):
redirect_output=False)
def install_dependencies(self):
print('Installing dependencies with pip (this can take a while)...')
print 'Installing dependencies with pip (this can take a while)...'
# First things first, make sure our venv has the latest pip and
# distribute.
@ -155,12 +153,12 @@ class Distro(InstallVenv):
return
if self.check_cmd('easy_install'):
print('Installing virtualenv via easy_install...', end=' ')
print 'Installing virtualenv via easy_install...',
if self.run_command(['easy_install', 'virtualenv']):
print('Succeeded')
print 'Succeeded'
return
else:
print('Failed')
print 'Failed'
self.die('ERROR: virtualenv not found.\n\n%s development'
' requires virtualenv, please install it using your'

View File

@ -17,7 +17,7 @@
import os
import sys
import tools.install_venv_common as install_venv
import install_venv_common as install_venv
def main(argv):
@ -25,8 +25,8 @@ def main(argv):
venv = os.environ['VIRTUAL_ENV']
pip_requires = os.path.join(root, 'requirements.txt')
test_requires = os.path.join(root, 'test-requirements.txt')
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 = 'Nova'
install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,

7
tools/with_venv.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
tools_path=${tools_path:-$(dirname $0)}
venv_path=${venv_path:-${tools_path}}
venv_dir=${venv_name:-/../.venv}
TOOLS=${tools_path}
VENV=${venv:-${venv_path}/${venv_dir}}
source ${VENV}/bin/activate && "$@"