summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Kearney <josh@jk0.org>2011-09-19 16:02:29 -0500
committerJosh Kearney <josh@jk0.org>2011-09-19 16:02:29 -0500
commitbff43a5f0da9a891386d2d09464fb8f5e222d46d (patch)
tree5e2cef98a04ccd01a86d7ece7523716837e5df1c
parent66977838d02ad51ced525321b21e648bcc2065bc (diff)
parent3da916de6165e1e7012f61a05a6a0d9d06906b48 (diff)
PEP8 cleanup.
-rw-r--r--nova/api/openstack/contrib/virtual_interfaces.py16
-rw-r--r--nova/api/openstack/servers.py6
-rw-r--r--nova/compute/api.py13
-rw-r--r--nova/db/api.py15
-rw-r--r--nova/db/sqlalchemy/api.py117
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py68
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_downgrade.sql47
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_upgrade.sql45
-rw-r--r--nova/db/sqlalchemy/models.py5
-rw-r--r--nova/network/api.py14
-rwxr-xr-xnova/network/linux_net.py19
-rw-r--r--nova/network/manager.py64
-rw-r--r--nova/tests/api/openstack/contrib/test_virtual_interfaces.py17
-rw-r--r--nova/tests/api/openstack/test_servers.py54
-rw-r--r--nova/tests/fake_network.py59
-rw-r--r--nova/tests/test_compute.py253
-rw-r--r--nova/tests/test_db_api.py6
-rw-r--r--nova/tests/test_metadata.py9
-rw-r--r--nova/tests/test_network.py182
19 files changed, 617 insertions, 392 deletions
diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py
index dab61efc8..1981cd372 100644
--- a/nova/api/openstack/contrib/virtual_interfaces.py
+++ b/nova/api/openstack/contrib/virtual_interfaces.py
@@ -15,15 +15,10 @@
"""The virtual interfaces extension."""
-from webob import exc
-import webob
-
-from nova import compute
-from nova import exception
from nova import log as logging
+from nova import network
from nova.api.openstack import common
from nova.api.openstack import extensions
-from nova.api.openstack import faults
from nova.api.openstack import wsgi
@@ -50,19 +45,14 @@ class ServerVirtualInterfaceController(object):
"""
def __init__(self):
- self.compute_api = compute.API()
+ self.network_api = network.API()
super(ServerVirtualInterfaceController, self).__init__()
def _items(self, req, server_id, entity_maker):
"""Returns a list of VIFs, transformed through entity_maker."""
context = req.environ['nova.context']
- try:
- instance = self.compute_api.get(context, server_id)
- except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
-
- vifs = instance['virtual_interfaces']
+ vifs = self.network_api.get_vifs_by_instance(context, server_id)
limited_list = common.limited(vifs, req)
res = [entity_maker(context, vif) for vif in limited_list]
return {'virtual_interfaces': res}
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 0ef246852..856c3c613 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -656,7 +656,11 @@ class ControllerV11(Controller):
def _get_key_name(self, req, body):
if 'server' in body:
- return body['server'].get('key_name')
+ try:
+ return body['server'].get('key_name')
+ except AttributeError:
+ msg = _("Malformed server entity")
+ raise exc.HTTPBadRequest(explanation=msg)
def _image_ref_from_req_data(self, data):
try:
diff --git a/nova/compute/api.py b/nova/compute/api.py
index d8657d403..853e6ef9e 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -905,7 +905,7 @@ class API(base.Base):
if 'reservation_id' in filters:
recurse_zones = True
- instances = self.db.instance_get_all_by_filters(context, filters)
+ instances = self._get_instances_by_filters(context, filters)
if not recurse_zones:
return instances
@@ -930,6 +930,17 @@ class API(base.Base):
return instances
+ def _get_instances_by_filters(self, context, filters):
+ ids = None
+ if 'ip6' in filters or 'ip' in filters:
+ res = self.network_api.get_instance_uuids_by_ip_filter(context,
+ filters)
+ # NOTE(jkoelker) It is possible that we will get the same
+ # instance uuid twice (one for ipv4 and ipv6)
+ ids = set([r['instance_uuid'] for r in res])
+
+ return self.db.instance_get_all_by_filters(context, filters, ids)
+
def _cast_compute_message(self, method, context, instance_id, host=None,
params=None):
"""Generic handler for RPC casts to compute.
diff --git a/nova/db/api.py b/nova/db/api.py
index efd6d9ae6..cdc7089cc 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -467,6 +467,11 @@ def virtual_interface_delete_by_instance(context, instance_id):
return IMPL.virtual_interface_delete_by_instance(context, instance_id)
+def virtual_interface_get_all(context):
+ """Gets all virtual interfaces from the table,"""
+ return IMPL.virtual_interface_get_all(context)
+
+
####################
@@ -505,9 +510,10 @@ def instance_get_all(context):
return IMPL.instance_get_all(context)
-def instance_get_all_by_filters(context, filters):
+def instance_get_all_by_filters(context, filters, instance_uuids=None):
"""Get all instances that match all filters."""
- return IMPL.instance_get_all_by_filters(context, filters)
+ return IMPL.instance_get_all_by_filters(context, filters,
+ instance_uuids=instance_uuids)
def instance_get_active_by_window(context, begin, end=None, project_id=None):
@@ -611,6 +617,11 @@ def instance_get_actions(context, instance_id):
return IMPL.instance_get_actions(context, instance_id)
+def instance_get_uuids_by_ids(context, ids):
+ """Return the UUIDs of the instances given the ids"""
+ return IMPL.instance_get_uuids_by_ids(context, ids)
+
+
###################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 6fe46eb88..e7bd852f4 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -931,7 +931,6 @@ def virtual_interface_get(context, vif_id, session=None):
vif_ref = session.query(models.VirtualInterface).\
filter_by(id=vif_id).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
first()
return vif_ref
@@ -947,7 +946,6 @@ def virtual_interface_get_by_address(context, address):
vif_ref = session.query(models.VirtualInterface).\
filter_by(address=address).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
first()
return vif_ref
@@ -963,7 +961,6 @@ def virtual_interface_get_by_uuid(context, vif_uuid):
vif_ref = session.query(models.VirtualInterface).\
filter_by(uuid=vif_uuid).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
first()
return vif_ref
@@ -979,7 +976,6 @@ def virtual_interface_get_by_fixed_ip(context, fixed_ip_id):
vif_ref = session.query(models.VirtualInterface).\
filter_by(fixed_ip_id=fixed_ip_id).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
first()
return vif_ref
@@ -996,7 +992,6 @@ def virtual_interface_get_by_instance(context, instance_id):
vif_refs = session.query(models.VirtualInterface).\
filter_by(instance_id=instance_id).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
all()
return vif_refs
@@ -1011,7 +1006,6 @@ def virtual_interface_get_by_instance_and_network(context, instance_id,
filter_by(instance_id=instance_id).\
filter_by(network_id=network_id).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
first()
return vif_ref
@@ -1027,7 +1021,6 @@ def virtual_interface_get_by_network(context, network_id):
vif_refs = session.query(models.VirtualInterface).\
filter_by(network_id=network_id).\
options(joinedload('network')).\
- options(joinedload('instance')).\
options(joinedload('fixed_ips')).\
all()
return vif_refs
@@ -1057,6 +1050,17 @@ def virtual_interface_delete_by_instance(context, instance_id):
virtual_interface_delete(context, vif_ref['id'])
+@require_context
+def virtual_interface_get_all(context):
+ """Get all vifs"""
+ session = get_session()
+ vif_refs = session.query(models.VirtualInterface).\
+ options(joinedload('network')).\
+ options(joinedload('fixed_ips')).\
+ all()
+ return vif_refs
+
+
###################
@@ -1173,7 +1177,6 @@ def _build_instance_get(context, session=None):
partial = session.query(models.Instance).\
options(joinedload_all('fixed_ips.floating_ips')).\
options(joinedload_all('fixed_ips.network')).\
- options(joinedload('virtual_interfaces')).\
options(joinedload_all('security_groups.rules')).\
options(joinedload('volumes')).\
options(joinedload('metadata')).\
@@ -1192,10 +1195,6 @@ def instance_get_all(context):
session = get_session()
return 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('virtual_interfaces.instance')).\
options(joinedload('security_groups')).\
options(joinedload_all('fixed_ips.network')).\
options(joinedload('metadata')).\
@@ -1205,32 +1204,11 @@ def instance_get_all(context):
@require_context
-def instance_get_all_by_filters(context, filters):
+def instance_get_all_by_filters(context, filters, instance_uuids=None):
"""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_metadata(instance, meta):
inst_metadata = [{node['key']: node['value']} \
for node in instance['metadata']]
@@ -1267,13 +1245,7 @@ def instance_get_all_by_filters(context, filters):
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('virtual_interfaces.instance')).\
options(joinedload('security_groups')).\
- options(joinedload_all('fixed_ips.network')).\
options(joinedload('metadata')).\
options(joinedload('instance_type')).\
order_by(desc(models.Instance.created_at))
@@ -1308,16 +1280,34 @@ def instance_get_all_by_filters(context, filters):
query_prefix = _exact_match_filter(query_prefix, filter_name,
filters.pop(filter_name))
- instances = query_prefix.all()
+ db_instances = query_prefix.all()
+ db_uuids = [instance['uuid'] for instance in db_instances \
+ if instance['uuid']]
+
+ if instance_uuids is None:
+ instance_uuids = []
+
+ uuids = []
+
+ # NOTE(jkoelker): String UUIDs only!
+ if not instance_uuids:
+ uuids = db_uuids
+ elif not db_instances:
+ uuids = instance_uuids
+ else:
+ uuids = list(set(instance_uuids) & set(db_uuids))
- if not instances:
+ if not uuids:
return []
+ instances = session.query(models.Instance).\
+ filter(models.Instance.uuid.in_(uuids)).\
+ all()
+
# 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}
+ regexp_filter_funcs = {}
for filter_name in filters.iterkeys():
filter_func = regexp_filter_funcs.get(filter_name, None)
@@ -1377,7 +1367,6 @@ def instance_get_all_by_user(context, user_id):
session = get_session()
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')).\
@@ -1392,7 +1381,6 @@ def instance_get_all_by_host(context, host):
session = get_session()
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')).\
@@ -1409,7 +1397,6 @@ def instance_get_all_by_project(context, project_id):
session = get_session()
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')).\
@@ -1425,7 +1412,6 @@ def instance_get_all_by_reservation(context, reservation_id):
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')).\
@@ -1442,36 +1428,11 @@ def instance_get_all_by_reservation(context, reservation_id):
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
def instance_get_project_vpn(context, project_id):
session = get_session()
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')).\
@@ -1603,6 +1564,16 @@ def instance_get_actions(context, instance_id):
all()
+@require_context
+def instance_get_uuids_by_ids(context, ids):
+ session = get_session()
+ instances = session.query(models.Instance).\
+ filter(models.Instance.id.in_(ids)).\
+ all()
+ return [{'uuid': instance['uuid'],
+ 'id': instance['id']} for instance in instances]
+
+
###################
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py b/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py
new file mode 100644
index 000000000..818925c32
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py
@@ -0,0 +1,68 @@
+# Copyright 2011 OpenStack LLC.
+#
+# 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, Integer, MetaData, Table
+from migrate import ForeignKeyConstraint
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+
+instances = Table('instances', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+
+vifs = Table('virtual_interfaces', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ Column('instance_id', Integer()),
+ )
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+ dialect = migrate_engine.url.get_dialect().name
+ if dialect.startswith('sqlite'):
+ return
+
+ try:
+ ForeignKeyConstraint(columns=[vifs.c.instance_id],
+ refcolumns=[instances.c.id]).drop()
+ except Exception:
+ try:
+ migrate_engine.execute("ALTER TABLE migrations DROP " \
+ "FOREIGN KEY " \
+ "`virtual_interfaces_ibfk_2`;")
+ except Exception:
+ logging.error(_("foreign key constraint couldn't be removed"))
+ raise
+
+
+def downgrade(migrate_engine):
+ # Operations to reverse the above upgrade go here.
+ meta.bind = migrate_engine
+ dialect = migrate_engine.url.get_dialect().name
+ if dialect.startswith('sqlite'):
+ return
+
+ try:
+ ForeignKeyConstraint(columns=[vifs.c.instance_id],
+ refcolumns=[instances.c.id]).create()
+ except Exception:
+ logging.error(_("foreign key constraint couldn't be added"))
+ raise
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_downgrade.sql b/nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_downgrade.sql
new file mode 100644
index 000000000..cf9afbb09
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_downgrade.sql
@@ -0,0 +1,47 @@
+COMMIT;
+BEGIN TRANSACTION;
+ CREATE TEMPORARY TABLE virtual_interfaces_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ address VARCHAR(255),
+ network_id INTEGER,
+ instance_id INTEGER NOT NULL,
+ uuid VARCHAR(36),
+ PRIMARY KEY (id)
+ );
+
+ INSERT INTO virtual_interfaces_backup
+ SELECT created_at, updated_at, deleted_at, deleted, id, address,
+ network_id, instance_id, uuid
+ FROM virtual_interfaces;
+
+ DROP TABLE virtual_interfaces;
+
+ CREATE TABLE virtual_interfaces (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ address VARCHAR(255),
+ network_id INTEGER,
+ instance_id INTEGER NOT NULL,
+ uuid VARCHAR(36),
+ PRIMARY KEY (id),
+ FOREIGN KEY(network_id) REFERENCES networks (id),
+ FOREIGN KEY(instance_id) REFERENCES instances (id),
+ UNIQUE (address),
+ CHECK (deleted IN (0, 1))
+ );
+
+ INSERT INTO virtual_interfaces
+ SELECT created_at, updated_at, deleted_at, deleted, id, address,
+ network_id, instance_id, uuid
+ FROM virtual_interfaces_backup;
+
+ DROP TABLE virtual_interfaces_backup;
+
+COMMIT;
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_upgrade.sql b/nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_upgrade.sql
new file mode 100644
index 000000000..2c0919f1d
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/047_sqlite_upgrade.sql
@@ -0,0 +1,45 @@
+BEGIN TRANSACTION;
+ CREATE TEMPORARY TABLE virtual_interfaces_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ address VARCHAR(255),
+ network_id INTEGER,
+ instance_id INTEGER NOT NULL,
+ uuid VARCHAR(36),
+ PRIMARY KEY (id)
+ );
+
+ INSERT INTO virtual_interfaces_backup
+ SELECT created_at, updated_at, deleted_at, deleted, id, address,
+ network_id, instance_id, uuid
+ FROM virtual_interfaces;
+
+ DROP TABLE virtual_interfaces;
+
+ CREATE TABLE virtual_interfaces (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ address VARCHAR(255),
+ network_id INTEGER,
+ instance_id INTEGER NOT NULL,
+ uuid VARCHAR(36),
+ PRIMARY KEY (id),
+ FOREIGN KEY(network_id) REFERENCES networks (id),
+ UNIQUE (address),
+ CHECK (deleted IN (0, 1))
+ );
+
+ INSERT INTO virtual_interfaces
+ SELECT created_at, updated_at, deleted_at, deleted, id, address,
+ network_id, instance_id, uuid
+ FROM virtual_interfaces_backup;
+
+ DROP TABLE virtual_interfaces_backup;
+
+COMMIT;
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index b5f30a1e3..089cd5450 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -642,10 +642,7 @@ class VirtualInterface(BASE, NovaBase):
address = Column(String(255), unique=True)
network_id = Column(Integer, ForeignKey('networks.id'))
network = relationship(Network, backref=backref('virtual_interfaces'))
-
- # TODO(tr3buchet): cut the cord, removed foreign key and backrefs
- instance_id = Column(Integer, ForeignKey('instances.id'), nullable=False)
- instance = relationship(Instance, backref=backref('virtual_interfaces'))
+ instance_id = Column(Integer, nullable=False)
uuid = Column(String(36))
diff --git a/nova/network/api.py b/nova/network/api.py
index 78580d360..a1ed28496 100644
--- a/nova/network/api.py
+++ b/nova/network/api.py
@@ -46,8 +46,9 @@ class API(base.Base):
return ips
def get_vifs_by_instance(self, context, instance_id):
- vifs = self.db.virtual_interface_get_by_instance(context, instance_id)
- return vifs
+ return rpc.call(context, FLAGS.network_topic,
+ {'method': 'get_vifs_by_instance',
+ 'args': {'instance_id': instance_id}})
def allocate_floating_ip(self, context):
"""Adds a floating ip to a project."""
@@ -210,3 +211,12 @@ class API(base.Base):
return rpc.call(context, FLAGS.network_topic,
{'method': 'validate_networks',
'args': args})
+
+ def get_instance_uuids_by_ip_filter(self, context, filters):
+ """Returns a list of dicts in the form of
+ {'instance_uuid': uuid, 'ip': ip} that matched the ip_filter
+ """
+ args = {'filters': filters}
+ return rpc.call(context, FLAGS.network_topic,
+ {'method': 'get_instance_uuids_by_ip_filter',
+ 'args': args})
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index e693e5939..9bf98fc27 100755
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -550,6 +550,10 @@ def get_dhcp_opts(context, network_ref):
return '\n'.join(hosts)
+def release_dhcp(dev, address, mac_address):
+ utils.execute('dhcp_release', dev, address, mac_address, run_as_root=True)
+
+
# NOTE(ja): Sending a HUP only reloads the hostfile, so any
# configuration options (like dchp-range, vlan, ...)
# aren't reloaded.
@@ -594,7 +598,6 @@ def update_dhcp(context, dev, network_ref):
'dnsmasq',
'--strict-order',
'--bind-interfaces',
- '--interface=%s' % dev,
'--conf-file=%s' % FLAGS.dnsmasq_config_file,
'--domain=%s' % FLAGS.dhcp_domain,
'--pid-file=%s' % _dhcp_file(dev, 'pid'),
@@ -800,6 +803,10 @@ def unplug(network):
return interface_driver.unplug(network)
+def get_dev(network):
+ return interface_driver.get_dev(network)
+
+
class LinuxNetInterfaceDriver(object):
"""Abstract class that defines generic network host API"""
""" for for all Linux interface drivers."""
@@ -812,6 +819,10 @@ class LinuxNetInterfaceDriver(object):
"""Destory Linux device, return device name"""
raise NotImplementedError()
+ def get_dev(self, network):
+ """Get device name"""
+ raise NotImplementedError()
+
# plugs interfaces using Linux Bridge
class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
@@ -833,6 +844,9 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
return network['bridge']
def unplug(self, network):
+ return self.get_dev(network)
+
+ def get_dev(self, network):
return network['bridge']
@classmethod
@@ -957,6 +971,9 @@ class LinuxOVSInterfaceDriver(LinuxNetInterfaceDriver):
return dev
def unplug(self, network):
+ return self.get_dev(network)
+
+ def get_dev(self, network):
dev = "gw-" + str(network['id'])
return dev
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 70e51888f..2687d8faf 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -48,6 +48,7 @@ import datetime
import itertools
import math
import netaddr
+import re
import socket
from eventlet import greenpool
@@ -110,6 +111,8 @@ flags.DEFINE_string('network_host', socket.gethostname(),
'Network host to use for ip allocation in flat modes')
flags.DEFINE_bool('fake_call', False,
'If True, skip using the queue and make local calls')
+flags.DEFINE_bool('force_dhcp_release', False,
+ 'If True, send a dhcp release on instance termination')
class AddressAlreadyAllocated(exception.Error):
@@ -397,6 +400,62 @@ class NetworkManager(manager.SchedulerDependentManager):
self.compute_api.trigger_security_group_members_refresh(admin_context,
group_ids)
+ def get_vifs_by_instance(self, context, instance_id):
+ vifs = self.db.virtual_interface_get_by_instance(context,
+ instance_id)
+ return vifs
+
+ def get_instance_uuids_by_ip_filter(self, context, filters):
+ fixed_ip_filter = filters.get('fixed_ip')
+ ip_filter = re.compile(str(filters.get('ip')))
+ ipv6_filter = re.compile(str(filters.get('ip6')))
+
+ # NOTE(jkoelker) Should probably figur out a better way to do
+ # this. But for now it "works", this could suck on
+ # large installs.
+
+ vifs = self.db.virtual_interface_get_all(context)
+ results = []
+
+ for vif in vifs:
+ if vif['instance_id'] is None:
+ continue
+
+ fixed_ipv6 = vif.get('fixed_ipv6')
+ if fixed_ipv6 and ipv6_filter.match(fixed_ipv6):
+ # NOTE(jkoelker) Will need to update for the UUID flip
+ results.append({'instance_id': vif['instance_id'],
+ 'ip': fixed_ipv6})
+
+ for fixed_ip in vif['fixed_ips']:
+ if not fixed_ip or not fixed_ip['address']:
+ continue
+ if fixed_ip['address'] == fixed_ip_filter:
+ results.append({'instance_id': vif['instance_id'],
+ 'ip': fixed_ip['address']})
+ continue
+ if ip_filter.match(fixed_ip['address']):
+ results.append({'instance_id': vif['instance_id'],
+ 'ip': fixed_ip['address']})
+ continue
+ for floating_ip in fixed_ip.get('floating_ips', []):
+ if not floating_ip or not floating_ip['address']:
+ continue
+ if ip_filter.match(floating_ip['address']):
+ results.append({'instance_id': vif['instance_id'],
+ 'ip': floating_ip['address']})
+ continue
+
+ # NOTE(jkoelker) Until we switch over to instance_uuid ;)
+ ids = [res['instance_id'] for res in results]
+ uuids = self.db.instance_get_uuids_by_ids(context, ids)
+ for res in results:
+ uuid = [u['uuid'] for u in uuids if u['id'] == res['instance_id']]
+ # NOTE(jkoelker) UUID must exist, so no test here
+ res['instance_uuid'] = uuid[0]
+
+ return results
+
def _get_networks_for_instance(self, context, instance_id, project_id,
requested_networks=None):
"""Determine & return which networks an instance should connect to."""
@@ -629,6 +688,11 @@ class NetworkManager(manager.SchedulerDependentManager):
instance_id = instance_ref['id']
self._do_trigger_security_group_members_refresh_for_instance(
instance_id)
+ if FLAGS.force_dhcp_release:
+ dev = self.driver.get_dev(fixed_ip_ref['network'])
+ vif = self.db.virtual_interface_get_by_instance_and_network(
+ context, instance_ref['id'], fixed_ip_ref['network']['id'])
+ self.driver.release_dhcp(dev, address, vif['address'])
def lease_fixed_ip(self, context, address):
"""Called by dhcp-bridge when ip is leased."""
diff --git a/nova/tests/api/openstack/contrib/test_virtual_interfaces.py b/nova/tests/api/openstack/contrib/test_virtual_interfaces.py
index 1db253b35..0260e89d4 100644
--- a/nova/tests/api/openstack/contrib/test_virtual_interfaces.py
+++ b/nova/tests/api/openstack/contrib/test_virtual_interfaces.py
@@ -14,22 +14,20 @@
# under the License.
import json
-import stubout
import webob
from nova import test
-from nova import compute
+from nova import network
from nova.tests.api.openstack import fakes
from nova.api.openstack.contrib.virtual_interfaces import \
ServerVirtualInterfaceController
-def compute_api_get(self, context, server_id):
- return {'virtual_interfaces': [
- {'uuid': '00000000-0000-0000-0000-00000000000000000',
- 'address': '00-00-00-00-00-00'},
- {'uuid': '11111111-1111-1111-1111-11111111111111111',
- 'address': '11-11-11-11-11-11'}]}
+def get_vifs_by_instance(self, context, server_id):
+ return [{'uuid': '00000000-0000-0000-0000-00000000000000000',
+ 'address': '00-00-00-00-00-00'},
+ {'uuid': '11111111-1111-1111-1111-11111111111111111',
+ 'address': '11-11-11-11-11-11'}]
class ServerVirtualInterfaceTest(test.TestCase):
@@ -37,7 +35,8 @@ class ServerVirtualInterfaceTest(test.TestCase):
def setUp(self):
super(ServerVirtualInterfaceTest, self).setUp()
self.controller = ServerVirtualInterfaceController()
- self.stubs.Set(compute.api.API, "get", compute_api_get)
+ self.stubs.Set(network.api.API, "get_vifs_by_instance",
+ get_vifs_by_instance)
def tearDown(self):
super(ServerVirtualInterfaceTest, self).tearDown()
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index a2c8b3b04..c21fb4a62 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -1247,7 +1247,7 @@ class ServersTest(test.TestCase):
self.assertEqual(servers[0]['id'], 100)
def test_tenant_id_filter_converts_to_project_id_for_admin(self):
- def fake_get_all(context, filters=None):
+ def fake_get_all(context, filters=None, instances=None):
self.assertNotEqual(filters, None)
self.assertEqual(filters['project_id'], 'faketenant')
self.assertFalse(filters.get('tenant_id'))
@@ -2194,6 +2194,58 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_create_instance_v1_1_malformed_entity(self):
+ self._setup_for_create_instance()
+ req = webob.Request.blank('/v1.1/fake/servers')
+ req.method = 'POST'
+ req.body = json.dumps({'server': 'string'})
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_create_instance_v1_1_malformed_body_string(self):
+ self._setup_for_create_instance()
+ req = webob.Request.blank('/v1.1/fake/servers')
+ req.method = 'POST'
+ req.body = 'string'
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_create_instance_v1_1_malformed_body_list(self):
+ self._setup_for_create_instance()
+ body = ['string']
+ req = webob.Request.blank('/v1.1/fake/servers')
+ req.method = 'POST'
+ req.body = json.dumps(['string'])
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 422)
+
+ def test_create_instance_v1_0_malformed_entity(self):
+ req = webob.Request.blank('/v1.0/servers')
+ req.method = 'POST'
+ req.body = json.dumps({'server': 'string'})
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_create_instance_v1_0_malformed_body_string(self):
+ req = webob.Request.blank('/v1.0/servers')
+ req.method = 'POST'
+ req.body = 'string'
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_create_instance_v1_0_malformed_body_list(self):
+ req = webob.Request.blank('/v1.0/servers')
+ req.method = 'POST'
+ req.body = json.dumps(['string'])
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 422)
+
def test_update_server_no_body(self):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
diff --git a/nova/tests/fake_network.py b/nova/tests/fake_network.py
index 142206755..d839f20b0 100644
--- a/nova/tests/fake_network.py
+++ b/nova/tests/fake_network.py
@@ -16,8 +16,9 @@
# under the License.
from nova import db
+from nova import exception
from nova import flags
-from nova import test
+from nova import utils
from nova.network import manager as network_manager
@@ -64,6 +65,62 @@ class FakeModel(dict):
return self[name]
+class FakeNetworkManager(network_manager.NetworkManager):
+ """This NetworkManager doesn't call the base class so we can bypass all
+ inherited service cruft and just perform unit tests.
+ """
+
+ class FakeDB:
+ def fixed_ip_get_by_instance(self, context, instance_id):
+ return [dict(address='10.0.0.0'), dict(address='10.0.0.1'),
+ dict(address='10.0.0.2')]
+
+ def network_get_by_cidr(self, context, cidr):
+ raise exception.NetworkNotFoundForCidr()
+
+ def network_create_safe(self, context, net):
+ fakenet = dict(net)
+ fakenet['id'] = 999
+ return fakenet
+
+ def network_get_all(self, context):
+ raise exception.NoNetworksFound()
+
+ def virtual_interface_get_all(self, context):
+ floats = [{'address': '172.16.1.1'},
+ {'address': '172.16.1.2'},
+ {'address': '173.16.1.2'}]
+
+ vifs = [{'instance_id': 0,
+ 'fixed_ipv6': '2001:db8::dcad:beff:feef:1',
+ 'fixed_ips': [{'address': '172.16.0.1',
+ 'floating_ips': [floats[0]]}]},
+ {'instance_id': 20,
+ 'fixed_ipv6': '2001:db8::dcad:beff:feef:2',
+ 'fixed_ips': [{'address': '172.16.0.2',
+ 'floating_ips': [floats[1]]}]},
+ {'instance_id': 30,
+ 'fixed_ipv6': '2002:db8::dcad:beff:feef:2',
+ 'fixed_ips': [{'address': '173.16.0.2',
+ 'floating_ips': [floats[2]]}]}]
+ return vifs
+
+ def instance_get_uuids_by_ids(self, context, ids):
+ # NOTE(jkoelker): This is just here until we can rely on UUIDs
+ return [{'uuid': str(utils.gen_uuid()),
+ 'id': id} for id in ids]
+
+ def __init__(self):
+ self.db = self.FakeDB()
+ self.deallocate_called = None
+
+ def deallocate_fixed_ip(self, context, address):
+ self.deallocate_called = address
+
+ def _create_fixed_ips(self, context, network_id):
+ pass
+
+
flavor = {'id': 0,
'name': 'fake_flavor',
'memory_mb': 2048,
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 356412dbf..4ef57b760 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -21,22 +21,24 @@ Tests For Compute
"""
from nova import compute
-from nova.compute import instance_types
-from nova.compute import manager as compute_manager
-from nova.compute import power_state
-from nova.compute import vm_states
from nova import context
from nova import db
-from nova.db.sqlalchemy import models
-from nova.db.sqlalchemy import api as sqlalchemy_api
from nova import exception
from nova import flags
-import nova.image.fake
from nova import log as logging
from nova import rpc
from nova import test
from nova import utils
+
+from nova.compute import instance_types
+from nova.compute import manager as compute_manager
+from nova.compute import power_state
+from nova.compute import vm_states
+from nova.db.sqlalchemy import models
+from nova.image import fake as fake_image
from nova.notifier import test_notifier
+from nova.tests import fake_network
+
LOG = logging.getLogger('nova.tests.compute')
FLAGS = flags.FLAGS
@@ -74,7 +76,7 @@ class ComputeTestCase(test.TestCase):
def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}}
- self.stubs.Set(nova.image.fake._FakeImageService, 'show', fake_show)
+ self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
def _create_instance(self, params=None):
"""Create a test instance"""
@@ -1023,190 +1025,19 @@ class ComputeTestCase(test.TestCase):
db.instance_destroy(c, instance_id2)
db.instance_destroy(c, instance_id3)
- def test_get_by_fixed_ip(self):
- """Test getting 1 instance by Fixed IP"""
- c = context.get_admin_context()
- instance_id1 = self._create_instance()
- instance_id2 = self._create_instance({'id': 20})
- instance_id3 = self._create_instance({'id': 30})
-
- vif_ref1 = db.virtual_interface_create(c,
- {'address': '12:34:56:78:90:12',
- 'instance_id': instance_id1,
- 'network_id': 1})
- vif_ref2 = db.virtual_interface_create(c,
- {'address': '90:12:34:56:78:90',
- 'instance_id': instance_id2,
- 'network_id': 1})
-
- db.fixed_ip_create(c,
- {'address': '1.1.1.1',
- 'instance_id': instance_id1,
- 'virtual_interface_id': vif_ref1['id']})
- db.fixed_ip_create(c,
- {'address': '1.1.2.1',
- 'instance_id': instance_id2,
- 'virtual_interface_id': vif_ref2['id']})
-
- # regex not allowed
- instances = self.compute_api.get_all(c,
- search_opts={'fixed_ip': '.*'})
- self.assertEqual(len(instances), 0)
-
- instances = self.compute_api.get_all(c,
- search_opts={'fixed_ip': '1.1.3.1'})
- self.assertEqual(len(instances), 0)
-
- instances = self.compute_api.get_all(c,
- search_opts={'fixed_ip': '1.1.1.1'})
- self.assertEqual(len(instances), 1)
- self.assertEqual(instances[0].id, instance_id1)
-
- instances = self.compute_api.get_all(c,
- search_opts={'fixed_ip': '1.1.2.1'})
- self.assertEqual(len(instances), 1)
- self.assertEqual(instances[0].id, instance_id2)
-
- db.virtual_interface_delete(c, vif_ref1['id'])
- db.virtual_interface_delete(c, vif_ref2['id'])
- db.instance_destroy(c, instance_id1)
- db.instance_destroy(c, instance_id2)
-
- def test_get_all_by_ip_regexp(self):
- """Test searching by Floating and Fixed IP"""
- c = context.get_admin_context()
- instance_id1 = self._create_instance({'display_name': 'woot'})
- instance_id2 = self._create_instance({
- 'display_name': 'woo',
- 'id': 20})
- instance_id3 = self._create_instance({
- 'display_name': 'not-woot',
- 'id': 30})
-
- vif_ref1 = db.virtual_interface_create(c,
- {'address': '12:34:56:78:90:12',
- 'instance_id': instance_id1,
- 'network_id': 1})
- vif_ref2 = db.virtual_interface_create(c,
- {'address': '90:12:34:56:78:90',
- 'instance_id': instance_id2,
- 'network_id': 1})
- vif_ref3 = db.virtual_interface_create(c,
- {'address': '34:56:78:90:12:34',
- 'instance_id': instance_id3,
- 'network_id': 1})
-
- db.fixed_ip_create(c,
- {'address': '1.1.1.1',
- 'instance_id': instance_id1,
- 'virtual_interface_id': vif_ref1['id']})
- db.fixed_ip_create(c,
- {'address': '1.1.2.1',
- 'instance_id': instance_id2,
- 'virtual_interface_id': vif_ref2['id']})
- fix_addr = db.fixed_ip_create(c,
- {'address': '1.1.3.1',
- 'instance_id': instance_id3,
- 'virtual_interface_id': vif_ref3['id']})
- fix_ref = db.fixed_ip_get_by_address(c, fix_addr)
- flo_ref = db.floating_ip_create(c,
- {'address': '10.0.0.2',
- 'fixed_ip_id': fix_ref['id']})
-
- # ends up matching 2nd octet here.. so all 3 match
- instances = self.compute_api.get_all(c,
- search_opts={'ip': '.*\.1'})
- self.assertEqual(len(instances), 3)
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip': '1.*'})
- self.assertEqual(len(instances), 3)
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip': '.*\.1.\d+$'})
- self.assertEqual(len(instances), 1)
- instance_ids = [instance.id for instance in instances]
- self.assertTrue(instance_id1 in instance_ids)
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip': '.*\.2.+'})
- self.assertEqual(len(instances), 1)
- self.assertEqual(instances[0].id, instance_id2)
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip': '10.*'})
- self.assertEqual(len(instances), 1)
- self.assertEqual(instances[0].id, instance_id3)
-
- db.virtual_interface_delete(c, vif_ref1['id'])
- db.virtual_interface_delete(c, vif_ref2['id'])
- db.virtual_interface_delete(c, vif_ref3['id'])
- db.floating_ip_destroy(c, '10.0.0.2')
- db.instance_destroy(c, instance_id1)
- db.instance_destroy(c, instance_id2)
- db.instance_destroy(c, instance_id3)
-
- def test_get_all_by_ipv6_regexp(self):
- """Test searching by IPv6 address"""
-
- c = context.get_admin_context()
- instance_id1 = self._create_instance({'display_name': 'woot'})
- instance_id2 = self._create_instance({
- 'display_name': 'woo',
- 'id': 20})
- instance_id3 = self._create_instance({
- 'display_name': 'not-woot',
- 'id': 30})
-
- vif_ref1 = db.virtual_interface_create(c,
- {'address': '12:34:56:78:90:12',
- 'instance_id': instance_id1,
- 'network_id': 1})
- vif_ref2 = db.virtual_interface_create(c,
- {'address': '90:12:34:56:78:90',
- 'instance_id': instance_id2,
- 'network_id': 1})
- vif_ref3 = db.virtual_interface_create(c,
- {'address': '34:56:78:90:12:34',
- 'instance_id': instance_id3,
- 'network_id': 1})
-
- # This will create IPv6 addresses of:
- # 1: fd00::1034:56ff:fe78:9012
- # 20: fd00::9212:34ff:fe56:7890
- # 30: fd00::3656:78ff:fe90:1234
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip6': '.*1034.*'})
- self.assertEqual(len(instances), 1)
- self.assertEqual(instances[0].id, instance_id1)
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip6': '^fd00.*'})
- self.assertEqual(len(instances), 3)
- instance_ids = [instance.id for instance in instances]
- self.assertTrue(instance_id1 in instance_ids)
- self.assertTrue(instance_id2 in instance_ids)
- self.assertTrue(instance_id3 in instance_ids)
-
- instances = self.compute_api.get_all(c,
- search_opts={'ip6': '^.*12.*34.*'})
- self.assertEqual(len(instances), 2)
- instance_ids = [instance.id for instance in instances]
- self.assertTrue(instance_id2 in instance_ids)
- self.assertTrue(instance_id3 in instance_ids)
-
- db.virtual_interface_delete(c, vif_ref1['id'])
- db.virtual_interface_delete(c, vif_ref2['id'])
- db.virtual_interface_delete(c, vif_ref3['id'])
- db.instance_destroy(c, instance_id1)
- db.instance_destroy(c, instance_id2)
- db.instance_destroy(c, instance_id3)
-
def test_get_all_by_multiple_options_at_once(self):
"""Test searching by multiple options at once"""
c = context.get_admin_context()
- instance_id1 = self._create_instance({'display_name': 'woot'})
+ network_manager = fake_network.FakeNetworkManager()
+ self.stubs.Set(self.compute_api.network_api,
+ 'get_instance_uuids_by_ip_filter',
+ network_manager.get_instance_uuids_by_ip_filter)
+ self.stubs.Set(network_manager.db,
+ 'instance_get_uuids_by_ids',
+ db.instance_get_uuids_by_ids)
+
+ instance_id1 = self._create_instance({'display_name': 'woot',
+ 'id': 0})
instance_id2 = self._create_instance({
'display_name': 'woo',
'id': 20})
@@ -1214,36 +1045,6 @@ class ComputeTestCase(test.TestCase):
'display_name': 'not-woot',
'id': 30})
- vif_ref1 = db.virtual_interface_create(c,
- {'address': '12:34:56:78:90:12',
- 'instance_id': instance_id1,
- 'network_id': 1})
- vif_ref2 = db.virtual_interface_create(c,
- {'address': '90:12:34:56:78:90',
- 'instance_id': instance_id2,
- 'network_id': 1})
- vif_ref3 = db.virtual_interface_create(c,
- {'address': '34:56:78:90:12:34',
- 'instance_id': instance_id3,
- 'network_id': 1})
-
- db.fixed_ip_create(c,
- {'address': '1.1.1.1',
- 'instance_id': instance_id1,
- 'virtual_interface_id': vif_ref1['id']})
- db.fixed_ip_create(c,
- {'address': '1.1.2.1',
- 'instance_id': instance_id2,
- 'virtual_interface_id': vif_ref2['id']})
- fix_addr = db.fixed_ip_create(c,
- {'address': '1.1.3.1',
- 'instance_id': instance_id3,
- 'virtual_interface_id': vif_ref3['id']})
- fix_ref = db.fixed_ip_get_by_address(c, fix_addr)
- flo_ref = db.floating_ip_create(c,
- {'address': '10.0.0.2',
- 'fixed_ip_id': fix_ref['id']})
-
# ip ends up matching 2nd octet here.. so all 3 match ip
# but 'name' only matches one
instances = self.compute_api.get_all(c,
@@ -1251,18 +1052,18 @@ class ComputeTestCase(test.TestCase):
self.assertEqual(len(instances), 1)
self.assertEqual(instances[0].id, instance_id3)
- # ip ends up matching any ip with a '2' in it.. so instance
- # 2 and 3.. but name should only match #2
+ # ip ends up matching any ip with a '1' in the last octet..
+ # so instance 1 and 3.. but name should only match #1
# but 'name' only matches one
instances = self.compute_api.get_all(c,
- search_opts={'ip': '.*2', 'name': '^woo.*'})
+ search_opts={'ip': '.*\.1$', 'name': '^woo.*'})
self.assertEqual(len(instances), 1)
- self.assertEqual(instances[0].id, instance_id2)
+ self.assertEqual(instances[0].id, instance_id1)
# same as above but no match on name (name matches instance_id1
# but the ip query doesn't
instances = self.compute_api.get_all(c,
- search_opts={'ip': '.*2.*', 'name': '^woot.*'})
+ search_opts={'ip': '.*\.2$', 'name': '^woot.*'})
self.assertEqual(len(instances), 0)
# ip matches all 3... ipv6 matches #2+#3...name matches #3
@@ -1273,10 +1074,6 @@ class ComputeTestCase(test.TestCase):
self.assertEqual(len(instances), 1)
self.assertEqual(instances[0].id, instance_id3)
- db.virtual_interface_delete(c, vif_ref1['id'])
- db.virtual_interface_delete(c, vif_ref2['id'])
- db.virtual_interface_delete(c, vif_ref3['id'])
- db.floating_ip_destroy(c, '10.0.0.2')
db.instance_destroy(c, instance_id1)
db.instance_destroy(c, instance_id2)
db.instance_destroy(c, instance_id3)
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index c99709ffa..35c2ed0e1 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -94,9 +94,9 @@ class DbApiTestCase(test.TestCase):
db.instance_destroy(self.context, inst1.id)
result = db.instance_get_all_by_filters(self.context.elevated(), {})
self.assertEqual(2, len(result))
- self.assertEqual(result[0].id, inst2.id)
- self.assertEqual(result[1].id, inst1.id)
- self.assertTrue(result[1].deleted)
+ self.assertEqual(result[0].id, inst1.id)
+ self.assertEqual(result[1].id, inst2.id)
+ self.assertTrue(result[0].deleted)
def test_migration_get_all_unconfirmed(self):
ctxt = context.get_admin_context()
diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
index b06e5c136..2f82132fa 100644
--- a/nova/tests/test_metadata.py
+++ b/nova/tests/test_metadata.py
@@ -19,22 +19,21 @@
"""Tests for the testing the metadata code."""
import base64
-import httplib
import webob
from nova import exception
from nova import test
-from nova import wsgi
from nova.api.ec2 import metadatarequesthandler
from nova.db.sqlalchemy import api
+from nova.tests import fake_network
USER_DATA_STRING = ("This is an encoded string")
ENCODE_USER_DATA_STRING = base64.b64encode(USER_DATA_STRING)
-def return_non_existing_server_by_address(context, address):
+def return_non_existing_server_by_address(context, address, *args, **kwarg):
raise exception.NotFound()
@@ -69,6 +68,10 @@ class MetadataTestCase(test.TestCase):
self.stubs.Set(api, 'instance_get_all_by_filters', instance_get_list)
self.stubs.Set(api, 'instance_get_floating_address', floating_get)
self.app = metadatarequesthandler.MetadataRequestHandler()
+ network_manager = fake_network.FakeNetworkManager()
+ self.stubs.Set(self.app.cc.network_api,
+ 'get_instance_uuids_by_ip_filter',
+ network_manager.get_instance_uuids_by_ip_filter)
def request(self, relative_url):
request = webob.Request.blank(relative_url)
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
index 926ea065a..15c179177 100644
--- a/nova/tests/test_network.py
+++ b/nova/tests/test_network.py
@@ -438,55 +438,23 @@ class VlanNetworkTestCase(test.TestCase):
class CommonNetworkTestCase(test.TestCase):
-
- class FakeNetworkManager(network_manager.NetworkManager):
- """This NetworkManager doesn't call the base class so we can bypass all
- inherited service cruft and just perform unit tests.
- """
-
- class FakeDB:
- def fixed_ip_get_by_instance(self, context, instance_id):
- return [dict(address='10.0.0.0'), dict(address='10.0.0.1'),
- dict(address='10.0.0.2')]
-
- def network_get_by_cidr(self, context, cidr):
- raise exception.NetworkNotFoundForCidr()
-
- def network_create_safe(self, context, net):
- fakenet = dict(net)
- fakenet['id'] = 999
- return fakenet
-
- def network_get_all(self, context):
- raise exception.NoNetworksFound()
-
- def __init__(self):
- self.db = self.FakeDB()
- self.deallocate_called = None
-
- def deallocate_fixed_ip(self, context, address):
- self.deallocate_called = address
-
- def _create_fixed_ips(self, context, network_id):
- pass
-
def fake_create_fixed_ips(self, context, network_id):
return None
def test_remove_fixed_ip_from_instance(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
manager.remove_fixed_ip_from_instance(None, 99, '10.0.0.1')
self.assertEquals(manager.deallocate_called, '10.0.0.1')
def test_remove_fixed_ip_from_instance_bad_input(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.assertRaises(exception.FixedIpNotFoundForSpecificInstance,
manager.remove_fixed_ip_from_instance,
None, 99, 'bad input')
def test_validate_cidrs(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
nets = manager.create_networks(None, 'fake', '192.168.0.0/24',
False, 1, 256, None, None, None,
None)
@@ -495,7 +463,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertTrue('192.168.0.0/24' in cidrs)
def test_validate_cidrs_split_exact_in_half(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
nets = manager.create_networks(None, 'fake', '192.168.0.0/24',
False, 2, 128, None, None, None,
None)
@@ -505,7 +473,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertTrue('192.168.0.128/25' in cidrs)
def test_validate_cidrs_split_cidr_in_use_middle_of_range(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
manager.db.network_get_all(ctxt).AndReturn([{'id': 1,
@@ -523,7 +491,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertFalse('192.168.2.0/24' in cidrs)
def test_validate_cidrs_smaller_subnet_in_use(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
manager.db.network_get_all(ctxt).AndReturn([{'id': 1,
@@ -536,7 +504,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertRaises(ValueError, manager.create_networks, *args)
def test_validate_cidrs_split_smaller_cidr_in_use(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
manager.db.network_get_all(ctxt).AndReturn([{'id': 1,
@@ -553,7 +521,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertFalse('192.168.2.0/24' in cidrs)
def test_validate_cidrs_split_smaller_cidr_in_use2(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
manager.db.network_get_all(ctxt).AndReturn([{'id': 1,
@@ -569,7 +537,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertFalse('192.168.2.0/27' in cidrs)
def test_validate_cidrs_split_all_in_use(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
in_use = [{'id': 1, 'cidr': '192.168.2.9/29'},
@@ -585,14 +553,14 @@ class CommonNetworkTestCase(test.TestCase):
self.assertRaises(ValueError, manager.create_networks, *args)
def test_validate_cidrs_one_in_use(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
args = (None, 'fake', '192.168.0.0/24', False, 2, 256, None, None,
None, None)
# ValueError: network_size * num_networks exceeds cidr size
self.assertRaises(ValueError, manager.create_networks, *args)
def test_validate_cidrs_already_used(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
manager.db.network_get_all(ctxt).AndReturn([{'id': 1,
@@ -604,7 +572,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertRaises(ValueError, manager.create_networks, *args)
def test_validate_cidrs_too_many(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
args = (None, 'fake', '192.168.0.0/24', False, 200, 256, None, None,
None, None)
# ValueError: Not enough subnets avail to satisfy requested
@@ -612,7 +580,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertRaises(ValueError, manager.create_networks, *args)
def test_validate_cidrs_split_partial(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
nets = manager.create_networks(None, 'fake', '192.168.0.0/16',
False, 2, 256, None, None, None, None)
returned_cidrs = [str(net['cidr']) for net in nets]
@@ -620,7 +588,7 @@ class CommonNetworkTestCase(test.TestCase):
self.assertTrue('192.168.1.0/24' in returned_cidrs)
def test_validate_cidrs_conflict_existing_supernet(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
fakecidr = [{'id': 1, 'cidr': '192.168.0.0/8'}]
@@ -634,16 +602,15 @@ class CommonNetworkTestCase(test.TestCase):
def test_create_networks(self):
cidr = '192.168.0.0/24'
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.stubs.Set(manager, '_create_fixed_ips',
self.fake_create_fixed_ips)
args = [None, 'foo', cidr, None, 1, 256, 'fd00::/48', None, None,
None]
- result = manager.create_networks(*args)
self.assertTrue(manager.create_networks(*args))
def test_create_networks_cidr_already_used(self):
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.mox.StubOutWithMock(manager.db, 'network_get_all')
ctxt = mox.IgnoreArg()
fakecidr = [{'id': 1, 'cidr': '192.168.0.0/24'}]
@@ -655,9 +622,124 @@ class CommonNetworkTestCase(test.TestCase):
def test_create_networks_many(self):
cidr = '192.168.0.0/16'
- manager = self.FakeNetworkManager()
+ manager = fake_network.FakeNetworkManager()
self.stubs.Set(manager, '_create_fixed_ips',
self.fake_create_fixed_ips)
args = [None, 'foo', cidr, None, 10, 256, 'fd00::/48', None, None,
None]
self.assertTrue(manager.create_networks(*args))
+
+ def test_get_instance_uuids_by_ip_regex(self):
+ manager = fake_network.FakeNetworkManager()
+ _vifs = manager.db.virtual_interface_get_all(None)
+
+ # Greedy get eveything
+ res = manager.get_instance_uuids_by_ip_filter(None, {'ip': '.*'})
+ self.assertEqual(len(res), len(_vifs))
+
+ # Doesn't exist
+ res = manager.get_instance_uuids_by_ip_filter(None, {'ip': '10.0.0.1'})
+ self.assertFalse(res)
+
+ # Get instance 1
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'ip': '172.16.0.2'})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 1)
+ self.assertEqual(res[0]['instance_id'], _vifs[1]['instance_id'])
+
+ # Get instance 2
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'ip': '173.16.0.2'})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 1)
+ self.assertEqual(res[0]['instance_id'], _vifs[2]['instance_id'])
+
+ # Get instance 0 and 1
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'ip': '172.16.0.*'})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 2)
+ self.assertEqual(res[0]['instance_id'], _vifs[0]['instance_id'])
+ self.assertEqual(res[1]['instance_id'], _vifs[1]['instance_id'])
+
+ # Get instance 1 and 2
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'ip': '17..16.0.2'})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 2)
+ self.assertEqual(res[0]['instance_id'], _vifs[1]['instance_id'])
+ self.assertEqual(res[1]['instance_id'], _vifs[2]['instance_id'])
+
+ def test_get_instance_uuids_by_ipv6_regex(self):
+ manager = fake_network.FakeNetworkManager()
+ _vifs = manager.db.virtual_interface_get_all(None)
+
+ # Greedy get eveything
+ res = manager.get_instance_uuids_by_ip_filter(None, {'ip6': '.*'})
+ self.assertEqual(len(res), len(_vifs))
+
+ # Doesn't exist
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'ip6': '.*1034.*'})
+ self.assertFalse(res)
+
+ # Get instance 1
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'ip6': '2001:.*:2'})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 1)
+ self.assertEqual(res[0]['instance_id'], _vifs[1]['instance_id'])
+
+ # Get instance 2
+ ip6 = '2002:db8::dcad:beff:feef:2'
+ res = manager.get_instance_uuids_by_ip_filter(None, {'ip6': ip6})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 1)
+ self.assertEqual(res[0]['instance_id'], _vifs[2]['instance_id'])
+
+ # Get instance 0 and 1
+ res = manager.get_instance_uuids_by_ip_filter(None, {'ip6': '2001:.*'})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 2)
+ self.assertEqual(res[0]['instance_id'], _vifs[0]['instance_id'])
+ self.assertEqual(res[1]['instance_id'], _vifs[1]['instance_id'])
+
+ # Get instance 1 and 2
+ ip6 = '200.:db8::dcad:beff:feef:2'
+ res = manager.get_instance_uuids_by_ip_filter(None, {'ip6': ip6})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 2)
+ self.assertEqual(res[0]['instance_id'], _vifs[1]['instance_id'])
+ self.assertEqual(res[1]['instance_id'], _vifs[2]['instance_id'])
+
+ def test_get_instance_uuids_by_ip(self):
+ manager = fake_network.FakeNetworkManager()
+ _vifs = manager.db.virtual_interface_get_all(None)
+
+ # No regex for you!
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'fixed_ip': '.*'})
+ self.assertFalse(res)
+
+ # Doesn't exist
+ ip = '10.0.0.1'
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'fixed_ip': ip})
+ self.assertFalse(res)
+
+ # Get instance 1
+ ip = '172.16.0.2'
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'fixed_ip': ip})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 1)
+ self.assertEqual(res[0]['instance_id'], _vifs[1]['instance_id'])
+
+ # Get instance 2
+ ip = '173.16.0.2'
+ res = manager.get_instance_uuids_by_ip_filter(None,
+ {'fixed_ip': ip})
+ self.assertTrue(res)
+ self.assertEqual(len(res), 1)
+ self.assertEqual(res[0]['instance_id'], _vifs[2]['instance_id'])