diff options
author | Jason Koelker <jason@koelker.net> | 2011-09-20 16:13:12 -0500 |
---|---|---|
committer | Jason Kölker <jason@koelker.net> | 2011-09-25 12:24:52 -0500 |
commit | 8be1c68f809b55088c1ad00ef86cb13b0103aab0 (patch) | |
tree | 7d5a5be076d679d70d84b2afcbf73828b17e6d50 /nova | |
parent | bca7dd3e1d8bec758faf511338617f6d4121e0b8 (diff) | |
download | nova-8be1c68f809b55088c1ad00ef86cb13b0103aab0.tar.gz |
* Rework osapi to use network API not FK backref
* Fixes lp854585
Change-Id: I270794a08a1bfafe7af427cd31f1f60df1faa4ba
Diffstat (limited to 'nova')
-rw-r--r-- | nova/api/openstack/ips.py | 93 | ||||
-rw-r--r-- | nova/api/openstack/servers.py | 23 | ||||
-rw-r--r-- | nova/api/openstack/views/addresses.py | 98 | ||||
-rw-r--r-- | nova/api/openstack/views/servers.py | 43 | ||||
-rw-r--r-- | nova/db/api.py | 5 | ||||
-rw-r--r-- | nova/db/sqlalchemy/api.py | 17 | ||||
-rw-r--r-- | nova/network/api.py | 6 | ||||
-rw-r--r-- | nova/network/manager.py | 11 | ||||
-rw-r--r-- | nova/tests/api/openstack/contrib/test_createserverext.py | 26 | ||||
-rw-r--r-- | nova/tests/api/openstack/contrib/test_volumes.py | 13 | ||||
-rw-r--r-- | nova/tests/api/openstack/fakes.py | 42 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_server_actions.py | 1 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_servers.py | 389 | ||||
-rw-r--r-- | nova/tests/integrated/test_servers.py | 2 | ||||
-rw-r--r-- | nova/tests/integrated/test_volumes.py | 1 |
15 files changed, 441 insertions, 329 deletions
diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py index b805c53f8d..49aa81958c 100644 --- a/nova/api/openstack/ips.py +++ b/nova/api/openstack/ips.py @@ -16,15 +16,19 @@ # under the License. from lxml import etree -import time from webob import exc import nova import nova.api.openstack.views.addresses +from nova import log as logging +from nova import flags from nova.api.openstack import wsgi from nova.api.openstack import xmlutil -from nova import db + + +LOG = logging.getLogger('nova.api.openstack.ips') +FLAGS = flags.FLAGS class Controller(object): @@ -32,13 +36,14 @@ class Controller(object): def __init__(self): self.compute_api = nova.compute.API() + self.network_api = nova.network.API() - def _get_instance(self, req, server_id): + def _get_instance(self, context, server_id): try: - instance = self.compute_api.get( - req.environ['nova.context'], server_id) + instance = self.compute_api.get(context, server_id) except nova.exception.NotFound: - raise exc.HTTPNotFound() + msg = _("Instance does not exist") + raise exc.HTTPNotFound(explanation=msg) return instance def create(self, req, server_id, body): @@ -51,17 +56,23 @@ class Controller(object): class ControllerV10(Controller): def index(self, req, server_id): - instance = self._get_instance(req, server_id) + context = req.environ['nova.context'] + instance = self._get_instance(context, server_id) + networks = _get_networks_for_instance(context, self.network_api, + instance) builder = nova.api.openstack.views.addresses.ViewBuilderV10() - return {'addresses': builder.build(instance)} + return {'addresses': builder.build(networks)} def show(self, req, server_id, id): - instance = self._get_instance(req, server_id) + context = req.environ['nova.context'] + instance = self._get_instance(context, server_id) + networks = _get_networks_for_instance(context, self.network_api, + instance) builder = self._get_view_builder(req) if id == 'private': - view = builder.build_private_parts(instance) + view = builder.build_private_parts(networks) elif id == 'public': - view = builder.build_public_parts(instance) + view = builder.build_public_parts(networks) else: msg = _("Only private and public networks available") raise exc.HTTPNotFound(explanation=msg) @@ -76,14 +87,18 @@ class ControllerV11(Controller): def index(self, req, server_id): context = req.environ['nova.context'] - interfaces = self._get_virtual_interfaces(context, server_id) - networks = self._get_view_builder(req).build(interfaces) - return {'addresses': networks} + instance = self._get_instance(context, server_id) + networks = _get_networks_for_instance(context, self.network_api, + instance) + return {'addresses': self._get_view_builder(req).build(networks)} def show(self, req, server_id, id): context = req.environ['nova.context'] - interfaces = self._get_virtual_interfaces(context, server_id) - network = self._get_view_builder(req).build_network(interfaces, id) + instance = self._get_instance(context, server_id) + networks = _get_networks_for_instance(context, self.network_api, + instance) + + network = self._get_view_builder(req).build_network(networks, id) if network is None: msg = _("Instance is not a member of specified network") @@ -91,13 +106,6 @@ class ControllerV11(Controller): return network - def _get_virtual_interfaces(self, context, server_id): - try: - return db.api.virtual_interface_get_by_instance(context, server_id) - except nova.exception.InstanceNotFound: - msg = _("Instance does not exist") - raise exc.HTTPNotFound(explanation=msg) - def _get_view_builder(self, req): return nova.api.openstack.views.addresses.ViewBuilderV11() @@ -135,6 +143,45 @@ class IPXMLSerializer(wsgi.XMLDictSerializer): return self._to_xml(addresses) +def _get_networks_for_instance(context, network_api, instance): + """Returns a prepared nw_info list for passing into the view + builders + + We end up with a datastructure like: + {'public': {'ips': [{'addr': '10.0.0.1', 'version': 4}, + {'addr': '2001::1', 'version': 6}], + 'floating_ips': [{'addr': '172.16.0.1', 'version': 4}, + {'addr': '172.16.2.1', 'version': 4}]}, + ...} + """ + def _get_floats(ip): + return network_api.get_floating_ips_by_fixed_address(context, ip) + + def _emit_addr(ip, version): + return {'addr': ip, 'version': version} + + if FLAGS.stub_network: + return {} + + nw_info = network_api.get_instance_nw_info(context, instance) + + networks = {} + for net, info in nw_info: + network = {'ips': []} + network['floating_ips'] = [] + if 'ip6s' in info: + network['ips'].extend([_emit_addr(ip['ip'], + 6) for ip in info['ip6s']]) + + for ip in info['ips']: + network['ips'].append(_emit_addr(ip['ip'], 4)) + floats = [_emit_addr(addr, + 4) for addr in _get_floats(ip['ip'])] + network['floating_ips'].extend(floats) + networks[info['label']] = network + return networks + + def create_resource(version): controller = { '1.0': ControllerV10, diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 6f55aef9ef..e92ab9bda9 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -23,6 +23,7 @@ from webob import exc import webob from nova import compute +from nova import network from nova import db from nova import exception from nova import flags @@ -32,7 +33,6 @@ from nova.api.openstack import common from nova.api.openstack import create_instance_helper as helper from nova.api.openstack import ips from nova.api.openstack import wsgi -from nova.compute import instance_types from nova.scheduler import api as scheduler_api import nova.api.openstack import nova.api.openstack.views.addresses @@ -72,6 +72,7 @@ class Controller(object): def __init__(self): self.compute_api = compute.API() + self.network_api = network.API() self.helper = helper.CreateInstanceHelper(self) def index(self, req): @@ -106,6 +107,11 @@ class Controller(object): def _action_rebuild(self, info, request, instance_id): raise NotImplementedError() + def _get_networks_for_instance(self, req, instance): + return ips._get_networks_for_instance(req.environ['nova.context'], + self.network_api, + instance) + def _get_servers(self, req, is_detail): """Returns a list of servers, taking into account any search options specified. @@ -639,12 +645,15 @@ class ControllerV10(Controller): def _build_view(self, req, instance, is_detail=False): addresses = nova.api.openstack.views.addresses.ViewBuilderV10() builder = nova.api.openstack.views.servers.ViewBuilderV10(addresses) - return builder.build(instance, is_detail=is_detail) + networks = self._get_networks_for_instance(req, instance) + return builder.build(instance, networks, is_detail=is_detail) def _build_list(self, req, instances, is_detail=False): addresses = nova.api.openstack.views.addresses.ViewBuilderV10() builder = nova.api.openstack.views.servers.ViewBuilderV10(addresses) - return builder.build_list(instances, is_detail=is_detail) + get_nw = self._get_networks_for_instance + inst_data = [(inst, get_nw(req, inst)) for inst in instances] + return builder.build_list(inst_data, is_detail=is_detail) def _limit_items(self, items, req): return common.limited(items, req) @@ -741,8 +750,8 @@ class ControllerV11(Controller): builder = nova.api.openstack.views.servers.ViewBuilderV11( addresses_builder, flavor_builder, image_builder, base_url, project_id) - - return builder.build(instance, is_detail=is_detail) + networks = self._get_networks_for_instance(req, instance) + return builder.build(instance, networks, is_detail=is_detail) def _build_list(self, req, instances, is_detail=False): params = req.GET.copy() @@ -761,7 +770,9 @@ class ControllerV11(Controller): builder = nova.api.openstack.views.servers.ViewBuilderV11( addresses_builder, flavor_builder, image_builder, base_url, project_id) - return builder.build_list(instances, is_detail=is_detail, **params) + get_nw = self._get_networks_for_instance + inst_data = [(inst, get_nw(req, inst)) for inst in instances] + return builder.build_list(inst_data, is_detail=is_detail, **params) def _action_change_password(self, input_dict, req, id): context = req.environ['nova.context'] diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py index 8d38bc9c3d..3454f50c8b 100644 --- a/nova/api/openstack/views/addresses.py +++ b/nova/api/openstack/views/addresses.py @@ -15,10 +15,11 @@ # License for the specific language governing permissions and limitations # under the License. +import itertools + from nova import flags -from nova import utils from nova import log as logging -from nova.api.openstack import common + FLAGS = flags.FLAGS LOG = logging.getLogger('nova.api.openstack.views.addresses') @@ -30,76 +31,55 @@ class ViewBuilder(object): def build(self, inst): raise NotImplementedError() + def _extract_ips(self, network, key=None): + if key: + chain = network[key] + else: + chain = itertools.chain(network['ips'], network['floating_ips']) + for ip in chain: + if not FLAGS.use_ipv6 and ip['version'] == 6: + continue + yield ip -class ViewBuilderV10(ViewBuilder): - - def build(self, inst): - private_ips = self.build_private_parts(inst) - public_ips = self.build_public_parts(inst) - return dict(public=public_ips, private=private_ips) - - def build_public_parts(self, inst): - return utils.get_from_path(inst, 'fixed_ips/floating_ips/address') - - def build_private_parts(self, inst): - return utils.get_from_path(inst, 'fixed_ips/address') +class ViewBuilderV10(ViewBuilder): -class ViewBuilderV11(ViewBuilder): + def build(self, networks): + if not networks: + return dict(public=[], private=[]) - def build(self, interfaces): - networks = {} - for interface in interfaces: - try: - network_label = self._extract_network_label(interface) - except TypeError: - continue + return dict(public=self.build_public_parts(networks), + private=self.build_private_parts(networks)) - if network_label not in networks: - networks[network_label] = [] + def build_public_parts(self, nets): + ips = [self._extract_ips(nets[label], + key='floating_ips') for label in nets] + return [ip['addr'] for ip in itertools.chain(*ips)] - ip_addresses = list(self._extract_ipv4_addresses(interface)) + def build_private_parts(self, nets): + ips = [self._extract_ips(nets[label], key='ips') for label in nets] + return [ip['addr'] for ip in itertools.chain(*ips)] - if FLAGS.use_ipv6: - ipv6_address = self._extract_ipv6_address(interface) - if ipv6_address is not None: - ip_addresses.append(ipv6_address) - networks[network_label].extend(ip_addresses) +class ViewBuilderV11(ViewBuilder): - return networks + def build(self, networks): + result = {} + for network in networks: + if network not in result: + result[network] = [] - def build_network(self, interfaces, requested_network): - for interface in interfaces: - try: - network_label = self._extract_network_label(interface) - except TypeError: - continue + result[network].extend(self._extract_ips(networks[network])) + return result - if network_label == requested_network: - ips = list(self._extract_ipv4_addresses(interface)) - ipv6 = self._extract_ipv6_address(interface) - if ipv6 is not None: - ips.append(ipv6) - return {network_label: ips} + def build_network(self, networks, requested_network): + for network in networks: + if network == requested_network: + return {network: list(self._extract_ips(networks[network]))} return None - def _extract_network_label(self, interface): + def _extract_network_label(self, network): try: - return interface['network']['label'] + return network['label'] except (TypeError, KeyError) as exc: raise TypeError - - def _extract_ipv4_addresses(self, interface): - for fixed_ip in interface['fixed_ips']: - yield self._build_ip_entity(fixed_ip['address'], 4) - for floating_ip in fixed_ip.get('floating_ips', []): - yield self._build_ip_entity(floating_ip['address'], 4) - - def _extract_ipv6_address(self, interface): - fixed_ipv6 = interface.get('fixed_ipv6') - if fixed_ipv6 is not None: - return self._build_ip_entity(fixed_ipv6, 6) - - def _build_ip_entity(self, address, version): - return {'addr': address, 'version': version} diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index f3666eb6bd..127a50c781 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -16,19 +16,19 @@ # License for the specific language governing permissions and limitations # under the License. -import datetime import hashlib import os from nova import exception -from nova.api.openstack import common -from nova.api.openstack.views import addresses as addresses_view -from nova.api.openstack.views import flavors as flavors_view -from nova.api.openstack.views import images as images_view +from nova import log as logging from nova import utils +from nova.api.openstack import common from nova.compute import vm_states +LOG = logging.getLogger('nova.api.openstack.views.servers') + + class ViewBuilder(object): """Model a server response as a python dictionary. @@ -40,13 +40,13 @@ class ViewBuilder(object): def __init__(self, addresses_builder): self.addresses_builder = addresses_builder - def build(self, inst, is_detail=False): + def build(self, inst, networks, is_detail=False): """Return a dict that represenst a server.""" if inst.get('_is_precooked', False): server = dict(server=inst) else: if is_detail: - server = self._build_detail(inst) + server = self._build_detail(inst, networks) else: server = self._build_simple(inst) @@ -59,8 +59,9 @@ class ViewBuilder(object): servers = [] servers_links = [] - for server_obj in server_objs: - servers.append(self.build(server_obj, is_detail)['server']) + for server_obj, networks in server_objs: + servers.append(self.build(server_obj, networks, + is_detail)['server']) return dict(servers=servers) @@ -68,7 +69,7 @@ class ViewBuilder(object): """Return a simple model of a server.""" return dict(server=dict(id=inst['id'], name=inst['display_name'])) - def _build_detail(self, inst): + def _build_detail(self, inst, networks): """Returns a detailed model of a server.""" vm_state = inst.get('vm_state', vm_states.BUILDING) task_state = inst.get('task_state') @@ -92,13 +93,13 @@ class ViewBuilder(object): self._build_image(inst_dict, inst) self._build_flavor(inst_dict, inst) - self._build_addresses(inst_dict, inst) + self._build_addresses(inst_dict, networks) return dict(server=inst_dict) - def _build_addresses(self, response, inst): + def _build_addresses(self, response, networks): """Return the addresses sub-resource of a server.""" - raise NotImplementedError() + response['addresses'] = self.addresses_builder.build(networks) def _build_image(self, response, inst): """Return the image sub-resource of a server.""" @@ -129,9 +130,6 @@ class ViewBuilderV10(ViewBuilder): if inst.get('instance_type', None): response['flavorId'] = inst['instance_type']['flavorid'] - def _build_addresses(self, response, inst): - response['addresses'] = self.addresses_builder.build(inst) - class ViewBuilderV11(ViewBuilder): """Model an Openstack API V1.0 server response.""" @@ -143,8 +141,8 @@ class ViewBuilderV11(ViewBuilder): self.base_url = base_url self.project_id = project_id - def _build_detail(self, inst): - response = super(ViewBuilderV11, self)._build_detail(inst) + def _build_detail(self, inst, network): + response = super(ViewBuilderV11, self)._build_detail(inst, network) response['server']['created'] = utils.isotime(inst['created_at']) response['server']['updated'] = utils.isotime(inst['updated_at']) @@ -190,10 +188,6 @@ class ViewBuilderV11(ViewBuilder): ] } - def _build_addresses(self, response, inst): - interfaces = inst.get('virtual_interfaces', []) - response['addresses'] = self.addresses_builder.build(interfaces) - def _build_extra(self, response, inst): self._build_links(response, inst) response['uuid'] = inst['uuid'] @@ -220,8 +214,9 @@ class ViewBuilderV11(ViewBuilder): servers = [] servers_links = [] - for server_obj in server_objs: - servers.append(self.build(server_obj, is_detail)['server']) + for server_obj, networks in server_objs: + servers.append(self.build(server_obj, networks, + is_detail)['server']) if (len(servers) and limit) and (limit == len(servers)): next_link = self.generate_next_link(servers[-1]['id'], diff --git a/nova/db/api.py b/nova/db/api.py index f776953db4..7ad02cdd42 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -290,6 +290,11 @@ def floating_ip_get_by_address(context, address): return IMPL.floating_ip_get_by_address(context, address) +def floating_ip_get_by_fixed_address(context, fixed_address): + """Get a floating ips by fixed address""" + return IMPL.floating_ip_get_by_fixed_address(context, fixed_address) + + def floating_ip_update(context, address, values): """Update a floating ip by address or raise if it doesn't exist.""" return IMPL.floating_ip_update(context, address, values) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index c91fa8c0d5..df09aebafb 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -661,6 +661,23 @@ def floating_ip_get_by_address(context, address, session=None): @require_context +def floating_ip_get_by_fixed_address(context, fixed_address, session=None): + if not session: + session = get_session() + + fixed_ip = fixed_ip_get_by_address(context, fixed_address, session) + fixed_ip_id = fixed_ip['id'] + + return session.query(models.FloatingIp).\ + options(joinedload_all('fixed_ip.network')).\ + filter_by(fixed_ip_id=fixed_ip_id).\ + filter_by(deleted=can_read_deleted(context)).\ + all() + + # NOTE(tr3buchet) please don't invent an exception here, empty list is fine + + +@require_context def floating_ip_update(context, address, values): session = get_session() with session.begin(): diff --git a/nova/network/api.py b/nova/network/api.py index a1ed284967..9bcf474a65 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -45,6 +45,12 @@ class API(base.Base): context.project_id) return ips + def get_floating_ips_by_fixed_address(self, context, fixed_address): + return rpc.call(context, + FLAGS.network_topic, + {'method': 'get_floating_ips_by_fixed_address', + 'args': {'fixed_address': fixed_address}}) + def get_vifs_by_instance(self, context, instance_id): return rpc.call(context, FLAGS.network_topic, {'method': 'get_vifs_by_instance', diff --git a/nova/network/manager.py b/nova/network/manager.py index ffb9f976c3..1c65942f53 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -308,6 +308,12 @@ class FloatingIP(object): """Returns an floating ip to the pool.""" self.db.floating_ip_deallocate(context, floating_address) + def get_floating_ips_by_fixed_address(self, context, fixed_address): + """Returns the floating IPs associated with a fixed_address""" + floating_ips = self.db.floating_ip_get_by_fixed_address(context, + fixed_address) + return [floating_ip['address'] for floating_ip in floating_ips] + class NetworkManager(manager.SchedulerDependentManager): """Implements common network manager functionality. @@ -400,6 +406,11 @@ class NetworkManager(manager.SchedulerDependentManager): self.compute_api.trigger_security_group_members_refresh(admin_context, group_ids) + def get_floating_ips_by_fixed_address(self, context, fixed_address): + # NOTE(jkoelker) This is just a stub function. Managers supporting + # floating ips MUST override this or use the Mixin + return [] + def get_vifs_by_instance(self, context, instance_id): vifs = self.db.virtual_interface_get_by_instance(context, instance_id) diff --git a/nova/tests/api/openstack/contrib/test_createserverext.py b/nova/tests/api/openstack/contrib/test_createserverext.py index dfd6142caf..d2fac26c78 100644 --- a/nova/tests/api/openstack/contrib/test_createserverext.py +++ b/nova/tests/api/openstack/contrib/test_createserverext.py @@ -18,10 +18,8 @@ import base64 import datetime import json -import unittest from xml.dom import minidom -import stubout import webob from nova import db @@ -91,6 +89,11 @@ class CreateserverextTest(test.TestCase): def tearDown(self): super(CreateserverextTest, self).tearDown() + def _make_stub_method(self, canned_return): + def stub_method(*args, **kwargs): + return canned_return + return stub_method + def _setup_mock_compute_api(self): class MockComputeAPI(nova.compute.API): @@ -126,18 +129,19 @@ class CreateserverextTest(test.TestCase): def set_admin_password(self, *args, **kwargs): pass - def make_stub_method(canned_return): - def stub_method(*args, **kwargs): - return canned_return - return stub_method - compute_api = MockComputeAPI() - self.stubs.Set(nova.compute, 'API', make_stub_method(compute_api)) + self.stubs.Set(nova.compute, 'API', + self._make_stub_method(compute_api)) self.stubs.Set( nova.api.openstack.create_instance_helper.CreateInstanceHelper, - '_get_kernel_ramdisk_from_image', make_stub_method((1, 1))) + '_get_kernel_ramdisk_from_image', + self._make_stub_method((1, 1))) + return compute_api + def _setup_mock_network_api(self): + fakes.stub_out_nw_api(self.stubs) + def _create_security_group_request_dict(self, security_groups): server = {} server['name'] = 'new-server-test' @@ -179,6 +183,7 @@ class CreateserverextTest(test.TestCase): def _run_create_instance_with_mock_compute_api(self, request): compute_api = self._setup_mock_compute_api() + self._setup_mock_network_api() response = request.get_response(fakes.wsgi_app()) return compute_api, response @@ -391,6 +396,7 @@ class CreateserverextTest(test.TestCase): return_security_group_get_by_name) self.stubs.Set(nova.db.api, 'instance_add_security_group', return_instance_add_security_group) + self._setup_mock_network_api() body_dict = self._create_security_group_request_dict(security_groups) request = self._get_create_request_json(body_dict) response = request.get_response(fakes.wsgi_app()) @@ -398,6 +404,7 @@ class CreateserverextTest(test.TestCase): def test_get_server_by_id_verify_security_groups_json(self): self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id) + self._setup_mock_network_api() req = webob.Request.blank('/v1.1/123/os-create-server-ext/1') req.headers['Content-Type'] = 'application/json' response = req.get_response(fakes.wsgi_app()) @@ -409,6 +416,7 @@ class CreateserverextTest(test.TestCase): def test_get_server_by_id_verify_security_groups_xml(self): self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id) + self._setup_mock_network_api() req = webob.Request.blank('/v1.1/123/os-create-server-ext/1') req.headers['Accept'] = 'application/xml' response = req.get_response(fakes.wsgi_app()) diff --git a/nova/tests/api/openstack/contrib/test_volumes.py b/nova/tests/api/openstack/contrib/test_volumes.py index ec69c1fd1b..f61e25d126 100644 --- a/nova/tests/api/openstack/contrib/test_volumes.py +++ b/nova/tests/api/openstack/contrib/test_volumes.py @@ -18,10 +18,8 @@ import json import webob import nova -from nova import context from nova import flags from nova import test -from nova.api.openstack.contrib.volumes import BootFromVolumeController from nova.compute import instance_types from nova.tests.api.openstack import fakes from nova.tests.api.openstack.test_servers import fake_gen_uuid @@ -47,11 +45,22 @@ def fake_compute_api_create(cls, context, instance_type, image_href, **kwargs): }] +def fake_get_instance_nw_info(cls, context, instance): + return [(None, {'label': 'public', + 'ips': [{'ip': '10.0.0.1'}], + 'ip6s': []})] + + +def fake_get_floating_ips_by_fixed_address(self, context, fixed_ip): + return ['172.16.0.1'] + + class BootFromVolumeTest(test.TestCase): def setUp(self): super(BootFromVolumeTest, self).setUp() self.stubs.Set(nova.compute.API, 'create', fake_compute_api_create) + fakes.stub_out_nw_api(self.stubs) def test_create_root_volume(self): body = dict(server=dict( diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 3a567f0cc4..a1c956324a 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -15,16 +15,11 @@ # License for the specific language governing permissions and limitations # under the License. -import copy -import random -import string - import webob import webob.dec from paste import urlmap from glance import client as glance_client -from glance.common import exception as glance_exc from nova import context from nova import exception as exc @@ -39,8 +34,6 @@ from nova.api.openstack import versions from nova.api.openstack import limits from nova.auth.manager import User, Project import nova.image.fake -from nova.image import glance -from nova.tests import fake_flags from nova.tests.glance import stubs as glance_stubs @@ -177,6 +170,41 @@ def stub_out_compute_api_backup(stubs): stubs.Set(nova.compute.API, 'backup', backup) +def stub_out_nw_api_get_instance_nw_info(stubs, func=None): + def get_instance_nw_info(self, context, instance): + return [(None, {'label': 'public', + 'ips': [{'ip': '192.168.0.3'}], + 'ip6s': []})] + + if func is None: + func = get_instance_nw_info + stubs.Set(nova.network.API, 'get_instance_nw_info', func) + + +def stub_out_nw_api_get_floating_ips_by_fixed_address(stubs, func=None): + def get_floating_ips_by_fixed_address(self, context, fixed_ip): + return ['1.2.3.4'] + + if func is None: + func = get_floating_ips_by_fixed_address + stubs.Set(nova.network.API, 'get_floating_ips_by_fixed_address', func) + + +def stub_out_nw_api(stubs, cls=None): + class Fake: + def get_instance_nw_info(*args, **kwargs): + pass + + def get_floating_ips_by_fixed_address(*args, **kwargs): + pass + + if cls is None: + cls = Fake + stubs.Set(nova.network, 'API', cls) + stub_out_nw_api_get_floating_ips_by_fixed_address(stubs) + stub_out_nw_api_get_instance_nw_info(stubs) + + def _make_image_fixtures(): NOW_GLANCE_FORMAT = "2010-10-11T10:30:22" diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 251b5d1265..3811fcf0f6 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -474,6 +474,7 @@ class ServerActionsTestV11(test.TestCase): self.stubs.Set(nova.db.api, 'instance_update', instance_update) fakes.stub_out_glance(self.stubs) + fakes.stub_out_nw_api(self.stubs) fakes.stub_out_compute_api_snapshot(self.stubs) service_class = 'nova.image.glance.GlanceImageService' self.service = utils.import_object(service_class) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index c8d62d71a2..29be7a8120 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -35,7 +35,6 @@ from nova import utils import nova.api.openstack from nova.api.openstack import create_instance_helper from nova.api.openstack import servers -from nova.api.openstack import wsgi from nova.api.openstack import xmlutil import nova.compute.api from nova.compute import instance_types @@ -43,7 +42,6 @@ from nova.compute import task_states from nova.compute import vm_states import nova.db.api import nova.scheduler.api -from nova.db.sqlalchemy.models import Instance from nova.db.sqlalchemy.models import InstanceMetadata import nova.image.fake import nova.rpc @@ -74,18 +72,6 @@ def return_server_by_uuid(context, uuid): return stub_instance(id, uuid=uuid) -def return_virtual_interface_by_instance(interfaces): - def _return_virtual_interface_by_instance(context, instance_id): - return interfaces - return _return_virtual_interface_by_instance - - -def return_virtual_interface_instance_nonexistant(interfaces): - def _return_virtual_interface_by_instance(context, instance_id): - raise exception.InstanceNotFound(instance_id=instance_id) - return _return_virtual_interface_by_instance - - def return_server_with_attributes(**kwargs): def _return_server(context, id): return stub_instance(id, **kwargs) @@ -260,6 +246,7 @@ class ServersTest(test.TestCase): fakes.stub_out_rate_limiting(self.stubs) fakes.stub_out_key_pair_funcs(self.stubs) fakes.stub_out_image_service(self.stubs) + fakes.stub_out_nw_api(self.stubs) self.stubs.Set(utils, 'gen_uuid', fake_gen_uuid) self.stubs.Set(nova.db.api, 'instance_get_all_by_filters', return_servers) @@ -324,29 +311,26 @@ class ServersTest(test.TestCase): def test_get_server_by_id_v1_1(self): image_bookmark = "http://localhost/fake/images/10" - flavor_ref = "http://localhost/v1.1/fake/flavors/1" - flavor_id = "1" flavor_bookmark = "http://localhost/fake/flavors/1" - public_ip = '192.168.0.3' private_ip = '172.19.0.1' - interfaces = [ - { - 'network': {'label': 'public'}, - 'fixed_ips': [ - {'address': public_ip}, - ], - }, - { - 'network': {'label': 'private'}, - 'fixed_ips': [ - {'address': private_ip}, - ], - }, - ] - new_return_server = return_server_with_attributes( - interfaces=interfaces) - self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + + nw_info = [(None, {'label': 'public', + 'ips': [{'ip': public_ip}], + 'ip6s': []}), + (None, {'label': 'private', + 'ips': [{'ip': private_ip}], + 'ip6s': []})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) req = webob.Request.blank('/v1.1/fake/servers/1') res = req.get_response(fakes.wsgi_app()) @@ -423,23 +407,23 @@ class ServersTest(test.TestCase): flavor_bookmark = "http://localhost/fake/flavors/1" public_ip = '192.168.0.3' private_ip = '172.19.0.1' - interfaces = [ - { - 'network': {'label': 'public'}, - 'fixed_ips': [ - {'address': public_ip}, - ], - }, - { - 'network': {'label': 'private'}, - 'fixed_ips': [ - {'address': private_ip}, - ], - }, - ] - new_return_server = return_server_with_attributes( - interfaces=interfaces) - self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + + nw_info = [(None, {'label': 'public', + 'ips': [{'ip': public_ip}], + 'ip6s': []}), + (None, {'label': 'private', + 'ips': [{'ip': private_ip}], + 'ip6s': []})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) req = webob.Request.blank('/v1.1/fake/servers/1') req.headers['Accept'] = 'application/xml' @@ -529,29 +513,28 @@ class ServersTest(test.TestCase): def test_get_server_with_active_status_by_id_v1_1(self): image_bookmark = "http://localhost/fake/images/10" - flavor_ref = "http://localhost/v1.1/fake/flavors/1" - flavor_id = "1" flavor_bookmark = "http://localhost/fake/flavors/1" private_ip = "192.168.0.3" public_ip = "1.2.3.4" - interfaces = [ - { - 'network': {'label': 'public'}, - 'fixed_ips': [ - {'address': public_ip}, - ], - }, - { - 'network': {'label': 'private'}, - 'fixed_ips': [ - {'address': private_ip}, - ], - }, - ] + nw_info = [(None, {'label': 'public', + 'ips': [{'ip': public_ip}], + 'ip6s': []}), + (None, {'label': 'private', + 'ips': [{'ip': private_ip}], + 'ip6s': []})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) new_return_server = return_server_with_attributes( - interfaces=interfaces, vm_state=vm_states.ACTIVE, - progress=100) + vm_state=vm_states.ACTIVE, progress=100) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) req = webob.Request.blank('/v1.1/fake/servers/1') @@ -626,28 +609,29 @@ class ServersTest(test.TestCase): def test_get_server_with_id_image_ref_by_id_v1_1(self): image_ref = "10" image_bookmark = "http://localhost/fake/images/10" - flavor_ref = "http://localhost/v1.1/fake/flavors/1" flavor_id = "1" flavor_bookmark = "http://localhost/fake/flavors/1" private_ip = "192.168.0.3" public_ip = "1.2.3.4" - interfaces = [ - { - 'network': {'label': 'public'}, - 'fixed_ips': [ - {'address': public_ip}, - ], - }, - { - 'network': {'label': 'private'}, - 'fixed_ips': [ - {'address': private_ip}, - ], - }, - ] + nw_info = [(None, {'label': 'public', + 'ips': [{'ip': public_ip}], + 'ip6s': []}), + (None, {'label': 'private', + 'ips': [{'ip': private_ip}], + 'ip6s': []})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) new_return_server = return_server_with_attributes( - interfaces=interfaces, vm_state=vm_states.ACTIVE, + vm_state=vm_states.ACTIVE, image_ref=image_ref, flavor_id=flavor_id, progress=100) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) @@ -857,26 +841,24 @@ class ServersTest(test.TestCase): def test_get_server_by_id_with_addresses_v1_1(self): self.flags(use_ipv6=True) - interfaces = [ - { - 'network': {'label': 'network_1'}, - 'fixed_ips': [ - {'address': '192.168.0.3'}, - {'address': '192.168.0.4'}, - ], - }, - { - 'network': {'label': 'network_2'}, - 'fixed_ips': [ - {'address': '172.19.0.1'}, - {'address': '172.19.0.2'}, - ], - 'fixed_ipv6': '2001:4860::12', - }, - ] - new_return_server = return_server_with_attributes( - interfaces=interfaces) - self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + nw_info = [(None, {'label': 'network_1', + 'ips': [{'ip': '192.168.0.3'}, + {'ip': '192.168.0.4'}], + 'ip6s': []}), + (None, {'label': 'network_2', + 'ips': [{'ip': '172.19.0.1'}, + {'ip': '172.19.0.2'}], + 'ip6s': [{'ip': '2001:4860::12'}]})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) req = webob.Request.blank('/v1.1/fake/servers/1') res = req.get_response(fakes.wsgi_app()) @@ -897,30 +879,33 @@ class ServersTest(test.TestCase): ], } - self.assertEqual(addresses, expected) + self.assertTrue('network_1' in addresses) + self.assertTrue('network_2' in addresses) + + for network in ('network_1', 'network_2'): + for ip in expected[network]: + self.assertTrue(ip in addresses[network]) def test_get_server_by_id_with_addresses_v1_1_ipv6_disabled(self): self.flags(use_ipv6=False) - interfaces = [ - { - 'network': {'label': 'network_1'}, - 'fixed_ips': [ - {'address': '192.168.0.3'}, - {'address': '192.168.0.4'}, - ], - }, - { - 'network': {'label': 'network_2'}, - 'fixed_ips': [ - {'address': '172.19.0.1'}, - {'address': '172.19.0.2'}, - ], - 'fixed_ipv6': '2001:4860::12', - }, - ] - new_return_server = return_server_with_attributes( - interfaces=interfaces) - self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + nw_info = [(None, {'label': 'network_1', + 'ips': [{'ip': '192.168.0.3'}, + {'ip': '192.168.0.4'}], + 'ip6s': []}), + (None, {'label': 'network_2', + 'ips': [{'ip': '172.19.0.1'}, + {'ip': '172.19.0.2'}], + 'ip6s': [{'ip': '2001:4860::12'}]})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) req = webob.Request.blank('/v1.1/fake/servers/1') res = req.get_response(fakes.wsgi_app()) @@ -940,37 +925,36 @@ class ServersTest(test.TestCase): ], } - self.assertEqual(addresses, expected) + self.assertTrue('network_1' in addresses) + self.assertTrue('network_2' in addresses) + + for network in ('network_1', 'network_2'): + for ip in expected[network]: + self.assertTrue(ip['version'] != 6) + self.assertTrue(ip in addresses[network]) def test_get_server_addresses_v1_1(self): self.flags(use_ipv6=True) - interfaces = [ - { - 'network': {'label': 'network_1'}, - 'fixed_ips': [ - {'address': '192.168.0.3'}, - {'address': '192.168.0.4'}, - ], - }, - { - 'network': {'label': 'network_2'}, - 'fixed_ips': [ - { - 'address': '172.19.0.1', - 'floating_ips': [ - {'address': '1.2.3.4'}, - ], - }, - {'address': '172.19.0.2'}, - ], - 'fixed_ipv6': '2001:4860::12', - }, - ] - - _return_vifs = return_virtual_interface_by_instance(interfaces) - self.stubs.Set(nova.db.api, - 'virtual_interface_get_by_instance', - _return_vifs) + nw_info = [(None, {'label': 'network_1', + 'ips': [{'ip': '192.168.0.3'}, + {'ip': '192.168.0.4'}], + 'ip6s': []}), + (None, {'label': 'network_2', + 'ips': [{'ip': '172.19.0.1'}, + {'ip': '172.19.0.2'}], + 'ip6s': [{'ip': '2001:4860::12'}]})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + if fixed_ip == '172.19.0.1': + return ['1.2.3.4'] + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) req = webob.Request.blank('/v1.1/fake/servers/1/ips') res = req.get_response(fakes.wsgi_app()) @@ -991,36 +975,36 @@ class ServersTest(test.TestCase): }, } - self.assertEqual(res_dict, expected) + self.assertTrue('addresses' in res_dict) + self.assertTrue('network_1' in res_dict['addresses']) + self.assertTrue('network_2' in res_dict['addresses']) + + for network in ('network_1', 'network_2'): + for ip in expected['addresses'][network]: + self.assertTrue(ip in res_dict['addresses'][network]) def test_get_server_addresses_single_network_v1_1(self): self.flags(use_ipv6=True) - interfaces = [ - { - 'network': {'label': 'network_1'}, - 'fixed_ips': [ - {'address': '192.168.0.3'}, - {'address': '192.168.0.4'}, - ], - }, - { - 'network': {'label': 'network_2'}, - 'fixed_ips': [ - { - 'address': '172.19.0.1', - 'floating_ips': [ - {'address': '1.2.3.4'}, - ], - }, - {'address': '172.19.0.2'}, - ], - 'fixed_ipv6': '2001:4860::12', - }, - ] - _return_vifs = return_virtual_interface_by_instance(interfaces) - self.stubs.Set(nova.db.api, - 'virtual_interface_get_by_instance', - _return_vifs) + nw_info = [(None, {'label': 'network_1', + 'ips': [{'ip': '192.168.0.3'}, + {'ip': '192.168.0.4'}], + 'ip6s': []}), + (None, {'label': 'network_2', + 'ips': [{'ip': '172.19.0.1'}, + {'ip': '172.19.0.2'}], + 'ip6s': [{'ip': '2001:4860::12'}]})] + + def get_nw_info(*args, **kwargs): + return nw_info + + def get_floats(self, context, fixed_ip): + if fixed_ip == '172.19.0.1': + return ['1.2.3.4'] + return [] + + fakes.stub_out_nw_api_get_instance_nw_info(self.stubs, get_nw_info) + fakes.stub_out_nw_api_get_floating_ips_by_fixed_address(self.stubs, + get_floats) req = webob.Request.blank('/v1.1/fake/servers/1/ips/network_2') res = req.get_response(fakes.wsgi_app()) @@ -1028,30 +1012,32 @@ class ServersTest(test.TestCase): res_dict = json.loads(res.body) expected = { 'network_2': [ + {'version': 6, 'addr': '2001:4860::12'}, {'version': 4, 'addr': '172.19.0.1'}, {'version': 4, 'addr': '1.2.3.4'}, {'version': 4, 'addr': '172.19.0.2'}, - {'version': 6, 'addr': '2001:4860::12'}, ], } - self.assertEqual(res_dict, expected) - def test_get_server_addresses_nonexistant_network_v1_1(self): - _return_vifs = return_virtual_interface_by_instance([]) - self.stubs.Set(nova.db.api, - 'virtual_interface_get_by_instance', - _return_vifs) + self.assertTrue('network_2' in res_dict) + self.assertTrue(len(res_dict['network_2']) == 4) + for ip in expected['network_2']: + self.assertTrue(ip in res_dict['network_2']) + def test_get_server_addresses_nonexistant_network_v1_1(self): req = webob.Request.blank('/v1.1/fake/servers/1/ips/network_0') res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 404) def test_get_server_addresses_nonexistant_server_v1_1(self): - _return_vifs = return_virtual_interface_instance_nonexistant([]) - self.stubs.Set(nova.db.api, - 'virtual_interface_get_by_instance', - _return_vifs) + def fake(*args, **kwargs): + return [] + + def fake_instance_get(*args, **kwargs): + raise nova.exception.InstanceNotFound() + self.stubs.Set(nova.db.api, 'instance_get', fake_instance_get) + self.stubs.Set(nova.network.API, 'get_instance_nw_info', fake) req = webob.Request.blank('/v1.1/fake/servers/600/ips') res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 404) @@ -2745,6 +2731,10 @@ class ServersTest(test.TestCase): class TestServerStatus(test.TestCase): + def setUp(self): + super(TestServerStatus, self).setUp() + fakes.stub_out_nw_api(self.stubs) + def _get_with_state(self, vm_state, task_state=None): new_server = return_server_with_state(vm_state, task_state) self.stubs.Set(nova.db.api, 'instance_get', new_server) @@ -3536,6 +3526,7 @@ class TestServerInstanceCreation(test.TestCase): super(TestServerInstanceCreation, self).setUp() fakes.stub_out_image_service(self.stubs) fakes.stub_out_key_pair_funcs(self.stubs) + fakes.stub_out_nw_api(self.stubs) def _setup_mock_compute_api_for_personality(self): @@ -3924,7 +3915,7 @@ class ServersViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self.instance, False) + output = self.view_builder.build(self.instance, {}, False) self.assertDictMatch(output, expected_server) def test_build_server_with_project_id(self): @@ -3947,7 +3938,7 @@ class ServersViewBuilderV11Test(test.TestCase): } view_builder = self._get_view_builder(project_id='fake') - output = view_builder.build(self.instance, False) + output = view_builder.build(self.instance, {}, False) self.assertDictMatch(output, expected_server) def test_build_server_detail(self): @@ -4002,7 +3993,7 @@ class ServersViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self.instance, True) + output = self.view_builder.build(self.instance, {}, True) self.assertDictMatch(output, expected_server) def test_build_server_detail_active_status(self): @@ -4060,7 +4051,7 @@ class ServersViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self.instance, True) + output = self.view_builder.build(self.instance, {}, True) self.assertDictMatch(output, expected_server) def test_build_server_detail_with_accessipv4(self): @@ -4118,7 +4109,7 @@ class ServersViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self.instance, True) + output = self.view_builder.build(self.instance, {}, True) self.assertDictMatch(output, expected_server) def test_build_server_detail_with_accessipv6(self): @@ -4176,7 +4167,7 @@ class ServersViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self.instance, True) + output = self.view_builder.build(self.instance, {}, True) self.assertDictMatch(output, expected_server) def test_build_server_detail_with_metadata(self): @@ -4240,7 +4231,7 @@ class ServersViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self.instance, True) + output = self.view_builder.build(self.instance, {}, True) self.assertDictMatch(output, expected_server) diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index e9c79aa138..ca3eb73408 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -257,6 +257,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_server_with_metadata(self): """Creates a server with metadata.""" + self.flags(stub_network=True) # Build the server data gradually, checking errors along the way server = self._build_minimal_create_server_request() @@ -418,6 +419,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_rename_server(self): """Test building and renaming a server.""" + self.flags(stub_network=True) # Create a server server = self._build_minimal_create_server_request() diff --git a/nova/tests/integrated/test_volumes.py b/nova/tests/integrated/test_volumes.py index d6c5e1ba12..36c0592eb5 100644 --- a/nova/tests/integrated/test_volumes.py +++ b/nova/tests/integrated/test_volumes.py @@ -137,6 +137,7 @@ class VolumesTest(integrated_helpers._IntegratedTestBase): def test_attach_and_detach_volume(self): """Creates, attaches, detaches and deletes a volume.""" + self.flags(stub_network=True) # Create server server_req = {'server': self._build_minimal_create_server_request()} |