From 01b9d211e606ee0be221b27edae8aab1d35096ff Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 11:51:46 -0700 Subject: First round of changes for ha-flatdhcp. * added 'host' column to fixed_ips to allow associating with a host * added 'multi_host' column to network for multi_host possibility * moved extra db access from linux_net to manager * added host parameter to network calls --- bin/nova-manage | 2 +- nova/db/api.py | 19 ++++-- nova/db/sqlalchemy/api.py | 29 ++++++--- .../migrate_repo/versions/032_ha_network.py | 37 +++++++++++ nova/db/sqlalchemy/models.py | 1 + nova/exception.py | 5 ++ nova/network/api.py | 13 +++- nova/network/linux_net.py | 15 ++--- nova/network/manager.py | 73 +++++++++++++++------- 9 files changed, 144 insertions(+), 50 deletions(-) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py diff --git a/bin/nova-manage b/bin/nova-manage index 7dfe91698..71c99138f 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -494,7 +494,7 @@ class FixedIpCommands(object): if host is None: fixed_ips = db.fixed_ip_get_all(ctxt) else: - fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host) + fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host) except exception.NotFound as ex: print "error: %s" % ex sys.exit(2) diff --git a/nova/db/api.py b/nova/db/api.py index b7c5700e5..febe33374 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -332,13 +332,15 @@ def fixed_ip_associate(context, address, instance_id): return IMPL.fixed_ip_associate(context, address, instance_id) -def fixed_ip_associate_pool(context, network_id, instance_id): - """Find free ip in network and associate it to instance. +def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): + """Find free ip in network and associate it to instance or host. + If reserved is true, it will pull the ip from the reserved pool. Raises if one is not available. """ - return IMPL.fixed_ip_associate_pool(context, network_id, instance_id) + return IMPL.fixed_ip_associate_pool(context, network_id, + instance_id, host, reserved) def fixed_ip_create(context, values): @@ -361,9 +363,9 @@ def fixed_ip_get_all(context): return IMPL.fixed_ip_get_all(context) -def fixed_ip_get_all_by_host(context, host): - """Get all defined fixed ips used by a host.""" - return IMPL.fixed_ip_get_all_by_host(context, host) +def fixed_ip_get_all_by_instance_host(context, host): + """Get all allocated fixed ips filtered by instance host.""" + return IMPL.fixed_ip_get_all_instance_by_host(context, host) def fixed_ip_get_by_address(context, address): @@ -376,6 +378,11 @@ def fixed_ip_get_by_instance(context, instance_id): return IMPL.fixed_ip_get_by_instance(context, instance_id) +def fixed_ip_get_by_network_host(context, network_id, host): + """Get fixed ip for a host in a network.""" + return IMPL.fixed_ip_get_by_network_host(context, network_id, host) + + def fixed_ip_get_by_virtual_interface(context, vif_id): """Get fixed ips by virtual interface or raise if none exist.""" return IMPL.fixed_ip_get_by_virtual_interface(context, vif_id) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index ffd009513..6db142276 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -18,7 +18,6 @@ """ Implementation of SQLAlchemy backend. """ -import traceback import warnings from nova import db @@ -33,7 +32,6 @@ from sqlalchemy import or_ from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload_all -from sqlalchemy.sql import exists from sqlalchemy.sql import func from sqlalchemy.sql.expression import literal_column @@ -657,7 +655,7 @@ def fixed_ip_associate(context, address, instance_id): @require_admin_context -def fixed_ip_associate_pool(context, network_id, instance_id): +def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): session = get_session() with session.begin(): network_or_none = or_(models.FixedIp.network_id == network_id, @@ -677,9 +675,12 @@ def fixed_ip_associate_pool(context, network_id, instance_id): fixed_ip_ref.network = network_get(context, network_id, session=session) - fixed_ip_ref.instance = instance_get(context, - instance_id, - session=session) + if instance_id: + fixed_ip_ref.instance = instance_get(context, + instance_id, + session=session) + if host: + fixed_ip_ref.host = host session.add(fixed_ip_ref) return fixed_ip_ref['address'] @@ -735,7 +736,7 @@ def fixed_ip_get_all(context, session=None): @require_admin_context -def fixed_ip_get_all_by_host(context, host=None): +def fixed_ip_get_all_by_instance_host(context, host=None): session = get_session() result = session.query(models.FixedIp).\ @@ -784,6 +785,20 @@ def fixed_ip_get_by_instance(context, instance_id): return rv +@require_context +def fixed_ip_get_by_network_host(context, network_id, host): + session = get_session() + rv = session.query(models.FixedIp).\ + filter_by(network_id=network_id).\ + filter_by(host=host).\ + filter_by(deleted=False).\ + all() + if not rv: + raise exception.FixedIpNotFoundForNetworkHost(network_id=network_id, + host=host) + return rv + + @require_context def fixed_ip_get_by_virtual_interface(context, vif_id): session = get_session() diff --git a/nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py b/nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py new file mode 100644 index 000000000..316c36cbc --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py @@ -0,0 +1,37 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 MORITA Kazutaka. +# All Rights Reserved. +# +# 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, Table, MetaData, Boolean, String + +meta = MetaData() + +fixed_ips_host = Column('host', String(255)) + +networks_multi_host = Column('multi_host', Boolean, default=False) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + # Add columns to existing tables + fixed_ips = Table('fixed_ips', meta, autoload=True) + fixed_ips.create_column(fixed_ips_host) + + networks = Table('networks', meta, autoload=True) + networks.create_column(networks_multi_host) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index d29d3d6f1..8c86870f0 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -543,6 +543,7 @@ class Network(BASE, NovaBase): injected = Column(Boolean, default=False) cidr = Column(String(255), unique=True) cidr_v6 = Column(String(255), unique=True) + multi_host = Column(Boolean, default=False) gateway_v6 = Column(String(255)) netmask_v6 = Column(String(255)) diff --git a/nova/exception.py b/nova/exception.py index a6776b64f..29a209c3e 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -377,6 +377,11 @@ class FixedIpNotFoundForInstance(FixedIpNotFound): message = _("Instance %(instance_id)s has zero fixed ips.") +class FixedIpNotFoundForNetworkHost(FixedIpNotFound): + message = _("Network host %(host)s has zero fixed ips " + "in network %(network_id)s.") + + class FixedIpNotFoundForVirtualInterface(FixedIpNotFound): message = _("Virtual interface %(vif_id)s has zero associated fixed ips.") diff --git a/nova/network/api.py b/nova/network/api.py index b2b96082b..c57394204 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -18,7 +18,6 @@ """Handles all requests relating to instances (guest vms).""" -from nova import db from nova import exception from nova import flags from nova import log as logging @@ -105,7 +104,10 @@ class API(base.Base): '(%(project)s)') % {'address': floating_ip['address'], 'project': context.project_id}) - host = fixed_ip['network']['host'] + if fixed_ip['network']['multi_gateway']: + host = fixed_ip['instance']['host'] + else: + host = fixed_ip['network']['host'] rpc.cast(context, self.db.queue_get_for(context, FLAGS.network_topic, host), {'method': 'associate_floating_ip', @@ -120,7 +122,10 @@ class API(base.Base): return if not floating_ip.get('fixed_ip'): raise exception.ApiError('Address is not associated.') - host = floating_ip['fixed_ip']['network']['host'] + if floating_ip['fixed_ip']['network']['multi_gateway']: + host = floating_ip['fixed_ip']['instance']['host'] + else: + host = floating_ip['fixed_ip']['network']['host'] rpc.call(context, self.db.queue_get_for(context, FLAGS.network_topic, host), {'method': 'disassociate_floating_ip', @@ -134,7 +139,9 @@ class API(base.Base): args = kwargs args['instance_id'] = instance['id'] args['project_id'] = instance['project_id'] + args['host'] = instance['host'] args['instance_type_id'] = instance['instance_type_id'] + return rpc.call(context, FLAGS.network_topic, {'method': 'allocate_for_instance', 'args': args}) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 283a5aca1..8d2bc5c0b 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -573,18 +573,16 @@ def get_dhcp_hosts(context, network_id): # configuration options (like dchp-range, vlan, ...) # aren't reloaded. @utils.synchronized('dnsmasq_start') -def update_dhcp(context, network_id): +def update_dhcp(context, network_ref): """(Re)starts a dnsmasq server for a given network. If a dnsmasq instance is already running then send a HUP signal causing it to reload, otherwise spawn a new instance. """ - network_ref = db.network_get(context, network_id) - conffile = _dhcp_file(network_ref['bridge'], 'conf') with open(conffile, 'w') as f: - f.write(get_dhcp_hosts(context, network_id)) + f.write(get_dhcp_hosts(context, network_ref['id'])) # Make sure dnsmasq can actually read it (it setuid()s to "nobody") os.chmod(conffile, 0644) @@ -612,9 +610,7 @@ def update_dhcp(context, network_id): @utils.synchronized('radvd_start') -def update_ra(context, network_id): - network_ref = db.network_get(context, network_id) - +def update_ra(context, network_ref): conffile = _ra_file(network_ref['bridge'], 'conf') with open(conffile, 'w') as f: conf_str = """ @@ -650,9 +646,6 @@ interface %s LOG.debug(_('Pid %d is stale, relaunching radvd'), pid) command = _ra_cmd(network_ref) _execute(*command) - db.network_update(context, network_id, - {'gateway_v6': - utils.get_my_linklocal(network_ref['bridge'])}) def _host_lease(fixed_ip_ref): @@ -704,7 +697,7 @@ def _dnsmasq_cmd(net): '--conf-file=%s' % FLAGS.dnsmasq_config_file, '--domain=%s' % FLAGS.dhcp_domain, '--pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), - '--listen-address=%s' % net['gateway'], + '--listen-address=%s' % net['dhcp_listen'], '--except-interface=lo', '--dhcp-range=%s,static,120s' % net['dhcp_start'], '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(net['cidr'])), diff --git a/nova/network/manager.py b/nova/network/manager.py index d42bc8c4e..f60763eba 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -124,15 +124,17 @@ class RPCAllocateFixedIP(object): used since they share code to RPC.call allocate_fixed_ip on the correct network host to configure dnsmasq """ - def _allocate_fixed_ips(self, context, instance_id, networks): + def _allocate_fixed_ips(self, context, instance_id, host, networks): """Calls allocate_fixed_ip once for each network.""" green_pool = greenpool.GreenPool() for network in networks: - if network['host'] != self.host: + # NOTE(vish): if we are multi_gateway pass to the specified host + if not network['multi_gateway']: + host = network['host'] + if host != self.host: # need to call allocate_fixed_ip to correct network host - topic = self.db.queue_get_for(context, FLAGS.network_topic, - network['host']) + topic = self.db.queue_get_for(context, FLAGS.network_topic, host) args = {} args['instance_id'] = instance_id args['network_id'] = network['id'] @@ -298,6 +300,21 @@ class NetworkManager(manager.SchedulerDependentManager): super(NetworkManager, self).__init__(service_name='network', *args, **kwargs) + def _update_dchp(self, context, network_ref): + """Sets the listen address before sending update to the driver.""" + network_ref['dhcp_listen'] = self._get_dhcp_ip() + return self.driver.update_dhcp(context, network_ref) + + def _get_dhcp_ip(self, context, network_ref): + """Get the proper dhcp address to listen on. + + If it is a multi_host network, get the ip assigned to this host, + otherwise, assume that dhcp is listening on the gateway.""" + if network_ref['multi_host']: + return self.db.network_get_host_ip(context, FLAGS.host) + else: + return network_ref['gateway'] + def init_host(self): """Do any initialization that needs to be run if this is a standalone service. @@ -360,6 +377,7 @@ class NetworkManager(manager.SchedulerDependentManager): rpc.called by network_api """ instance_id = kwargs.pop('instance_id') + host = kwargs.pop('host') project_id = kwargs.pop('project_id') type_id = kwargs.pop('instance_type_id') admin_context = context.elevated() @@ -368,7 +386,7 @@ class NetworkManager(manager.SchedulerDependentManager): networks = self._get_networks_for_instance(admin_context, instance_id, project_id) self._allocate_mac_addresses(context, instance_id, networks) - self._allocate_fixed_ips(admin_context, instance_id, networks) + self._allocate_fixed_ips(admin_context, instance_id, host, networks) return self.get_instance_nw_info(context, instance_id, type_id) def deallocate_for_instance(self, context, **kwargs): @@ -475,10 +493,10 @@ class NetworkManager(manager.SchedulerDependentManager): random.randint(0x00, 0xff)] return ':'.join(map(lambda x: "%02x" % x, mac)) - def add_fixed_ip_to_instance(self, context, instance_id, network_id): + def add_fixed_ip_to_instance(self, context, instance_id, host, network_id): """Adds a fixed ip to an instance from specified network.""" networks = [self.db.network_get(context, network_id)] - self._allocate_fixed_ips(context, instance_id, networks) + self._allocate_fixed_ips(context, instance_id, host, networks) def allocate_fixed_ip(self, context, instance_id, network, **kwargs): """Gets a fixed ip from the pool.""" @@ -540,8 +558,9 @@ class NetworkManager(manager.SchedulerDependentManager): # means there will stale entries in the conf file # the code below will update the file if necessary if FLAGS.update_dhcp_on_disassociate: - network = self.db.fixed_ip_get_network(context, address) - self.driver.update_dhcp(context, network['id']) + network_ref = self.db.fixed_ip_get_network(context, address) + network_ref['dhcp_listen'] = self._get_dhcp_ip(context, network_ref) + self._update_dhcp(context, network_ref) def create_networks(self, context, label, cidr, num_networks, network_size, cidr_v6, gateway_v6, bridge, @@ -637,7 +656,7 @@ class NetworkManager(manager.SchedulerDependentManager): 'address': address, 'reserved': reserved}) - def _allocate_fixed_ips(self, context, instance_id, networks): + def _allocate_fixed_ips(self, context, instance_id, host, networks): """Calls allocate_fixed_ip once for each network.""" raise NotImplementedError() @@ -684,7 +703,7 @@ class FlatManager(NetworkManager): timeout_fixed_ips = False - def _allocate_fixed_ips(self, context, instance_id, networks): + def _allocate_fixed_ips(self, context, instance_id, host, networks): """Calls allocate_fixed_ip once for each network.""" for network in networks: self.allocate_fixed_ip(context, instance_id, network) @@ -738,8 +757,9 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): """ networks = db.network_get_all_by_instance(context, instance_id) for network in networks: - self.driver.ensure_bridge(network['bridge'], - network['bridge_interface']) + if not network['multi_host']: + self.driver.ensure_bridge(network['bridge'], + network['bridge_interface']) def allocate_fixed_ip(self, context, instance_id, network): """Allocate flat_network fixed_ip, then setup dhcp for this network.""" @@ -747,7 +767,7 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): instance_id, network) if not FLAGS.fake_network: - self.driver.update_dhcp(context, network['id']) + self._update_dhcp(context, network) def _on_set_network_host(self, context, network_id): """Called when this host becomes the host for a project.""" @@ -759,9 +779,13 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): network['bridge_interface'], network) if not FLAGS.fake_network: - self.driver.update_dhcp(context, network_id) + network_ref = self.db.network_get(context, network_id) + self._update_dhcp(context, network_ref) if(FLAGS.use_ipv6): - self.driver.update_ra(context, network_id) + self.driver.update_ra(context, network_ref) + gateway = utils.get_my_linklocal(network_ref['bridge']) + self.db.network_update(context, network_id, + {'gateway_v6': gateway}) class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): @@ -810,7 +834,7 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): 'virtual_interface_id': vif['id']} self.db.fixed_ip_update(context, address, values) if not FLAGS.fake_network: - self.driver.update_dhcp(context, network['id']) + self._update_dhcp(context, network) def add_network_to_project(self, context, project_id): """Force adds another network to a project.""" @@ -822,9 +846,10 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): """ networks = self.db.network_get_all_by_instance(context, instance_id) for network in networks: - self.driver.ensure_vlan_bridge(network['vlan'], - network['bridge'], - network['bridge_interface']) + if not network['multi_host']: + self.driver.ensure_vlan_bridge(network['vlan'], + network['bridge'], + network['bridge_interface']) def _get_networks_for_instance(self, context, instance_id, project_id): """Determine which networks an instance should connect to.""" @@ -874,9 +899,13 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): network['vpn_public_port'], network['vpn_private_address']) if not FLAGS.fake_network: - self.driver.update_dhcp(context, network_id) + network_ref = self.db.network_get(context, network_id) + self._update_dhcp(context, network_ref) if(FLAGS.use_ipv6): - self.driver.update_ra(context, network_id) + self.driver.update_ra(context, network_ref) + gateway = utils.get_my_linklocal(network_ref['bridge']) + self.db.network_update(context, network_id, + {'gateway_v6': gateway}) @property def _bottom_reserved_ips(self): -- cgit From 9a8254ef2751e1b7502107a9c6afe05ea1e2efd4 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 12:00:11 -0700 Subject: it is multi_host not multi_gateway --- nova/network/api.py | 6 ++++-- nova/network/manager.py | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/nova/network/api.py b/nova/network/api.py index c57394204..c0f0fb8eb 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -104,7 +104,8 @@ class API(base.Base): '(%(project)s)') % {'address': floating_ip['address'], 'project': context.project_id}) - if fixed_ip['network']['multi_gateway']: + # NOTE(vish): if we are multi_host, send to the instances host + if fixed_ip['network']['multi_host']: host = fixed_ip['instance']['host'] else: host = fixed_ip['network']['host'] @@ -122,7 +123,8 @@ class API(base.Base): return if not floating_ip.get('fixed_ip'): raise exception.ApiError('Address is not associated.') - if floating_ip['fixed_ip']['network']['multi_gateway']: + # NOTE(vish): if we are multi_host, send to the instances host + if floating_ip['fixed_ip']['network']['multi_host']: host = floating_ip['fixed_ip']['instance']['host'] else: host = floating_ip['fixed_ip']['network']['host'] diff --git a/nova/network/manager.py b/nova/network/manager.py index f60763eba..84d2cbbcb 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -49,7 +49,6 @@ import datetime import math import netaddr import socket -import pickle from eventlet import greenpool from nova import context @@ -129,8 +128,8 @@ class RPCAllocateFixedIP(object): green_pool = greenpool.GreenPool() for network in networks: - # NOTE(vish): if we are multi_gateway pass to the specified host - if not network['multi_gateway']: + # NOTE(vish): if we are not multi_host pass to the network host + if not network['multi_host']: host = network['host'] if host != self.host: # need to call allocate_fixed_ip to correct network host -- cgit From 8d2f3f26e8089020616312334689f1c594a67b4f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 12:16:46 -0700 Subject: make sure to filter out ips associated by host and add some sync for allocating ip to host --- nova/db/sqlalchemy/api.py | 1 + nova/network/manager.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 6db142276..7065de00f 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -665,6 +665,7 @@ def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): filter_by(reserved=False).\ filter_by(deleted=False).\ filter_by(instance=None).\ + filter_by(host=None).\ with_lockmode('update').\ first() # NOTE(vish): if with_lockmode isn't supported, as in sqlite, diff --git a/nova/network/manager.py b/nova/network/manager.py index 84d2cbbcb..55f81da9e 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -310,7 +310,18 @@ class NetworkManager(manager.SchedulerDependentManager): If it is a multi_host network, get the ip assigned to this host, otherwise, assume that dhcp is listening on the gateway.""" if network_ref['multi_host']: - return self.db.network_get_host_ip(context, FLAGS.host) + + @utils.synchronized('get_dhcp') + def _sync_get_dhcp_ip(): + try: + return self.db.fixed_ip_get_by_network_host(context, + FLAGS.host) + except exception.FixedIpNotFoundForNetworkHost: + return self.db.fixed_ip_associate_pool(context.elevated(), + network_ref['id'], + host=FLAGS.host) + return _sync_get_dhcp_ip() + else: return network_ref['gateway'] -- cgit From 9b5adcbe92a4f7e0f9b1592be123c58f743def34 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 15:55:16 -0700 Subject: pass in dhcp server address, fix a bunch of bugs --- nova/compute/manager.py | 17 ++++++++------- nova/db/api.py | 2 +- nova/db/sqlalchemy/api.py | 3 ++- nova/db/sqlalchemy/models.py | 1 + nova/network/linux_net.py | 4 ++-- nova/network/manager.py | 47 ++++++++++++++++++++++++++++------------- nova/virt/libvirt/connection.py | 3 +-- 7 files changed, 48 insertions(+), 29 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index bbbddde0a..b198adc97 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -77,8 +77,6 @@ flags.DEFINE_integer('live_migration_retry_count', 30, flags.DEFINE_integer("rescue_timeout", 0, "Automatically unrescue an instance after N seconds." " Set to 0 to disable.") -flags.DEFINE_bool('auto_assign_floating_ip', False, - 'Autoassigning floating ip to VM') flags.DEFINE_integer('host_state_interval', 120, 'Interval in seconds for querying the host status') @@ -268,16 +266,19 @@ class ComputeManager(manager.SchedulerDependentManager): """Launch a new instance with specified options.""" context = context.elevated() instance = self.db.instance_get(context, instance_id) - instance.injected_files = kwargs.get('injected_files', []) - instance.admin_pass = kwargs.get('admin_password', None) if instance['name'] in self.driver.list_instances(): raise exception.Error(_("Instance has already been created")) LOG.audit(_("instance %s: starting..."), instance_id, context=context) - self.db.instance_update(context, - instance_id, - {'host': self.host, 'launched_on': self.host}) - + updates = {} + updates['host'] = self.host + updates['launched_on'] = self.host + # NOTE(vish): used by virt but not in database + updates['injected_files'] = kwargs.get('injected_files', []) + updates['admin_pass'] = kwargs.get('admin_password', None) + instance = self.db.instance_update(context, + instance_id, + updates) self.db.instance_set_state(context, instance_id, power_state.NOSTATE, diff --git a/nova/db/api.py b/nova/db/api.py index febe33374..ee4cbad57 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -340,7 +340,7 @@ def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): """ return IMPL.fixed_ip_associate_pool(context, network_id, - instance_id, host, reserved) + instance_id, host) def fixed_ip_create(context, values): diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 7065de00f..9c138d2fd 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -683,6 +683,7 @@ def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): if host: fixed_ip_ref.host = host session.add(fixed_ip_ref) + LOG.warn("gave address %s to %s, %s", fixed_ip_ref['address'], instance_id, host) return fixed_ip_ref['address'] @@ -793,7 +794,7 @@ def fixed_ip_get_by_network_host(context, network_id, host): filter_by(network_id=network_id).\ filter_by(host=host).\ filter_by(deleted=False).\ - all() + first() if not rv: raise exception.FixedIpNotFoundForNetworkHost(network_id=network_id, host=host) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 8c86870f0..639941dc8 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -602,6 +602,7 @@ class FixedIp(BASE, NovaBase): # leased means dhcp bridge has leased the ip leased = Column(Boolean, default=False) reserved = Column(Boolean, default=False) + host = Column(String(255)) class FloatingIp(BASE, NovaBase): diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 8d2bc5c0b..0a7a62510 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -497,7 +497,7 @@ def ensure_bridge(bridge, interface, net_attrs=None): suffix = net_attrs['cidr'].rpartition('/')[2] out, err = _execute('sudo', 'ip', 'addr', 'add', '%s/%s' % - (net_attrs['gateway'], suffix), + (net_attrs['dhcp_server'], suffix), 'brd', net_attrs['broadcast'], 'dev', @@ -697,7 +697,7 @@ def _dnsmasq_cmd(net): '--conf-file=%s' % FLAGS.dnsmasq_config_file, '--domain=%s' % FLAGS.dhcp_domain, '--pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), - '--listen-address=%s' % net['dhcp_listen'], + '--listen-address=%s' % net['dhcp_server'], '--except-interface=lo', '--dhcp-range=%s,static,120s' % net['dhcp_start'], '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(net['cidr'])), diff --git a/nova/network/manager.py b/nova/network/manager.py index 55f81da9e..ce631ce75 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -103,7 +103,8 @@ flags.DEFINE_integer('fixed_ip_disassociate_timeout', 600, 'Seconds after which a deallocated ip is disassociated') flags.DEFINE_integer('create_unique_mac_address_attempts', 5, 'Number of attempts to create unique mac address') - +flags.DEFINE_bool('auto_assign_floating_ip', False, + 'Autoassigning floating ip to VM') flags.DEFINE_bool('use_ipv6', False, 'use the ipv6') flags.DEFINE_string('network_host', socket.gethostname(), @@ -192,7 +193,7 @@ class FloatingIP(object): # which is currently the NetworkManager version # do this first so fixed ip is already allocated ips = super(FloatingIP, self).allocate_for_instance(context, **kwargs) - if hasattr(FLAGS, 'auto_assign_floating_ip'): + if FLAGS.auto_assign_floating_ip: # allocate a floating ip (public_ip is just the address string) public_ip = self.allocate_floating_ip(context, project_id) # set auto_assigned column to true for the floating ip @@ -299,9 +300,9 @@ class NetworkManager(manager.SchedulerDependentManager): super(NetworkManager, self).__init__(service_name='network', *args, **kwargs) - def _update_dchp(self, context, network_ref): + def _update_dhcp(self, context, network_ref): """Sets the listen address before sending update to the driver.""" - network_ref['dhcp_listen'] = self._get_dhcp_ip() + network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) return self.driver.update_dhcp(context, network_ref) def _get_dhcp_ip(self, context, network_ref): @@ -313,13 +314,18 @@ class NetworkManager(manager.SchedulerDependentManager): @utils.synchronized('get_dhcp') def _sync_get_dhcp_ip(): + network_id = network_ref['id'] try: - return self.db.fixed_ip_get_by_network_host(context, - FLAGS.host) + fip = self.db.fixed_ip_get_by_network_host(context, + network_id, + self.host) + return fip['address'] except exception.FixedIpNotFoundForNetworkHost: - return self.db.fixed_ip_associate_pool(context.elevated(), - network_ref['id'], - host=FLAGS.host) + addr = self.db.fixed_ip_associate_pool(context.elevated(), + network_id, + host=self.host) + return addr + return _sync_get_dhcp_ip() else: @@ -334,6 +340,11 @@ class NetworkManager(manager.SchedulerDependentManager): ctxt = context.get_admin_context() for network in self.db.network_get_all_by_host(ctxt, self.host): self._on_set_network_host(ctxt, network['id']) + for network in self.db.network_get_all(ctxt): + # NOTE(vish): multi_host networks need to be set on all boxes + if network['multi_host']: + self._on_set_network_host(ctxt, network['id']) + def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" @@ -349,7 +360,7 @@ class NetworkManager(manager.SchedulerDependentManager): LOG.debug(_('Dissassociated %s stale fixed ip(s)'), num) # setup any new networks which have been created - self.set_network_hosts(context) + #self.set_network_hosts(context) def set_network_host(self, context, network_id): """Safely sets the host of the network.""" @@ -378,8 +389,8 @@ class NetworkManager(manager.SchedulerDependentManager): networks = self.db.network_get_all(context) # return only networks which are not vlan networks and have host set - return [network for network in networks if - not network['vlan'] and network['host']] + return [network for network in networks if not network['vlan'] + and network['host'] or network['multi_host']] def allocate_for_instance(self, context, **kwargs): """Handles allocating the various network resources for an instance. @@ -395,6 +406,7 @@ class NetworkManager(manager.SchedulerDependentManager): context=context) networks = self._get_networks_for_instance(admin_context, instance_id, project_id) + LOG.warn(networks) self._allocate_mac_addresses(context, instance_id, networks) self._allocate_fixed_ips(admin_context, instance_id, host, networks) return self.get_instance_nw_info(context, instance_id, type_id) @@ -464,6 +476,7 @@ class NetworkManager(manager.SchedulerDependentManager): info = { 'label': network['label'], 'gateway': network['gateway'], + 'dhcp_server': self._get_dhcp_ip(context, network), 'broadcast': network['broadcast'], 'mac': vif['address'], 'rxtx_cap': flavor['rxtx_cap'], @@ -569,7 +582,7 @@ class NetworkManager(manager.SchedulerDependentManager): # the code below will update the file if necessary if FLAGS.update_dhcp_on_disassociate: network_ref = self.db.fixed_ip_get_network(context, address) - network_ref['dhcp_listen'] = self._get_dhcp_ip(context, network_ref) + network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) self._update_dhcp(context, network_ref) def create_networks(self, context, label, cidr, num_networks, @@ -628,6 +641,7 @@ class NetworkManager(manager.SchedulerDependentManager): # robust solution would be to make them uniq per ip net['vpn_public_port'] = kwargs['vpn_start'] + index + net['multi_host'] = True # None if network with cidr or cidr_v6 already exists network = self.db.network_create_safe(context, net) @@ -785,6 +799,7 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): net['dhcp_start'] = FLAGS.flat_network_dhcp_start self.db.network_update(context, network_id, net) network = db.network_get(context, network_id) + network['dhcp_server'] = self._get_dhcp_ip(context, network) self.driver.ensure_bridge(network['bridge'], network['bridge_interface'], network) @@ -866,8 +881,9 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): # get networks associated with project networks = self.db.project_get_networks(context, project_id) - # return only networks which have host set - return [network for network in networks if network['host']] + # return only networks which have host set or are multi_host + return [network for network in networks + if network['host'] or network['multi_host']] def create_networks(self, context, **kwargs): """Create networks based on parameters.""" @@ -896,6 +912,7 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): db.network_update(context, network_id, net) else: address = network['vpn_public_address'] + network['dhcp_server'] = self._get_dhcp_ip(context, network) self.driver.ensure_vlan_bridge(network['vlan'], network['bridge'], network['bridge_interface'], diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 0c6eaab84..5e8fcdd2f 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -928,7 +928,6 @@ class LibvirtConnection(driver.ComputeDriver): def _get_nic_for_xml(self, network, mapping): # Assume that the gateway also acts as the dhcp server. - dhcp_server = mapping['gateway'] gateway6 = mapping.get('gateway6') mac_id = mapping['mac'].replace(':', '') @@ -951,7 +950,7 @@ class LibvirtConnection(driver.ComputeDriver): 'bridge_name': network['bridge'], 'mac_address': mapping['mac'], 'ip_address': mapping['ips'][0]['ip'], - 'dhcp_server': dhcp_server, + 'dhcp_server': mapping['dhcp_server'], 'extra_params': extra_params, } -- cgit From 8e1a74e5604e1569e314af67b72966122940330b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 16:06:20 -0700 Subject: filter the dhcp to only respond to requests from this host --- bin/nova-dhcpbridge | 2 +- nova/network/linux_net.py | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/bin/nova-dhcpbridge b/bin/nova-dhcpbridge index 6d9d85896..325642d52 100755 --- a/bin/nova-dhcpbridge +++ b/bin/nova-dhcpbridge @@ -91,7 +91,7 @@ def init_leases(interface): """Get the list of hosts for an interface.""" ctxt = context.get_admin_context() network_ref = db.network_get_by_bridge(ctxt, interface) - return linux_net.get_dhcp_leases(ctxt, network_ref['id']) + return linux_net.get_dhcp_leases(ctxt, network_ref) def main(): diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 0a7a62510..848e40643 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -551,21 +551,27 @@ def ensure_bridge(bridge, interface, net_attrs=None): bridge) -def get_dhcp_leases(context, network_id): +def get_dhcp_leases(context, network_ref): """Return a network's hosts config in dnsmasq leasefile format.""" hosts = [] - for fixed_ip_ref in db.network_get_associated_fixed_ips(context, - network_id): - hosts.append(_host_lease(fixed_ip_ref)) + for fixed_ref in db.network_get_associated_fixed_ips(context, + network_ref['id']): + host = fixed_ref['instance']['host'] + if network_ref['multi_host'] and FLAGS.host != host: + continue + hosts.append(_host_lease(fixed_ref)) return '\n'.join(hosts) -def get_dhcp_hosts(context, network_id): +def get_dhcp_hosts(context, network_ref): """Get network's hosts config in dhcp-host format.""" hosts = [] - for fixed_ip_ref in db.network_get_associated_fixed_ips(context, - network_id): - hosts.append(_host_dhcp(fixed_ip_ref)) + for fixed_ref in db.network_get_associated_fixed_ips(context, + network_ref['id']): + host = fixed_ref['instance']['host'] + if network_ref['multi_host'] and FLAGS.host != host: + continue + hosts.append(_host_dhcp(fixed_ref)) return '\n'.join(hosts) @@ -582,7 +588,7 @@ def update_dhcp(context, network_ref): """ conffile = _dhcp_file(network_ref['bridge'], 'conf') with open(conffile, 'w') as f: - f.write(get_dhcp_hosts(context, network_ref['id'])) + f.write(get_dhcp_hosts(context, network_ref)) # Make sure dnsmasq can actually read it (it setuid()s to "nobody") os.chmod(conffile, 0644) -- cgit From 53213dc4cd0f6f940d707c5d5932f4af7e5f988a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 16:22:41 -0700 Subject: add ability to set multi_host in nova-manage and remove debugging issues --- bin/nova-manage | 9 +++++++-- nova/db/sqlalchemy/api.py | 1 - nova/network/manager.py | 8 +++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 71c99138f..cd43f734f 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -558,12 +558,12 @@ class NetworkCommands(object): """Class for managing networks.""" def create(self, label=None, fixed_range=None, num_networks=None, - network_size=None, vlan_start=None, + network_size=None, multi_host=None, vlan_start=None, vpn_start=None, fixed_range_v6=None, gateway_v6=None, flat_network_bridge=None, bridge_interface=None): """Creates fixed ips for host by range arguments: label, fixed_range, [num_networks=FLAG], - [network_size=FLAG], [vlan_start=FLAG], + [network_size=FLAG], [multi_host=FLAG], [vlan_start=FLAG], [vpn_start=FLAG], [fixed_range_v6=FLAG], [gateway_v6=FLAG], [flat_network_bridge=FLAG], [bridge_interface=FLAG] If you wish to use a later argument fill in the gaps with 0s @@ -583,6 +583,10 @@ class NetworkCommands(object): num_networks = FLAGS.num_networks if not network_size: network_size = FLAGS.network_size + if not multi_host: + multi_host = FLAGS.multi_host + else: + multi_host = multi_host == 'T' if not vlan_start: vlan_start = FLAGS.vlan_start if not vpn_start: @@ -601,6 +605,7 @@ class NetworkCommands(object): net_manager.create_networks(context.get_admin_context(), label=label, cidr=fixed_range, + multi_host=multi_host, num_networks=int(num_networks), network_size=int(network_size), vlan_start=int(vlan_start), diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 9c138d2fd..472513329 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -683,7 +683,6 @@ def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): if host: fixed_ip_ref.host = host session.add(fixed_ip_ref) - LOG.warn("gave address %s to %s, %s", fixed_ip_ref['address'], instance_id, host) return fixed_ip_ref['address'] diff --git a/nova/network/manager.py b/nova/network/manager.py index ce631ce75..d799d5346 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -86,6 +86,8 @@ flags.DEFINE_integer('num_networks', 1, 'Number of networks to support') flags.DEFINE_string('vpn_ip', '$my_ip', 'Public IP for the cloudpipe VPN servers') flags.DEFINE_integer('vpn_start', 1000, 'First Vpn port for private networks') +flags.DEFINE_bool('multi_host', False, + 'Default value for multi_host in networks') flags.DEFINE_integer('network_size', 256, 'Number of addresses in each private subnet') flags.DEFINE_string('floating_range', '4.4.4.0/24', @@ -360,7 +362,7 @@ class NetworkManager(manager.SchedulerDependentManager): LOG.debug(_('Dissassociated %s stale fixed ip(s)'), num) # setup any new networks which have been created - #self.set_network_hosts(context) + self.set_network_hosts(context) def set_network_host(self, context, network_id): """Safely sets the host of the network.""" @@ -585,7 +587,7 @@ class NetworkManager(manager.SchedulerDependentManager): network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) self._update_dhcp(context, network_ref) - def create_networks(self, context, label, cidr, num_networks, + def create_networks(self, context, label, cidr, multi_host, num_networks, network_size, cidr_v6, gateway_v6, bridge, bridge_interface, **kwargs): """Create networks based on parameters.""" @@ -604,6 +606,7 @@ class NetworkManager(manager.SchedulerDependentManager): net['bridge_interface'] = bridge_interface net['dns'] = FLAGS.flat_network_dns net['cidr'] = cidr + net['multi_host'] = multi_host net['netmask'] = str(project_net.netmask) net['gateway'] = str(project_net[1]) net['broadcast'] = str(project_net.broadcast) @@ -641,7 +644,6 @@ class NetworkManager(manager.SchedulerDependentManager): # robust solution would be to make them uniq per ip net['vpn_public_port'] = kwargs['vpn_start'] + index - net['multi_host'] = True # None if network with cidr or cidr_v6 already exists network = self.db.network_create_safe(context, net) -- cgit From 11dfe937bcfa542c985a977e9ff855f717e80e69 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 16:24:43 -0700 Subject: don't set network host for multi_host networks --- nova/network/manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index d799d5346..83ab4dd72 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -378,8 +378,7 @@ class NetworkManager(manager.SchedulerDependentManager): """Set the network hosts for any networks which are unset.""" networks = self.db.network_get_all(context) for network in networks: - host = network['host'] - if not host: + if not network['multi_host'] and not network['host']: # return so worker will only grab 1 (to help scale flatter) return self.set_network_host(context, network['id']) -- cgit From 77b655cd16a265eb2b8fc369941d19890766e712 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 17:01:19 -0700 Subject: update tests --- nova/tests/__init__.py | 1 + nova/tests/test_network.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/nova/tests/__init__.py b/nova/tests/__init__.py index e4ed75d37..b885000e1 100644 --- a/nova/tests/__init__.py +++ b/nova/tests/__init__.py @@ -59,6 +59,7 @@ def setup(): network.create_networks(ctxt, label='test', cidr=FLAGS.fixed_range, + multi_host=FLAGS.multi_host, num_networks=FLAGS.num_networks, network_size=FLAGS.network_size, cidr_v6=FLAGS.fixed_range_v6, diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py index 6d5166019..390cdc003 100644 --- a/nova/tests/test_network.py +++ b/nova/tests/test_network.py @@ -44,6 +44,7 @@ class FakeModel(dict): networks = [{'id': 0, 'label': 'test0', 'injected': False, + 'multi_host': False, 'cidr': '192.168.0.0/24', 'cidr_v6': '2001:db8::/64', 'gateway_v6': '2001:db8::1', @@ -61,6 +62,7 @@ networks = [{'id': 0, {'id': 1, 'label': 'test1', 'injected': False, + 'multi_host': False, 'cidr': '192.168.1.0/24', 'cidr_v6': '2001:db9::/64', 'gateway_v6': '2001:db9::1', @@ -163,6 +165,7 @@ class FlatNetworkTestCase(test.TestCase): self.assertDictMatch(nw[0], check) check = {'broadcast': '192.168.%s.255' % i, + 'dhcp_server': '192.168.%s.1' % i, 'dns': 'DONTCARE', 'gateway': '192.168.%s.1' % i, 'gateway6': '2001:db%s::1' % i8, -- cgit From e24c1d998331444235480be241484b0408cdaf9e Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Jul 2011 17:07:44 -0700 Subject: fix libvirt test --- nova/tests/test_libvirt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index f99e1713d..6e2ec7ed6 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -58,6 +58,7 @@ def _create_network_info(count=1, ipv6=None): 'cidr': fake_ip, 'cidr_v6': fake_ip} mapping = {'mac': fake, + 'dhcp_server': fake, 'gateway': fake, 'gateway6': fake, 'ips': [{'ip': fake_ip}, {'ip': fake_ip}]} -- cgit From 0af41b8c50631252f0dfe0b11268beb3d5e49508 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 6 Jul 2011 12:58:04 -0700 Subject: removed extra comment --- nova/db/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/db/api.py b/nova/db/api.py index ee4cbad57..c9d5bc72b 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -335,7 +335,6 @@ def fixed_ip_associate(context, address, instance_id): def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): """Find free ip in network and associate it to instance or host. - If reserved is true, it will pull the ip from the reserved pool. Raises if one is not available. """ -- cgit From 5ef4e6e318caa038f2af31a930f6b2b952176661 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 8 Jul 2011 18:28:25 -0700 Subject: cleaned up on set network host to _setup_network and made networks allocate ips dynamically --- nova/db/sqlalchemy/api.py | 2 + nova/network/api.py | 3 +- nova/network/linux_net.py | 1 + nova/network/manager.py | 184 ++++++++++++++++++---------------------------- 4 files changed, 75 insertions(+), 115 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 472513329..c22ece068 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1706,7 +1706,9 @@ def network_get_all_by_host(context, host): with session.begin(): return session.query(models.Network).\ filter_by(deleted=False).\ + join(models.Network.fixed_ips).\ filter_by(host=host).\ + filter_by(deleted=False).\ all() diff --git a/nova/network/api.py b/nova/network/api.py index c0f0fb8eb..38560b037 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -174,7 +174,8 @@ class API(base.Base): def get_instance_nw_info(self, context, instance): """Returns all network info related to an instance.""" args = {'instance_id': instance['id'], - 'instance_type_id': instance['instance_type_id']} + 'instance_type_id': instance['instance_type_id'], + 'host': instance['host']} return rpc.call(context, FLAGS.network_topic, {'method': 'get_instance_nw_info', 'args': args}) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 848e40643..a8ce1c16a 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -700,6 +700,7 @@ def _dnsmasq_cmd(net): cmd = ['sudo', '-E', 'dnsmasq', '--strict-order', '--bind-interfaces', + '--interface=%s' % net['bridge'], '--conf-file=%s' % FLAGS.dnsmasq_config_file, '--domain=%s' % FLAGS.dhcp_domain, '--pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), diff --git a/nova/network/manager.py b/nova/network/manager.py index 83ab4dd72..8ef9c9a33 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -28,7 +28,6 @@ topologies. All of the network commands are issued to a subclass of :flat_network_bridge: Bridge device for simple network instances :flat_interface: FlatDhcp will bridge into this interface if set :flat_network_dns: Dns for simple network -:flat_network_dhcp_start: Dhcp start for FlatDhcp :vlan_start: First VLAN for private networks :vpn_ip: Public IP for the cloudpipe VPN servers :vpn_start: First Vpn port for private networks @@ -77,8 +76,6 @@ flags.DEFINE_bool('flat_injected', True, 'Whether to attempt to inject network setup into guest') flags.DEFINE_string('flat_interface', None, 'FlatDhcp will bridge into this interface if set') -flags.DEFINE_string('flat_network_dhcp_start', '10.0.0.2', - 'Dhcp start for FlatDhcp') flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks') flags.DEFINE_string('vlan_interface', None, 'vlans will bridge into this interface if set') @@ -134,6 +131,11 @@ class RPCAllocateFixedIP(object): # NOTE(vish): if we are not multi_host pass to the network host if not network['multi_host']: host = network['host'] + # NOTE(vish): if there is no network host, set one + if host == None: + host = rpc.call(context, FLAGS.network_topic, + {'method': 'set_network_host', + 'args': {'network_ref': network}}) if host != self.host: # need to call allocate_fixed_ip to correct network host topic = self.db.queue_get_for(context, FLAGS.network_topic, host) @@ -302,51 +304,34 @@ class NetworkManager(manager.SchedulerDependentManager): super(NetworkManager, self).__init__(service_name='network', *args, **kwargs) - def _update_dhcp(self, context, network_ref): - """Sets the listen address before sending update to the driver.""" - network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) - return self.driver.update_dhcp(context, network_ref) - - def _get_dhcp_ip(self, context, network_ref): - """Get the proper dhcp address to listen on. - - If it is a multi_host network, get the ip assigned to this host, - otherwise, assume that dhcp is listening on the gateway.""" - if network_ref['multi_host']: - - @utils.synchronized('get_dhcp') - def _sync_get_dhcp_ip(): - network_id = network_ref['id'] - try: - fip = self.db.fixed_ip_get_by_network_host(context, - network_id, - self.host) - return fip['address'] - except exception.FixedIpNotFoundForNetworkHost: - addr = self.db.fixed_ip_associate_pool(context.elevated(), - network_id, - host=self.host) - return addr - - return _sync_get_dhcp_ip() + @utils.synchronized('get_dhcp') + def _get_dhcp_ip(self, context, network_ref, host=None): + """Get the proper dhcp address to listen on.""" + if not host: + host = self.host + network_id = network_ref['id'] + try: + fip = self.db.fixed_ip_get_by_network_host(context, + network_id, + host) + return fip['address'] + except exception.FixedIpNotFoundForNetworkHost: + elevated = context.elevated() + addr = self.db.fixed_ip_associate_pool(elevated, + network_id, + host=host) + return addr - else: - return network_ref['gateway'] def init_host(self): """Do any initialization that needs to be run if this is a standalone service. """ - # Set up this host for networks in which it's already - # the designated network host. + # NOTE(vish): Set up networks for which this host already has + # an ip address. ctxt = context.get_admin_context() for network in self.db.network_get_all_by_host(ctxt, self.host): - self._on_set_network_host(ctxt, network['id']) - for network in self.db.network_get_all(ctxt): - # NOTE(vish): multi_host networks need to be set on all boxes - if network['multi_host']: - self._on_set_network_host(ctxt, network['id']) - + self._setup_network(ctxt, network) def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" @@ -361,37 +346,21 @@ class NetworkManager(manager.SchedulerDependentManager): if num: LOG.debug(_('Dissassociated %s stale fixed ip(s)'), num) - # setup any new networks which have been created - self.set_network_hosts(context) - - def set_network_host(self, context, network_id): + def set_network_host(self, context, network_ref): """Safely sets the host of the network.""" LOG.debug(_('setting network host'), context=context) host = self.db.network_set_host(context, - network_id, + network_ref['id'], self.host) - if host == self.host: - self._on_set_network_host(context, network_id) return host - def set_network_hosts(self, context): - """Set the network hosts for any networks which are unset.""" - networks = self.db.network_get_all(context) - for network in networks: - if not network['multi_host'] and not network['host']: - # return so worker will only grab 1 (to help scale flatter) - return self.set_network_host(context, network['id']) - def _get_networks_for_instance(self, context, instance_id, project_id): """Determine & return which networks an instance should connect to.""" # TODO(tr3buchet) maybe this needs to be updated in the future if # there is a better way to determine which networks # a non-vlan instance should connect to - networks = self.db.network_get_all(context) - - # return only networks which are not vlan networks and have host set - return [network for network in networks if not network['vlan'] - and network['host'] or network['multi_host']] + return [network for network in self.db.network_get_all(context) + if not network['vlan']] def allocate_for_instance(self, context, **kwargs): """Handles allocating the various network resources for an instance. @@ -410,7 +379,7 @@ class NetworkManager(manager.SchedulerDependentManager): LOG.warn(networks) self._allocate_mac_addresses(context, instance_id, networks) self._allocate_fixed_ips(admin_context, instance_id, host, networks) - return self.get_instance_nw_info(context, instance_id, type_id) + return self.get_instance_nw_info(context, instance_id, type_id, host) def deallocate_for_instance(self, context, **kwargs): """Handles deallocating various network resources for an instance. @@ -430,7 +399,7 @@ class NetworkManager(manager.SchedulerDependentManager): # deallocate vifs (mac addresses) self.db.virtual_interface_delete_by_instance(context, instance_id) - def get_instance_nw_info(self, context, instance_id, instance_type_id): + def get_instance_nw_info(self, context, instance_id, instance_type_id, host): """Creates network info list for instance. called by allocate_for_instance and netowrk_api @@ -474,10 +443,16 @@ class NetworkManager(manager.SchedulerDependentManager): 'cidr': network['cidr'], 'cidr_v6': network['cidr_v6'], 'injected': network['injected']} + if network['multi_host']: + dhcp_server = self._get_dhcp_ip(context, network, host) + else: + dhcp_server = self._get_dhcp_ip(context, + network, + network['host']) info = { 'label': network['label'], 'gateway': network['gateway'], - 'dhcp_server': self._get_dhcp_ip(context, network), + 'dhcp_server': dhcp_server, 'broadcast': network['broadcast'], 'mac': vif['address'], 'rxtx_cap': flavor['rxtx_cap'], @@ -537,6 +512,7 @@ class NetworkManager(manager.SchedulerDependentManager): values = {'allocated': True, 'virtual_interface_id': vif['id']} self.db.fixed_ip_update(context, address, values) + self._setup_network(context, network) return address def deallocate_fixed_ip(self, context, address, **kwargs): @@ -583,8 +559,7 @@ class NetworkManager(manager.SchedulerDependentManager): # the code below will update the file if necessary if FLAGS.update_dhcp_on_disassociate: network_ref = self.db.fixed_ip_get_network(context, address) - network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) - self._update_dhcp(context, network_ref) + self._setup_network(context, network_ref) def create_networks(self, context, label, cidr, multi_host, num_networks, network_size, cidr_v6, gateway_v6, bridge, @@ -685,8 +660,8 @@ class NetworkManager(manager.SchedulerDependentManager): """Calls allocate_fixed_ip once for each network.""" raise NotImplementedError() - def _on_set_network_host(self, context, network_id): - """Called when this host becomes the host for a network.""" + def _setup_network(self, context, network_ref): + """Sets up network on this host.""" raise NotImplementedError() def setup_compute_network(self, context, instance_id): @@ -746,12 +721,12 @@ class FlatManager(NetworkManager): """ pass - def _on_set_network_host(self, context, network_id): - """Called when this host becomes the host for a network.""" + def _setup_network(self, context, network_ref): + """Setup Network on this host.""" net = {} net['injected'] = FLAGS.flat_injected net['dns'] = FLAGS.flat_network_dns - self.db.network_update(context, network_id, net) + self.db.network_update(context, network_ref['id'], net) class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): @@ -786,31 +761,18 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): self.driver.ensure_bridge(network['bridge'], network['bridge_interface']) - def allocate_fixed_ip(self, context, instance_id, network): - """Allocate flat_network fixed_ip, then setup dhcp for this network.""" - address = super(FlatDHCPManager, self).allocate_fixed_ip(context, - instance_id, - network) - if not FLAGS.fake_network: - self._update_dhcp(context, network) - - def _on_set_network_host(self, context, network_id): - """Called when this host becomes the host for a project.""" - net = {} - net['dhcp_start'] = FLAGS.flat_network_dhcp_start - self.db.network_update(context, network_id, net) - network = db.network_get(context, network_id) - network['dhcp_server'] = self._get_dhcp_ip(context, network) - self.driver.ensure_bridge(network['bridge'], - network['bridge_interface'], - network) + def _setup_network(self, context, network_ref): + """Sets up network on this host.""" + network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) + self.driver.ensure_bridge(network_ref['bridge'], + network_ref['bridge_interface'], + network_ref) if not FLAGS.fake_network: - network_ref = self.db.network_get(context, network_id) - self._update_dhcp(context, network_ref) + self.driver.update_dhcp(context, network_ref) if(FLAGS.use_ipv6): self.driver.update_ra(context, network_ref) gateway = utils.get_my_linklocal(network_ref['bridge']) - self.db.network_update(context, network_id, + self.db.network_update(context, network_ref['id'], {'gateway_v6': gateway}) @@ -859,8 +821,8 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): values = {'allocated': True, 'virtual_interface_id': vif['id']} self.db.fixed_ip_update(context, address, values) - if not FLAGS.fake_network: - self._update_dhcp(context, network) + self._setup_network(context, network) + return address def add_network_to_project(self, context, project_id): """Force adds another network to a project.""" @@ -880,11 +842,7 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): def _get_networks_for_instance(self, context, instance_id, project_id): """Determine which networks an instance should connect to.""" # get networks associated with project - networks = self.db.project_get_networks(context, project_id) - - # return only networks which have host set or are multi_host - return [network for network in networks - if network['host'] or network['multi_host']] + return self.db.project_get_networks(context, project_id) def create_networks(self, context, **kwargs): """Create networks based on parameters.""" @@ -903,36 +861,34 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): NetworkManager.create_networks(self, context, vpn=True, **kwargs) - def _on_set_network_host(self, context, network_id): - """Called when this host becomes the host for a network.""" - network = self.db.network_get(context, network_id) - if not network['vpn_public_address']: + def _setup_network(self, context, network_ref): + """Sets up network on this host.""" + network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) + if not network_ref['vpn_public_address']: net = {} address = FLAGS.vpn_ip net['vpn_public_address'] = address - db.network_update(context, network_id, net) + network_ref = db.network_update(context, network_ref, net) else: - address = network['vpn_public_address'] - network['dhcp_server'] = self._get_dhcp_ip(context, network) - self.driver.ensure_vlan_bridge(network['vlan'], - network['bridge'], - network['bridge_interface'], - network) + address = network_ref['vpn_public_address'] + self.driver.ensure_vlan_bridge(network_ref['vlan'], + network_ref['bridge'], + network_ref['bridge_interface'], + network_ref) # NOTE(vish): only ensure this forward if the address hasn't been set # manually. if address == FLAGS.vpn_ip and hasattr(self.driver, "ensure_vlan_forward"): self.driver.ensure_vlan_forward(FLAGS.vpn_ip, - network['vpn_public_port'], - network['vpn_private_address']) + network_ref['vpn_public_port'], + network_ref['vpn_private_address']) if not FLAGS.fake_network: - network_ref = self.db.network_get(context, network_id) - self._update_dhcp(context, network_ref) + self.driver.update_dhcp(context, network_ref) if(FLAGS.use_ipv6): self.driver.update_ra(context, network_ref) gateway = utils.get_my_linklocal(network_ref['bridge']) - self.db.network_update(context, network_id, + self.db.network_update(context, network_ref['id'], {'gateway_v6': gateway}) @property -- cgit From 71cbb30cfaf9b38786949fbf6314f0284e9a7efc Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 8 Jul 2011 18:45:13 -0700 Subject: make sure that old networks get the same dhcp ip so we don't break existing deployments --- nova/db/sqlalchemy/api.py | 7 ++++++- nova/network/manager.py | 8 +++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index c22ece068..8b7ab8cbd 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1704,10 +1704,15 @@ def network_get_all_by_instance(_context, instance_id): def network_get_all_by_host(context, host): session = get_session() with session.begin(): + # NOTE(vish): return networks that have host set + # or that have a fixed ip with host set + host_filter = or_(models.Network.host == host, + models.FixedIp.host == host) + return session.query(models.Network).\ filter_by(deleted=False).\ join(models.Network.fixed_ips).\ - filter_by(host=host).\ + filter(host_filter).\ filter_by(deleted=False).\ all() diff --git a/nova/network/manager.py b/nova/network/manager.py index 8ef9c9a33..dac42e7ec 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -307,6 +307,10 @@ class NetworkManager(manager.SchedulerDependentManager): @utils.synchronized('get_dhcp') def _get_dhcp_ip(self, context, network_ref, host=None): """Get the proper dhcp address to listen on.""" + # NOTE(vish): this is for compatibility + if not network_ref['multi_host']: + return network_ref['gateway'] + if not host: host = self.host network_id = network_ref['id'] @@ -317,11 +321,9 @@ class NetworkManager(manager.SchedulerDependentManager): return fip['address'] except exception.FixedIpNotFoundForNetworkHost: elevated = context.elevated() - addr = self.db.fixed_ip_associate_pool(elevated, + return self.db.fixed_ip_associate_pool(elevated, network_id, host=host) - return addr - def init_host(self): """Do any initialization that needs to be run if this is a -- cgit From 4858a276a4cb779de55d987f2b3c37db5bf24492 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 8 Jul 2011 18:58:24 -0700 Subject: fix tests --- nova/tests/__init__.py | 2 +- nova/tests/test_network.py | 16 +--------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/nova/tests/__init__.py b/nova/tests/__init__.py index b885000e1..7df6c06eb 100644 --- a/nova/tests/__init__.py +++ b/nova/tests/__init__.py @@ -69,7 +69,7 @@ def setup(): vpn_start=FLAGS.vpn_start, vlan_start=FLAGS.vlan_start) for net in db.network_get_all(ctxt): - network.set_network_host(ctxt, net['id']) + network.set_network_host(ctxt, net) cleandb = os.path.join(FLAGS.state_path, FLAGS.sqlite_clean_db) shutil.copyfile(testdb, cleandb) diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py index 390cdc003..1740d4f54 100644 --- a/nova/tests/test_network.py +++ b/nova/tests/test_network.py @@ -123,20 +123,6 @@ class FlatNetworkTestCase(test.TestCase): self.network = network_manager.FlatManager(host=HOST) self.network.db = db - def test_set_network_hosts(self): - self.mox.StubOutWithMock(db, 'network_get_all') - self.mox.StubOutWithMock(db, 'network_set_host') - self.mox.StubOutWithMock(db, 'network_update') - - db.network_get_all(mox.IgnoreArg()).AndReturn([networks[0]]) - db.network_set_host(mox.IgnoreArg(), - networks[0]['id'], - mox.IgnoreArg()).AndReturn(HOST) - db.network_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.mox.ReplayAll() - - self.network.set_network_hosts(None) - def test_get_instance_nw_info(self): self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance') self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance') @@ -150,7 +136,7 @@ class FlatNetworkTestCase(test.TestCase): mox.IgnoreArg()).AndReturn(flavor) self.mox.ReplayAll() - nw_info = self.network.get_instance_nw_info(None, 0, 0) + nw_info = self.network.get_instance_nw_info(None, 0, 0, None) self.assertTrue(nw_info) -- cgit From 67e5492d6723a00b0ad5d7e8c44f5762a9b0a206 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 18 Jul 2011 12:16:10 -0700 Subject: fix issues that were breaking vlan mode --- bin/nova-manage | 8 ++++---- nova/db/sqlalchemy/api.py | 4 +--- nova/network/manager.py | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index cd43f734f..a37d68f42 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -473,7 +473,7 @@ class ProjectCommands(object): except db.api.NoMoreNetworks: print _('No more networks available. If this is a new ' 'installation, you need\nto call something like this:\n\n' - ' nova-manage network create 10.0.0.0/8 10 64\n\n') + ' nova-manage network create pvt 10.0.0.0/8 10 64\n\n') except exception.ProcessExecutionError, e: print e print _("The above error may show that the certificate db has not " @@ -566,9 +566,9 @@ class NetworkCommands(object): [network_size=FLAG], [multi_host=FLAG], [vlan_start=FLAG], [vpn_start=FLAG], [fixed_range_v6=FLAG], [gateway_v6=FLAG], [flat_network_bridge=FLAG], [bridge_interface=FLAG] - If you wish to use a later argument fill in the gaps with 0s - Ex: network create private 10.0.0.0/8 1 15 0 0 0 0 xenbr1 eth1 - network create private 10.0.0.0/8 1 15 + If you wish to use a later argument fill in the gaps with ""s + Ex: network create private 10.0.0.0/8 1 16 T "" "" "" "" xenbr1 eth1 + network create private 10.0.0.0/8 1 16 """ if not label: msg = _('a label (ex: public) is required to create networks.') diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 8b7ab8cbd..a90b61e39 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1480,8 +1480,6 @@ def network_associate(context, project_id, force=False): called by project_get_networks under certain conditions and network manager add_network_to_project() - only associates projects with networks that have configured hosts - only associate if the project doesn't already have a network or if force is True @@ -1497,7 +1495,6 @@ def network_associate(context, project_id, force=False): def network_query(project_filter): return session.query(models.Network).\ filter_by(deleted=False).\ - filter(models.Network.host != None).\ filter_by(project_id=project_filter).\ with_lockmode('update').\ first() @@ -1745,6 +1742,7 @@ def network_update(context, network_id, values): network_ref = network_get(context, network_id, session=session) network_ref.update(values) network_ref.save(session=session) + return network_ref ################### diff --git a/nova/network/manager.py b/nova/network/manager.py index dac42e7ec..4568d0fa7 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -870,7 +870,7 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): net = {} address = FLAGS.vpn_ip net['vpn_public_address'] = address - network_ref = db.network_update(context, network_ref, net) + network_ref = db.network_update(context, network_ref['id'], net) else: address = network_ref['vpn_public_address'] self.driver.ensure_vlan_bridge(network_ref['vlan'], -- cgit From 55de6a262f40024c2c9c8f7c6e84c56eaa14d206 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 18 Jul 2011 17:34:36 -0400 Subject: adding fixed_ipv6 property to VirtualInterface model; exposing ipv6 in api --- nova/api/openstack/views/addresses.py | 22 ++++++++++++++++++---- nova/db/sqlalchemy/api.py | 2 +- nova/db/sqlalchemy/models.py | 13 +++++++++++++ nova/tests/api/openstack/test_servers.py | 6 ++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py index a242efa45..77310e4b1 100644 --- a/nova/api/openstack/views/addresses.py +++ b/nova/api/openstack/views/addresses.py @@ -50,22 +50,36 @@ class ViewBuilderV11(ViewBuilder): if network_label not in networks: networks[network_label] = [] - networks[network_label].extend(self._extract_ipv4(interface)) + ip_addresses = list(self._extract_ipv4_addresses(interface)) + + ipv6_address = self._extract_ipv6_address(interface) + if ipv6_address is not None: + ip_addresses.append(ipv6_address) + + networks[network_label].extend(ip_addresses) return networks def build_network(self, interfaces, network_label): for interface in interfaces: if interface['network']['label'] == network_label: - ips = self._extract_ipv4(interface) - return {network_label: list(ips)} + 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} return None - def _extract_ipv4(self, interface): + 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/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index a831516a8..8a4bd11b7 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -949,8 +949,8 @@ def virtual_interface_get_by_instance(context, instance_id): options(joinedload('instance')).\ options(joinedload('fixed_ips')).\ all() - return vif_refs + return vif_refs @require_context def virtual_interface_get_by_instance_and_network(context, instance_id, diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index d29d3d6f1..def33d056 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -31,6 +31,7 @@ from nova.db.sqlalchemy.session import get_session from nova import auth from nova import exception from nova import flags +from nova import ipv6 from nova import utils @@ -575,6 +576,18 @@ class VirtualInterface(BASE, NovaBase): instance_id = Column(Integer, ForeignKey('instances.id'), nullable=False) instance = relationship(Instance, backref=backref('virtual_interfaces')) + @property + def fixed_ipv6(self): + cidr_v6 = self.network.cidr_v6 + if cidr_v6 is None: + ipv6_address = None + else: + project_id = self.instance.project_id + mac = self.address + ipv6_address = ipv6.to_global(cidr_v6, mac, project_id) + + return ipv6_address + # TODO(vish): can these both come from the same baseclass? class FixedIp(BASE, NovaBase): diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 1577c922b..467aa907c 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -447,6 +447,7 @@ class ServersTest(test.TestCase): {'address': '172.19.0.1'}, {'address': '172.19.0.2'}, ], + 'fixed_ipv6': '2001:4860::12', }, ] new_return_server = return_server_with_interfaces(interfaces) @@ -467,6 +468,7 @@ class ServersTest(test.TestCase): 'network_2': [ {'addr': '172.19.0.1', 'version': 4}, {'addr': '172.19.0.2', 'version': 4}, + {'addr': '2001:4860::12', 'version': 6}, ], } @@ -492,6 +494,7 @@ class ServersTest(test.TestCase): }, {'address': '172.19.0.2'}, ], + 'fixed_ipv6': '2001:4860::12', }, ] @@ -514,6 +517,7 @@ class ServersTest(test.TestCase): {'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'}, ], }, } @@ -540,6 +544,7 @@ class ServersTest(test.TestCase): }, {'address': '172.19.0.2'}, ], + 'fixed_ipv6': '2001:4860::12', }, ] _return_vifs = return_virtual_interface_by_instance(interfaces) @@ -556,6 +561,7 @@ class ServersTest(test.TestCase): {'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) -- cgit -- cgit From acf3e24c4b6d782543c1b8cdc4d25c9d129ecb95 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 18 Jul 2011 17:45:39 -0400 Subject: pep8 cleanup --- nova/db/sqlalchemy/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 8a4bd11b7..a831516a8 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -949,9 +949,9 @@ def virtual_interface_get_by_instance(context, instance_id): options(joinedload('instance')).\ options(joinedload('fixed_ips')).\ all() - return vif_refs + @require_context def virtual_interface_get_by_instance_and_network(context, instance_id, network_id): -- cgit From 87434352e7dc165d269b5831af8ff690fcdbdb5b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 18 Jul 2011 17:17:30 -0700 Subject: change migration number --- .../migrate_repo/versions/032_ha_network.py | 37 ---------------------- .../migrate_repo/versions/033_ha_network.py | 37 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py b/nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py deleted file mode 100644 index 316c36cbc..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/032_ha_network.py +++ /dev/null @@ -1,37 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 MORITA Kazutaka. -# All Rights Reserved. -# -# 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, Table, MetaData, Boolean, String - -meta = MetaData() - -fixed_ips_host = Column('host', String(255)) - -networks_multi_host = Column('multi_host', Boolean, default=False) - - -def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata - meta.bind = migrate_engine - - # Add columns to existing tables - fixed_ips = Table('fixed_ips', meta, autoload=True) - fixed_ips.create_column(fixed_ips_host) - - networks = Table('networks', meta, autoload=True) - networks.create_column(networks_multi_host) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py b/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py new file mode 100644 index 000000000..316c36cbc --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py @@ -0,0 +1,37 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 MORITA Kazutaka. +# All Rights Reserved. +# +# 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, Table, MetaData, Boolean, String + +meta = MetaData() + +fixed_ips_host = Column('host', String(255)) + +networks_multi_host = Column('multi_host', Boolean, default=False) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + # Add columns to existing tables + fixed_ips = Table('fixed_ips', meta, autoload=True) + fixed_ips.create_column(fixed_ips_host) + + networks = Table('networks', meta, autoload=True) + networks.create_column(networks_multi_host) -- cgit From 89ead61d521c8f585732d50b8d3d31361d7c1d82 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 18 Jul 2011 17:26:38 -0700 Subject: fix bad merge --- nova/network/manager.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index a411ad9ff..360e08ceb 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -776,14 +776,6 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): self.driver.metadata_forward() - def allocate_fixed_ip(self, context, instance_id, network, **kwargs): - """Allocate flat_network fixed_ip, then setup dhcp for this network.""" - address = super(FlatDHCPManager, self).allocate_fixed_ip(context, - instance_id, - network) - if not FLAGS.fake_network: - self.driver.update_dhcp(context, network['id']) - def setup_compute_network(self, context, instance_id): """Sets up matching networks for compute hosts. -- cgit From 39701e13188275fc2f798a790e2edc4488ecb3e4 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 18 Jul 2011 17:35:14 -0700 Subject: missed the vpn kwarg in rpc --- nova/network/manager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index 360e08ceb..7a7520f5d 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -156,12 +156,13 @@ class RPCAllocateFixedIP(object): # wait for all of the allocates (if any) to finish green_pool.waitall() - def _rpc_allocate_fixed_ip(self, context, instance_id, network_id): + def _rpc_allocate_fixed_ip(self, context, instance_id, network_id, + **kwargs): """Sits in between _allocate_fixed_ips and allocate_fixed_ip to perform network lookup on the far side of rpc. """ network = self.db.network_get(context, network_id) - self.allocate_fixed_ip(context, instance_id, network) + self.allocate_fixed_ip(context, instance_id, network, **kwargs) class FloatingIP(object): -- cgit From 82e2eeb5a097f1c3c6cb56fc3dfa862575f5da9a Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Jul 2011 09:36:37 -0400 Subject: respecting use_ipv6 flag if set to False --- nova/api/openstack/views/addresses.py | 10 ++++--- nova/tests/api/openstack/test_servers.py | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py index 77310e4b1..ddbf7a144 100644 --- a/nova/api/openstack/views/addresses.py +++ b/nova/api/openstack/views/addresses.py @@ -15,9 +15,12 @@ # License for the specific language governing permissions and limitations # under the License. +from nova import flags from nova import utils from nova.api.openstack import common +FLAGS = flags.FLAGS + class ViewBuilder(object): """Models a server addresses response as a python dictionary.""" @@ -52,9 +55,10 @@ class ViewBuilderV11(ViewBuilder): ip_addresses = list(self._extract_ipv4_addresses(interface)) - ipv6_address = self._extract_ipv6_address(interface) - if ipv6_address is not None: - ip_addresses.append(ipv6_address) + 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) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 467aa907c..3fc38b73c 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -433,6 +433,7 @@ class ServersTest(test.TestCase): self.assertEquals(ip.getAttribute('addr'), private) def test_get_server_by_id_with_addresses_v1_1(self): + FLAGS.use_ipv6 = True interfaces = [ { 'network': {'label': 'network_1'}, @@ -474,7 +475,50 @@ class ServersTest(test.TestCase): self.assertEqual(addresses, expected) + def test_get_server_by_id_with_addresses_v1_1_ipv6_disabled(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_interfaces(interfaces) + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + + req = webob.Request.blank('/v1.1/servers/1') + res = req.get_response(fakes.wsgi_app()) + + res_dict = json.loads(res.body) + self.assertEqual(res_dict['server']['id'], 1) + self.assertEqual(res_dict['server']['name'], 'server1') + addresses = res_dict['server']['addresses'] + expected = { + 'network_1': [ + {'addr': '192.168.0.3', 'version': 4}, + {'addr': '192.168.0.4', 'version': 4}, + ], + 'network_2': [ + {'addr': '172.19.0.1', 'version': 4}, + {'addr': '172.19.0.2', 'version': 4}, + ], + } + + self.assertEqual(addresses, expected) + def test_get_server_addresses_v1_1(self): + FLAGS.use_ipv6 = True interfaces = [ { 'network': {'label': 'network_1'}, @@ -525,6 +569,7 @@ class ServersTest(test.TestCase): self.assertEqual(res_dict, expected) def test_get_server_addresses_single_network_v1_1(self): + FLAGS.use_ipv6 = True interfaces = [ { 'network': {'label': 'network_1'}, -- cgit From 9febf1eec69708d8c54b6348e882da384d8b42a9 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 19 Jul 2011 12:26:41 -0400 Subject: correct broken logic for lxc and uml to avoid adding vnc arguments (LP: #812553) This fixes the logic, so that lxc and uml will not get vnc arguments added to their libvirt xml. To also seems more readable to me. --- nova/virt/libvirt/connection.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 977bb7dfe..56aaa6c50 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -1014,8 +1014,7 @@ class LibvirtConnection(driver.ComputeDriver): 'ebs_root': ebs_root, 'volumes': block_device_mapping} - if FLAGS.vnc_enabled: - if FLAGS.libvirt_type != 'lxc' or FLAGS.libvirt_type != 'uml': + if FLAGS.vnc_enabled and FLAGS.libvirt_type not in ('lxc', 'uml'): xml_info['vncserver_host'] = FLAGS.vncserver_host xml_info['vnc_keymap'] = FLAGS.vnc_keymap if not rescue: -- cgit From cfa755c6f3bbcc3dd376d66b3722021ad4b4ec62 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Jul 2011 10:00:00 -0700 Subject: add downgrade --- .../db/sqlalchemy/migrate_repo/versions/033_ha_network.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py b/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py index 316c36cbc..3a5f7eba8 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py @@ -1,6 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2011 MORITA Kazutaka. +# Copyright (c) 2011 OpenStack, LLC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -25,13 +25,20 @@ networks_multi_host = Column('multi_host', Boolean, default=False) def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata meta.bind = migrate_engine - # Add columns to existing tables fixed_ips = Table('fixed_ips', meta, autoload=True) fixed_ips.create_column(fixed_ips_host) networks = Table('networks', meta, autoload=True) networks.create_column(networks_multi_host) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + + fixed_ips = Table('fixed_ips', meta, autoload=True) + fixed_ips.drop_column(fixed_ips_host) + + networks = Table('networks', meta, autoload=True) + networks.drop_column(networks_multi_host) -- cgit From 36f8bd801bc8a7696e7850613747a5f7ae8c487a Mon Sep 17 00:00:00 2001 From: Adam Gandelman Date: Tue, 19 Jul 2011 10:19:10 -0700 Subject: Fix unchecked key reference to mappings['gateway6']. Fixes LP #807764. --- nova/virt/libvirt/connection.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 977bb7dfe..572be38d8 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -881,9 +881,12 @@ class LibvirtConnection(driver.ComputeDriver): address = mapping['ips'][0]['ip'] netmask = mapping['ips'][0]['netmask'] address_v6 = None + gateway_v6 = None + netmask_v6 = None if FLAGS.use_ipv6: address_v6 = mapping['ip6s'][0]['ip'] netmask_v6 = mapping['ip6s'][0]['netmask'] + gateway_v6 = mapping['gateway6'] net_info = {'name': 'eth%d' % ifc_num, 'address': address, 'netmask': netmask, @@ -891,7 +894,7 @@ class LibvirtConnection(driver.ComputeDriver): 'broadcast': mapping['broadcast'], 'dns': mapping['dns'], 'address_v6': address_v6, - 'gateway6': mapping['gateway6'], + 'gateway6': gateway_v6, 'netmask_v6': netmask_v6} nets.append(net_info) -- cgit From d8132fd792d3316420033435a43604f7e09cfcdb Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Tue, 19 Jul 2011 14:29:44 -0500 Subject: better handling of periodic network host setup --- nova/network/manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index 24736f53d..33cf86e37 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -334,21 +334,21 @@ class NetworkManager(manager.SchedulerDependentManager): self.host) if host == self.host: self._on_set_network_host(context, network_id) - return host def set_network_hosts(self, context): """Set the network hosts for any networks which are unset.""" try: networks = self.db.network_get_all(context) except exception.NoNetworksFound: - # we don't care if no networks are found - pass + # no networks found, nothing to do + return for network in networks: host = network['host'] if not host: - # return so worker will only grab 1 (to help scale flatter) - return self.set_network_host(context, network['id']) + # break so worker will only grab 1 (to help scale flatter) + self.set_network_host(context, network['id']) + break def _get_networks_for_instance(self, context, instance_id, project_id): """Determine & return which networks an instance should connect to.""" -- cgit From 686cd2c5b50b1a50bd3c942b8dde960b7b5fb5d8 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 20 Jul 2011 14:08:38 +0000 Subject: Some older windows agents will crash if the public key for the keyinit command is not a string. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index b8a1b936a..6c6b0930f 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -72,7 +72,9 @@ def key_init(self, arg_dict): info to be passed, such as passwords. Returns the shared secret key value. """ - pub = int(arg_dict["pub"]) + # WARNING: Some older Windows agents will crash if the public key isn't + # a string + pub = arg_dict["pub"] arg_dict["value"] = json.dumps({"name": "keyinit", "value": pub}) request_id = arg_dict["id"] arg_dict["path"] = "data/host/%s" % request_id -- cgit From 6a88f87c11472484f35e1116f107410c031b6838 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 20 Jul 2011 15:16:36 +0000 Subject: Fix permissions for plugins --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/migration | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/glance mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/migration mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore mode change 100755 => 100644 plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance old mode 100644 new mode 100755 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration old mode 100644 new mode 100755 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore b/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore old mode 100644 new mode 100755 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py old mode 100755 new mode 100644 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost old mode 100644 new mode 100755 -- cgit From e65a9fe5827e0d5961e618a3163382c2ad02274c Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 20 Jul 2011 12:17:44 -0400 Subject: correct indentation --- nova/virt/libvirt/connection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 56aaa6c50..4905d931a 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -1015,8 +1015,8 @@ class LibvirtConnection(driver.ComputeDriver): 'volumes': block_device_mapping} if FLAGS.vnc_enabled and FLAGS.libvirt_type not in ('lxc', 'uml'): - xml_info['vncserver_host'] = FLAGS.vncserver_host - xml_info['vnc_keymap'] = FLAGS.vnc_keymap + xml_info['vncserver_host'] = FLAGS.vncserver_host + xml_info['vnc_keymap'] = FLAGS.vnc_keymap if not rescue: if instance['kernel_id']: xml_info['kernel'] = xml_info['basepath'] + "/kernel" -- cgit From 6178861ffdbc183962d8e519d2147b71ca3f2db8 Mon Sep 17 00:00:00 2001 From: Adam Gandelman Date: Wed, 20 Jul 2011 10:03:56 -0700 Subject: Update Authors file --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 8ffb7d8d4..95b6906ce 100644 --- a/Authors +++ b/Authors @@ -1,3 +1,4 @@ +Adam Gandelman Alex Meade Alexander Sakhnov Andrey Brindeyev -- cgit From 1b423b464e0dd849d1a6dafde08b3c4420217151 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 20 Jul 2011 13:52:22 -0400 Subject: Set the status_int on fault wrapped exceptions. Fixes WSGI logging issues when faults are returned. Updated so that webob exceptions aren't used for the happy path (HTTP 200 responses). We now return a proper webob object response in these cases. This fixes issues where HTML/XML would get returned with the old style happy path exceptions. --- nova/api/openstack/consoles.py | 3 +- nova/api/openstack/contrib/multinic.py | 5 ++-- nova/api/openstack/contrib/volumes.py | 5 ++-- nova/api/openstack/faults.py | 1 + nova/api/openstack/servers.py | 49 ++++++++++++++++----------------- nova/tests/api/openstack/test_faults.py | 5 ++++ 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/nova/api/openstack/consoles.py b/nova/api/openstack/consoles.py index 7a43fba96..9c7b37f0d 100644 --- a/nova/api/openstack/consoles.py +++ b/nova/api/openstack/consoles.py @@ -16,6 +16,7 @@ # under the License. from webob import exc +import webob from nova import console from nova import exception @@ -86,7 +87,7 @@ class Controller(object): int(id)) except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def create_resource(): diff --git a/nova/api/openstack/contrib/multinic.py b/nova/api/openstack/contrib/multinic.py index 841061721..da8dcee5d 100644 --- a/nova/api/openstack/contrib/multinic.py +++ b/nova/api/openstack/contrib/multinic.py @@ -16,6 +16,7 @@ """The multinic extension.""" from webob import exc +import webob from nova import compute from nova import log as logging @@ -103,7 +104,7 @@ class Multinic(extensions.ExtensionDescriptor): except Exception, e: LOG.exception(_("Error in addFixedIp %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _remove_fixed_ip(self, input_dict, req, id): """Removes an IP from an instance.""" @@ -122,4 +123,4 @@ class Multinic(extensions.ExtensionDescriptor): except Exception, e: LOG.exception(_("Error in removeFixedIp %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) diff --git a/nova/api/openstack/contrib/volumes.py b/nova/api/openstack/contrib/volumes.py index e5e2c5b50..827e36097 100644 --- a/nova/api/openstack/contrib/volumes.py +++ b/nova/api/openstack/contrib/volumes.py @@ -16,6 +16,7 @@ """The volumes extension.""" from webob import exc +import webob from nova import compute from nova import exception @@ -104,7 +105,7 @@ class VolumeController(object): self.volume_api.delete(context, volume_id=id) except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def index(self, req): """Returns a summary list of volumes.""" @@ -279,7 +280,7 @@ class VolumeAttachmentController(object): self.compute_api.detach_volume(context, volume_id=volume_id) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _items(self, req, server_id, entity_maker): """Returns a list of attachments, transformed through entity_maker.""" diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py index b9a23c126..24cde69e4 100644 --- a/nova/api/openstack/faults.py +++ b/nova/api/openstack/faults.py @@ -40,6 +40,7 @@ class Fault(webob.exc.HTTPException): def __init__(self, exception): """Create a Fault for the given webob.exc.exception.""" self.wrapped_exc = exception + self.status_int = exception.status_int @webob.dec.wsgify(RequestClass=wsgi.Request) def __call__(self, req): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 93f8e832c..3b3d0685d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -17,6 +17,7 @@ import base64 import traceback from webob import exc +import webob from nova import compute from nova import db @@ -189,7 +190,7 @@ class Controller(object): except Exception, e: LOG.exception(_("Error in revert-resize %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _action_resize(self, input_dict, req, id): return exc.HTTPNotImplemented() @@ -207,7 +208,7 @@ class Controller(object): except Exception, e: LOG.exception(_("Error in reboot %s"), e) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _action_migrate(self, input_dict, req, id): try: @@ -215,7 +216,7 @@ class Controller(object): except Exception, e: LOG.exception(_("Error in migrate %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def lock(self, req, id): @@ -231,7 +232,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::lock %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def unlock(self, req, id): @@ -247,7 +248,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::unlock %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def get_lock(self, req, id): @@ -262,7 +263,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::get_lock %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def reset_network(self, req, id, body): @@ -277,7 +278,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::reset_network %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def inject_network_info(self, req, id, body): @@ -292,7 +293,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::inject_network_info %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def pause(self, req, id, body): @@ -304,7 +305,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::pause %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def unpause(self, req, id, body): @@ -316,7 +317,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("Compute.api::unpause %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def suspend(self, req, id, body): @@ -328,7 +329,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("compute.api::suspend %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def resume(self, req, id, body): @@ -340,7 +341,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("compute.api::resume %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def rescue(self, req, id): @@ -352,7 +353,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("compute.api::rescue %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def unrescue(self, req, id): @@ -364,7 +365,7 @@ class Controller(object): readable = traceback.format_exc() LOG.exception(_("compute.api::unrescue %s"), readable) return faults.Fault(exc.HTTPUnprocessableEntity()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def get_ajax_console(self, req, id): @@ -374,7 +375,7 @@ class Controller(object): int(id)) except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def get_vnc_console(self, req, id): @@ -384,7 +385,7 @@ class Controller(object): int(id)) except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) @scheduler_api.redirect_handler def diagnostics(self, req, id): @@ -416,7 +417,7 @@ class ControllerV10(Controller): self.compute_api.delete(req.environ['nova.context'], id) except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _image_ref_from_req_data(self, data): return data['server']['imageId'] @@ -450,7 +451,7 @@ class ControllerV10(Controller): except Exception, e: LOG.exception(_("Error in resize %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _action_rebuild(self, info, request, instance_id): context = request.environ['nova.context'] @@ -470,9 +471,7 @@ class ControllerV10(Controller): LOG.debug(msg) return faults.Fault(exc.HTTPConflict(explanation=msg)) - response = exc.HTTPAccepted() - response.empty_body = True - return response + return webob.Response(status_int=202) def _get_server_admin_password(self, server): """ Determine the admin password for a server on creation """ @@ -519,7 +518,7 @@ class ControllerV11(Controller): msg = _("Invalid adminPass") return exc.HTTPBadRequest(explanation=msg) self.compute_api.set_admin_password(context, id, password) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _limit_items(self, items, req): return common.limited_by_marker(items, req) @@ -565,7 +564,7 @@ class ControllerV11(Controller): except Exception, e: LOG.exception(_("Error in resize %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return exc.HTTPAccepted() + return webob.Response(status_int=202) def _action_rebuild(self, info, request, instance_id): context = request.environ['nova.context'] @@ -594,9 +593,7 @@ class ControllerV11(Controller): LOG.debug(msg) return faults.Fault(exc.HTTPConflict(explanation=msg)) - response = exc.HTTPAccepted() - response.empty_body = True - return response + return webob.Response(status_int=202) def get_default_xmlns(self, req): return common.XML_NS_V11 diff --git a/nova/tests/api/openstack/test_faults.py b/nova/tests/api/openstack/test_faults.py index 4d86ffb26..927009e77 100644 --- a/nova/tests/api/openstack/test_faults.py +++ b/nova/tests/api/openstack/test_faults.py @@ -139,3 +139,8 @@ class TestFaults(test.TestCase): self.assertEqual(resp.content_type, "application/xml") self.assertEqual(resp.status_int, 404) self.assertTrue('whut?' in resp.body) + + def test_fault_has_status_int(self): + """Ensure the status_int is set correctly on faults""" + fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='what?')) + self.assertEqual(fault.status_int, 400) -- cgit From a01afcd449d7f1f6ffd74d9ca314edcdbb9b155d Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 20 Jul 2011 18:27:15 +0000 Subject: pep8 --- nova/network/manager.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index 7a7520f5d..34001657b 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -140,7 +140,9 @@ class RPCAllocateFixedIP(object): 'args': {'network_ref': network}}) if host != self.host: # need to call allocate_fixed_ip to correct network host - topic = self.db.queue_get_for(context, FLAGS.network_topic, host) + topic = self.db.queue_get_for(context, + FLAGS.network_topic, + host) args = {} args['instance_id'] = instance_id args['network_id'] = network['id'] @@ -414,7 +416,8 @@ class NetworkManager(manager.SchedulerDependentManager): # deallocate vifs (mac addresses) self.db.virtual_interface_delete_by_instance(context, instance_id) - def get_instance_nw_info(self, context, instance_id, instance_type_id, host): + def get_instance_nw_info(self, context, instance_id, + instance_type_id, host): """Creates network info list for instance. called by allocate_for_instance and netowrk_api -- cgit From 58a76cede01b6bb141d060636c21318db1712527 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 20 Jul 2011 18:46:29 +0000 Subject: Make sure reset_network() call happens after we've determined the agent is running. --- nova/virt/xenapi/vmops.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index bade23889..419685a6f 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -311,6 +311,7 @@ class VMOps(object): _check_agent_version() _inject_files() _set_admin_password() + self.reset_network(instance, vm_ref) return True except Exception, exc: LOG.warn(exc) @@ -320,9 +321,6 @@ class VMOps(object): timer.f = _wait_for_boot - # call to reset network to configure network from xenstore - self.reset_network(instance, vm_ref) - return timer.start(interval=0.5, now=True) def _get_vm_opaque_ref(self, instance_or_vm): -- cgit From 617fd37492af95e7276fbbe3b1cd400dea42beae Mon Sep 17 00:00:00 2001 From: Adam Gandelman Date: Wed, 20 Jul 2011 12:10:01 -0700 Subject: Fix email address in Author --- Authors | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Authors b/Authors index 95b6906ce..f3129c26e 100644 --- a/Authors +++ b/Authors @@ -1,4 +1,4 @@ -Adam Gandelman +Adam Gandelman Alex Meade Alexander Sakhnov Andrey Brindeyev -- cgit