213 lines
7.1 KiB
Python
213 lines
7.1 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2010 United States Government as represented by the
|
|
# Administrator of the National Aeronautics and Space Administration.
|
|
# All Rights Reserved.
|
|
# Copyright (c) 2010 Citrix Systems, Inc.
|
|
# Copyright 2013 IBM Corp.
|
|
#
|
|
# 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.
|
|
|
|
|
|
"""Network-related utilities for supporting libvirt connection code."""
|
|
|
|
|
|
import netaddr
|
|
|
|
from oslo.config import cfg
|
|
|
|
from nova.network import model
|
|
|
|
CONF = cfg.CONF
|
|
CONF.import_opt('use_ipv6', 'nova.netconf')
|
|
CONF.import_opt('injected_network_template', 'nova.virt.disk.api')
|
|
|
|
Template = None
|
|
|
|
|
|
def _late_load_cheetah():
|
|
global Template
|
|
if Template is None:
|
|
t = __import__('Cheetah.Template', globals(), locals(),
|
|
['Template'], -1)
|
|
Template = t.Template
|
|
|
|
|
|
def get_net_and_mask(cidr):
|
|
net = netaddr.IPNetwork(cidr)
|
|
return str(net.ip), str(net.netmask)
|
|
|
|
|
|
def get_net_and_prefixlen(cidr):
|
|
net = netaddr.IPNetwork(cidr)
|
|
return str(net.ip), str(net._prefixlen)
|
|
|
|
|
|
def get_ip_version(cidr):
|
|
net = netaddr.IPNetwork(cidr)
|
|
return int(net.version)
|
|
|
|
|
|
def get_non_legacy_network_template(network_info, use_ipv6=CONF.use_ipv6,
|
|
template=CONF.injected_network_template):
|
|
"""A new version of get_injected_network_template that does not rely on
|
|
legacy network info.
|
|
|
|
Returns a rendered network template for the given network_info. When
|
|
libvirt's dependency on using legacy network info for network config
|
|
injection goes away, this function can replace
|
|
get_injected_network_template entirely.
|
|
|
|
:param network_info:
|
|
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
|
|
:param use_ipv6: If False, do not return IPv6 template information
|
|
even if an IPv6 subnet is present in network_info.
|
|
:param template: Path to the interfaces template file.
|
|
"""
|
|
if not (network_info and template):
|
|
return
|
|
|
|
nets = []
|
|
ifc_num = -1
|
|
ipv6_is_available = False
|
|
|
|
for vif in network_info:
|
|
if not vif['network'] or not vif['network']['subnets']:
|
|
continue
|
|
|
|
network = vif['network']
|
|
# NOTE(bnemec): The template only supports a single subnet per
|
|
# interface and I'm not sure how/if that can be fixed, so this
|
|
# code only takes the first subnet of the appropriate type.
|
|
subnet_v4 = [i for i in network['subnets'] if i['version'] == 4][0]
|
|
subnet_v6 = [i for i in network['subnets'] if i['version'] == 6]
|
|
if subnet_v6:
|
|
subnet_v6 = subnet_v6[0]
|
|
|
|
ifc_num += 1
|
|
|
|
if (not network.get_meta('injected') or not subnet_v4['ips'] or
|
|
subnet_v4.get_meta('dhcp_server') is not None):
|
|
continue
|
|
|
|
ip = subnet_v4['ips'][0]
|
|
address = ip['address']
|
|
netmask = model.get_netmask(ip, subnet_v4)
|
|
gateway = ''
|
|
if subnet_v4['gateway']:
|
|
gateway = subnet_v4['gateway']['address']
|
|
broadcast = str(subnet_v4.as_netaddr().broadcast)
|
|
dns = ' '.join([i['address'] for i in subnet_v4['dns']])
|
|
# NOTE(bnemec): I don't think this code would handle a pure IPv6
|
|
# environment properly, but I don't have such an environment in
|
|
# which to test/fix that.
|
|
address_v6 = None
|
|
gateway_v6 = None
|
|
netmask_v6 = None
|
|
have_ipv6 = (use_ipv6 and subnet_v6)
|
|
if have_ipv6:
|
|
if subnet_v6['ips']:
|
|
ipv6_is_available = True
|
|
ip_v6 = subnet_v6['ips'][0]
|
|
address_v6 = ip_v6['address']
|
|
netmask_v6 = model.get_netmask(ip_v6, subnet_v6)
|
|
gateway_v6 = ''
|
|
if subnet_v6['gateway']:
|
|
gateway_v6 = subnet_v6['gateway']['address']
|
|
|
|
net_info = {'name': 'eth%d' % ifc_num,
|
|
'address': address,
|
|
'netmask': netmask,
|
|
'gateway': gateway,
|
|
'broadcast': broadcast,
|
|
'dns': dns,
|
|
'address_v6': address_v6,
|
|
'gateway_v6': gateway_v6,
|
|
'netmask_v6': netmask_v6,
|
|
}
|
|
nets.append(net_info)
|
|
|
|
if not nets:
|
|
return
|
|
|
|
return build_template(template, nets, ipv6_is_available)
|
|
|
|
|
|
def get_injected_network_template(network_info, use_ipv6=CONF.use_ipv6,
|
|
template=CONF.injected_network_template):
|
|
"""
|
|
return a rendered network template for the given network_info
|
|
|
|
:param network_info:
|
|
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
|
|
:param use_ipv6: If False, do not return IPv6 template information
|
|
even if an IPv6 subnet is present in network_info.
|
|
:param template: Path to the interfaces template file.
|
|
"""
|
|
|
|
if not (network_info and template):
|
|
return
|
|
|
|
# If we're passed new network_info, make use of it instead of forcing
|
|
# it to the legacy format required below.
|
|
if isinstance(network_info, model.NetworkInfo):
|
|
return get_non_legacy_network_template(network_info,
|
|
use_ipv6,
|
|
template)
|
|
|
|
nets = []
|
|
ifc_num = -1
|
|
have_injected_networks = False
|
|
|
|
for (network_ref, mapping) in network_info:
|
|
ifc_num += 1
|
|
|
|
if not network_ref['injected']:
|
|
continue
|
|
|
|
have_injected_networks = True
|
|
address = mapping['ips'][0]['ip']
|
|
netmask = mapping['ips'][0]['netmask']
|
|
address_v6 = None
|
|
gateway_v6 = None
|
|
netmask_v6 = None
|
|
ipv6_is_available = use_ipv6 and 'ip6s' in mapping
|
|
if ipv6_is_available:
|
|
address_v6 = mapping['ip6s'][0]['ip']
|
|
netmask_v6 = mapping['ip6s'][0]['netmask']
|
|
gateway_v6 = mapping['gateway_v6']
|
|
net_info = {'name': 'eth%d' % ifc_num,
|
|
'address': address,
|
|
'netmask': netmask,
|
|
'gateway': mapping['gateway'],
|
|
'broadcast': mapping['broadcast'],
|
|
'dns': ' '.join(mapping['dns']),
|
|
'address_v6': address_v6,
|
|
'gateway_v6': gateway_v6,
|
|
'netmask_v6': netmask_v6}
|
|
nets.append(net_info)
|
|
|
|
if have_injected_networks is False:
|
|
return
|
|
|
|
return build_template(template, nets, ipv6_is_available)
|
|
|
|
|
|
def build_template(template, nets, ipv6_is_available):
|
|
_late_load_cheetah()
|
|
|
|
ifc_template = open(template).read()
|
|
return str(Template(ifc_template,
|
|
searchList=[{'interfaces': nets,
|
|
'use_ipv6': ipv6_is_available}]))
|