Rename files and fix things.
This commit is contained in:
parent
1f276b1a4a
commit
6cbb3b5ccc
5
.gitignore
vendored
5
.gitignore
vendored
@ -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
6
etc/ironic/policy.json
Normal 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
16
ironic/__init__.py
Normal 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
27
ironic/cmd/__init__.py
Normal 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
16
ironic/db/__init__.py
Normal 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
178
ironic/db/api.py
Normal 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
38
ironic/db/migration.py
Normal 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()
|
14
ironic/db/sqlalchemy/__init__.py
Normal file
14
ironic/db/sqlalchemy/__init__.py
Normal 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
433
ironic/db/sqlalchemy/api.py
Normal 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
|
14
ironic/db/sqlalchemy/migrate_repo/__init__.py
Normal file
14
ironic/db/sqlalchemy/migrate_repo/__init__.py
Normal 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.
|
20
ironic/db/sqlalchemy/migrate_repo/migrate.cfg
Normal file
20
ironic/db/sqlalchemy/migrate_repo/migrate.cfg
Normal 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=[]
|
119
ironic/db/sqlalchemy/migrate_repo/versions/001_init.py
Normal file
119
ironic/db/sqlalchemy/migrate_repo/versions/001_init.py
Normal 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.')
|
@ -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()
|
@ -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')
|
@ -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')
|
@ -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)))
|
@ -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.
|
14
ironic/db/sqlalchemy/migrate_repo/versions/__init__.py
Normal file
14
ironic/db/sqlalchemy/migrate_repo/versions/__init__.py
Normal 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.
|
111
ironic/db/sqlalchemy/migration.py
Normal file
111
ironic/db/sqlalchemy/migration.py
Normal 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
|
75
ironic/db/sqlalchemy/models.py
Normal file
75
ironic/db/sqlalchemy/models.py
Normal 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)
|
65
ironic/db/sqlalchemy/session.py
Normal file
65
ironic/db/sqlalchemy/session.py
Normal 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
|
17
ironic/manager/__init__.py
Normal file
17
ironic/manager/__init__.py
Normal 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
|
@ -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
38
ironic/tests/__init__.py
Normal 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)
|
@ -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)
|
||||
|
16
ironic/tests/db/__init__.py
Normal file
16
ironic/tests/db/__init__.py
Normal 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
50
ironic/tests/db/base.py
Normal 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()
|
@ -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"
|
||||
}
|
||||
"""
|
||||
|
15
ironic/tests/manager/__init__.py
Normal file
15
ironic/tests/manager/__init__.py
Normal 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 *
|
@ -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(
|
||||
|
@ -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'
|
||||
|
@ -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
7
tools/with_venv.sh
Executable 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 && "$@"
|
Loading…
x
Reference in New Issue
Block a user