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/api | |
| parent | bca7dd3e1d8bec758faf511338617f6d4121e0b8 (diff) | |
* Rework osapi to use network API not FK backref
* Fixes lp854585
Change-Id: I270794a08a1bfafe7af427cd31f1f60df1faa4ba
Diffstat (limited to 'nova/api')
| -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 |
4 files changed, 145 insertions, 112 deletions
diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py index b805c53f8..49aa81958 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 6f55aef9e..e92ab9bda 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 8d38bc9c3..3454f50c8 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 f3666eb6b..127a50c78 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'], |
