summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/compute/manager.py2
-rw-r--r--nova/compute/utils.py118
-rw-r--r--nova/network/manager.py2
-rw-r--r--nova/network/model.py128
-rw-r--r--nova/network/quantum/manager.py2
-rw-r--r--nova/tests/fake_network.py7
-rw-r--r--nova/tests/network/test_manager.py4
-rw-r--r--nova/tests/test_libvirt.py3
-rw-r--r--nova/tests/test_libvirt_vif.py10
-rw-r--r--nova/tests/test_xenapi.py154
-rw-r--r--nova/virt/firewall.py29
-rw-r--r--nova/virt/libvirt/connection.py6
-rw-r--r--nova/virt/libvirt/vif.py22
-rw-r--r--nova/virt/vif.py4
-rw-r--r--nova/virt/vmwareapi/vif.py4
-rw-r--r--nova/virt/vmwareapi/vmops.py4
-rw-r--r--nova/virt/xenapi/connection.py7
-rw-r--r--nova/virt/xenapi/vif.py43
-rw-r--r--nova/virt/xenapi/vm_utils.py94
-rw-r--r--nova/virt/xenapi/vmops.py86
20 files changed, 401 insertions, 328 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 6a0251a15..2e56bc539 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -361,7 +361,7 @@ class ComputeManager(manager.SchedulerDependentManager):
def _legacy_nw_info(self, network_info):
"""Converts the model nw_info object to legacy style"""
if self.driver.legacy_nwinfo():
- network_info = compute_utils.legacy_network_info(network_info)
+ network_info = network_info.legacy()
return network_info
def _setup_block_device_mapping(self, context, instance):
diff --git a/nova/compute/utils.py b/nova/compute/utils.py
index ab5ccfbf0..f5f3c5f5e 100644
--- a/nova/compute/utils.py
+++ b/nova/compute/utils.py
@@ -16,11 +16,8 @@
"""Compute-related Utilities and helpers."""
-import netaddr
-
import nova.context
from nova import db
-from nova import exception
from nova import flags
from nova import log
from nova import network
@@ -79,121 +76,6 @@ def notify_usage_exists(context, instance_ref, current_period=False,
system_metadata=system_metadata, extra_usage_info=extra_info)
-def legacy_network_info(network_model):
- """
- Return the legacy network_info representation of the network_model
- """
- def get_ip(ip):
- if not ip:
- return None
- return ip['address']
-
- def fixed_ip_dict(ip, subnet):
- if ip['version'] == 4:
- netmask = str(subnet.as_netaddr().netmask)
- else:
- netmask = subnet.as_netaddr()._prefixlen
-
- return {'ip': ip['address'],
- 'enabled': '1',
- 'netmask': netmask,
- 'gateway': get_ip(subnet['gateway'])}
-
- def get_meta(model, key, default=None):
- if 'meta' in model and key in model['meta']:
- return model['meta'][key]
- return default
-
- def convert_routes(routes):
- routes_list = []
- for route in routes:
- r = {'route': str(netaddr.IPNetwork(route['cidr']).network),
- 'netmask': str(netaddr.IPNetwork(route['cidr']).netmask),
- 'gateway': get_ip(route['gateway'])}
- routes_list.append(r)
- return routes_list
-
- network_info = []
- for vif in network_model:
- if not vif['network'] or not vif['network']['subnets']:
- continue
- network = vif['network']
-
- # NOTE(jkoelker) The legacy format only supports one subnet per
- # network, so we only use the 1st one of each type
- # NOTE(tr3buchet): o.O
- v4_subnets = []
- v6_subnets = []
- for subnet in vif['network']['subnets']:
- if subnet['version'] == 4:
- v4_subnets.append(subnet)
- else:
- v6_subnets.append(subnet)
-
- subnet_v4 = None
- subnet_v6 = None
-
- if v4_subnets:
- subnet_v4 = v4_subnets[0]
-
- if v6_subnets:
- subnet_v6 = v6_subnets[0]
-
- if not subnet_v4:
- raise exception.NovaException(
- message=_('v4 subnets are required for legacy nw_info'))
-
- routes = convert_routes(subnet_v4['routes'])
-
- should_create_bridge = get_meta(network, 'should_create_bridge',
- False)
- should_create_vlan = get_meta(network, 'should_create_vlan', False)
- gateway = get_ip(subnet_v4['gateway'])
- dhcp_server = get_meta(subnet_v4, 'dhcp_server')
- network_dict = dict(bridge=network['bridge'],
- id=network['id'],
- cidr=subnet_v4['cidr'],
- cidr_v6=subnet_v6['cidr'] if subnet_v6 else None,
- vlan=get_meta(network, 'vlan'),
- injected=get_meta(network, 'injected', False),
- multi_host=get_meta(network, 'multi_host',
- False),
- bridge_interface=get_meta(network,
- 'bridge_interface'))
- # NOTE(tr3buchet): the 'ips' bit here is tricky, we support a single
- # subnet but we want all the IPs to be there
- # so we use the v4_subnets[0] and its IPs are first
- # so that eth0 will be from subnet_v4, the rest of the
- # IPs will be aliased eth0:1 etc and the gateways from
- # their subnets will not be used
- info_dict = dict(label=network['label'],
- broadcast=str(subnet_v4.as_netaddr().broadcast),
- mac=vif['address'],
- vif_uuid=vif['id'],
- rxtx_cap=get_meta(network, 'rxtx_cap', 0),
- dns=[get_ip(ip) for ip in subnet_v4['dns']],
- ips=[fixed_ip_dict(ip, subnet)
- for subnet in v4_subnets
- for ip in subnet['ips']],
- should_create_bridge=should_create_bridge,
- should_create_vlan=should_create_vlan,
- dhcp_server=dhcp_server)
- if routes:
- info_dict['routes'] = routes
-
- if gateway:
- info_dict['gateway'] = gateway
-
- if v6_subnets:
- if subnet_v6['gateway']:
- info_dict['gateway_v6'] = get_ip(subnet_v6['gateway'])
- info_dict['ip6s'] = [fixed_ip_dict(ip, subnet_v6)
- for ip in subnet_v6['ips']]
-
- network_info.append((network_dict, info_dict))
- return network_info
-
-
def notify_about_instance_usage(context, instance, event_suffix,
network_info=None, system_metadata=None,
extra_usage_info=None, host=None):
diff --git a/nova/network/manager.py b/nova/network/manager.py
index ac77ebaf7..31871c1a9 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -1013,7 +1013,7 @@ class NetworkManager(manager.SchedulerDependentManager):
nw_info = self.build_network_info_model(context, vifs, networks,
rxtx_factor, host)
self.db.instance_info_cache_update(context, instance_uuid,
- {'network_info': nw_info.as_cache()})
+ {'network_info': nw_info.json()})
return nw_info
def build_network_info_model(self, context, vifs, networks,
diff --git a/nova/network/model.py b/nova/network/model.py
index 843416591..84a8ab35e 100644
--- a/nova/network/model.py
+++ b/nova/network/model.py
@@ -31,12 +31,16 @@ class Model(dict):
def __repr__(self):
return self.__class__.__name__ + '(' + dict.__repr__(self) + ')'
- def set_meta(self, kwargs):
+ def _set_meta(self, kwargs):
# pull meta out of kwargs if it's there
self['meta'] = kwargs.pop('meta', {})
# update meta with any additional kwargs that may exist
self['meta'].update(kwargs)
+ def get_meta(self, key, default=None):
+ """calls get(key, default) on self['meta']"""
+ return self['meta'].get(key, default)
+
class IP(Model):
"""Represents an IP address in Nova"""
@@ -47,7 +51,7 @@ class IP(Model):
self['type'] = type
self['version'] = kwargs.pop('version', None)
- self.set_meta(kwargs)
+ self._set_meta(kwargs)
# determine version from address if not passed in
if self['address'] and not self['version']:
@@ -106,7 +110,7 @@ class Route(Model):
self['gateway'] = gateway
self['interface'] = interface
- self.set_meta(kwargs)
+ self._set_meta(kwargs)
@classmethod
def hydrate(cls, route):
@@ -128,7 +132,7 @@ class Subnet(Model):
self['routes'] = routes or []
self['version'] = kwargs.pop('version', None)
- self.set_meta(kwargs)
+ self._set_meta(kwargs)
if self['cidr'] and not self['version']:
self['version'] = netaddr.IPNetwork(self['cidr']).version
@@ -173,7 +177,7 @@ class Network(Model):
self['label'] = label
self['subnets'] = subnets or []
- self.set_meta(kwargs)
+ self._set_meta(kwargs)
def add_subnet(self, subnet):
if subnet not in self['subnets']:
@@ -197,7 +201,7 @@ class VIF(Model):
self['address'] = address
self['network'] = network or None
- self.set_meta(kwargs)
+ self._set_meta(kwargs)
def __eq__(self, other):
return self['id'] == other['id']
@@ -270,5 +274,115 @@ class NetworkInfo(list):
network_info = json.loads(network_info)
return NetworkInfo([VIF.hydrate(vif) for vif in network_info])
- def as_cache(self):
+ def json(self):
return json.dumps(self)
+
+ def legacy(self):
+ """
+ Return the legacy network_info representation of self
+ """
+ def get_ip(ip):
+ if not ip:
+ return None
+ return ip['address']
+
+ def fixed_ip_dict(ip, subnet):
+ if ip['version'] == 4:
+ netmask = str(subnet.as_netaddr().netmask)
+ else:
+ netmask = subnet.as_netaddr()._prefixlen
+
+ return {'ip': ip['address'],
+ 'enabled': '1',
+ 'netmask': netmask,
+ 'gateway': get_ip(subnet['gateway'])}
+
+ def convert_routes(routes):
+ routes_list = []
+ for route in routes:
+ r = {'route': str(netaddr.IPNetwork(route['cidr']).network),
+ 'netmask': str(netaddr.IPNetwork(route['cidr']).netmask),
+ 'gateway': get_ip(route['gateway'])}
+ routes_list.append(r)
+ return routes_list
+
+ network_info = []
+ for vif in self:
+ # if vif doesn't have network or that network has no subnets, quit
+ if not vif['network'] or not vif['network']['subnets']:
+ continue
+ network = vif['network']
+
+ # NOTE(jkoelker) The legacy format only supports one subnet per
+ # network, so we only use the 1st one of each type
+ # NOTE(tr3buchet): o.O
+ v4_subnets = []
+ v6_subnets = []
+ for subnet in vif['network']['subnets']:
+ if subnet['version'] == 4:
+ v4_subnets.append(subnet)
+ else:
+ v6_subnets.append(subnet)
+
+ subnet_v4 = None
+ subnet_v6 = None
+
+ if v4_subnets:
+ subnet_v4 = v4_subnets[0]
+
+ if v6_subnets:
+ subnet_v6 = v6_subnets[0]
+
+ if not subnet_v4:
+ msg = _('v4 subnets are required for legacy nw_info')
+ raise exception.NovaException(message=msg)
+
+ routes = convert_routes(subnet_v4['routes'])
+ should_create_bridge = network.get_meta('should_create_bridge',
+ False)
+ should_create_vlan = network.get_meta('should_create_vlan', False)
+ gateway = get_ip(subnet_v4['gateway'])
+ dhcp_server = subnet_v4.get_meta('dhcp_server', gateway)
+
+ network_dict = \
+ {'bridge': network['bridge'],
+ 'id': network['id'],
+ 'cidr': subnet_v4['cidr'],
+ 'cidr_v6': subnet_v6['cidr'] if subnet_v6 else None,
+ 'vlan': network.get_meta('vlan'),
+ 'injected': network.get_meta('injected', False),
+ 'multi_host': network.get_meta('multi_host', False),
+ 'bridge_interface': network.get_meta('bridge_interface')}
+ # NOTE(tr3buchet): 'ips' bit here is tricky, we support a single
+ # subnet but we want all the IPs to be there
+ # so use the v4_subnets[0] and its IPs are first
+ # so that eth0 will be from subnet_v4, the rest of
+ # the IPs will be aliased eth0:1 etc and the
+ # gateways from their subnets will not be used
+ info_dict = {'label': network['label'],
+ 'broadcast': str(subnet_v4.as_netaddr().broadcast),
+ 'mac': vif['address'],
+ 'vif_uuid': vif['id'],
+ 'rxtx_cap': vif.get_meta('rxtx_cap', 0),
+ 'dns': [get_ip(ip) for ip in subnet_v4['dns']],
+ 'ips': [fixed_ip_dict(ip, subnet)
+ for subnet in v4_subnets
+ for ip in subnet['ips']],
+ 'should_create_bridge': should_create_bridge,
+ 'should_create_vlan': should_create_vlan,
+ 'dhcp_server': dhcp_server}
+ if routes:
+ info_dict['routes'] = routes
+
+ if gateway:
+ info_dict['gateway'] = gateway
+
+ if v6_subnets:
+ if subnet_v6['gateway']:
+ info_dict['gateway_v6'] = get_ip(subnet_v6['gateway'])
+ # NOTE(tr3buchet): only supporting single v6 subnet here
+ info_dict['ip6s'] = [fixed_ip_dict(ip, subnet_v6)
+ for ip in subnet_v6['ips']]
+
+ network_info.append((network_dict, info_dict))
+ return network_info
diff --git a/nova/network/quantum/manager.py b/nova/network/quantum/manager.py
index c034b5e2a..8765f1082 100644
--- a/nova/network/quantum/manager.py
+++ b/nova/network/quantum/manager.py
@@ -577,7 +577,7 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager):
nw_info = self.build_network_info_model(context, vifs, networks,
rxtx_factor, host)
db.instance_info_cache_update(context, instance_uuid,
- {'network_info': nw_info.as_cache()})
+ {'network_info': nw_info.json()})
return nw_info
diff --git a/nova/tests/fake_network.py b/nova/tests/fake_network.py
index d2d9ba017..ef98d3337 100644
--- a/nova/tests/fake_network.py
+++ b/nova/tests/fake_network.py
@@ -15,7 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import nova.compute.utils
import nova.context
from nova import db
from nova import exception
@@ -180,11 +179,13 @@ def fake_network(network_id, ipv6=None):
'host': None,
'project_id': 'fake_project',
'vpn_public_address': '192.168.%d.2' % network_id,
- 'rxtx_base': '%d' % network_id * 10}
+ 'rxtx_base': network_id * 10}
if ipv6:
fake_network['cidr_v6'] = '2001:db8:0:%x::/64' % network_id
fake_network['gateway_v6'] = '2001:db8:0:%x::1' % network_id
fake_network['netmask_v6'] = '64'
+ if FLAGS.flat_injected:
+ fake_network['injected'] = True
return fake_network
@@ -353,7 +354,7 @@ def fake_get_instance_nw_info(stubs, num_networks=1, ips_per_vif=2,
0, 0, 3, None)
if spectacular:
return nw_model
- return nova.compute.utils.legacy_network_info(nw_model)
+ return nw_model.legacy()
def stub_out_nw_api_get_instance_nw_info(stubs, func=None,
diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py
index f6931a876..9e0a754b7 100644
--- a/nova/tests/network/test_manager.py
+++ b/nova/tests/network/test_manager.py
@@ -166,7 +166,7 @@ class FlatNetworkTestCase(test.TestCase):
self.assertDictMatch(nw, check)
check = {'broadcast': '192.168.%d.255' % nid,
- 'dhcp_server': None,
+ 'dhcp_server': '192.168.1.1',
'dns': ['192.168.%d.3' % nid, '192.168.%d.4' % nid],
'gateway': '192.168.%d.1' % nid,
'gateway_v6': 'fe80::def',
@@ -174,7 +174,7 @@ class FlatNetworkTestCase(test.TestCase):
'ips': 'DONTCARE',
'label': 'test%d' % nid,
'mac': 'DE:AD:BE:EF:00:%02x' % nid,
- 'rxtx_cap': 0,
+ 'rxtx_cap': 30,
'vif_uuid':
'00000000-0000-0000-0000-00000000000000%02d' % nid,
'should_create_vlan': False,
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 9ba45481c..329f81ab4 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -30,7 +30,6 @@ from xml.dom import minidom
from nova.api.ec2 import cloud
from nova.compute import instance_types
from nova.compute import power_state
-from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import context
from nova import db
@@ -1892,7 +1891,7 @@ class IptablesFirewallTestCase(test.TestCase):
_fake_stub_out_get_nw_info(self.stubs, lambda *a, **kw: network_model)
- network_info = compute_utils.legacy_network_info(network_model)
+ network_info = network_model.legacy()
self.fw.prepare_instance_filter(instance_ref, network_info)
self.fw.apply_instance_filter(instance_ref, network_info)
diff --git a/nova/tests/test_libvirt_vif.py b/nova/tests/test_libvirt_vif.py
index dfa18325a..81b44e861 100644
--- a/nova/tests/test_libvirt_vif.py
+++ b/nova/tests/test_libvirt_vif.py
@@ -75,7 +75,7 @@ class LibvirtVifTestCase(test.TestCase):
conf.memory = 100 * 1024
conf.vcpus = 4
- nic = driver.plug(self.instance, self.net, self.mapping)
+ nic = driver.plug(self.instance, (self.net, self.mapping))
conf.add_device(nic)
return conf.to_xml()
@@ -93,7 +93,7 @@ class LibvirtVifTestCase(test.TestCase):
mac = node.find("mac").get("address")
self.assertEqual(mac, self.mapping['mac'])
- d.unplug(None, self.net, self.mapping)
+ d.unplug(None, (self.net, self.mapping))
def test_ovs_ethernet_driver(self):
d = vif.LibvirtOpenVswitchDriver()
@@ -111,7 +111,7 @@ class LibvirtVifTestCase(test.TestCase):
script = node.find("script").get("path")
self.assertEquals(script, "")
- d.unplug(None, self.net, self.mapping)
+ d.unplug(None, (self.net, self.mapping))
def test_ovs_virtualport_driver(self):
d = vif.LibvirtOpenVswitchVirtualPortDriver()
@@ -137,7 +137,7 @@ class LibvirtVifTestCase(test.TestCase):
iface_id_found = True
self.assertTrue(iface_id_found)
- d.unplug(None, self.net, self.mapping)
+ d.unplug(None, (self.net, self.mapping))
def test_quantum_bridge_ethernet_driver(self):
d = vif.QuantumLinuxBridgeVIFDriver()
@@ -155,4 +155,4 @@ class LibvirtVifTestCase(test.TestCase):
script = node.find("script").get("path")
self.assertEquals(script, "")
- d.unplug(None, self.net, self.mapping)
+ d.unplug(None, (self.net, self.mapping))
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index f65b2fce7..b2a15c109 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -28,7 +28,6 @@ from nova.compute import aggregate_states
from nova.compute import instance_types
from nova.compute import power_state
from nova.compute import task_states
-from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import context
from nova import db
@@ -381,24 +380,28 @@ class XenAPIVMTestCase(test.TestCase):
if check_injection:
xenstore_data = self.vm['xenstore_data']
self.assertEquals(xenstore_data['vm-data/hostname'], 'test')
- key = 'vm-data/networking/DEADBEEF0000'
+ key = 'vm-data/networking/DEADBEEF0001'
xenstore_value = xenstore_data[key]
tcpip_data = ast.literal_eval(xenstore_value)
self.assertEquals(tcpip_data,
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
+ {'broadcast': '192.168.1.255',
+ 'dns': ['192.168.1.3', '192.168.1.4'],
+ 'gateway': '192.168.1.1',
+ 'gateway_v6': 'fe80::def',
'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
+ 'ip': '2001:db8:0:1::1',
+ 'netmask': 64,
+ 'gateway': 'fe80::def'}],
'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'dhcp_server': '192.168.0.1',
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})
+ 'ip': '192.168.1.100',
+ 'netmask': '255.255.255.0',
+ 'gateway': '192.168.1.1'},
+ {'enabled': '1',
+ 'ip': '192.168.1.101',
+ 'netmask': '255.255.255.0',
+ 'gateway': '192.168.1.1'}],
+ 'label': 'test1',
+ 'mac': 'DE:AD:BE:EF:00:01'})
def check_vm_params_for_windows(self):
self.assertEquals(self.vm['platform']['nx'], 'true')
@@ -471,27 +474,12 @@ class XenAPIVMTestCase(test.TestCase):
instance = db.instance_create(self.context, instance_values)
else:
instance = db.instance_get(self.context, instance_id)
- network_info = [({'bridge': 'fa0', 'id': 0,
- 'injected': True,
- 'cidr': '192.168.0.0/24',
- 'cidr_v6': 'dead:beef::1/120',
- },
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'dhcp_server': '192.168.0.1',
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
+
+ network_info = fake_network.fake_get_instance_nw_info(self.stubs,
+ spectacular=True)
if empty_dns:
- network_info[0][1]['dns'] = []
+ # NOTE(tr3buchet): this is a terrible way to do this...
+ network_info[0]['network']['subnets'][0]['dns'] = []
# admin_pass isn't part of the DB model, but it does get set as
# an attribute for spawn to use
@@ -609,11 +597,11 @@ class XenAPIVMTestCase(test.TestCase):
index = config.index('auto eth0')
self.assertEquals(config[index + 1:index + 8], [
'iface eth0 inet static',
- 'address 192.168.0.100',
+ 'address 192.168.1.100',
'netmask 255.255.255.0',
- 'broadcast 192.168.0.255',
- 'gateway 192.168.0.1',
- 'dns-nameservers 192.168.0.1',
+ 'broadcast 192.168.1.255',
+ 'gateway 192.168.1.1',
+ 'dns-nameservers 192.168.1.3 192.168.1.4',
''])
self._tee_executed = True
return '', ''
@@ -712,7 +700,7 @@ class XenAPIVMTestCase(test.TestCase):
vif_rec = xenapi_fake.get_record('VIF', vif_ref)
self.assertEquals(vif_rec['qos_algorithm_type'], 'ratelimit')
self.assertEquals(vif_rec['qos_algorithm_params']['kbps'],
- str(3 * 1024))
+ str(3 * 10 * 1024))
def test_rescue(self):
instance = self._create_instance()
@@ -782,25 +770,8 @@ class XenAPIVMTestCase(test.TestCase):
'os_type': 'linux',
'architecture': 'x86-64'}
instance = db.instance_create(self.context, instance_values)
- network_info = [({'bridge': 'fa0', 'id': 0,
- 'injected': False,
- 'cidr': '192.168.0.0/24',
- 'cidr_v6': 'dead:beef::1/120',
- },
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'dhcp_server': '192.168.0.1',
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
+ network_info = fake_network.fake_get_instance_nw_info(self.stubs,
+ spectacular=True)
image_meta = {'id': glance_stubs.FakeGlance.IMAGE_VHD,
'disk_format': 'vhd'}
if spawn:
@@ -955,20 +926,8 @@ class XenAPIMigrateInstance(test.TestCase):
fake_finish_revert_migration)
conn = xenapi_conn.get_connection(False)
- network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
+ network_info = fake_network.fake_get_instance_nw_info(self.stubs,
+ spectacular=True)
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
base = xenapi_fake.create_vdi('hurr', 'fake')
base_uuid = xenapi_fake.get_record('VDI', base)['uuid']
@@ -999,20 +958,8 @@ class XenAPIMigrateInstance(test.TestCase):
"VDI_resize_online", fake_vdi_resize)
conn = xenapi_conn.get_connection(False)
- network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
+ network_info = fake_network.fake_get_instance_nw_info(self.stubs,
+ spectacular=True)
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
dict(base_copy='hurr', cow='durr'),
@@ -1033,20 +980,8 @@ class XenAPIMigrateInstance(test.TestCase):
self.stubs.Set(stubs.FakeSessionForVMTests,
"VDI_resize_online", fake_vdi_resize)
conn = xenapi_conn.get_connection(False)
- network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
+ network_info = fake_network.fake_get_instance_nw_info(self.stubs,
+ spectacular=True)
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
dict(base_copy='hurr', cow='durr'),
@@ -1061,21 +996,8 @@ class XenAPIMigrateInstance(test.TestCase):
self.stubs.Set(stubs.FakeSessionForVMTests,
"VDI_resize_online", fake_vdi_resize)
conn = xenapi_conn.get_connection(False)
- network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
-
+ network_info = fake_network.fake_get_instance_nw_info(self.stubs,
+ spectacular=True)
# Resize instance would be determined by the compute call
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
@@ -1572,7 +1494,7 @@ class XenAPIDom0IptablesFirewallTestCase(test.TestCase):
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
lambda *a, **kw: network_model)
- network_info = compute_utils.legacy_network_info(network_model)
+ network_info = network_model.legacy()
self.fw.prepare_instance_filter(instance_ref, network_info)
self.fw.apply_instance_filter(instance_ref, network_info)
diff --git a/nova/virt/firewall.py b/nova/virt/firewall.py
index aa05a2261..bca50d21f 100644
--- a/nova/virt/firewall.py
+++ b/nova/virt/firewall.py
@@ -97,6 +97,14 @@ class FirewallDriver(object):
"""Check nova-instance-instance-xxx exists"""
raise NotImplementedError()
+ def _handle_network_info_model(self, network_info):
+ # make sure this is legacy network_info
+ try:
+ return network_info.legacy()
+ except AttributeError:
+ # no "legacy" function means network_info is legacy
+ return network_info
+
class IptablesFirewallDriver(FirewallDriver):
"""Driver which enforces security groups through iptables rules."""
@@ -121,6 +129,9 @@ class IptablesFirewallDriver(FirewallDriver):
pass
def unfilter_instance(self, instance, network_info):
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
if self.instances.pop(instance['id'], None):
# NOTE(vish): use the passed info instead of the stored info
self.network_infos.pop(instance['id'])
@@ -131,6 +142,9 @@ class IptablesFirewallDriver(FirewallDriver):
'filtered'), instance=instance)
def prepare_instance_filter(self, instance, network_info):
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
self.instances[instance['id']] = instance
self.network_infos[instance['id']] = network_info
self.add_filters_for_instance(instance)
@@ -146,6 +160,9 @@ class IptablesFirewallDriver(FirewallDriver):
"""Creates a rule corresponding to each ip that defines a
jump to the corresponding instance - chain for all the traffic
destined to that ip."""
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
ips_v4 = [ip['ip'] for (_n, mapping) in network_info
for ip in mapping['ips']]
ipv4_rules = self._create_filter(ips_v4, chain_name)
@@ -206,6 +223,9 @@ class IptablesFirewallDriver(FirewallDriver):
ipv6_rules += ['-j $provider']
def _do_dhcp_rules(self, ipv4_rules, network_info):
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
dhcp_servers = [info['dhcp_server'] for (_n, info) in network_info]
for dhcp_server in dhcp_servers:
@@ -214,6 +234,9 @@ class IptablesFirewallDriver(FirewallDriver):
'-j ACCEPT' % (dhcp_server,))
def _do_project_network_rules(self, ipv4_rules, ipv6_rules, network_info):
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
cidrs = [network['cidr'] for (network, _i) in network_info]
for cidr in cidrs:
ipv4_rules.append('-s %s -j ACCEPT' % (cidr,))
@@ -225,6 +248,9 @@ class IptablesFirewallDriver(FirewallDriver):
ipv6_rules.append('-s %s -j ACCEPT' % (cidrv6,))
def _do_ra_rules(self, ipv6_rules, network_info):
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
gateways_v6 = [mapping['gateway_v6'] for (_n, mapping) in
network_info]
for gateway_v6 in gateways_v6:
@@ -259,6 +285,9 @@ class IptablesFirewallDriver(FirewallDriver):
rule.to_port)]
def instance_rules(self, instance, network_info):
+ # make sure this is legacy nw_info
+ network_info = self._handle_network_info_model(network_info)
+
ctxt = context.get_admin_context()
ipv4_rules = []
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 7e012a87c..1622550ed 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -370,12 +370,12 @@ class LibvirtConnection(driver.ComputeDriver):
def plug_vifs(self, instance, network_info):
"""Plug VIFs into networks."""
for (network, mapping) in network_info:
- self.vif_driver.plug(instance, network, mapping)
+ self.vif_driver.plug(instance, (network, mapping))
def unplug_vifs(self, instance, network_info):
"""Unplug VIFs from networks."""
for (network, mapping) in network_info:
- self.vif_driver.unplug(instance, network, mapping)
+ self.vif_driver.unplug(instance, (network, mapping))
def _destroy(self, instance, network_info, block_device_info=None,
cleanup=True):
@@ -1626,7 +1626,7 @@ class LibvirtConnection(driver.ComputeDriver):
guest.add_device(diskconfig)
for (network, mapping) in network_info:
- cfg = self.vif_driver.plug(instance, network, mapping)
+ cfg = self.vif_driver.plug(instance, (network, mapping))
guest.add_device(cfg)
if FLAGS.libvirt_type == "qemu" or FLAGS.libvirt_type == "kvm":
diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py
index 07ac50520..5333e0992 100644
--- a/nova/virt/libvirt/vif.py
+++ b/nova/virt/libvirt/vif.py
@@ -83,8 +83,9 @@ class LibvirtBridgeDriver(vif.VIFDriver):
return conf
- def plug(self, instance, network, mapping):
+ def plug(self, instance, vif):
"""Ensure that the bridge exists, and add VIF to it."""
+ network, mapping = vif
if (not network.get('multi_host') and
mapping.get('should_create_bridge')):
if mapping.get('should_create_vlan'):
@@ -107,7 +108,7 @@ class LibvirtBridgeDriver(vif.VIFDriver):
return self._get_configurations(instance, network, mapping)
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
"""No manual unplugging required."""
pass
@@ -120,7 +121,8 @@ class LibvirtOpenVswitchDriver(vif.VIFDriver):
def get_dev_name(_self, iface_id):
return "tap" + iface_id[0:11]
- def plug(self, instance, network, mapping):
+ def plug(self, instance, vif):
+ network, mapping = vif
iface_id = mapping['vif_uuid']
dev = self.get_dev_name(iface_id)
if not linux_net._device_exists(dev):
@@ -157,9 +159,10 @@ class LibvirtOpenVswitchDriver(vif.VIFDriver):
return conf
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
"""Unplug the VIF from the network by deleting the port from
the bridge."""
+ network, mapping = vif
dev = self.get_dev_name(mapping['vif_uuid'])
try:
utils.execute('ovs-vsctl', 'del-port',
@@ -173,8 +176,9 @@ class LibvirtOpenVswitchVirtualPortDriver(vif.VIFDriver):
"""VIF driver for Open vSwitch that uses integrated libvirt
OVS virtual port XML (introduced in libvirt 0.9.11)."""
- def plug(self, instance, network, mapping):
+ def plug(self, instance, vif):
""" Pass data required to create OVS virtual port element"""
+ network, mapping = vif
conf = config.LibvirtConfigGuestInterface()
@@ -188,7 +192,7 @@ class LibvirtOpenVswitchVirtualPortDriver(vif.VIFDriver):
return conf
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
"""No action needed. Libvirt takes care of cleanup"""
pass
@@ -199,7 +203,8 @@ class QuantumLinuxBridgeVIFDriver(vif.VIFDriver):
def get_dev_name(self, iface_id):
return "tap" + iface_id[0:11]
- def plug(self, instance, network, mapping):
+ def plug(self, instance, vif):
+ network, mapping = vif
iface_id = mapping['vif_uuid']
dev = self.get_dev_name(iface_id)
@@ -215,9 +220,10 @@ class QuantumLinuxBridgeVIFDriver(vif.VIFDriver):
return conf
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
"""Unplug the VIF from the network by deleting the port from
the bridge."""
+ network, mapping = vif
dev = self.get_dev_name(mapping['vif_uuid'])
try:
utils.execute('ip', 'link', 'delete', dev, run_as_root=True)
diff --git a/nova/virt/vif.py b/nova/virt/vif.py
index 07139b200..69cfd996c 100644
--- a/nova/virt/vif.py
+++ b/nova/virt/vif.py
@@ -25,10 +25,10 @@ class VIFDriver(object):
# advantage of any kwargs should they need to
pass
- def plug(self, instance, network, mapping, **kwargs):
+ def plug(self, instance, vif, **kwargs):
"""Plug VIF into network."""
raise NotImplementedError()
- def unplug(self, instance, network, mapping, **kwargs):
+ def unplug(self, instance, vif, **kwargs):
"""Unplug VIF from network."""
raise NotImplementedError()
diff --git a/nova/virt/vmwareapi/vif.py b/nova/virt/vmwareapi/vif.py
index 0a5d78b51..52205c461 100644
--- a/nova/virt/vmwareapi/vif.py
+++ b/nova/virt/vmwareapi/vif.py
@@ -33,7 +33,7 @@ FLAGS.set_default('vmwareapi_vlan_interface', 'vmnic0')
class VMWareVlanBridgeDriver(vif.VIFDriver):
"""VIF Driver to setup bridge/VLAN networking using VMWare API."""
- def plug(self, instance, network, mapping):
+ def plug(self, instance, vif):
"""Plug the VIF to specified instance using information passed.
Currently we are plugging the VIF(s) during instance creation itself.
We can use this method when we add support to add additional NIC to
@@ -83,7 +83,7 @@ class VMWareVlanBridgeDriver(vif.VIFDriver):
raise exception.InvalidVLANTag(bridge=bridge, tag=vlan_num,
pgroup=pg_vlanid)
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
"""Cleanup operations like deleting port group if no instance
is associated with it."""
pass
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py
index 1e35776fa..000dc6981 100644
--- a/nova/virt/vmwareapi/vmops.py
+++ b/nova/virt/vmwareapi/vmops.py
@@ -825,9 +825,9 @@ class VMWareVMOps(object):
def plug_vifs(self, instance, network_info):
"""Plug VIFs into networks."""
for (network, mapping) in network_info:
- self._vif_driver.plug(instance, network, mapping)
+ self._vif_driver.plug(instance, (network, mapping))
def _unplug_vifs(self, instance, network_info):
"""Unplug VIFs from networks."""
for (network, mapping) in network_info:
- self._vif_driver.unplug(instance, network, mapping)
+ self._vif_driver.unplug(instance, (network, mapping))
diff --git a/nova/virt/xenapi/connection.py b/nova/virt/xenapi/connection.py
index 184e34aa4..bd26e86a6 100644
--- a/nova/virt/xenapi/connection.py
+++ b/nova/virt/xenapi/connection.py
@@ -492,6 +492,13 @@ class XenAPIConnection(driver.ComputeDriver):
return self._pool.remove_from_aggregate(context,
aggregate, host, **kwargs)
+ def legacy_nwinfo(self):
+ """
+ Indicate if the driver requires the legacy network_info format.
+ """
+ # TODO(tr3buchet): remove this function once all virts return false
+ return False
+
class XenAPISession(object):
"""The session to invoke XenAPI SDK calls"""
diff --git a/nova/virt/xenapi/vif.py b/nova/virt/xenapi/vif.py
index 900d0cc5f..905cbc30c 100644
--- a/nova/virt/xenapi/vif.py
+++ b/nova/virt/xenapi/vif.py
@@ -44,39 +44,40 @@ class XenVIFDriver(vif.VIFDriver):
class XenAPIBridgeDriver(XenVIFDriver):
"""VIF Driver for XenAPI that uses XenAPI to create Networks."""
- def plug(self, instance, network, mapping, vm_ref=None, device=None):
+ def plug(self, instance, vif, vm_ref=None, device=None):
if not vm_ref:
vm_ref = vm_utils.VMHelper.lookup(self._session, instance.name)
if not device:
device = 0
- if mapping.get('should_create_vlan'):
- network_ref = self._ensure_vlan_bridge(network)
+ if vif['network'].get_meta('should_create_vlan'):
+ network_ref = self._ensure_vlan_bridge(vif['network'])
else:
network_ref = network_utils.NetworkHelper.find_network_with_bridge(
- self._session, network['bridge'])
+ self._session, vif['network']['bridge'])
vif_rec = {}
vif_rec['device'] = str(device)
vif_rec['network'] = network_ref
vif_rec['VM'] = vm_ref
- vif_rec['MAC'] = mapping['mac']
+ vif_rec['MAC'] = vif['address']
vif_rec['MTU'] = '1500'
vif_rec['other_config'] = {}
- if "rxtx_cap" in mapping:
- vif_rec['qos_algorithm_type'] = "ratelimit"
- vif_rec['qos_algorithm_params'] = {"kbps":
- str(mapping['rxtx_cap'] * 1024)}
+ if vif.get_meta('rxtx_cap'):
+ vif_rec['qos_algorithm_type'] = 'ratelimit'
+ vif_rec['qos_algorithm_params'] = {'kbps':
+ str(int(vif.get_meta('rxtx_cap')) * 1024)}
else:
- vif_rec['qos_algorithm_type'] = ""
+ vif_rec['qos_algorithm_type'] = ''
vif_rec['qos_algorithm_params'] = {}
return vif_rec
def _ensure_vlan_bridge(self, network):
"""Ensure that a VLAN bridge exists"""
- vlan_num = network['vlan']
+ vlan_num = network.get_meta('vlan')
bridge = network['bridge']
- bridge_interface = FLAGS.vlan_interface or network['bridge_interface']
+ bridge_interface = FLAGS.vlan_interface or \
+ network.get_meta('bridge_interface')
# Check whether bridge already exists
# Retrieve network whose name_label is "bridge"
network_ref = network_utils.NetworkHelper.find_network_with_name_label(
@@ -86,8 +87,8 @@ class XenAPIBridgeDriver(XenVIFDriver):
# 1 - create network
description = 'network for nova bridge %s' % bridge
network_rec = {'name_label': bridge,
- 'name_description': description,
- 'other_config': {}}
+ 'name_description': description,
+ 'other_config': {}}
network_ref = self._session.call_xenapi('network.create',
network_rec)
# 2 - find PIF for VLAN NOTE(salvatore-orlando): using double
@@ -101,7 +102,7 @@ class XenAPIBridgeDriver(XenVIFDriver):
# Multiple PIF are ok: we are dealing with a pool
if len(pifs) == 0:
raise Exception(_('Found no PIF for device %s') %
- bridge_interface)
+ bridge_interface)
for pif_ref in pifs.keys():
self._session.call_xenapi('VLAN.create',
pif_ref,
@@ -126,14 +127,14 @@ class XenAPIBridgeDriver(XenVIFDriver):
return network_ref
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
pass
class XenAPIOpenVswitchDriver(XenVIFDriver):
"""VIF driver for Open vSwitch with XenAPI."""
- def plug(self, instance, network, mapping, vm_ref=None, device=None):
+ def plug(self, instance, vif, vm_ref=None, device=None):
if not vm_ref:
vm_ref = vm_utils.VMHelper.lookup(self._session, instance.name)
@@ -148,14 +149,14 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
vif_rec['device'] = str(device)
vif_rec['network'] = network_ref
vif_rec['VM'] = vm_ref
- vif_rec['MAC'] = mapping['mac']
+ vif_rec['MAC'] = vif['address']
vif_rec['MTU'] = '1500'
- vif_rec['qos_algorithm_type'] = ""
+ vif_rec['qos_algorithm_type'] = ''
vif_rec['qos_algorithm_params'] = {}
# OVS on the hypervisor monitors this key and uses it to
# set the iface-id attribute
- vif_rec['other_config'] = {"nicira-iface-id": mapping['vif_uuid']}
+ vif_rec['other_config'] = {'nicira-iface-id': vif['id']}
return vif_rec
- def unplug(self, instance, network, mapping):
+ def unplug(self, instance, vif):
pass
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 30f65e1b5..508fd34e9 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -1782,7 +1782,7 @@ def _mounted_processing(device, key, net, metadata):
'non-linux instances): %s') % err)
-def _prepare_injectables(inst, networks_info):
+def _prepare_injectables(inst, network_info):
"""
prepares the ssh key and the network configuration file to be
injected into the disk image
@@ -1796,38 +1796,84 @@ def _prepare_injectables(inst, networks_info):
metadata = inst['metadata']
key = str(inst['key_data'])
net = None
- if networks_info:
+ if network_info:
ifc_num = -1
interfaces_info = []
- have_injected_networks = False
- for (network_ref, info) in networks_info:
+ for vif in network_info:
ifc_num += 1
- if not network_ref['injected']:
+ try:
+ if not vif['network'].get_meta('injected'):
+ # network is not specified injected
+ continue
+ except KeyError:
+ # vif network is None
continue
- have_injected_networks = True
- ip_v4 = ip_v6 = None
- if 'ips' in info and len(info['ips']) > 0:
- ip_v4 = info['ips'][0]
- if 'ip6s' in info and len(info['ip6s']) > 0:
- ip_v6 = info['ip6s'][0]
- if len(info['dns']) > 0:
- dns = info['dns'][0]
- else:
- dns = ''
+ # NOTE(tr3buchet): using all subnets in case dns is stored in a
+ # subnet that isn't chosen as first v4 or v6
+ # subnet in the case where there is more than one
+ # dns = list of address of each dns entry from each vif subnet
+ dns = [ip['address'] for subnet in vif['network']['subnets']
+ for ip in subnet['dns']]
+ dns = ' '.join(dns).strip()
+
interface_info = {'name': 'eth%d' % ifc_num,
- 'address': ip_v4 and ip_v4['ip'] or '',
- 'netmask': ip_v4 and ip_v4['netmask'] or '',
- 'gateway': info['gateway'],
- 'broadcast': info['broadcast'],
- 'dns': dns,
- 'address_v6': ip_v6 and ip_v6['ip'] or '',
- 'netmask_v6': ip_v6 and ip_v6['netmask'] or '',
- 'gateway_v6': ip_v6 and info['gateway_v6'] or '',
+ 'address': '',
+ 'netmask': '',
+ 'gateway': '',
+ 'broadcast': '',
+ 'dns': dns or '',
+ 'address_v6': '',
+ 'netmask_v6': '',
+ 'gateway_v6': '',
'use_ipv6': FLAGS.use_ipv6}
+
+ # NOTE(tr3buchet): the original code used the old network_info
+ # which only supported a single ipv4 subnet
+ # (and optionally, a single ipv6 subnet).
+ # I modified it to use the new network info model,
+ # which adds support for multiple v4 or v6
+ # subnets. I chose to ignore any additional
+ # subnets, just as the original code ignored
+ # additional IP information
+
+ # populate v4 info if v4 subnet and ip exist
+ try:
+ # grab the first v4 subnet (or it raises)
+ subnet = [s for s in vif['network']['subnets']
+ if s['version'] == 4][0]
+ # get the subnet's first ip (or it raises)
+ ip = subnet['ips'][0]
+
+ # populate interface_info
+ subnet_netaddr = subnet.as_netaddr()
+ interface_info['address'] = ip['address']
+ interface_info['netmask'] = subnet_netaddr.netmask
+ interface_info['gateway'] = subnet['gateway']['address']
+ interface_info['broadcast'] = subnet_netaddr.broadcast
+ except IndexError:
+ # there isn't a v4 subnet or there are no ips
+ pass
+
+ # populate v6 info if v6 subnet and ip exist
+ try:
+ # grab the first v6 subnet (or it raises)
+ subnet = [s for s in vif['network']['subnets']
+ if s['version'] == 6][0]
+ # get the subnet's first ip (or it raises)
+ ip = subnet['ips'][0]
+
+ # populate interface_info
+ interface_info['address_v6'] = ip['address']
+ interface_info['netmask_v6'] = subnet.as_netaddr().netmask
+ interface_info['gateway_v6'] = subnet['gateway']['address']
+ except IndexError:
+ # there isn't a v6 subnet or there are no ips
+ pass
+
interfaces_info.append(interface_info)
- if have_injected_networks:
+ if interfaces_info:
net = str(template(template_data,
searchList=[{'interfaces': interfaces_info,
'use_ipv6': FLAGS.use_ipv6}]))
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 7ac455367..8ede49983 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -1357,6 +1357,70 @@ class VMOps(object):
return {'host': FLAGS.vncserver_proxyclient_address, 'port': 80,
'internal_access_path': path}
+ def _vif_xenstore_data(self, vif):
+ """convert a network info vif to injectable instance data"""
+
+ def get_ip(ip):
+ if not ip:
+ return None
+ return ip['address']
+
+ def fixed_ip_dict(ip, subnet):
+ if ip['version'] == 4:
+ netmask = str(subnet.as_netaddr().netmask)
+ else:
+ netmask = subnet.as_netaddr()._prefixlen
+
+ return {'ip': ip['address'],
+ 'enabled': '1',
+ 'netmask': netmask,
+ 'gateway': get_ip(subnet['gateway'])}
+
+ def convert_route(route):
+ return {'route': str(netaddr.IPNetwork(route['cidr']).network),
+ 'netmask': str(netaddr.IPNetwork(route['cidr']).netmask),
+ 'gateway': get_ip(route['gateway'])}
+
+ network = vif['network']
+ v4_subnets = [subnet for subnet in network['subnets']
+ if subnet['version'] == 4]
+ v6_subnets = [subnet for subnet in network['subnets']
+ if subnet['version'] == 6]
+
+ # NOTE(tr3buchet): routes and DNS come from all subnets
+ routes = [convert_route(route) for subnet in network['subnets']
+ for route in subnet['routes']]
+ dns = [get_ip(ip) for subnet in network['subnets']
+ for ip in subnet['dns']]
+
+ info_dict = {'label': network['label'],
+ 'mac': vif['address']}
+
+ if v4_subnets:
+ # NOTE(tr3buchet): gateway and broadcast from first subnet
+ # primary IP will be from first subnet
+ # subnets are generally unordered :(
+ info_dict['gateway'] = get_ip(v4_subnets[0]['gateway'])
+ info_dict['broadcast'] = str(v4_subnets[0].as_netaddr().broadcast)
+ info_dict['ips'] = [fixed_ip_dict(ip, subnet)
+ for subnet in v4_subnets
+ for ip in subnet['ips']]
+ if v6_subnets:
+ # NOTE(tr3buchet): gateway from first subnet
+ # primary IP will be from first subnet
+ # subnets are generally unordered :(
+ info_dict['gateway_v6'] = get_ip(v6_subnets[0]['gateway'])
+ info_dict['ip6s'] = [fixed_ip_dict(ip, subnet)
+ for subnet in v6_subnets
+ for ip in subnet['ips']]
+ if routes:
+ info_dict['routes'] = routes
+
+ if dns:
+ info_dict['dns'] = dns
+
+ return info_dict
+
def inject_network_info(self, instance, network_info, vm_ref=None):
"""
Generate the network info and make calls to place it into the
@@ -1367,11 +1431,13 @@ class VMOps(object):
vm_ref = vm_ref or self._get_vm_opaque_ref(instance)
LOG.debug(_("Injecting network info to xenstore"), instance=instance)
- for (network, info) in network_info:
- location = 'vm-data/networking/%s' % info['mac'].replace(':', '')
- self._add_to_param_xenstore(vm_ref, location, json.dumps(info))
+ for vif in network_info:
+ xs_data = self._vif_xenstore_data(vif)
+ location = \
+ 'vm-data/networking/%s' % vif['address'].replace(':', '')
+ self._add_to_param_xenstore(vm_ref, location, json.dumps(xs_data))
try:
- self._write_to_xenstore(instance, location, info,
+ self._write_to_xenstore(instance, location, xs_data,
vm_ref=vm_ref)
except KeyError:
# catch KeyError for domid if instance isn't running
@@ -1385,8 +1451,8 @@ class VMOps(object):
# this function raises if vm_ref is not a vm_opaque_ref
self._session.call_xenapi("VM.get_record", vm_ref)
- for device, (network, info) in enumerate(network_info):
- vif_rec = self.vif_driver.plug(instance, network, info,
+ for device, vif in enumerate(network_info):
+ vif_rec = self.vif_driver.plug(instance, vif,
vm_ref=vm_ref, device=device)
network_ref = vif_rec['network']
LOG.debug(_('Creating VIF for network %(network_ref)s'),
@@ -1397,13 +1463,13 @@ class VMOps(object):
def plug_vifs(self, instance, network_info):
"""Set up VIF networking on the host."""
- for device, (network, mapping) in enumerate(network_info):
- self.vif_driver.plug(instance, network, mapping, device=device)
+ for device, vif in enumerate(network_info):
+ self.vif_driver.plug(instance, vif, device=device)
def unplug_vifs(self, instance, network_info):
if network_info:
- for (network, mapping) in network_info:
- self.vif_driver.unplug(instance, network, mapping)
+ for vif in network_info:
+ self.vif_driver.unplug(instance, vif)
def reset_network(self, instance, vm_ref=None):
"""Calls resetnetwork method in agent."""