summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSoren Hansen <soren.hansen@rackspace.com>2010-10-04 12:53:55 +0200
committerSoren Hansen <soren.hansen@rackspace.com>2010-10-04 12:53:55 +0200
commit3543d8430e02c1b22f1932cb9d0af028d9ef648b (patch)
treebe585b618e3d01f28602c959ee7642b7a8b2aa57
parent14d78899f953fa047b5fd6ad3667313f544027b8 (diff)
parent104940614784c69ed3d17581ff2cb1ed344eaa0f (diff)
Merge trunk
-rw-r--r--nova/api/context.py (renamed from nova/api/ec2/context.py)13
-rw-r--r--nova/api/ec2/__init__.py8
-rw-r--r--nova/db/api.py17
-rw-r--r--nova/db/sqlalchemy/api.py739
-rw-r--r--nova/db/sqlalchemy/models.py150
-rw-r--r--nova/network/linux_net.py50
-rw-r--r--nova/network/manager.py14
-rw-r--r--nova/tests/compute_unittest.py6
-rw-r--r--nova/tests/network_unittest.py50
9 files changed, 668 insertions, 379 deletions
diff --git a/nova/api/ec2/context.py b/nova/api/context.py
index c53ba98d9..b66cfe468 100644
--- a/nova/api/ec2/context.py
+++ b/nova/api/context.py
@@ -31,3 +31,16 @@ class APIRequestContext(object):
[random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-')
for x in xrange(20)]
)
+ if user:
+ self.is_admin = user.is_admin()
+ else:
+ self.is_admin = False
+ self.read_deleted = False
+
+
+def get_admin_context(user=None, read_deleted=False):
+ context_ref = APIRequestContext(user=user, project=None)
+ context_ref.is_admin = True
+ context_ref.read_deleted = read_deleted
+ return context_ref
+
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index 8111ef023..6e771f064 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -27,8 +27,8 @@ import webob.exc
from nova import exception
from nova import flags
from nova import wsgi
+from nova.api import context
from nova.api.ec2 import apirequest
-from nova.api.ec2 import context
from nova.api.ec2 import admin
from nova.api.ec2 import cloud
from nova.auth import manager
@@ -195,15 +195,15 @@ class Authorizer(wsgi.Middleware):
return True
if 'none' in roles:
return False
- return any(context.project.has_role(context.user.id, role)
+ return any(context.project.has_role(context.user.id, role)
for role in roles)
-
+
class Executor(wsgi.Application):
"""Execute an EC2 API request.
- Executes 'ec2.action' upon 'ec2.controller', passing 'ec2.context' and
+ Executes 'ec2.action' upon 'ec2.controller', passing 'ec2.context' and
'ec2.action_args' (all variables in WSGI environ.) Returns an XML
response, or a 400 upon failure.
"""
diff --git a/nova/db/api.py b/nova/db/api.py
index 8a1ba2872..08f91aee8 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -175,11 +175,6 @@ def floating_ip_get_by_address(context, address):
return IMPL.floating_ip_get_by_address(context, address)
-def floating_ip_get_instance(context, address):
- """Get an instance for a floating ip by address."""
- return IMPL.floating_ip_get_instance(context, address)
-
-
####################
@@ -640,3 +635,15 @@ def security_group_rule_get_by_security_group(context, security_group_id):
def security_group_rule_destroy(context, security_group_rule_id):
"""Deletes a security group rule"""
return IMPL.security_group_rule_destroy(context, security_group_rule_id)
+
+
+###################
+
+
+def host_get_networks(context, host):
+ """Return all networks for which the given host is the designated
+ network host
+ """
+ return IMPL.host_get_networks(context, host)
+
+
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 565e1e126..d395b7e2c 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -19,6 +19,8 @@
Implementation of SQLAlchemy backend
"""
+import warnings
+
from nova import db
from nova import exception
from nova import flags
@@ -27,6 +29,7 @@ from nova.db.sqlalchemy import models
from nova.db.sqlalchemy.session import get_session
from sqlalchemy import or_
from sqlalchemy.exc import IntegrityError
+from sqlalchemy.orm import joinedload
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql import exists
from sqlalchemy.sql import func
@@ -35,32 +38,102 @@ from sqlalchemy.orm.exc import NoResultFound
FLAGS = flags.FLAGS
-# NOTE(vish): disabling docstring pylint because the docstrings are
-# in the interface definition
-# pylint: disable-msg=C0111
-def _deleted(context):
- """Calculates whether to include deleted objects based on context.
+def is_admin_context(context):
+ """Indicates if the request context is an administrator."""
+ if not context:
+ warnings.warn('Use of empty request context is deprecated',
+ DeprecationWarning)
+ return True
+ return context.is_admin
+
+
+def is_user_context(context):
+ """Indicates if the request context is a normal user."""
+ if not context:
+ return False
+ if not context.user or not context.project:
+ return False
+ return True
+
- Currently just looks for a flag called deleted in the context dict.
+def authorize_project_context(context, project_id):
+ """Ensures that the request context has permission to access the
+ given project.
"""
- if not hasattr(context, 'get'):
+ if is_user_context(context):
+ if not context.project:
+ raise exception.NotAuthorized()
+ elif context.project.id != project_id:
+ raise exception.NotAuthorized()
+
+
+def authorize_user_context(context, user_id):
+ """Ensures that the request context has permission to access the
+ given user.
+ """
+ if is_user_context(context):
+ if not context.user:
+ raise exception.NotAuthorized()
+ elif context.user.id != user_id:
+ raise exception.NotAuthorized()
+
+
+def can_read_deleted(context):
+ """Indicates if the context has access to deleted objects."""
+ if not context:
return False
- return context.get('deleted', False)
+ return context.read_deleted
-###################
+def require_admin_context(f):
+ """Decorator used to indicate that the method requires an
+ administrator context.
+ """
+ def wrapper(*args, **kwargs):
+ if not is_admin_context(args[0]):
+ raise exception.NotAuthorized()
+ return f(*args, **kwargs)
+ return wrapper
+
+
+def require_context(f):
+ """Decorator used to indicate that the method requires either
+ an administrator or normal user context.
+ """
+ def wrapper(*args, **kwargs):
+ if not is_admin_context(args[0]) and not is_user_context(args[0]):
+ raise exception.NotAuthorized()
+ return f(*args, **kwargs)
+ return wrapper
+###################
+
+@require_admin_context
def service_destroy(context, service_id):
session = get_session()
with session.begin():
- service_ref = models.Service.find(service_id, session=session)
+ service_ref = service_get(context, service_id, session=session)
service_ref.delete(session=session)
-def service_get(_context, service_id):
- return models.Service.find(service_id)
+@require_admin_context
+def service_get(context, service_id, session=None):
+ if not session:
+ session = get_session()
+
+ result = session.query(models.Service
+ ).filter_by(id=service_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ if not result:
+ raise exception.NotFound('No service for id %s' % service_id)
+
+ return result
+
+
+@require_admin_context
def service_get_all_by_topic(context, topic):
session = get_session()
return session.query(models.Service
@@ -70,7 +143,8 @@ def service_get_all_by_topic(context, topic):
).all()
-def _service_get_all_topic_subquery(_context, session, topic, subq, label):
+@require_admin_context
+def _service_get_all_topic_subquery(context, session, topic, subq, label):
sort_value = getattr(subq.c, label)
return session.query(models.Service, func.coalesce(sort_value, 0)
).filter_by(topic=topic
@@ -81,6 +155,7 @@ def _service_get_all_topic_subquery(_context, session, topic, subq, label):
).all()
+@require_admin_context
def service_get_all_compute_sorted(context):
session = get_session()
with session.begin():
@@ -105,6 +180,7 @@ def service_get_all_compute_sorted(context):
label)
+@require_admin_context
def service_get_all_network_sorted(context):
session = get_session()
with session.begin():
@@ -122,6 +198,7 @@ def service_get_all_network_sorted(context):
label)
+@require_admin_context
def service_get_all_volume_sorted(context):
session = get_session()
with session.begin():
@@ -139,11 +216,22 @@ def service_get_all_volume_sorted(context):
label)
-def service_get_by_args(_context, host, binary):
- return models.Service.find_by_args(host, binary)
+@require_admin_context
+def service_get_by_args(context, host, binary):
+ session = get_session()
+ result = session.query(models.Service
+ ).filter_by(host=host
+ ).filter_by(binary=binary
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ if not result:
+ raise exception.NotFound('No service for %s, %s' % (host, binary))
+ return result
-def service_create(_context, values):
+
+@require_admin_context
+def service_create(context, values):
service_ref = models.Service()
for (key, value) in values.iteritems():
service_ref[key] = value
@@ -151,10 +239,11 @@ def service_create(_context, values):
return service_ref
-def service_update(_context, service_id, values):
+@require_admin_context
+def service_update(context, service_id, values):
session = get_session()
with session.begin():
- service_ref = models.Service.find(service_id, session=session)
+ service_ref = service_get(context, service_id, session=session)
for (key, value) in values.iteritems():
service_ref[key] = value
service_ref.save(session=session)
@@ -163,7 +252,9 @@ def service_update(_context, service_id, values):
###################
-def floating_ip_allocate_address(_context, host, project_id):
+@require_context
+def floating_ip_allocate_address(context, host, project_id):
+ authorize_project_context(context, project_id)
session = get_session()
with session.begin():
floating_ip_ref = session.query(models.FloatingIp
@@ -182,7 +273,8 @@ def floating_ip_allocate_address(_context, host, project_id):
return floating_ip_ref['address']
-def floating_ip_create(_context, values):
+@require_context
+def floating_ip_create(context, values):
floating_ip_ref = models.FloatingIp()
for (key, value) in values.iteritems():
floating_ip_ref[key] = value
@@ -190,7 +282,9 @@ def floating_ip_create(_context, values):
return floating_ip_ref['address']
-def floating_ip_count_by_project(_context, project_id):
+@require_context
+def floating_ip_count_by_project(context, project_id):
+ authorize_project_context(context, project_id)
session = get_session()
return session.query(models.FloatingIp
).filter_by(project_id=project_id
@@ -198,39 +292,53 @@ def floating_ip_count_by_project(_context, project_id):
).count()
-def floating_ip_fixed_ip_associate(_context, floating_address, fixed_address):
+@require_context
+def floating_ip_fixed_ip_associate(context, floating_address, fixed_address):
session = get_session()
with session.begin():
- floating_ip_ref = models.FloatingIp.find_by_str(floating_address,
- session=session)
- fixed_ip_ref = models.FixedIp.find_by_str(fixed_address,
- session=session)
+ # TODO(devcamcar): How to ensure floating_id belongs to user?
+ floating_ip_ref = floating_ip_get_by_address(context,
+ floating_address,
+ session=session)
+ fixed_ip_ref = fixed_ip_get_by_address(context,
+ fixed_address,
+ session=session)
floating_ip_ref.fixed_ip = fixed_ip_ref
floating_ip_ref.save(session=session)
-def floating_ip_deallocate(_context, address):
+@require_context
+def floating_ip_deallocate(context, address):
session = get_session()
with session.begin():
- floating_ip_ref = models.FloatingIp.find_by_str(address,
- session=session)
+ # TODO(devcamcar): How to ensure floating id belongs to user?
+ floating_ip_ref = floating_ip_get_by_address(context,
+ address,
+ session=session)
floating_ip_ref['project_id'] = None
floating_ip_ref.save(session=session)
-def floating_ip_destroy(_context, address):
+@require_context
+def floating_ip_destroy(context, address):
session = get_session()
with session.begin():
- floating_ip_ref = models.FloatingIp.find_by_str(address,
- session=session)
+ # TODO(devcamcar): Ensure address belongs to user.
+ floating_ip_ref = get_floating_ip_by_address(context,
+ address,
+ session=session)
floating_ip_ref.delete(session=session)
-def floating_ip_disassociate(_context, address):
+@require_context
+def floating_ip_disassociate(context, address):
session = get_session()
with session.begin():
- floating_ip_ref = models.FloatingIp.find_by_str(address,
- session=session)
+ # TODO(devcamcar): Ensure address belongs to user.
+ # Does get_floating_ip_by_address handle this?
+ floating_ip_ref = floating_ip_get_by_address(context,
+ address,
+ session=session)
fixed_ip_ref = floating_ip_ref.fixed_ip
if fixed_ip_ref:
fixed_ip_address = fixed_ip_ref['address']
@@ -241,7 +349,8 @@ def floating_ip_disassociate(_context, address):
return fixed_ip_address
-def floating_ip_get_all(_context):
+@require_admin_context
+def floating_ip_get_all(context):
session = get_session()
return session.query(models.FloatingIp
).options(joinedload_all('fixed_ip.instance')
@@ -249,7 +358,8 @@ def floating_ip_get_all(_context):
).all()
-def floating_ip_get_all_by_host(_context, host):
+@require_admin_context
+def floating_ip_get_all_by_host(context, host):
session = get_session()
return session.query(models.FloatingIp
).options(joinedload_all('fixed_ip.instance')
@@ -257,7 +367,10 @@ def floating_ip_get_all_by_host(_context, host):
).filter_by(deleted=False
).all()
-def floating_ip_get_all_by_project(_context, project_id):
+
+@require_context
+def floating_ip_get_all_by_project(context, project_id):
+ authorize_project_context(context, project_id)
session = get_session()
return session.query(models.FloatingIp
).options(joinedload_all('fixed_ip.instance')
@@ -265,24 +378,31 @@ def floating_ip_get_all_by_project(_context, project_id):
).filter_by(deleted=False
).all()
-def floating_ip_get_by_address(_context, address):
- return models.FloatingIp.find_by_str(address)
+@require_context
+def floating_ip_get_by_address(context, address, session=None):
+ # TODO(devcamcar): Ensure the address belongs to user.
+ if not session:
+ session = get_session()
-def floating_ip_get_instance(_context, address):
- session = get_session()
- with session.begin():
- floating_ip_ref = models.FloatingIp.find_by_str(address,
- session=session)
- return floating_ip_ref.fixed_ip.instance
+ result = session.query(models.FloatingIp
+ ).filter_by(address=address
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ if not result:
+ raise exception.NotFound('No fixed ip for address %s' % address)
+
+ return result
###################
-def fixed_ip_associate(_context, address, instance_id):
+@require_context
+def fixed_ip_associate(context, address, instance_id):
session = get_session()
with session.begin():
+ instance = instance_get(context, instance_id, session=session)
fixed_ip_ref = session.query(models.FixedIp
).filter_by(address=address
).filter_by(deleted=False
@@ -293,12 +413,12 @@ def fixed_ip_associate(_context, address, instance_id):
# then this has concurrency issues
if not fixed_ip_ref:
raise db.NoMoreAddresses()
- fixed_ip_ref.instance = models.Instance.find(instance_id,
- session=session)
+ fixed_ip_ref.instance = instance
session.add(fixed_ip_ref)
-def fixed_ip_associate_pool(_context, network_id, instance_id):
+@require_admin_context
+def fixed_ip_associate_pool(context, network_id, instance_id):
session = get_session()
with session.begin():
network_or_none = or_(models.FixedIp.network_id == network_id,
@@ -315,14 +435,17 @@ def fixed_ip_associate_pool(_context, network_id, instance_id):
if not fixed_ip_ref:
raise db.NoMoreAddresses()
if not fixed_ip_ref.network:
- fixed_ip_ref.network = models.Network.find(network_id,
- session=session)
- fixed_ip_ref.instance = models.Instance.find(instance_id,
- session=session)
+ fixed_ip_ref.network = network_get(context,
+ network_id,
+ session=session)
+ fixed_ip_ref.instance = instance_get(context,
+ instance_id,
+ session=session)
session.add(fixed_ip_ref)
return fixed_ip_ref['address']
+@require_context
def fixed_ip_create(_context, values):
fixed_ip_ref = models.FixedIp()
for (key, value) in values.iteritems():
@@ -331,14 +454,18 @@ def fixed_ip_create(_context, values):
return fixed_ip_ref['address']
-def fixed_ip_disassociate(_context, address):
+@require_context
+def fixed_ip_disassociate(context, address):
session = get_session()
with session.begin():
- fixed_ip_ref = models.FixedIp.find_by_str(address, session=session)
+ fixed_ip_ref = fixed_ip_get_by_address(context,
+ address,
+ session=session)
fixed_ip_ref.instance = None
fixed_ip_ref.save(session=session)
+@require_admin_context
def fixed_ip_disassociate_all_by_timeout(_context, host, time):
session = get_session()
# NOTE(vish): The nested select is because sqlite doesn't support
@@ -355,34 +482,44 @@ def fixed_ip_disassociate_all_by_timeout(_context, host, time):
return result.rowcount
-def fixed_ip_get_by_address(_context, address):
- session = get_session()
+@require_context
+def fixed_ip_get_by_address(context, address, session=None):
+ if not session:
+ session = get_session()
result = session.query(models.FixedIp
- ).options(joinedload_all('instance')
).filter_by(address=address
- ).filter_by(deleted=False
+ ).filter_by(deleted=can_read_deleted(context)
+ ).options(joinedload('network')
+ ).options(joinedload('instance')
).first()
if not result:
- raise exception.NotFound("No model for address %s" % address)
+ raise exception.NotFound('No floating ip for address %s' % address)
+
+ if is_user_context(context):
+ authorize_project_context(context, result.instance.project_id)
+
return result
-def fixed_ip_get_instance(_context, address):
- session = get_session()
- with session.begin():
- return models.FixedIp.find_by_str(address, session=session).instance
+@require_context
+def fixed_ip_get_instance(context, address):
+ fixed_ip_ref = fixed_ip_get_by_address(context, address)
+ return fixed_ip_ref.instance
-def fixed_ip_get_network(_context, address):
- session = get_session()
- with session.begin():
- return models.FixedIp.find_by_str(address, session=session).network
+@require_admin_context
+def fixed_ip_get_network(context, address):
+ fixed_ip_ref = fixed_ip_get_by_address(context, address)
+ return fixed_ip_ref.network
-def fixed_ip_update(_context, address, values):
+@require_context
+def fixed_ip_update(context, address, values):
session = get_session()
with session.begin():
- fixed_ip_ref = models.FixedIp.find_by_str(address, session=session)
+ fixed_ip_ref = fixed_ip_get_by_address(context,
+ address,
+ session=session)
for (key, value) in values.iteritems():
fixed_ip_ref[key] = value
fixed_ip_ref.save(session=session)
@@ -391,7 +528,8 @@ def fixed_ip_update(_context, address, values):
###################
-def instance_create(_context, values):
+@require_context
+def instance_create(context, values):
instance_ref = models.Instance()
for (key, value) in values.iteritems():
instance_ref[key] = value
@@ -400,12 +538,14 @@ def instance_create(_context, values):
with session.begin():
while instance_ref.ec2_id == None:
ec2_id = utils.generate_uid(instance_ref.__prefix__)
- if not instance_ec2_id_exists(_context, ec2_id, session=session):
+ if not instance_ec2_id_exists(context, ec2_id, session=session):
instance_ref.ec2_id = ec2_id
instance_ref.save(session=session)
return instance_ref
-def instance_data_get_for_project(_context, project_id):
+
+@require_admin_context
+def instance_data_get_for_project(context, project_id):
session = get_session()
result = session.query(func.count(models.Instance.id),
func.sum(models.Instance.vcpus)
@@ -416,91 +556,130 @@ def instance_data_get_for_project(_context, project_id):
return (result[0] or 0, result[1] or 0)
-def instance_destroy(_context, instance_id):
+@require_context
+def instance_destroy(context, instance_id):
session = get_session()
with session.begin():
- instance_ref = models.Instance.find(instance_id, session=session)
+ instance_ref = instance_get(context, instance_id, session=session)
instance_ref.delete(session=session)
-def instance_get(context, instance_id):
- session = get_session()
- instance_ref = session.query(models.Instance
- ).filter_by(id=instance_id
- ).filter_by(deleted=_deleted(context)
- ).options(joinedload_all('security_groups')
- ).options(joinedload_all('fixed_ip.floating_ips')
- ).first()
- if not instance_ref:
- raise exception.NotFound('Instance %s not found' % (instance_id))
+@require_context
+def instance_get(context, instance_id, session=None):
+ if not session:
+ session = get_session()
+ result = None
- return instance_ref
+ if is_admin_context(context):
+ result = session.query(models.Instance
+ ).filter_by(id=instance_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ elif is_user_context(context):
+ result = session.query(models.Instance
+ ).filter_by(project_id=context.project.id
+ ).filter_by(id=instance_id
+ ).filter_by(deleted=False
+ ).first()
+ if not result:
+ raise exception.NotFound('No instance for id %s' % instance_id)
+
+ return result
+@require_admin_context
def instance_get_all(context):
session = get_session()
return session.query(models.Instance
).options(joinedload_all('fixed_ip.floating_ips')
- ).filter_by(deleted=_deleted(context)
+ ).filter_by(deleted=can_read_deleted(context)
).all()
+
+@require_admin_context
def instance_get_all_by_user(context, user_id):
session = get_session()
return session.query(models.Instance
).options(joinedload_all('fixed_ip.floating_ips')
- ).filter_by(deleted=_deleted(context)
+ ).filter_by(deleted=can_read_deleted(context)
).filter_by(user_id=user_id
).all()
+
+@require_context
def instance_get_all_by_project(context, project_id):
+ authorize_project_context(context, project_id)
+
session = get_session()
return session.query(models.Instance
).options(joinedload_all('fixed_ip.floating_ips')
).filter_by(project_id=project_id
- ).filter_by(deleted=_deleted(context)
+ ).filter_by(deleted=can_read_deleted(context)
).all()
-def instance_get_all_by_reservation(_context, reservation_id):
+@require_context
+def instance_get_all_by_reservation(context, reservation_id):
session = get_session()
- return session.query(models.Instance
- ).options(joinedload_all('fixed_ip.floating_ips')
- ).filter_by(reservation_id=reservation_id
- ).filter_by(deleted=False
- ).all()
+
+ if is_admin_context(context):
+ return session.query(models.Instance
+ ).options(joinedload_all('fixed_ip.floating_ips')
+ ).filter_by(reservation_id=reservation_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).all()
+ elif is_user_context(context):
+ return session.query(models.Instance
+ ).options(joinedload_all('fixed_ip.floating_ips')
+ ).filter_by(project_id=context.project.id
+ ).filter_by(reservation_id=reservation_id
+ ).filter_by(deleted=False
+ ).all()
+@require_context
def instance_get_by_ec2_id(context, ec2_id):
session = get_session()
- instance_ref = session.query(models.Instance
+
+ if is_admin_context(context):
+ result = session.query(models.Instance
+ ).filter_by(ec2_id=ec2_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ elif is_user_context(context):
+ result = session.query(models.Instance
+ ).filter_by(project_id=context.project.id
).filter_by(ec2_id=ec2_id
- ).filter_by(deleted=_deleted(context)
+ ).filter_by(deleted=False
).first()
- if not instance_ref:
+ if not result:
raise exception.NotFound('Instance %s not found' % (ec2_id))
- return instance_ref
+ return result
+@require_context
def instance_ec2_id_exists(context, ec2_id, session=None):
if not session:
session = get_session()
return session.query(exists().where(models.Instance.id==ec2_id)).one()[0]
-def instance_get_fixed_address(_context, instance_id):
+@require_context
+def instance_get_fixed_address(context, instance_id):
session = get_session()
with session.begin():
- instance_ref = models.Instance.find(instance_id, session=session)
+ instance_ref = instance_get(context, instance_id, session=session)
if not instance_ref.fixed_ip:
return None
return instance_ref.fixed_ip['address']
-def instance_get_floating_address(_context, instance_id):
+@require_context
+def instance_get_floating_address(context, instance_id):
session = get_session()
with session.begin():
- instance_ref = models.Instance.find(instance_id, session=session)
+ instance_ref = instance_get(context, instance_id, session=session)
if not instance_ref.fixed_ip:
return None
if not instance_ref.fixed_ip.floating_ips:
@@ -509,12 +688,14 @@ def instance_get_floating_address(_context, instance_id):
return instance_ref.fixed_ip.floating_ips[0]['address']
+@require_admin_context
def instance_is_vpn(context, instance_id):
# TODO(vish): Move this into image code somewhere
instance_ref = instance_get(context, instance_id)
return instance_ref['image_id'] == FLAGS.vpn_image_id
+@require_admin_context
def instance_set_state(context, instance_id, state, description=None):
# TODO(devcamcar): Move this out of models and into driver
from nova.compute import power_state
@@ -526,10 +707,11 @@ def instance_set_state(context, instance_id, state, description=None):
'state_description': description})
-def instance_update(_context, instance_id, values):
+@require_context
+def instance_update(context, instance_id, values):
session = get_session()
with session.begin():
- instance_ref = models.Instance.find(instance_id, session=session)
+ instance_ref = instance_get(context, instance_id, session=session)
for (key, value) in values.iteritems():
instance_ref[key] = value
instance_ref.save(session=session)
@@ -549,7 +731,8 @@ def instance_add_security_group(context, instance_id, security_group_id):
###################
-def key_pair_create(_context, values):
+@require_context
+def key_pair_create(context, values):
key_pair_ref = models.KeyPair()
for (key, value) in values.iteritems():
key_pair_ref[key] = value
@@ -557,16 +740,18 @@ def key_pair_create(_context, values):
return key_pair_ref
-def key_pair_destroy(_context, user_id, name):
+@require_context
+def key_pair_destroy(context, user_id, name):
+ authorize_user_context(context, user_id)
session = get_session()
with session.begin():
- key_pair_ref = models.KeyPair.find_by_args(user_id,
- name,
- session=session)
+ key_pair_ref = key_pair_get(context, user_id, name, session=session)
key_pair_ref.delete(session=session)
-def key_pair_destroy_all_by_user(_context, user_id):
+@require_context
+def key_pair_destroy_all_by_user(context, user_id):
+ authorize_user_context(context, user_id)
session = get_session()
with session.begin():
# TODO(vish): do we have to use sql here?
@@ -574,11 +759,27 @@ def key_pair_destroy_all_by_user(_context, user_id):
{'id': user_id})
-def key_pair_get(_context, user_id, name):
- return models.KeyPair.find_by_args(user_id, name)
+@require_context
+def key_pair_get(context, user_id, name, session=None):
+ authorize_user_context(context, user_id)
+ if not session:
+ session = get_session()
-def key_pair_get_all_by_user(_context, user_id):
+ result = session.query(models.KeyPair
+ ).filter_by(user_id=user_id
+ ).filter_by(name=name
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ if not result:
+ raise exception.NotFound('no keypair for user %s, name %s' %
+ (user_id, name))
+ return result
+
+
+@require_context
+def key_pair_get_all_by_user(context, user_id):
+ authorize_user_context(context, user_id)
session = get_session()
return session.query(models.KeyPair
).filter_by(user_id=user_id
@@ -589,11 +790,16 @@ def key_pair_get_all_by_user(_context, user_id):
###################
-def network_count(_context):
- return models.Network.count()
+@require_admin_context
+def network_count(context):
+ session = get_session()
+ return session.query(models.Network
+ ).filter_by(deleted=can_read_deleted(context)
+ ).count()
-def network_count_allocated_ips(_context, network_id):
+@require_admin_context
+def network_count_allocated_ips(context, network_id):
session = get_session()
return session.query(models.FixedIp
).filter_by(network_id=network_id
@@ -602,7 +808,8 @@ def network_count_allocated_ips(_context, network_id):
).count()
-def network_count_available_ips(_context, network_id):
+@require_admin_context
+def network_count_available_ips(context, network_id):
session = get_session()
return session.query(models.FixedIp
).filter_by(network_id=network_id
@@ -612,7 +819,8 @@ def network_count_available_ips(_context, network_id):
).count()
-def network_count_reserved_ips(_context, network_id):
+@require_admin_context
+def network_count_reserved_ips(context, network_id):
session = get_session()
return session.query(models.FixedIp
).filter_by(network_id=network_id
@@ -621,7 +829,8 @@ def network_count_reserved_ips(_context, network_id):
).count()
-def network_create(_context, values):
+@require_admin_context
+def network_create(context, values):
network_ref = models.Network()
for (key, value) in values.iteritems():
network_ref[key] = value
@@ -629,7 +838,8 @@ def network_create(_context, values):
return network_ref
-def network_destroy(_context, network_id):
+@require_admin_context
+def network_destroy(context, network_id):
session = get_session()
with session.begin():
# TODO(vish): do we have to use sql here?
@@ -647,14 +857,34 @@ def network_destroy(_context, network_id):
{'id': network_id})
-def network_get(_context, network_id):
- return models.Network.find(network_id)
+@require_context
+def network_get(context, network_id, session=None):
+ if not session:
+ session = get_session()
+ result = None
+
+ if is_admin_context(context):
+ result = session.query(models.Network
+ ).filter_by(id=network_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ elif is_user_context(context):
+ result = session.query(models.Network
+ ).filter_by(project_id=context.project.id
+ ).filter_by(id=network_id
+ ).filter_by(deleted=False
+ ).first()
+ if not result:
+ raise exception.NotFound('No network for id %s' % network_id)
+
+ return result
# NOTE(vish): pylint complains because of the long method name, but
# it fits with the names of the rest of the methods
# pylint: disable-msg=C0103
-def network_get_associated_fixed_ips(_context, network_id):
+@require_admin_context
+def network_get_associated_fixed_ips(context, network_id):
session = get_session()
return session.query(models.FixedIp
).options(joinedload_all('instance')
@@ -664,18 +894,22 @@ def network_get_associated_fixed_ips(_context, network_id):
).all()
-def network_get_by_bridge(_context, bridge):
+@require_admin_context
+def network_get_by_bridge(context, bridge):
session = get_session()
- rv = session.query(models.Network
+ result = session.query(models.Network
).filter_by(bridge=bridge
).filter_by(deleted=False
).first()
- if not rv:
+
+ if not result:
raise exception.NotFound('No network for bridge %s' % bridge)
- return rv
+ return result
-def network_get_index(_context, network_id):
+
+@require_admin_context
+def network_get_index(context, network_id):
session = get_session()
with session.begin():
network_index = session.query(models.NetworkIndex
@@ -683,19 +917,28 @@ def network_get_index(_context, network_id):
).filter_by(deleted=False
).with_lockmode('update'
).first()
+
if not network_index:
raise db.NoMoreNetworks()
- network_index['network'] = models.Network.find(network_id,
- session=session)
+
+ network_index['network'] = network_get(context,
+ network_id,
+ session=session)
session.add(network_index)
+
return network_index['index']
-def network_index_count(_context):
- return models.NetworkIndex.count()
+@require_admin_context
+def network_index_count(context):
+ session = get_session()
+ return session.query(models.NetworkIndex
+ ).filter_by(deleted=can_read_deleted(context)
+ ).count()
-def network_index_create_safe(_context, values):
+@require_admin_context
+def network_index_create_safe(context, values):
network_index_ref = models.NetworkIndex()
for (key, value) in values.iteritems():
network_index_ref[key] = value
@@ -705,29 +948,32 @@ def network_index_create_safe(_context, values):
pass
-def network_set_host(_context, network_id, host_id):
+@require_admin_context
+def network_set_host(context, network_id, host_id):
session = get_session()
with session.begin():
- network = session.query(models.Network
- ).filter_by(id=network_id
- ).filter_by(deleted=False
- ).with_lockmode('update'
- ).first()
- if not network:
- raise exception.NotFound("Couldn't find network with %s" %
- network_id)
+ network_ref = session.query(models.Network
+ ).filter_by(id=network_id
+ ).filter_by(deleted=False
+ ).with_lockmode('update'
+ ).first()
+ if not network_ref:
+ raise exception.NotFound('No network for id %s' % network_id)
+
# NOTE(vish): if with_lockmode isn't supported, as in sqlite,
# then this has concurrency issues
- if not network['host']:
- network['host'] = host_id
- session.add(network)
- return network['host']
+ if not network_ref['host']:
+ network_ref['host'] = host_id
+ session.add(network_ref)
+
+ return network_ref['host']
-def network_update(_context, network_id, values):
+@require_context
+def network_update(context, network_id, values):
session = get_session()
with session.begin():
- network_ref = models.Network.find(network_id, session=session)
+ network_ref = network_get(context, network_id, session=session)
for (key, value) in values.iteritems():
network_ref[key] = value
network_ref.save(session=session)
@@ -736,15 +982,18 @@ def network_update(_context, network_id, values):
###################
-def project_get_network(_context, project_id):
+@require_context
+def project_get_network(context, project_id):
session = get_session()
- rv = session.query(models.Network
+ result= session.query(models.Network
).filter_by(project_id=project_id
).filter_by(deleted=False
).first()
- if not rv:
+
+ if not result:
raise exception.NotFound('No network for project: %s' % project_id)
- return rv
+
+ return result
###################
@@ -754,14 +1003,20 @@ def queue_get_for(_context, topic, physical_node_id):
# FIXME(ja): this should be servername?
return "%s.%s" % (topic, physical_node_id)
+
###################
-def export_device_count(_context):
- return models.ExportDevice.count()
+@require_admin_context
+def export_device_count(context):
+ session = get_session()
+ return session.query(models.ExportDevice
+ ).filter_by(deleted=can_read_deleted(context)
+ ).count()
-def export_device_create(_context, values):
+@require_admin_context
+def export_device_create(context, values):
export_device_ref = models.ExportDevice()
for (key, value) in values.iteritems():
export_device_ref[key] = value
@@ -795,7 +1050,23 @@ def auth_create_token(_context, token):
###################
-def quota_create(_context, values):
+@require_admin_context
+def quota_get(context, project_id, session=None):
+ if not session:
+ session = get_session()
+
+ result = session.query(models.Quota
+ ).filter_by(project_id=project_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ if not result:
+ raise exception.NotFound('No quota for project_id %s' % project_id)
+
+ return result
+
+
+@require_admin_context
+def quota_create(context, values):
quota_ref = models.Quota()
for (key, value) in values.iteritems():
quota_ref[key] = value
@@ -803,30 +1074,29 @@ def quota_create(_context, values):
return quota_ref
-def quota_get(_context, project_id):
- return models.Quota.find_by_str(project_id)
-
-
-def quota_update(_context, project_id, values):
+@require_admin_context
+def quota_update(context, project_id, values):
session = get_session()
with session.begin():
- quota_ref = models.Quota.find_by_str(project_id, session=session)
+ quota_ref = quota_get(context, project_id, session=session)
for (key, value) in values.iteritems():
quota_ref[key] = value
quota_ref.save(session=session)
-def quota_destroy(_context, project_id):
+@require_admin_context
+def quota_destroy(context, project_id):
session = get_session()
with session.begin():
- quota_ref = models.Quota.find_by_str(project_id, session=session)
+ quota_ref = quota_get(context, project_id, session=session)
quota_ref.delete(session=session)
###################
-def volume_allocate_shelf_and_blade(_context, volume_id):
+@require_admin_context
+def volume_allocate_shelf_and_blade(context, volume_id):
session = get_session()
with session.begin():
export_device = session.query(models.ExportDevice
@@ -843,19 +1113,20 @@ def volume_allocate_shelf_and_blade(_context, volume_id):
return (export_device.shelf_id, export_device.blade_id)
-def volume_attached(_context, volume_id, instance_id, mountpoint):
+@require_admin_context
+def volume_attached(context, volume_id, instance_id, mountpoint):
session = get_session()
with session.begin():
- volume_ref = models.Volume.find(volume_id, session=session)
+ volume_ref = volume_get(context, volume_id, session=session)
volume_ref['status'] = 'in-use'
volume_ref['mountpoint'] = mountpoint
volume_ref['attach_status'] = 'attached'
- volume_ref.instance = models.Instance.find(instance_id,
- session=session)
+ volume_ref.instance = instance_get(context, instance_id, session=session)
volume_ref.save(session=session)
-def volume_create(_context, values):
+@require_context
+def volume_create(context, values):
volume_ref = models.Volume()
for (key, value) in values.iteritems():
volume_ref[key] = value
@@ -864,13 +1135,14 @@ def volume_create(_context, values):
with session.begin():
while volume_ref.ec2_id == None:
ec2_id = utils.generate_uid(volume_ref.__prefix__)
- if not volume_ec2_id_exists(_context, ec2_id, session=session):
+ if not volume_ec2_id_exists(context, ec2_id, session=session):
volume_ref.ec2_id = ec2_id
volume_ref.save(session=session)
return volume_ref
-def volume_data_get_for_project(_context, project_id):
+@require_admin_context
+def volume_data_get_for_project(context, project_id):
session = get_session()
result = session.query(func.count(models.Volume.id),
func.sum(models.Volume.size)
@@ -881,7 +1153,8 @@ def volume_data_get_for_project(_context, project_id):
return (result[0] or 0, result[1] or 0)
-def volume_destroy(_context, volume_id):
+@require_admin_context
+def volume_destroy(context, volume_id):
session = get_session()
with session.begin():
# TODO(vish): do we have to use sql here?
@@ -892,10 +1165,11 @@ def volume_destroy(_context, volume_id):
{'id': volume_id})
-def volume_detached(_context, volume_id):
+@require_admin_context
+def volume_detached(context, volume_id):
session = get_session()
with session.begin():
- volume_ref = models.Volume.find(volume_id, session=session)
+ volume_ref = volume_get(context, volume_id, session=session)
volume_ref['status'] = 'available'
volume_ref['mountpoint'] = None
volume_ref['attach_status'] = 'detached'
@@ -903,60 +1177,113 @@ def volume_detached(_context, volume_id):
volume_ref.save(session=session)
-def volume_get(context, volume_id):
- return models.Volume.find(volume_id, deleted=_deleted(context))
+@require_context
+def volume_get(context, volume_id, session=None):
+ if not session:
+ session = get_session()
+ result = None
+
+ if is_admin_context(context):
+ result = session.query(models.Volume
+ ).filter_by(id=volume_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ elif is_user_context(context):
+ result = session.query(models.Volume
+ ).filter_by(project_id=context.project.id
+ ).filter_by(id=volume_id
+ ).filter_by(deleted=False
+ ).first()
+ if not result:
+ raise exception.NotFound('No volume for id %s' % volume_id)
+
+ return result
+@require_admin_context
def volume_get_all(context):
- return models.Volume.all(deleted=_deleted(context))
-
+ return session.query(models.Volume
+ ).filter_by(deleted=can_read_deleted(context)
+ ).all()
+@require_context
def volume_get_all_by_project(context, project_id):
+ authorize_project_context(context, project_id)
+
session = get_session()
return session.query(models.Volume
).filter_by(project_id=project_id
- ).filter_by(deleted=_deleted(context)
+ ).filter_by(deleted=can_read_deleted(context)
).all()
+@require_context
def volume_get_by_ec2_id(context, ec2_id):
session = get_session()
- volume_ref = session.query(models.Volume
+ result = None
+
+ if is_admin_context(context):
+ result = session.query(models.Volume
+ ).filter_by(ec2_id=ec2_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).first()
+ elif is_user_context(context):
+ result = session.query(models.Volume
+ ).filter_by(project_id=context.project.id
).filter_by(ec2_id=ec2_id
- ).filter_by(deleted=_deleted(context)
+ ).filter_by(deleted=False
).first()
- if not volume_ref:
- raise exception.NotFound('Volume %s not found' % (ec2_id))
+ else:
+ raise exception.NotAuthorized()
- return volume_ref
+ if not result:
+ raise exception.NotFound('Volume %s not found' % ec2_id)
+
+ return result
+@require_context
def volume_ec2_id_exists(context, ec2_id, session=None):
if not session:
session = get_session()
- return session.query(exists().where(models.Volume.id==ec2_id)).one()[0]
+
+ return session.query(exists(
+ ).where(models.Volume.id==ec2_id)
+ ).one()[0]
-def volume_get_instance(_context, volume_id):
+@require_admin_context
+def volume_get_instance(context, volume_id):
session = get_session()
- with session.begin():
- return models.Volume.find(volume_id, session=session).instance
+ result = session.query(models.Volume
+ ).filter_by(id=volume_id
+ ).filter_by(deleted=can_read_deleted(context)
+ ).options(joinedload('instance')
+ ).first()
+ if not result:
+ raise exception.NotFound('Volume %s not found' % ec2_id)
+
+ return result.instance
-def volume_get_shelf_and_blade(_context, volume_id):
+@require_admin_context
+def volume_get_shelf_and_blade(context, volume_id):
session = get_session()
- export_device = session.query(models.ExportDevice
- ).filter_by(volume_id=volume_id
- ).first()
- if not export_device:
- raise exception.NotFound()
- return (export_device.shelf_id, export_device.blade_id)
+ result = session.query(models.ExportDevice
+ ).filter_by(volume_id=volume_id
+ ).first()
+ if not result:
+ raise exception.NotFound('No export device found for volume %s' %
+ volume_id)
+
+ return (result.shelf_id, result.blade_id)
-def volume_update(_context, volume_id, values):
+@require_context
+def volume_update(context, volume_id, values):
session = get_session()
with session.begin():
- volume_ref = models.Volume.find(volume_id, session=session)
+ volume_ref = volume_get(context, volume_id, session=session)
for (key, value) in values.iteritems():
volume_ref[key] = value
volume_ref.save(session=session)
@@ -1075,3 +1402,15 @@ def security_group_rule_destroy(_context, security_group_rule_id):
security_group_rule = model.find(security_group_rule_id,
session=session)
security_group_rule.delete(session=session)
+
+
+###################
+
+
+def host_get_networks(context, host):
+ session = get_session()
+ with session.begin():
+ return session.query(models.Network
+ ).filter_by(deleted=False
+ ).filter_by(host=host
+ ).all()
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 5149f32cd..829b279a0 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -50,48 +50,6 @@ class NovaBase(object):
deleted_at = Column(DateTime)
deleted = Column(Boolean, default=False)
- @classmethod
- def all(cls, session=None, deleted=False):
- """Get all objects of this type"""
- if not session:
- session = get_session()
- return session.query(cls
- ).filter_by(deleted=deleted
- ).all()
-
- @classmethod
- def count(cls, session=None, deleted=False):
- """Count objects of this type"""
- if not session:
- session = get_session()
- return session.query(cls
- ).filter_by(deleted=deleted
- ).count()
-
- @classmethod
- def find(cls, obj_id, session=None, deleted=False, options=None):
- """Find object by id"""
- if not session:
- session = get_session()
- try:
- query = session.query(cls
- ).filter_by(id=obj_id
- ).filter_by(deleted=deleted)
-
- if options:
- query = query.options(options)
-
- return query.one()
- except exc.NoResultFound:
- new_exc = exception.NotFound("No model for id %s" % obj_id)
- raise new_exc.__class__, new_exc, sys.exc_info()[2]
-
- @classmethod
- def find_by_str(cls, str_id, session=None, deleted=False):
- """Find object by str_id"""
- int_id = int(str_id.rpartition('-')[2])
- return cls.find(int_id, session=session, deleted=deleted)
-
@property
def str_id(self):
"""Get string id of object (generally prefix + '-' + id)"""
@@ -180,21 +138,6 @@ class Service(BASE, NovaBase):
report_count = Column(Integer, nullable=False, default=0)
disabled = Column(Boolean, default=False)
- @classmethod
- def find_by_args(cls, host, binary, session=None, deleted=False):
- if not session:
- session = get_session()
- try:
- return session.query(cls
- ).filter_by(host=host
- ).filter_by(binary=binary
- ).filter_by(deleted=deleted
- ).one()
- except exc.NoResultFound:
- new_exc = exception.NotFound("No model for %s, %s" % (host,
- binary))
- raise new_exc.__class__, new_exc, sys.exc_info()[2]
-
class Instance(BASE, NovaBase):
"""Represents a guest vm"""
@@ -287,7 +230,11 @@ class Volume(BASE, NovaBase):
size = Column(Integer)
availability_zone = Column(String(255)) # TODO(vish): foreign key?
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
- instance = relationship(Instance, backref=backref('volumes'))
+ instance = relationship(Instance,
+ backref=backref('volumes'),
+ foreign_keys=instance_id,
+ primaryjoin='and_(Volume.instance_id==Instance.id,'
+ 'Volume.deleted==False)')
mountpoint = Column(String(255))
attach_time = Column(String(255)) # TODO(vish): datetime
status = Column(String(255)) # TODO(vish): enum?
@@ -318,18 +265,6 @@ class Quota(BASE, NovaBase):
def str_id(self):
return self.project_id
- @classmethod
- def find_by_str(cls, str_id, session=None, deleted=False):
- if not session:
- session = get_session()
- try:
- return session.query(cls
- ).filter_by(project_id=str_id
- ).filter_by(deleted=deleted
- ).one()
- except exc.NoResultFound:
- new_exc = exception.NotFound("No model for project_id %s" % str_id)
- raise new_exc.__class__, new_exc, sys.exc_info()[2]
class ExportDevice(BASE, NovaBase):
"""Represates a shelf and blade that a volume can be exported on"""
@@ -338,8 +273,11 @@ class ExportDevice(BASE, NovaBase):
shelf_id = Column(Integer)
blade_id = Column(Integer)
volume_id = Column(Integer, ForeignKey('volumes.id'), nullable=True)
- volume = relationship(Volume, backref=backref('export_device',
- uselist=False))
+ volume = relationship(Volume,
+ backref=backref('export_device', uselist=False),
+ foreign_keys=volume_id,
+ primaryjoin='and_(ExportDevice.volume_id==Volume.id,'
+ 'ExportDevice.deleted==False)')
class SecurityGroupInstanceAssociation(BASE, NovaBase):
@@ -414,26 +352,6 @@ class KeyPair(BASE, NovaBase):
def str_id(self):
return '%s.%s' % (self.user_id, self.name)
- @classmethod
- def find_by_str(cls, str_id, session=None, deleted=False):
- user_id, _sep, name = str_id.partition('.')
- return cls.find_by_str(user_id, name, session, deleted)
-
- @classmethod
- def find_by_args(cls, user_id, name, session=None, deleted=False):
- if not session:
- session = get_session()
- try:
- return session.query(cls
- ).filter_by(user_id=user_id
- ).filter_by(name=name
- ).filter_by(deleted=deleted
- ).one()
- except exc.NoResultFound:
- new_exc = exception.NotFound("No model for user %s, name %s" %
- (user_id, name))
- raise new_exc.__class__, new_exc, sys.exc_info()[2]
-
class Network(BASE, NovaBase):
"""Represents a network"""
@@ -469,8 +387,12 @@ class NetworkIndex(BASE, NovaBase):
id = Column(Integer, primary_key=True)
index = Column(Integer, unique=True)
network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
- network = relationship(Network, backref=backref('network_index',
- uselist=False))
+ network = relationship(Network,
+ backref=backref('network_index', uselist=False),
+ foreign_keys=network_id,
+ primaryjoin='and_(NetworkIndex.network_id==Network.id,'
+ 'NetworkIndex.deleted==False)')
+
class AuthToken(BASE, NovaBase):
"""Represents an authorization token for all API transactions. Fields
@@ -494,8 +416,11 @@ class FixedIp(BASE, NovaBase):
network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
network = relationship(Network, backref=backref('fixed_ips'))
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
- instance = relationship(Instance, backref=backref('fixed_ip',
- uselist=False))
+ instance = relationship(Instance,
+ backref=backref('fixed_ip', uselist=False),
+ foreign_keys=instance_id,
+ primaryjoin='and_(FixedIp.instance_id==Instance.id,'
+ 'FixedIp.deleted==False)')
allocated = Column(Boolean, default=False)
leased = Column(Boolean, default=False)
reserved = Column(Boolean, default=False)
@@ -504,19 +429,6 @@ class FixedIp(BASE, NovaBase):
def str_id(self):
return self.address
- @classmethod
- def find_by_str(cls, str_id, session=None, deleted=False):
- if not session:
- session = get_session()
- try:
- return session.query(cls
- ).filter_by(address=str_id
- ).filter_by(deleted=deleted
- ).one()
- except exc.NoResultFound:
- new_exc = exception.NotFound("No model for address %s" % str_id)
- raise new_exc.__class__, new_exc, sys.exc_info()[2]
-
class FloatingIp(BASE, NovaBase):
"""Represents a floating ip that dynamically forwards to a fixed ip"""
@@ -524,24 +436,14 @@ class FloatingIp(BASE, NovaBase):
id = Column(Integer, primary_key=True)
address = Column(String(255))
fixed_ip_id = Column(Integer, ForeignKey('fixed_ips.id'), nullable=True)
- fixed_ip = relationship(FixedIp, backref=backref('floating_ips'))
-
+ fixed_ip = relationship(FixedIp,
+ backref=backref('floating_ips'),
+ foreign_keys=fixed_ip_id,
+ primaryjoin='and_(FloatingIp.fixed_ip_id==FixedIp.id,'
+ 'FloatingIp.deleted==False)')
project_id = Column(String(255))
host = Column(String(255)) # , ForeignKey('hosts.id'))
- @classmethod
- def find_by_str(cls, str_id, session=None, deleted=False):
- if not session:
- session = get_session()
- try:
- return session.query(cls
- ).filter_by(address=str_id
- ).filter_by(deleted=deleted
- ).one()
- except exc.NoResultFound:
- new_exc = exception.NotFound("No model for address %s" % str_id)
- raise new_exc.__class__, new_exc, sys.exc_info()[2]
-
def register_models():
"""Register Models and create metadata"""
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 709195ba4..37f9c8253 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -28,6 +28,11 @@ from nova import flags
from nova import utils
+def _bin_file(script):
+ """Return the absolute path to scipt in the bin directory"""
+ return os.path.abspath(os.path.join(__file__, "../../../bin", script))
+
+
FLAGS = flags.FLAGS
flags.DEFINE_string('dhcpbridge_flagfile',
'/etc/nova/nova-dhcpbridge.conf',
@@ -38,7 +43,9 @@ flags.DEFINE_string('networks_path', utils.abspath('../networks'),
flags.DEFINE_string('public_interface', 'vlan1',
'Interface for public IP addresses')
flags.DEFINE_string('bridge_dev', 'eth0',
- 'network device for bridges')
+ 'network device for bridges')
+flags.DEFINE_string('dhcpbridge', _bin_file('nova-dhcpbridge'),
+ 'location of nova-dhcpbridge')
flags.DEFINE_string('routing_source_ip', '127.0.0.1',
'Public IP of network host')
flags.DEFINE_bool('use_nova_chains', False,
@@ -139,16 +146,16 @@ def ensure_bridge(bridge, interface, net_attrs=None):
# _execute("sudo brctl setageing %s 10" % bridge)
_execute("sudo brctl stp %s off" % bridge)
_execute("sudo brctl addif %s %s" % (bridge, interface))
- if net_attrs:
- _execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \
- (bridge,
- net_attrs['gateway'],
- net_attrs['broadcast'],
- net_attrs['netmask']))
- else:
- _execute("sudo ifconfig %s up" % bridge)
- _confirm_rule("FORWARD", "--in-interface %s -j ACCEPT" % bridge)
- _confirm_rule("FORWARD", "--out-interface %s -j ACCEPT" % bridge)
+ if net_attrs:
+ _execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \
+ (bridge,
+ net_attrs['gateway'],
+ net_attrs['broadcast'],
+ net_attrs['netmask']))
+ else:
+ _execute("sudo ifconfig %s up" % bridge)
+ _confirm_rule("FORWARD", "--in-interface %s -j ACCEPT" % bridge)
+ _confirm_rule("FORWARD", "--out-interface %s -j ACCEPT" % bridge)
def get_dhcp_hosts(context, network_id):
@@ -172,9 +179,14 @@ def update_dhcp(context, network_id):
signal causing it to reload, otherwise spawn a new instance
"""
network_ref = db.network_get(context, network_id)
- with open(_dhcp_file(network_ref['vlan'], 'conf'), 'w') as f:
+
+ conffile = _dhcp_file(network_ref['vlan'], 'conf')
+ with open(conffile, 'w') as f:
f.write(get_dhcp_hosts(context, network_id))
+ # Make sure dnsmasq can actually read it (it setuid()s to "nobody")
+ os.chmod(conffile, 0644)
+
pid = _dnsmasq_pid_for(network_ref['vlan'])
# if dnsmasq is already running, then tell it to reload
@@ -182,7 +194,7 @@ def update_dhcp(context, network_id):
# TODO(ja): use "/proc/%d/cmdline" % (pid) to determine if pid refers
# correct dnsmasq process
try:
- os.kill(pid, signal.SIGHUP)
+ _execute('sudo kill -HUP %d' % pid)
return
except Exception as exc: # pylint: disable-msg=W0703
logging.debug("Hupping dnsmasq threw %s", exc)
@@ -243,7 +255,7 @@ def _dnsmasq_cmd(net):
' --except-interface=lo',
' --dhcp-range=%s,static,120s' % net['dhcp_start'],
' --dhcp-hostsfile=%s' % _dhcp_file(net['vlan'], 'conf'),
- ' --dhcp-script=%s' % _bin_file('nova-dhcpbridge'),
+ ' --dhcp-script=%s' % FLAGS.dhcpbridge,
' --leasefile-ro']
return ''.join(cmd)
@@ -254,7 +266,7 @@ def _stop_dnsmasq(network):
if pid:
try:
- os.kill(pid, signal.SIGTERM)
+ _execute('sudo kill -TERM %d' % pid)
except Exception as exc: # pylint: disable-msg=W0703
logging.debug("Killing dnsmasq threw %s", exc)
@@ -262,12 +274,10 @@ def _stop_dnsmasq(network):
def _dhcp_file(vlan, kind):
"""Return path to a pid, leases or conf file for a vlan"""
- return os.path.abspath("%s/nova-%s.%s" % (FLAGS.networks_path, vlan, kind))
-
+ if not os.path.exists(FLAGS.networks_path):
+ os.makedirs(FLAGS.networks_path)
-def _bin_file(script):
- """Return the absolute path to scipt in the bin directory"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
+ return os.path.abspath("%s/nova-%s.%s" % (FLAGS.networks_path, vlan, kind))
def _dnsmasq_pid_for(vlan):
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 6e4d37755..093a6be9a 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -85,6 +85,12 @@ class NetworkManager(manager.Manager):
self.driver = utils.import_object(network_driver)
super(NetworkManager, self).__init__(*args, **kwargs)
+ def init_host(self):
+ # Set up networking for the projects for which we're already
+ # the designated network host.
+ for network in self.db.host_get_networks(None, self.host):
+ self._on_set_network_host(None, network['id'])
+
def set_network_host(self, context, project_id):
"""Safely sets the host of the projects network"""
logging.debug("setting network host")
@@ -92,7 +98,7 @@ class NetworkManager(manager.Manager):
# TODO(vish): can we minimize db access by just getting the
# id here instead of the ref?
network_id = network_ref['id']
- host = self.db.network_set_host(context,
+ host = self.db.network_set_host(None,
network_id,
self.host)
self._on_set_network_host(context, network_id)
@@ -229,7 +235,7 @@ class VlanManager(NetworkManager):
now = datetime.datetime.utcnow()
timeout = FLAGS.fixed_ip_disassociate_timeout
time = now - datetime.timedelta(seconds=timeout)
- num = self.db.fixed_ip_disassociate_all_by_timeout(self,
+ num = self.db.fixed_ip_disassociate_all_by_timeout(context,
self.host,
time)
if num:
@@ -239,6 +245,7 @@ class VlanManager(NetworkManager):
"""Do any initialization that needs to be run if this is a
standalone service.
"""
+ super(VlanManager, self).init_host()
self.driver.init_host()
def allocate_fixed_ip(self, context, instance_id, *args, **kwargs):
@@ -248,7 +255,7 @@ class VlanManager(NetworkManager):
address = network_ref['vpn_private_address']
self.db.fixed_ip_associate(context, address, instance_id)
else:
- address = self.db.fixed_ip_associate_pool(context,
+ address = self.db.fixed_ip_associate_pool(None,
network_ref['id'],
instance_id)
self.db.fixed_ip_update(context, address, {'allocated': True})
@@ -366,6 +373,7 @@ class VlanManager(NetworkManager):
self.driver.ensure_vlan_bridge(network_ref['vlan'],
network_ref['bridge'],
network_ref)
+ self.driver.update_dhcp(context, network_id)
@property
def _bottom_reserved_ips(self):
diff --git a/nova/tests/compute_unittest.py b/nova/tests/compute_unittest.py
index f5c0f1c09..1e2bb113b 100644
--- a/nova/tests/compute_unittest.py
+++ b/nova/tests/compute_unittest.py
@@ -30,7 +30,7 @@ from nova import flags
from nova import test
from nova import utils
from nova.auth import manager
-
+from nova.api import context
FLAGS = flags.FLAGS
@@ -96,7 +96,9 @@ class ComputeTestCase(test.TrialTestCase):
self.assertEqual(instance_ref['deleted_at'], None)
terminate = datetime.datetime.utcnow()
yield self.compute.terminate_instance(self.context, instance_id)
- instance_ref = db.instance_get({'deleted': True}, instance_id)
+ self.context = context.get_admin_context(user=self.user,
+ read_deleted=True)
+ instance_ref = db.instance_get(self.context, instance_id)
self.assert_(instance_ref['launched_at'] < terminate)
self.assert_(instance_ref['deleted_at'] > terminate)
diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py
index da65b50a2..59b0a36e4 100644
--- a/nova/tests/network_unittest.py
+++ b/nova/tests/network_unittest.py
@@ -56,12 +56,12 @@ class NetworkTestCase(test.TrialTestCase):
'netuser',
name))
# create the necessary network data for the project
- self.network.set_network_host(self.context, self.projects[i].id)
- instance_ref = db.instance_create(None,
- {'mac_address': utils.generate_mac()})
+ user_context = context.get_admin_context(user=self.user)
+
+ self.network.set_network_host(user_context, self.projects[i].id)
+ instance_ref = self._create_instance(0)
self.instance_id = instance_ref['id']
- instance_ref = db.instance_create(None,
- {'mac_address': utils.generate_mac()})
+ instance_ref = self._create_instance(1)
self.instance2_id = instance_ref['id']
def tearDown(self): # pylint: disable-msg=C0103
@@ -74,6 +74,15 @@ class NetworkTestCase(test.TrialTestCase):
self.manager.delete_project(project)
self.manager.delete_user(self.user)
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context.project = project
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
def _create_address(self, project_num, instance_id=None):
"""Create an address in given project num"""
if instance_id is None:
@@ -81,9 +90,15 @@ class NetworkTestCase(test.TrialTestCase):
self.context.project = self.projects[project_num]
return self.network.allocate_fixed_ip(self.context, instance_id)
+ def _deallocate_address(self, project_num, address):
+ self.context.project = self.projects[project_num]
+ self.network.deallocate_fixed_ip(self.context, address)
+
+
def test_public_network_association(self):
"""Makes sure that we can allocaate a public ip"""
# TODO(vish): better way of adding floating ips
+ self.context.project = self.projects[0]
pubnet = IPy.IP(flags.FLAGS.public_range)
address = str(pubnet[0])
try:
@@ -109,7 +124,7 @@ class NetworkTestCase(test.TrialTestCase):
address = self._create_address(0)
self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
lease_ip(address)
- self.network.deallocate_fixed_ip(self.context, address)
+ self._deallocate_address(0, address)
# Doesn't go away until it's dhcp released
self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
@@ -130,14 +145,14 @@ class NetworkTestCase(test.TrialTestCase):
lease_ip(address)
lease_ip(address2)
- self.network.deallocate_fixed_ip(self.context, address)
+ self._deallocate_address(0, address)
release_ip(address)
self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
# First address release shouldn't affect the second
self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
- self.network.deallocate_fixed_ip(self.context, address2)
+ self._deallocate_address(1, address2)
release_ip(address2)
self.assertFalse(is_allocated_in_project(address2,
self.projects[1].id))
@@ -148,24 +163,19 @@ class NetworkTestCase(test.TrialTestCase):
lease_ip(first)
instance_ids = []
for i in range(1, 5):
- mac = utils.generate_mac()
- instance_ref = db.instance_create(None,
- {'mac_address': mac})
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
instance_ids.append(instance_ref['id'])
address = self._create_address(i, instance_ref['id'])
- mac = utils.generate_mac()
- instance_ref = db.instance_create(None,
- {'mac_address': mac})
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
instance_ids.append(instance_ref['id'])
address2 = self._create_address(i, instance_ref['id'])
- mac = utils.generate_mac()
- instance_ref = db.instance_create(None,
- {'mac_address': mac})
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
instance_ids.append(instance_ref['id'])
address3 = self._create_address(i, instance_ref['id'])
lease_ip(address)
lease_ip(address2)
lease_ip(address3)
+ self.context.project = self.projects[i]
self.assertFalse(is_allocated_in_project(address,
self.projects[0].id))
self.assertFalse(is_allocated_in_project(address2,
@@ -181,7 +191,7 @@ class NetworkTestCase(test.TrialTestCase):
for instance_id in instance_ids:
db.instance_destroy(None, instance_id)
release_ip(first)
- self.network.deallocate_fixed_ip(self.context, first)
+ self._deallocate_address(0, first)
def test_vpn_ip_and_port_looks_valid(self):
"""Ensure the vpn ip and port are reasonable"""
@@ -242,9 +252,7 @@ class NetworkTestCase(test.TrialTestCase):
addresses = []
instance_ids = []
for i in range(num_available_ips):
- mac = utils.generate_mac()
- instance_ref = db.instance_create(None,
- {'mac_address': mac})
+ instance_ref = self._create_instance(0)
instance_ids.append(instance_ref['id'])
address = self._create_address(0, instance_ref['id'])
addresses.append(address)