summaryrefslogtreecommitdiffstats
path: root/nova/db
diff options
context:
space:
mode:
authorTushar Patil <tushar.vitthal.patil@gmail.com>2011-08-09 16:26:12 -0700
committerTushar Patil <tushar.vitthal.patil@gmail.com>2011-08-09 16:26:12 -0700
commit8a8b71b2eaf72b03c0c2bc847b449d2d640fc6c0 (patch)
treeb5be7eacff26e098b93eff60b90e57a25160cb6c /nova/db
parent96631a9e1188d1781381cafc409c2ec3ead895fb (diff)
parent4b3165429797d40da17f5c59aaeadb00673b71b2 (diff)
downloadnova-8a8b71b2eaf72b03c0c2bc847b449d2d640fc6c0.tar.gz
nova-8a8b71b2eaf72b03c0c2bc847b449d2d640fc6c0.tar.xz
nova-8a8b71b2eaf72b03c0c2bc847b449d2d640fc6c0.zip
Merged with trunk
Diffstat (limited to 'nova/db')
-rw-r--r--nova/db/api.py32
-rw-r--r--nova/db/sqlalchemy/api.py253
-rw-r--r--nova/db/sqlalchemy/models.py1
3 files changed, 216 insertions, 70 deletions
diff --git a/nova/db/api.py b/nova/db/api.py
index 789e9bc97..b12448ab2 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -395,15 +395,6 @@ def fixed_ip_get_by_virtual_interface(context, vif_id):
return IMPL.fixed_ip_get_by_virtual_interface(context, vif_id)
-def fixed_ip_get_instance(context, address):
- """Get an instance for a fixed ip by address."""
- return IMPL.fixed_ip_get_instance(context, address)
-
-
-def fixed_ip_get_instance_v6(context, address):
- return IMPL.fixed_ip_get_instance_v6(context, address)
-
-
def fixed_ip_get_network(context, address):
"""Get a network for a fixed ip by address."""
return IMPL.fixed_ip_get_network(context, address)
@@ -515,6 +506,11 @@ def instance_get_all(context):
return IMPL.instance_get_all(context)
+def instance_get_all_by_filters(context, filters):
+ """Get all instances that match all filters."""
+ return IMPL.instance_get_all_by_filters(context, filters)
+
+
def instance_get_active_by_window(context, begin, end=None):
"""Get instances active during a certain time window."""
return IMPL.instance_get_active_by_window(context, begin, end)
@@ -536,10 +532,20 @@ def instance_get_all_by_host(context, host):
def instance_get_all_by_reservation(context, reservation_id):
- """Get all instance belonging to a reservation."""
+ """Get all instances belonging to a reservation."""
return IMPL.instance_get_all_by_reservation(context, reservation_id)
+def instance_get_by_fixed_ip(context, address):
+ """Get an instance for a fixed ip by address."""
+ return IMPL.instance_get_by_fixed_ip(context, address)
+
+
+def instance_get_by_fixed_ipv6(context, address):
+ """Get an instance for a fixed ip by IPv6 address."""
+ return IMPL.instance_get_by_fixed_ipv6(context, address)
+
+
def instance_get_fixed_addresses(context, instance_id):
"""Get the fixed ip address of an instance."""
return IMPL.instance_get_fixed_addresses(context, instance_id)
@@ -1413,9 +1419,9 @@ def instance_metadata_delete(context, instance_id, key):
IMPL.instance_metadata_delete(context, instance_id, key)
-def instance_metadata_update_or_create(context, instance_id, metadata):
- """Create or update instance metadata."""
- IMPL.instance_metadata_update_or_create(context, instance_id, metadata)
+def instance_metadata_update(context, instance_id, metadata, delete):
+ """Update metadata if it exists, otherwise create it."""
+ IMPL.instance_metadata_update(context, instance_id, metadata, delete)
####################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 20c717255..fafea8ca0 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -18,8 +18,10 @@
"""
Implementation of SQLAlchemy backend.
"""
+import re
import warnings
+from nova import block_device
from nova import db
from nova import exception
from nova import flags
@@ -882,28 +884,6 @@ def fixed_ip_get_by_virtual_interface(context, vif_id):
return rv
-@require_context
-def fixed_ip_get_instance(context, address):
- fixed_ip_ref = fixed_ip_get_by_address(context, address)
- return fixed_ip_ref.instance
-
-
-@require_context
-def fixed_ip_get_instance_v6(context, address):
- session = get_session()
-
- # convert IPv6 address to mac
- mac = ipv6.to_mac(address)
-
- # get virtual interface
- vif_ref = virtual_interface_get_by_address(context, mac)
-
- # look up instance based on instance_id from vif row
- result = session.query(models.Instance).\
- filter_by(id=vif_ref['instance_id'])
- return result
-
-
@require_admin_context
def fixed_ip_get_network(context, address):
fixed_ip_ref = fixed_ip_get_by_address(context, address)
@@ -1222,6 +1202,114 @@ def instance_get_all(context):
all()
+@require_context
+def instance_get_all_by_filters(context, filters):
+ """Return instances that match all filters. Deleted instances
+ will be returned by default, unless there's a filter that says
+ otherwise"""
+
+ def _regexp_filter_by_ipv6(instance, filter_re):
+ for interface in instance['virtual_interfaces']:
+ fixed_ipv6 = interface.get('fixed_ipv6')
+ if fixed_ipv6 and filter_re.match(fixed_ipv6):
+ return True
+ return False
+
+ def _regexp_filter_by_ip(instance, filter_re):
+ for interface in instance['virtual_interfaces']:
+ for fixed_ip in interface['fixed_ips']:
+ if not fixed_ip or not fixed_ip['address']:
+ continue
+ if filter_re.match(fixed_ip['address']):
+ return True
+ for floating_ip in fixed_ip.get('floating_ips', []):
+ if not floating_ip or not floating_ip['address']:
+ continue
+ if filter_re.match(floating_ip['address']):
+ return True
+ return False
+
+ def _regexp_filter_by_column(instance, filter_name, filter_re):
+ try:
+ v = getattr(instance, filter_name)
+ except AttributeError:
+ return True
+ if v and filter_re.match(str(v)):
+ return True
+ return False
+
+ def _exact_match_filter(query, column, value):
+ """Do exact match against a column. value to match can be a list
+ so you can match any value in the list.
+ """
+ if isinstance(value, list):
+ column_attr = getattr(models.Instance, column)
+ return query.filter(column_attr.in_(value))
+ else:
+ filter_dict = {}
+ filter_dict[column] = value
+ return query.filter_by(**filter_dict)
+
+ session = get_session()
+ query_prefix = session.query(models.Instance).\
+ options(joinedload_all('fixed_ips.floating_ips')).\
+ options(joinedload_all('virtual_interfaces.network')).\
+ options(joinedload_all(
+ 'virtual_interfaces.fixed_ips.floating_ips')).\
+ options(joinedload('security_groups')).\
+ options(joinedload_all('fixed_ips.network')).\
+ options(joinedload('metadata')).\
+ options(joinedload('instance_type'))
+
+ # Make a copy of the filters dictionary to use going forward, as we'll
+ # be modifying it and we shouldn't affect the caller's use of it.
+ filters = filters.copy()
+
+ if not context.is_admin:
+ # If we're not admin context, add appropriate filter..
+ if context.project_id:
+ filters['project_id'] = context.project_id
+ else:
+ filters['user_id'] = context.user_id
+
+ # Filters for exact matches that we can do along with the SQL query...
+ # For other filters that don't match this, we will do regexp matching
+ exact_match_filter_names = ['project_id', 'user_id', 'image_ref',
+ 'state', 'instance_type_id', 'deleted']
+
+ query_filters = [key for key in filters.iterkeys()
+ if key in exact_match_filter_names]
+
+ for filter_name in query_filters:
+ # Do the matching and remove the filter from the dictionary
+ # so we don't try it again below..
+ query_prefix = _exact_match_filter(query_prefix, filter_name,
+ filters.pop(filter_name))
+
+ instances = query_prefix.all()
+
+ if not instances:
+ return []
+
+ # Now filter on everything else for regexp matching..
+ # For filters not in the list, we'll attempt to use the filter_name
+ # as a column name in Instance..
+ regexp_filter_funcs = {'ip6': _regexp_filter_by_ipv6,
+ 'ip': _regexp_filter_by_ip}
+
+ for filter_name in filters.iterkeys():
+ filter_func = regexp_filter_funcs.get(filter_name, None)
+ filter_re = re.compile(str(filters[filter_name]))
+ if filter_func:
+ filter_l = lambda instance: filter_func(instance, filter_re)
+ else:
+ filter_l = lambda instance: _regexp_filter_by_column(instance,
+ filter_name, filter_re)
+ instances = filter(filter_l, instances)
+
+ return instances
+
+
@require_admin_context
def instance_get_active_by_window(context, begin, end=None):
"""Return instances that were continuously active over the given window"""
@@ -1290,30 +1378,48 @@ def instance_get_all_by_project(context, project_id):
@require_context
def instance_get_all_by_reservation(context, reservation_id):
session = get_session()
+ query = session.query(models.Instance).\
+ filter_by(reservation_id=reservation_id).\
+ options(joinedload_all('fixed_ips.floating_ips')).\
+ options(joinedload('virtual_interfaces')).\
+ options(joinedload('security_groups')).\
+ options(joinedload_all('fixed_ips.network')).\
+ options(joinedload('metadata')).\
+ options(joinedload('instance_type'))
if is_admin_context(context):
- return session.query(models.Instance).\
- options(joinedload_all('fixed_ips.floating_ips')).\
- options(joinedload('virtual_interfaces')).\
- options(joinedload('security_groups')).\
- options(joinedload_all('fixed_ips.network')).\
- options(joinedload('metadata')).\
- options(joinedload('instance_type')).\
- filter_by(reservation_id=reservation_id).\
- filter_by(deleted=can_read_deleted(context)).\
- all()
+ return query.\
+ filter_by(deleted=can_read_deleted(context)).\
+ all()
elif is_user_context(context):
- return session.query(models.Instance).\
- options(joinedload_all('fixed_ips.floating_ips')).\
- options(joinedload('virtual_interfaces')).\
- options(joinedload('security_groups')).\
- options(joinedload_all('fixed_ips.network')).\
- options(joinedload('metadata')).\
- options(joinedload('instance_type')).\
- filter_by(project_id=context.project_id).\
- filter_by(reservation_id=reservation_id).\
- filter_by(deleted=False).\
- all()
+ return query.\
+ filter_by(project_id=context.project_id).\
+ filter_by(deleted=False).\
+ all()
+
+
+@require_context
+def instance_get_by_fixed_ip(context, address):
+ """Return instance ref by exact match of FixedIP"""
+ fixed_ip_ref = fixed_ip_get_by_address(context, address)
+ return fixed_ip_ref.instance
+
+
+@require_context
+def instance_get_by_fixed_ipv6(context, address):
+ """Return instance ref by exact match of IPv6"""
+ session = get_session()
+
+ # convert IPv6 address to mac
+ mac = ipv6.to_mac(address)
+
+ # get virtual interface
+ vif_ref = virtual_interface_get_by_address(context, mac)
+
+ # look up instance based on instance_id from vif row
+ result = session.query(models.Instance).\
+ filter_by(id=vif_ref['instance_id'])
+ return result
@require_admin_context
@@ -1355,7 +1461,7 @@ def instance_get_fixed_addresses_v6(context, instance_id):
network_refs = network_get_all_by_instance(context, instance_id)
# compile a list of cidr_v6 prefixes sorted by network id
prefixes = [ref.cidr_v6 for ref in
- sorted(network_refs, key=lambda ref: ref.id)]
+ sorted(network_refs, key=lambda ref: ref.id)]
# get vifs associated with instance
vif_refs = virtual_interface_get_by_instance(context, instance_ref.id)
# compile list of the mac_addresses for vifs sorted by network id
@@ -1399,9 +1505,10 @@ def instance_update(context, instance_id, values):
session = get_session()
metadata = values.get('metadata')
if metadata is not None:
- instance_metadata_delete_all(context, instance_id)
- instance_metadata_update_or_create(context, instance_id,
- values.pop('metadata'))
+ instance_metadata_update(context,
+ instance_id,
+ values.pop('metadata'),
+ delete=True)
with session.begin():
if utils.is_uuid_like(instance_id):
instance_ref = instance_get_by_uuid(context, instance_id,
@@ -1768,7 +1875,9 @@ def network_get_by_cidr(context, cidr):
session = get_session()
result = session.query(models.Network).\
filter(or_(models.Network.cidr == cidr,
- models.Network.cidr_v6 == cidr)).first()
+ models.Network.cidr_v6 == cidr)).\
+ filter_by(deleted=False).\
+ first()
if not result:
raise exception.NetworkNotFoundForCidr(cidr=cidr)
@@ -2352,6 +2461,20 @@ def block_device_mapping_update_or_create(context, values):
else:
result.update(values)
+ # NOTE(yamahata): same virtual device name can be specified multiple
+ # times. So delete the existing ones.
+ virtual_name = values['virtual_name']
+ if (virtual_name is not None and
+ block_device.is_swap_or_ephemeral(virtual_name)):
+ session.query(models.BlockDeviceMapping).\
+ filter_by(instance_id=values['instance_id']).\
+ filter_by(virtual_name=virtual_name).\
+ filter(models.BlockDeviceMapping.device_name !=
+ values['device_name']).\
+ update({'deleted': True,
+ 'deleted_at': utils.utcnow(),
+ 'updated_at': literal_column('updated_at')})
+
@require_context
def block_device_mapping_get_all_by_instance(context, instance_id):
@@ -3314,21 +3437,37 @@ def instance_metadata_get_item(context, instance_id, key, session=None):
@require_context
@require_instance_exists
-def instance_metadata_update_or_create(context, instance_id, metadata):
+def instance_metadata_update(context, instance_id, metadata, delete):
session = get_session()
- original_metadata = instance_metadata_get(context, instance_id)
+ # Set existing metadata to deleted if delete argument is True
+ if delete:
+ original_metadata = instance_metadata_get(context, instance_id)
+ for meta_key, meta_value in original_metadata.iteritems():
+ if meta_key not in metadata:
+ meta_ref = instance_metadata_get_item(context, instance_id,
+ meta_key, session)
+ meta_ref.update({'deleted': True})
+ meta_ref.save(session=session)
meta_ref = None
- for key, value in metadata.iteritems():
+
+ # Now update all existing items with new values, or create new meta objects
+ for meta_key, meta_value in metadata.iteritems():
+
+ # update the value whether it exists or not
+ item = {"value": meta_value}
+
try:
- meta_ref = instance_metadata_get_item(context, instance_id, key,
- session)
+ meta_ref = instance_metadata_get_item(context, instance_id,
+ meta_key, session)
+
+ # if the item doesn't exist, we also need to set key and instance_id
except exception.InstanceMetadataNotFound, e:
meta_ref = models.InstanceMetadata()
- meta_ref.update({"key": key, "value": value,
- "instance_id": instance_id,
- "deleted": False})
+ item.update({"key": meta_key, "instance_id": instance_id})
+
+ meta_ref.update(item)
meta_ref.save(session=session)
return metadata
@@ -3420,7 +3559,7 @@ def instance_type_extra_specs_delete(context, instance_type_id, key):
@require_context
def instance_type_extra_specs_get_item(context, instance_type_id, key,
- session=None):
+ session=None):
if not session:
session = get_session()
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 9f4c7a0aa..939fde199 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -180,6 +180,7 @@ class Instance(BASE, NovaBase):
image_ref = Column(String(255))
kernel_id = Column(String(255))
ramdisk_id = Column(String(255))
+ server_name = Column(String(255))
# image_ref = Column(Integer, ForeignKey('images.id'), nullable=True)
# kernel_id = Column(Integer, ForeignKey('images.id'), nullable=True)