nova-net: Kill it

Finish the job by removing all the now-unused modules. This also allows
us to - wait for it - kill mox at long last. It's a great day in the
parish.

Partial-Implements: blueprint remove-nova-network-ussuri
Partial-Implements: blueprint mox-removal-ussuri

Change-Id: Ia33ec2604b2fc2d3b6830b596cac669cc3ad6c96
This commit is contained in:
Stephen Finucane 2019-05-20 16:26:35 +01:00 committed by Eric Fried
parent 828f3f2691
commit f5f73b4c4e
59 changed files with 108 additions and 15966 deletions

View File

@ -1,13 +0,0 @@
# nova-rootwrap command filters for api-metadata nodes
# This is needed on nova-api hosts running with "metadata" in enabled_apis
# or when running nova-api-metadata
# This file should be owned by (and only-writeable by) the root user
[Filters]
# nova/network/linux_net.py: 'ip[6]tables-save' % (cmd, '-t', ...
iptables-save: CommandFilter, iptables-save, root
ip6tables-save: CommandFilter, ip6tables-save, root
# nova/network/linux_net.py: 'ip[6]tables-restore' % (cmd,)
iptables-restore: CommandFilter, iptables-restore, root
ip6tables-restore: CommandFilter, ip6tables-restore, root

View File

@ -1,91 +0,0 @@
# nova-rootwrap command filters for network nodes
# This file should be owned by (and only-writeable by) the root user
[Filters]
# nova/virt/libvirt/vif.py: 'ip', 'tuntap', 'add', dev, 'mode', 'tap'
# nova/virt/libvirt/vif.py: 'ip', 'link', 'set', dev, 'up'
# nova/virt/libvirt/vif.py: 'ip', 'link', 'delete', dev
# nova/network/linux_net.py: 'ip', 'addr', 'add', str(floating_ip)+'/32'i..
# nova/network/linux_net.py: 'ip', 'addr', 'del', str(floating_ip)+'/32'..
# nova/network/linux_net.py: 'ip', 'addr', 'add', '169.254.169.254/32',..
# nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', dev, 'scope',..
# nova/network/linux_net.py: 'ip', 'addr', 'del/add', ip_params, dev)
# nova/network/linux_net.py: 'ip', 'addr', 'del', params, fields[-1]
# nova/network/linux_net.py: 'ip', 'addr', 'add', params, bridge
# nova/network/linux_net.py: 'ip', '-f', 'inet6', 'addr', 'change', ..
# nova/network/linux_net.py: 'ip', 'link', 'set', 'dev', dev, 'promisc',..
# nova/network/linux_net.py: 'ip', 'link', 'add', 'link', bridge_if ...
# nova/network/linux_net.py: 'ip', 'link', 'set', interface, address,..
# nova/network/linux_net.py: 'ip', 'link', 'set', interface, 'up'
# nova/network/linux_net.py: 'ip', 'link', 'set', bridge, 'up'
# nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', interface, ..
# nova/network/linux_net.py: 'ip', 'link', 'set', dev, address, ..
# nova/network/linux_net.py: 'ip', 'link', 'set', dev, 'up'
# nova/network/linux_net.py: 'ip', 'route', 'add', ..
# nova/network/linux_net.py: 'ip', 'route', 'del', .
# nova/network/linux_net.py: 'ip', 'route', 'show', 'dev', dev
ip: CommandFilter, ip, root
# nova/virt/libvirt/vif.py: 'ovs-vsctl', ...
# nova/virt/libvirt/vif.py: 'ovs-vsctl', 'del-port', ...
# nova/network/linux_net.py: 'ovs-vsctl', ....
ovs-vsctl: CommandFilter, ovs-vsctl, root
# nova/network/linux_net.py: 'ovs-ofctl', ....
ovs-ofctl: CommandFilter, ovs-ofctl, root
# nova/virt/libvirt/vif.py: 'ivs-ctl', ...
# nova/virt/libvirt/vif.py: 'ivs-ctl', 'del-port', ...
# nova/network/linux_net.py: 'ivs-ctl', ....
ivs-ctl: CommandFilter, ivs-ctl, root
# nova/virt/libvirt/vif.py: 'ifc_ctl', ...
ifc_ctl: CommandFilter, /opt/pg/bin/ifc_ctl, root
# nova/network/linux_net.py: 'ebtables', '-D' ...
# nova/network/linux_net.py: 'ebtables', '-I' ...
ebtables: CommandFilter, ebtables, root
ebtables_usr: CommandFilter, ebtables, root
# nova/network/linux_net.py: 'ip[6]tables-save' % (cmd, '-t', ...
iptables-save: CommandFilter, iptables-save, root
ip6tables-save: CommandFilter, ip6tables-save, root
# nova/network/linux_net.py: 'ip[6]tables-restore' % (cmd,)
iptables-restore: CommandFilter, iptables-restore, root
ip6tables-restore: CommandFilter, ip6tables-restore, root
# nova/network/linux_net.py: 'arping', '-U', floating_ip, '-A', '-I', ...
# nova/network/linux_net.py: 'arping', '-U', network_ref['dhcp_server'],..
arping: CommandFilter, arping, root
# nova/network/linux_net.py: 'dhcp_release', dev, address, mac_address
dhcp_release: CommandFilter, dhcp_release, root
# nova/network/linux_net.py: 'kill', '-9', pid
# nova/network/linux_net.py: 'kill', '-HUP', pid
kill_dnsmasq: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP
# nova/network/linux_net.py: 'kill', pid
kill_radvd: KillFilter, root, /usr/sbin/radvd
# nova/network/linux_net.py: dnsmasq call
dnsmasq: EnvFilter, env, root, CONFIG_FILE=, NETWORK_ID=, dnsmasq
# nova/network/linux_net.py: 'radvd', '-C', '%s' % _ra_file(dev, 'conf'..
radvd: CommandFilter, radvd, root
# nova/network/linux_net.py: 'brctl', 'addbr', bridge
# nova/network/linux_net.py: 'brctl', 'setfd', bridge, 0
# nova/network/linux_net.py: 'brctl', 'stp', bridge, 'off'
# nova/network/linux_net.py: 'brctl', 'addif', bridge, interface
brctl: CommandFilter, brctl, root
# nova/network/linux_net.py: 'sysctl', ....
sysctl: CommandFilter, sysctl, root
# nova/network/linux_net.py: 'conntrack'
conntrack: CommandFilter, conntrack, root
# nova/network/linux_net.py: 'fp-vdev'
fp-vdev: CommandFilter, fp-vdev, root

View File

@ -54,7 +54,6 @@ mccabe==0.2.1
microversion-parse==0.2.1
mock==3.0.0
monotonic==1.4
mox3==0.20.0
msgpack==0.5.6
msgpack-python==0.5.6
munch==2.2.0

View File

@ -42,7 +42,6 @@ from nova.conf import keystone
from nova.conf import libvirt
from nova.conf import mks
from nova.conf import netconf
from nova.conf import network
from nova.conf import neutron
from nova.conf import notifications
from nova.conf import novnc
@ -94,7 +93,6 @@ key_manager.register_opts(CONF)
keystone.register_opts(CONF)
libvirt.register_opts(CONF)
netconf.register_opts(CONF)
network.register_opts(CONF)
neutron.register_opts(CONF)
notifications.register_opts(CONF)
novnc.register_opts(CONF)

View File

@ -34,10 +34,7 @@ Possible values:
Related options:
* metadata_host
* my_block_storage_ip
* routing_source_ip
* vpn_ip
"""),
cfg.StrOpt("my_block_storage_ip",
default="$my_ip",
@ -70,6 +67,21 @@ Must be valid within AMQP key.
Possible values:
* String with hostname, FQDN or IP address. Default is hostname of this host.
"""),
# TODO(sfinucan): This option is tied into the XenAPI, VMWare and Libvirt
# drivers.
# We should remove this dependency by either adding a new opt for each
# driver or simply removing the offending code. Until then we cannot
# deprecate this option.
cfg.BoolOpt("flat_injected",
default=False,
help="""
This option determines whether the network setup information is injected into
the VM before it is booted. While it was originally designed to be used only
by nova-network, it is also used by the vmware and xenapi virt drivers to
control whether network information is injected into a VM. The libvirt virt
driver also uses it when we use config_drive to configure network to control
whether network information is injected into a VM.
"""),
]

File diff suppressed because it is too large Load Diff

View File

@ -96,24 +96,6 @@ Conductor RPC API version cap.
Possible values:
* By default send the latest version the client knows about
* A string representing a version number in the format 'N.N';
for example, possible values might be '1.12' or '2.0'.
* An OpenStack release name, in lower case, such as 'mitaka' or
'liberty'.
"""),
cfg.StrOpt('network',
deprecated_for_removal=True,
deprecated_since='18.0.0',
deprecated_reason="""
The nova-network service was deprecated in 14.0.0 (Newton) and will be
removed in an upcoming release.
""",
help="""
Network RPC API version cap.
Possible values:
* By default send the latest version the client knows about
* A string representing a version number in the format 'N.N';
for example, possible values might be '1.12' or '2.0'.

View File

@ -499,31 +499,6 @@ def floating_ip_update(context, address, values):
return IMPL.floating_ip_update(context, address, values)
def dnsdomain_get_all(context):
"""Get a list of all dnsdomains in our database."""
return IMPL.dnsdomain_get_all(context)
def dnsdomain_register_for_zone(context, fqdomain, zone):
"""Associated a DNS domain with an availability zone."""
return IMPL.dnsdomain_register_for_zone(context, fqdomain, zone)
def dnsdomain_register_for_project(context, fqdomain, project):
"""Associated a DNS domain with a project id."""
return IMPL.dnsdomain_register_for_project(context, fqdomain, project)
def dnsdomain_unregister(context, fqdomain):
"""Purge associations for the specified DNS zone."""
return IMPL.dnsdomain_unregister(context, fqdomain)
def dnsdomain_get(context, fqdomain):
"""Get the db record for the specified domain."""
return IMPL.dnsdomain_get(context, fqdomain)
####################

View File

@ -1182,58 +1182,6 @@ def floating_ip_update(context, address, values):
###################
@require_context
@pick_context_manager_reader
def dnsdomain_get(context, fqdomain):
return model_query(context, models.DNSDomain, read_deleted="no").\
filter_by(domain=fqdomain).\
with_for_update().\
first()
def _dnsdomain_get_or_create(context, fqdomain):
domain_ref = dnsdomain_get(context, fqdomain)
if not domain_ref:
dns_ref = models.DNSDomain()
dns_ref.update({'domain': fqdomain,
'availability_zone': None,
'project_id': None})
return dns_ref
return domain_ref
@pick_context_manager_writer
def dnsdomain_register_for_zone(context, fqdomain, zone):
domain_ref = _dnsdomain_get_or_create(context, fqdomain)
domain_ref.scope = 'private'
domain_ref.availability_zone = zone
context.session.add(domain_ref)
@pick_context_manager_writer
def dnsdomain_register_for_project(context, fqdomain, project):
domain_ref = _dnsdomain_get_or_create(context, fqdomain)
domain_ref.scope = 'public'
domain_ref.project_id = project
context.session.add(domain_ref)
@pick_context_manager_writer
def dnsdomain_unregister(context, fqdomain):
model_query(context, models.DNSDomain).\
filter_by(domain=fqdomain).\
delete()
@pick_context_manager_reader
def dnsdomain_get_all(context):
return model_query(context, models.DNSDomain, read_deleted="no").all()
###################
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
@pick_context_manager_writer
def fixed_ip_associate(context, address, instance_uuid, network_id=None,
@ -5329,6 +5277,7 @@ def _archive_deleted_rows_for_table(metadata, tablename, max_rows, before):
# No corresponding shadow table; skip it.
return rows_archived, deleted_instance_uuids
# TODO(stephenfin): Drop this when we drop the table
if tablename == "dns_domains":
# We have one table (dns_domains) where the key is called
# "domain" rather than "id"

View File

@ -971,6 +971,7 @@ class FloatingIp(BASE, NovaBase, models.SoftDeleteMixin):
'FixedIp.deleted == 0)')
# TODO(stephenfin): Remove in V or later
class DNSDomain(BASE, NovaBase, models.SoftDeleteMixin):
"""Represents a DNS domain with availability zone or project info."""
__tablename__ = 'dns_domains'

View File

@ -1,15 +0,0 @@
# Copyright (c) 2011 OpenStack Foundation
#
# 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 nova.ipv6.api import * # noqa

View File

@ -1,55 +0,0 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 Justin Santa Barbara
# 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.
"""IPv6 address generation with account identifier embedded."""
import hashlib
import netaddr
import six
from nova.i18n import _
def to_global(prefix, mac, project_id):
addr = project_id
if isinstance(addr, six.text_type):
addr = addr.encode('utf-8')
addr = hashlib.sha1(addr)
addr = int(addr.hexdigest()[:8], 16) << 32
project_hash = netaddr.IPAddress(addr)
static_num = netaddr.IPAddress(0xff << 24)
try:
mac_suffix = netaddr.EUI(mac).value & 0xffffff
mac_addr = netaddr.IPAddress(mac_suffix)
except netaddr.AddrFormatError:
raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac)
try:
maskIP = netaddr.IPNetwork(prefix).ip
return (project_hash ^ static_num ^ mac_addr | maskIP).format()
except netaddr.AddrFormatError:
raise TypeError(_('Bad prefix for to_global_ipv6: %s') % prefix)
def to_mac(ipv6_address):
address = netaddr.IPAddress(ipv6_address)
mask1 = netaddr.IPAddress('::ff:ffff')
mac = netaddr.EUI(int(address & mask1)).words
return ':'.join(['02', '16', '3e'] + ['%02x' % i for i in mac[3:6]])

View File

@ -1,37 +0,0 @@
# Copyright (c) 2011 OpenStack Foundation
#
# 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 stevedore import driver
import nova.conf
CONF = nova.conf.CONF
IMPL = None
def reset_backend():
global IMPL
IMPL = driver.DriverManager("nova.ipv6_backend",
CONF.ipv6_backend).driver
def to_global(prefix, mac, project_id):
return IMPL.to_global(prefix, mac, project_id)
def to_mac(ipv6_address):
return IMPL.to_mac(ipv6_address)
reset_backend()

View File

@ -1,44 +0,0 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 Justin Santa Barbara
# 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.
"""RFC2462 style IPv6 address generation."""
import netaddr
from nova.i18n import _
def to_global(prefix, mac, project_id):
try:
mac64 = netaddr.EUI(mac).modified_eui64().value
mac64_addr = netaddr.IPAddress(mac64)
except netaddr.AddrFormatError:
raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac)
try:
maskIP = netaddr.IPNetwork(prefix).ip
return (mac64_addr | maskIP).format()
except netaddr.AddrFormatError:
raise TypeError(_('Bad prefix for to_global_ipv6: %s') % prefix)
def to_mac(ipv6_address):
address = netaddr.IPAddress(ipv6_address)
mask1 = netaddr.IPAddress('::ffff:ffff:ffff:ffff')
mask2 = netaddr.IPAddress('::0200:0:0:0')
mac64 = netaddr.EUI(int(address & mask1 ^ mask2)).words
return ':'.join(['%02x' % i for i in mac64[0:3] + mac64[5:8]])

View File

@ -16,28 +16,8 @@
from oslo_utils import importutils
import nova.conf
NOVA_NET_API = 'nova.network.api.API'
NEUTRON_NET_API = 'nova.network.neutronv2.api.API'
CONF = nova.conf.CONF
def is_neutron():
"""Does this configuration mean we're neutron.
This logic exists as a separate config option
"""
return CONF.use_neutron
# TODO(stephenfin): Remove this layer of indirection
def API():
if is_neutron():
network_api_class = NEUTRON_NET_API
else:
network_api_class = NOVA_NET_API
cls = importutils.import_class(network_api_class)
cls = importutils.import_class('nova.network.neutronv2.api.API')
return cls()

View File

@ -1,511 +0,0 @@
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2013 IBM Corp.
# 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 oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import strutils
from nova import exception
from nova.network import base_api
from nova.network import floating_ips
from nova.network import model as network_model
from nova.network import rpcapi as network_rpcapi
from nova import objects
from nova.objects import base as obj_base
from nova import profiler
from nova import utils
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
@profiler.trace_cls("network_api")
class API(base_api.NetworkAPI):
"""API for doing networking via the nova-network network manager.
This is a pluggable module - other implementations do networking via
other services (such as Neutron).
"""
def __init__(self, **kwargs):
self.network_rpcapi = network_rpcapi.NetworkAPI()
helper = utils.ExceptionHelper
# NOTE(vish): this local version of floating_manager has to convert
# ClientExceptions back since they aren't going over rpc.
self.floating_manager = helper(floating_ips.LocalManager())
super(API, self).__init__(**kwargs)
def get_all(self, context):
"""Get all the networks.
If it is an admin user then api will return all the
networks. If it is a normal user and nova Flat or FlatDHCP
networking is being used then api will return all
networks. Otherwise api will only return the networks which
belong to the user's project.
"""
if "nova.network.manager.Flat" in CONF.network_manager:
project_only = "allow_none"
else:
project_only = True
try:
return objects.NetworkList.get_all(context,
project_only=project_only)
except exception.NoNetworksFound:
return []
def get(self, context, network_uuid):
return objects.Network.get_by_uuid(context, network_uuid)
def create(self, context, **kwargs):
return self.network_rpcapi.create_networks(context, **kwargs)
def delete(self, context, network_uuid):
network = self.get(context, network_uuid)
if network.project_id is not None:
raise exception.NetworkInUse(network_id=network_uuid)
return self.network_rpcapi.delete_network(context, network_uuid, None)
def get_fixed_ip(self, context, id):
return objects.FixedIP.get_by_id(context, id)
def get_fixed_ip_by_address(self, context, address):
return objects.FixedIP.get_by_address(context, address)
def get_floating_ip(self, context, id):
if not strutils.is_int_like(id):
raise exception.InvalidID(id=id)
return objects.FloatingIP.get_by_id(context, id)
def get_floating_ip_pools(self, context):
return objects.FloatingIP.get_pool_names(context)
def get_floating_ip_by_address(self, context, address):
return objects.FloatingIP.get_by_address(context, address)
def get_floating_ips_by_project(self, context):
return objects.FloatingIPList.get_by_project(context,
context.project_id)
def get_instance_id_by_floating_address(self, context, address):
fixed_ip = objects.FixedIP.get_by_floating_address(context, address)
if fixed_ip is None:
return None
else:
return fixed_ip.instance_uuid
def get_vifs_by_instance(self, context, instance):
vifs = objects.VirtualInterfaceList.get_by_instance_uuid(context,
instance.uuid)
for vif in vifs:
if vif.network_id is not None:
network = objects.Network.get_by_id(context, vif.network_id,
project_only='allow_none')
vif.net_uuid = network.uuid
return vifs
def get_vif_by_mac_address(self, context, mac_address):
vif = objects.VirtualInterface.get_by_address(context,
mac_address)
if vif.network_id is not None:
network = objects.Network.get_by_id(context, vif.network_id,
project_only='allow_none')
vif.net_uuid = network.uuid
return vif
def allocate_floating_ip(self, context, pool=None):
"""Adds (allocates) a floating IP to a project from a pool."""
return self.floating_manager.allocate_floating_ip(context,
context.project_id, False, pool)
def release_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Removes (deallocates) a floating IP with address from a project."""
return self.floating_manager.deallocate_floating_ip(context, address,
affect_auto_assigned)
def disassociate_and_release_floating_ip(self, context, instance,
floating_ip):
"""Removes (deallocates) and deletes the floating IP.
This api call was added to allow this to be done in one operation
if using neutron.
"""
address = floating_ip['address']
if floating_ip.get('fixed_ip_id'):
try:
self.disassociate_floating_ip(context, instance, address)
except exception.FloatingIpNotAssociated:
msg = ("Floating IP %s has already been disassociated, "
"perhaps by another concurrent action.") % address
LOG.debug(msg)
# release ip from project
return self.release_floating_ip(context, address)
@base_api.refresh_cache
def associate_floating_ip(self, context, instance,
floating_address, fixed_address,
affect_auto_assigned=False):
"""Associates a floating IP with a fixed IP.
Ensures floating IP is allocated to the project in context.
Does not verify ownership of the fixed IP. Caller is assumed to have
checked that the instance is properly owned.
"""
orig_instance_uuid = self.floating_manager.associate_floating_ip(
context, floating_address, fixed_address, affect_auto_assigned)
if orig_instance_uuid:
msg_dict = dict(address=floating_address,
instance_id=orig_instance_uuid)
LOG.info('re-assign floating IP %(address)s from '
'instance %(instance_id)s', msg_dict)
orig_instance = objects.Instance.get_by_uuid(
context, orig_instance_uuid, expected_attrs=['flavor'])
# purge cached nw info for the original instance
base_api.update_instance_cache_with_nw_info(self, context,
orig_instance)
@base_api.refresh_cache
def disassociate_floating_ip(self, context, instance, address,
affect_auto_assigned=False):
"""Disassociates a floating IP from fixed IP it is associated with."""
return self.floating_manager.disassociate_floating_ip(context, address,
affect_auto_assigned)
@staticmethod
def _requested_nets_as_obj_list(requested_networks):
"""Helper method to convert a list of requested network tuples into an
objects.NetworkRequestList.
:param requested_networks: List of requested networks.
:return: objects.NetworkRequestList instance
"""
if requested_networks and not isinstance(requested_networks,
objects.NetworkRequestList):
requested_networks = objects.NetworkRequestList.from_tuples(
requested_networks)
return requested_networks
@base_api.refresh_cache
def allocate_for_instance(self, context, instance, vpn,
requested_networks,
security_groups=None,
bind_host_id=None, attach=False,
resource_provider_mapping=None):
"""Allocates all network structures for an instance.
:param context: The request context.
:param instance: nova.objects.instance.Instance object.
:param vpn: A boolean, if True, indicate a vpn to access the instance.
:param requested_networks: A list of requested_network tuples
containing network_id and fixed_ip
:param security_groups: None or security groups to allocate for
instance.
:param bind_host_id: ignored by this driver.
:param attach: ignored by this driver
:param resource_provider_mapping: ignored by this driver
:returns: network info as from get_instance_nw_info() below
"""
# NOTE(vish): We can't do the floating ip allocation here because
# this is called from compute.manager which shouldn't
# have db access so we do it on the other side of the
# rpc.
flavor = instance.get_flavor()
args = {}
args['vpn'] = vpn
args['requested_networks'] = requested_networks
args['instance_id'] = instance.uuid
args['project_id'] = instance.project_id
args['host'] = instance.host
args['rxtx_factor'] = flavor['rxtx_factor']
# Check to see if we're asked to 'auto' allocate networks because if
# so we need to just null out the requested_networks value so the
# network manager doesn't try to get networks with uuid 'auto' which
# doesn't exist.
if requested_networks:
requested_networks = self._requested_nets_as_obj_list(
requested_networks)
if requested_networks.auto_allocate:
args['requested_networks'] = None
nw_info = self.network_rpcapi.allocate_for_instance(context, **args)
nw_info = network_model.NetworkInfo.hydrate(nw_info)
# check to see if nothing was allocated and we were requested to
# auto-allocate
if (not nw_info and requested_networks and
requested_networks.auto_allocate):
raise exception.UnableToAutoAllocateNetwork(
project_id=instance.project_id)
return nw_info
def deallocate_for_instance(self, context, instance,
requested_networks=None):
"""Deallocates all network structures related to instance."""
# NOTE(vish): We can't do the floating ip deallocation here because
# this is called from compute.manager which shouldn't
# have db access so we do it on the other side of the
# rpc.
if not isinstance(instance, obj_base.NovaObject):
instance = objects.Instance._from_db_object(context,
objects.Instance(), instance)
# In the case of 'auto' allocation for networks, just pass None for
# requested_networks since 'auto' isn't an actual network.
requested_networks = self._requested_nets_as_obj_list(
requested_networks)
if requested_networks and requested_networks.auto_allocate:
requested_networks = None
self.network_rpcapi.deallocate_for_instance(context, instance=instance,
requested_networks=requested_networks)
# NOTE(danms): Here for neutron compatibility
def allocate_port_for_instance(self, context, instance, port_id,
network_id=None, requested_ip=None,
bind_host_id=None, tag=None):
raise NotImplementedError()
# NOTE(danms): Here for neutron compatibility
def deallocate_port_for_instance(self, context, instance, port_id):
raise NotImplementedError()
# NOTE(danms): Here for neutron compatibility
def list_ports(self, *args, **kwargs):
raise NotImplementedError()
# NOTE(danms): Here for neutron compatibility
def show_port(self, *args, **kwargs):
raise NotImplementedError()
@base_api.refresh_cache
def add_fixed_ip_to_instance(self, context, instance, network_id):
"""Adds a fixed IP to instance from specified network."""
flavor = instance.get_flavor()
args = {'instance_id': instance.uuid,
'rxtx_factor': flavor['rxtx_factor'],
'host': instance.host,
'network_id': network_id}
nw_info = self.network_rpcapi.add_fixed_ip_to_instance(
context, **args)
return network_model.NetworkInfo.hydrate(nw_info)
@base_api.refresh_cache
def remove_fixed_ip_from_instance(self, context, instance, address):
"""Removes a fixed IP from instance from specified network."""
flavor = instance.get_flavor()
args = {'instance_id': instance.uuid,
'rxtx_factor': flavor['rxtx_factor'],
'host': instance.host,
'address': address}
nw_info = self.network_rpcapi.remove_fixed_ip_from_instance(
context, **args)
return network_model.NetworkInfo.hydrate(nw_info)
def _get_instance_nw_info(self, context, instance, **kwargs):
"""Returns all network info related to an instance."""
flavor = instance.get_flavor()
args = {'instance_id': instance.uuid,
'rxtx_factor': flavor['rxtx_factor'],
'host': instance.host,
'project_id': instance.project_id}
nw_info = self.network_rpcapi.get_instance_nw_info(context, **args)
return network_model.NetworkInfo.hydrate(nw_info)
def validate_networks(self, context, requested_networks, num_instances):
"""validate the networks passed at the time of creating
the server.
Return the number of instances that can be successfully allocated
with the requested network configuration.
"""
if requested_networks:
self.network_rpcapi.validate_networks(context,
requested_networks)
# Neutron validation checks and returns how many of num_instances
# instances can be supported by the quota. For Nova network
# this is part of the subsequent quota check, so we just return
# the requested number in this case.
return num_instances
def create_resource_requests(
self, context, requested_networks, pci_requests=None,
affinity_policy=None):
"""Retrieve all information for the networks passed at the time of
creating the server.
:param context: The request context.
:param requested_networks: The networks requested for the server.
:type requested_networks: nova.objects.NetworkRequestList
:param pci_requests: The list of PCI requests to which additional PCI
requests created here will be added.
:type pci_requests: nova.objects.InstancePCIRequests
:param affinity_policy: requested pci numa affinity policy
:type affinity_policy: nova.objects.fields.PCINUMAAffinityPolicy
:returns: A tuple with an instance of ``objects.NetworkMetadata`` for
use by the scheduler or None and a list of RequestGroup
objects representing the resource needs of each requested
port
"""
# This is NOOP for Nova network since it doesn't support SR-IOV or
# NUMA-aware vSwitch functionality.
return None, []
def get_dns_domains(self, context):
"""Returns a list of available dns domains.
These can be used to create DNS entries for floating IPs.
"""
return self.network_rpcapi.get_dns_domains(context)
def add_dns_entry(self, context, address, name, dns_type, domain):
"""Create specified DNS entry for address."""
args = {'address': address,
'name': name,
'dns_type': dns_type,
'domain': domain}
return self.network_rpcapi.add_dns_entry(context, **args)
def modify_dns_entry(self, context, name, address, domain):
"""Create specified DNS entry for address."""
args = {'address': address,
'name': name,
'domain': domain}
return self.network_rpcapi.modify_dns_entry(context, **args)
def delete_dns_entry(self, context, name, domain):
"""Delete the specified dns entry."""
args = {'name': name, 'domain': domain}
return self.network_rpcapi.delete_dns_entry(context, **args)
def delete_dns_domain(self, context, domain):
"""Delete the specified dns domain."""
return self.network_rpcapi.delete_dns_domain(context, domain=domain)
def get_dns_entries_by_address(self, context, address, domain):
"""Get entries for address and domain."""
args = {'address': address, 'domain': domain}
return self.network_rpcapi.get_dns_entries_by_address(context, **args)
def get_dns_entries_by_name(self, context, name, domain):
"""Get entries for name and domain."""
args = {'name': name, 'domain': domain}
return self.network_rpcapi.get_dns_entries_by_name(context, **args)
def create_private_dns_domain(self, context, domain, availability_zone):
"""Create a private DNS domain with nova availability zone."""
args = {'domain': domain, 'av_zone': availability_zone}
return self.network_rpcapi.create_private_dns_domain(context, **args)
def create_public_dns_domain(self, context, domain, project=None):
"""Create a public DNS domain with optional nova project."""
args = {'domain': domain, 'project': project}
return self.network_rpcapi.create_public_dns_domain(context, **args)
def setup_networks_on_host(self, context, instance, host=None,
teardown=False):
"""Setup or teardown the network structures on hosts related to
instance.
"""
host = host or instance.host
# NOTE(tr3buchet): host is passed in cases where we need to setup
# or teardown the networks on a host which has been migrated to/from
# and instance.host is not yet or is no longer equal to
args = {'instance_id': instance.id,
'host': host,
'teardown': teardown,
'instance': instance}
self.network_rpcapi.setup_networks_on_host(context, **args)
def _get_multi_addresses(self, context, instance):
try:
fixed_ips = objects.FixedIPList.get_by_instance_uuid(
context, instance.uuid)
except exception.FixedIpNotFoundForInstance:
return False, []
addresses = []
for fixed in fixed_ips:
for floating in fixed.floating_ips:
addresses.append(floating.address)
return fixed_ips[0].network.multi_host, addresses
def migrate_instance_start(self, context, instance, migration):
"""Start to migrate the network of an instance."""
flavor = instance.get_flavor()
args = dict(
instance_uuid=instance.uuid,
rxtx_factor=flavor['rxtx_factor'],
project_id=instance.project_id,
source_compute=migration['source_compute'],
dest_compute=migration['dest_compute'],
floating_addresses=None,
)
multi_host, addresses = self._get_multi_addresses(context, instance)
if multi_host:
args['floating_addresses'] = addresses
args['host'] = migration['source_compute']
self.network_rpcapi.migrate_instance_start(context, **args)
def migrate_instance_finish(
self, context, instance, migration, provider_mappings):
"""Finish migrating the network of an instance."""
flavor = instance.get_flavor()
args = dict(
instance_uuid=instance.uuid,
rxtx_factor=flavor['rxtx_factor'],
project_id=instance.project_id,
source_compute=migration.source_compute,
dest_compute=migration.dest_compute,
floating_addresses=None,
)
multi_host, addresses = self._get_multi_addresses(context, instance)
if multi_host:
args['floating_addresses'] = addresses
args['host'] = migration.dest_compute
self.network_rpcapi.migrate_instance_finish(context, **args)
def setup_instance_network_on_host(
self, context, instance, host, migration=None,
provider_mappings=None):
"""Setup network for specified instance on host."""
self.migrate_instance_finish(
context, instance, {'source_compute': None, 'dest_compute': host},
None)
def cleanup_instance_network_on_host(self, context, instance, host):
"""Cleanup network for specified instance on host."""
self.migrate_instance_start(context, instance,
{'source_compute': host,
'dest_compute': None})

View File

@ -102,18 +102,6 @@ class NetworkAPI(base.Base):
"""Get specific network for client."""
raise NotImplementedError()
def create(self, context, **kwargs):
"""Create a network."""
raise NotImplementedError()
def delete(self, context, network_uuid):
"""Delete a specific network."""
raise NotImplementedError()
def get_fixed_ip(self, context, id):
"""Get fixed IP by id."""
raise NotImplementedError()
def get_fixed_ip_by_address(self, context, address):
"""Get fixed IP by address."""
raise NotImplementedError()
@ -149,10 +137,6 @@ class NetworkAPI(base.Base):
"""
raise NotImplementedError()
def get_vif_by_mac_address(self, context, mac_address):
"""Get vif mac address."""
raise NotImplementedError()
def allocate_floating_ip(self, context, pool=None):
"""Adds (allocate) floating IP to a project from a pool."""
raise NotImplementedError()
@ -281,44 +265,6 @@ class NetworkAPI(base.Base):
"""
raise NotImplementedError()
def get_dns_domains(self, context):
"""Returns a list of available dns domains.
These can be used to create DNS entries for floating IPs.
"""
raise NotImplementedError()
def add_dns_entry(self, context, address, name, dns_type, domain):
"""Create specified DNS entry for address."""
raise NotImplementedError()
def modify_dns_entry(self, context, name, address, domain):
"""Create specified DNS entry for address."""
raise NotImplementedError()
def delete_dns_entry(self, context, name, domain):
"""Delete the specified dns entry."""
raise NotImplementedError()
def delete_dns_domain(self, context, domain):
"""Delete the specified dns domain."""
raise NotImplementedError()
def get_dns_entries_by_address(self, context, address, domain):
"""Get entries for address and domain."""
raise NotImplementedError()
def get_dns_entries_by_name(self, context, name, domain):
"""Get entries for name and domain."""
raise NotImplementedError()
def create_private_dns_domain(self, context, domain, availability_zone):
"""Create a private DNS domain with nova availability zone."""
raise NotImplementedError()
def create_public_dns_domain(self, context, domain, project=None):
"""Create a public DNS domain with optional nova project."""
raise NotImplementedError()
def setup_networks_on_host(self, context, instance, host=None,
teardown=False):
"""Setup or teardown the network structures on hosts related to

View File

@ -1,44 +0,0 @@
# Copyright 2011 Andrew Bogott for the Wikimedia Foundation
#
# 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.
class DNSDriver(object):
"""Defines the DNS manager interface. Does nothing."""
def __init__(self):
pass
def get_domains(self):
raise NotImplementedError()
def create_entry(self, _name, _address, _type, _domain):
raise NotImplementedError()
def delete_entry(self, _name, _domain):
raise NotImplementedError()
def modify_address(self, _name, _address, _domain):
raise NotImplementedError()
def get_entries_by_address(self, _address, _domain):
raise NotImplementedError()
def get_entries_by_name(self, _name, _domain):
raise NotImplementedError()
def create_domain(self, _fqdomain):
raise NotImplementedError()
def delete_domain(self, _fqdomain):
raise NotImplementedError()

View File

@ -1,37 +0,0 @@
# Copyright 2012 Red Hat, Inc.
#
# 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.
import sys
from oslo_log import log as logging
from oslo_utils import importutils
import nova.conf
CONF = nova.conf.CONF
LOG = logging.getLogger(__name__)
def load_network_driver(network_driver=None):
if not network_driver:
network_driver = CONF.network_driver
if not network_driver:
LOG.error("Network driver option required, but not specified")
sys.exit(1)
LOG.info("Loading network driver '%s'", network_driver)
return importutils.import_module(network_driver)

View File

@ -1,659 +0,0 @@
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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 oslo_concurrency import processutils
from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_utils import excutils
from oslo_utils import importutils
from oslo_utils import uuidutils
import six
import nova.conf
from nova import context
from nova.db import base
from nova import exception
from nova.network import rpcapi as network_rpcapi
from nova import objects
from nova import rpc
from nova import servicegroup
from nova import utils
LOG = logging.getLogger(__name__)
CONF = nova.conf.CONF
class FloatingIP(object):
"""Mixin class for adding floating IP functionality to a manager."""
servicegroup_api = None
def init_host_floating_ips(self):
"""Configures floating IPs owned by host."""
admin_context = context.get_admin_context()
try:
floating_ips = objects.FloatingIPList.get_by_host(admin_context,
self.host)
except exception.NotFound:
return
for floating_ip in floating_ips:
if floating_ip.fixed_ip_id:
try:
fixed_ip = floating_ip.fixed_ip
except exception.FixedIpNotFound:
LOG.debug('Fixed IP %s not found', floating_ip.fixed_ip_id)
continue
interface = CONF.public_interface or floating_ip.interface
try:
self.l3driver.add_floating_ip(floating_ip.address,
fixed_ip.address,
interface,
fixed_ip.network)
except processutils.ProcessExecutionError:
LOG.debug('Interface %s not found', interface)
raise exception.NoFloatingIpInterface(interface=interface)
def allocate_for_instance(self, context, **kwargs):
"""Handles allocating the floating IP resources for an instance.
calls super class allocate_for_instance() as well
rpc.called by network_api
"""
instance_uuid = kwargs.get('instance_id')
if not uuidutils.is_uuid_like(instance_uuid):
instance_uuid = kwargs.get('instance_uuid')
project_id = kwargs.get('project_id')
# call the next inherited class's allocate_for_instance()
# which is currently the NetworkManager version
# do this first so fixed ip is already allocated
nw_info = super(FloatingIP, self).allocate_for_instance(context,
**kwargs)
if CONF.auto_assign_floating_ip:
context = context.elevated()
# allocate a floating ip
floating_address = self.allocate_floating_ip(context, project_id,
True)
LOG.debug("floating IP allocation for instance "
"|%s|", floating_address,
instance_uuid=instance_uuid)
# get the first fixed address belonging to the instance
fixed_ips = nw_info.fixed_ips()
fixed_address = fixed_ips[0]['address']
# associate the floating ip to fixed_ip
self.associate_floating_ip(context,
floating_address,
fixed_address,
affect_auto_assigned=True)
# create a fresh set of network info that contains the floating ip
nw_info = self.get_instance_nw_info(context, **kwargs)
return nw_info
def deallocate_for_instance(self, context, **kwargs):
"""Handles deallocating floating IP resources for an instance.
calls super class deallocate_for_instance() as well.
rpc.called by network_api
"""
if 'instance' in kwargs:
instance_uuid = kwargs['instance'].uuid
else:
instance_uuid = kwargs['instance_id']
if not uuidutils.is_uuid_like(instance_uuid):
# NOTE(francois.charlier): in some cases the instance might be
# deleted before the IPs are released, so we need to get
# deleted instances too
instance = objects.Instance.get_by_id(
context.elevated(read_deleted='yes'), instance_uuid)
instance_uuid = instance.uuid
try:
fixed_ips = objects.FixedIPList.get_by_instance_uuid(
context, instance_uuid)
except exception.FixedIpNotFoundForInstance:
fixed_ips = []
# add to kwargs so we can pass to super to save a db lookup there
kwargs['fixed_ips'] = fixed_ips
for fixed_ip in fixed_ips:
fixed_id = fixed_ip.id
floating_ips = objects.FloatingIPList.get_by_fixed_ip_id(context,
fixed_id)
# disassociate floating ips related to fixed_ip
for floating_ip in floating_ips:
address = str(floating_ip.address)
try:
self.disassociate_floating_ip(context,
address,
affect_auto_assigned=True)
except exception.FloatingIpNotAssociated:
LOG.info("Floating IP %s is not associated. Ignore.",
address)
# deallocate if auto_assigned
if floating_ip.auto_assigned:
self.deallocate_floating_ip(context, address,
affect_auto_assigned=True)
# call the next inherited class's deallocate_for_instance()
# which is currently the NetworkManager version
# call this after so floating IPs are handled first
super(FloatingIP, self).deallocate_for_instance(context, **kwargs)
def _floating_ip_owned_by_project(self, context, floating_ip):
"""Raises if floating IP does not belong to project."""
if context.is_admin:
return
if floating_ip.project_id != context.project_id:
if floating_ip.project_id is None:
LOG.warning('Address |%(address)s| is not allocated',
{'address': floating_ip.address})
raise exception.Forbidden()
else:
LOG.warning('Address |%(address)s| is not allocated '
'to your project |%(project)s|',
{'address': floating_ip.address,
'project': context.project_id})
raise exception.Forbidden()
def _floating_ip_pool_exists(self, context, name):
"""Returns true if the specified floating IP pool exists. Otherwise,
returns false.
"""
pools = [pool.get('name') for pool in
self.get_floating_ip_pools(context)]
if name in pools:
return True
return False
def allocate_floating_ip(self, context, project_id, auto_assigned=False,
pool=None):
"""Gets a floating IP from the pool."""
# NOTE(tr3buchet): all network hosts in zone now use the same pool
pool = pool or CONF.default_floating_pool
use_quota = not auto_assigned
if not self._floating_ip_pool_exists(context, pool):
raise exception.FloatingIpPoolNotFound()
# Check the quota; can't put this in the API because we get
# called into from other places
try:
if use_quota:
objects.Quotas.check_deltas(context, {'floating_ips': 1},
project_id)
except exception.OverQuota:
LOG.warning("Quota exceeded for %s, tried to allocate "
"floating IP", context.project_id)
raise exception.FloatingIpLimitExceeded()
floating_ip = objects.FloatingIP.allocate_address(
context, project_id, pool, auto_assigned=auto_assigned)
# NOTE(melwitt): We recheck the quota after creating the object to
# prevent users from allocating more resources than their allowed quota
# in the event of a race. This is configurable because it can be
# expensive if strict quota limits are not required in a deployment.
if CONF.quota.recheck_quota and use_quota:
try:
objects.Quotas.check_deltas(context, {'floating_ips': 0},
project_id)
except exception.OverQuota:
objects.FloatingIP.deallocate(context, floating_ip.address)
LOG.warning("Quota exceeded for %s, tried to allocate "
"floating IP", context.project_id)
raise exception.FloatingIpLimitExceeded()
payload = dict(project_id=project_id, floating_ip=floating_ip)
self.notifier.info(context,
'network.floating_ip.allocate', payload)
return floating_ip
@messaging.expected_exceptions(exception.FloatingIpNotFoundForAddress)
def deallocate_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Returns a floating IP to the pool."""
floating_ip = objects.FloatingIP.get_by_address(context, address)
# handle auto_assigned
if not affect_auto_assigned and floating_ip.auto_assigned:
return
# make sure project owns this floating ip (allocated)
self._floating_ip_owned_by_project(context, floating_ip)
# make sure floating ip is not associated
if floating_ip.fixed_ip_id:
floating_address = floating_ip.address
raise exception.FloatingIpAssociated(address=floating_address)
# clean up any associated DNS entries
self._delete_all_entries_for_ip(context,
floating_ip.address)
payload = dict(project_id=floating_ip.project_id,
floating_ip=str(floating_ip.address))
self.notifier.info(context, 'network.floating_ip.deallocate', payload)
objects.FloatingIP.deallocate(context, address)
@messaging.expected_exceptions(exception.FloatingIpNotFoundForAddress)
def associate_floating_ip(self, context, floating_address, fixed_address,
affect_auto_assigned=False):
"""Associates a floating IP with a fixed IP.
Makes sure everything makes sense then calls _associate_floating_ip,
rpc'ing to correct host if i'm not it.
Access to the floating_address is verified but access to the
fixed_address is not verified. This assumes that the calling
side has already verified that the fixed_address is legal by
checking access to the instance.
"""
floating_ip = objects.FloatingIP.get_by_address(context,
floating_address)
# handle auto_assigned
if not affect_auto_assigned and floating_ip.auto_assigned:
return
# make sure project owns this floating ip (allocated)
self._floating_ip_owned_by_project(context, floating_ip)
# disassociate any already associated
orig_instance_uuid = None
if floating_ip.fixed_ip_id:
# find previously associated instance
fixed_ip = floating_ip.fixed_ip
if str(fixed_ip.address) == fixed_address:
# NOTE(vish): already associated to this address
return
orig_instance_uuid = fixed_ip.instance_uuid
self.disassociate_floating_ip(context, floating_address)
fixed_ip = objects.FixedIP.get_by_address(context, fixed_address)
# send to correct host, unless i'm the correct host
network = objects.Network.get_by_id(context.elevated(),
fixed_ip.network_id)
if network.multi_host:
instance = objects.Instance.get_by_uuid(
context, fixed_ip.instance_uuid)
host = instance.host
else:
host = network.host
interface = floating_ip.interface
if host == self.host:
# i'm the correct host
self._associate_floating_ip(context, floating_address,
fixed_address, interface,
fixed_ip.instance_uuid)
else:
# send to correct host
self.network_rpcapi._associate_floating_ip(context,
floating_address, fixed_address, interface, host,
fixed_ip.instance_uuid)
return orig_instance_uuid
def _associate_floating_ip(self, context, floating_address, fixed_address,
interface, instance_uuid):
"""Performs db and driver calls to associate floating IP & fixed IP."""
interface = CONF.public_interface or interface
@utils.synchronized(six.text_type(floating_address))
def do_associate():
# associate floating ip
floating = objects.FloatingIP.associate(context, floating_address,
fixed_address, self.host)
fixed = floating.fixed_ip
if not fixed:
# NOTE(vish): ip was already associated
return
try:
# gogo driver time
self.l3driver.add_floating_ip(floating_address, fixed_address,
interface, fixed['network'])
except processutils.ProcessExecutionError as e:
with excutils.save_and_reraise_exception():
try:
objects.FloatingIP.disassociate(context,
floating_address)
except Exception:
LOG.warning('Failed to disassociated floating '
'address: %s', floating_address)
pass
if "Cannot find device" in six.text_type(e):
try:
LOG.error('Interface %s not found', interface)
except Exception:
pass
raise exception.NoFloatingIpInterface(
interface=interface)
payload = dict(project_id=context.project_id,
instance_id=instance_uuid,
floating_ip=floating_address)
self.notifier.info(context,
'network.floating_ip.associate', payload)
do_associate()
@messaging.expected_exceptions(exception.FloatingIpNotFoundForAddress)
def disassociate_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Disassociates a floating IP from its fixed IP.
Makes sure everything makes sense then calls _disassociate_floating_ip,
rpc'ing to correct host if i'm not it.
"""
floating_ip = objects.FloatingIP.get_by_address(context, address)
# handle auto assigned
if not affect_auto_assigned and floating_ip.auto_assigned:
raise exception.CannotDisassociateAutoAssignedFloatingIP()
# make sure project owns this floating ip (allocated)
self._floating_ip_owned_by_project(context, floating_ip)
# make sure floating ip is associated
if not floating_ip.fixed_ip_id:
floating_address = floating_ip.address
raise exception.FloatingIpNotAssociated(address=floating_address)
fixed_ip = objects.FixedIP.get_by_id(context, floating_ip.fixed_ip_id)
# send to correct host, unless i'm the correct host
network = objects.Network.get_by_id(context.elevated(),
fixed_ip.network_id)
interface = floating_ip.interface
if network.multi_host:
instance = objects.Instance.get_by_uuid(
context, fixed_ip.instance_uuid)
service = objects.Service.get_by_host_and_binary(
context.elevated(), instance.host, 'nova-network')
if service and self.servicegroup_api.service_is_up(service):
host = instance.host
else:
# NOTE(vish): if the service is down just deallocate the data
# locally. Set the host to local so the call will
# not go over rpc and set interface to None so the
# teardown in the driver does not happen.
host = self.host
interface = None
else:
host = network.host
if host == self.host:
# i'm the correct host
self._disassociate_floating_ip(context, address, interface,
fixed_ip.instance_uuid)
else:
# send to correct host
self.network_rpcapi._disassociate_floating_ip(context, address,
interface, host, fixed_ip.instance_uuid)
def _disassociate_floating_ip(self, context, address, interface,
instance_uuid):
"""Performs db and driver calls to disassociate floating IP."""
interface = CONF.public_interface or interface
@utils.synchronized(six.text_type(address))
def do_disassociate():
# NOTE(vish): Note that we are disassociating in the db before we
# actually remove the ip address on the host. We are
# safe from races on this host due to the decorator,
# but another host might grab the ip right away. We
# don't worry about this case because the minuscule
# window where the ip is on both hosts shouldn't cause
# any problems.
floating = objects.FloatingIP.disassociate(context, address)
fixed = floating.fixed_ip
if not fixed:
# NOTE(vish): ip was already disassociated
return
if interface:
# go go driver time
self.l3driver.remove_floating_ip(address, fixed.address,
interface, fixed.network)
payload = dict(project_id=context.project_id,
instance_id=instance_uuid,
floating_ip=address)
self.notifier.info(context,
'network.floating_ip.disassociate', payload)
do_disassociate()
@messaging.expected_exceptions(exception.FloatingIpNotFound)
def get_floating_ip(self, context, id):
"""Returns a floating IP as a dict."""
# NOTE(vish): This is no longer used but can't be removed until
# we major version the network_rpcapi.
return dict(objects.FloatingIP.get_by_id(context, id))
def get_floating_pools(self, context):
"""Returns list of floating pools."""
# NOTE(maurosr) This method should be removed in future, replaced by
# get_floating_ip_pools. See bug #1091668
return self.get_floating_ip_pools(context)
def get_floating_ip_pools(self, context):
"""Returns list of floating ip pools."""
# NOTE(vish): This is no longer used but can't be removed until
# we major version the network_rpcapi.
pools = objects.FloatingIP.get_pool_names(context)
return [dict(name=name) for name in pools]
def get_floating_ip_by_address(self, context, address):
"""Returns a floating IP as a dict."""
# NOTE(vish): This is no longer used but can't be removed until
# we major version the network_rpcapi.
return objects.FloatingIP.get_by_address(context, address)
def get_floating_ips_by_project(self, context):
"""Returns the floating IPs allocated to a project."""
# NOTE(vish): This is no longer used but can't be removed until
# we major version the network_rpcapi.
return objects.FloatingIPList.get_by_project(context,
context.project_id)
def get_floating_ips_by_fixed_address(self, context, fixed_address):
"""Returns the floating IPs associated with a fixed_address."""
# NOTE(vish): This is no longer used but can't be removed until
# we major version the network_rpcapi.
floating_ips = objects.FloatingIPList.get_by_fixed_address(
context, fixed_address)
return [str(floating_ip.address) for floating_ip in floating_ips]
def _is_stale_floating_ip_address(self, context, floating_ip):
try:
self._floating_ip_owned_by_project(context, floating_ip)
except exception.Forbidden:
return True
return False if floating_ip.get('fixed_ip_id') else True
def migrate_instance_start(self, context, instance_uuid,
floating_addresses,
rxtx_factor=None, project_id=None,
source=None, dest=None):
# We only care if floating_addresses are provided and we're
# switching hosts
if not floating_addresses or (source and source == dest):
return
LOG.info("Starting migration network for instance %s", instance_uuid)
for address in floating_addresses:
floating_ip = objects.FloatingIP.get_by_address(context, address)
if self._is_stale_floating_ip_address(context, floating_ip):
LOG.warning("Floating IP address |%(address)s| no longer "
"belongs to instance %(instance_uuid)s. "
"Will not migrate it ",
{'address': address,
'instance_uuid': instance_uuid})
continue
interface = CONF.public_interface or floating_ip.interface
fixed_ip = floating_ip.fixed_ip
self.l3driver.remove_floating_ip(floating_ip.address,
fixed_ip.address,
interface,
fixed_ip.network)
# NOTE(wenjianhn): Make this address will not be bound to public
# interface when restarts nova-network on dest compute node
floating_ip.host = None
floating_ip.save()
def migrate_instance_finish(self, context, instance_uuid,
floating_addresses, host=None,
rxtx_factor=None, project_id=None,
source=None, dest=None):
# We only care if floating_addresses are provided and we're
# switching hosts
if host and not dest:
dest = host
if not floating_addresses or (source and source == dest):
return
LOG.info("Finishing migration network for instance %s", instance_uuid)
for address in floating_addresses:
floating_ip = objects.FloatingIP.get_by_address(context, address)
if self._is_stale_floating_ip_address(context, floating_ip):
LOG.warning("Floating IP address |%(address)s| no longer "
"belongs to instance %(instance_uuid)s. "
"Will not setup it.",
{'address': address,
'instance_uuid': instance_uuid})
continue
floating_ip.host = dest
floating_ip.save()
interface = CONF.public_interface or floating_ip.interface
fixed_ip = floating_ip.fixed_ip
self.l3driver.add_floating_ip(floating_ip.address,
fixed_ip.address,
interface,
fixed_ip.network)
def _prepare_domain_entry(self, context, domainref):
scope = domainref.scope
if scope == 'private':
this_domain = {'domain': domainref.domain,
'scope': scope,
'availability_zone': domainref.availability_zone}
else:
this_domain = {'domain': domainref.domain,
'scope': scope,
'project': domainref.project_id}
return this_domain
def get_dns_domains(self, context):
domains = []
domain_list = objects.DNSDomainList.get_all(context)
floating_driver_domain_list = self.floating_dns_manager.get_domains()
instance_driver_domain_list = self.instance_dns_manager.get_domains()
for dns_domain in domain_list:
if (dns_domain.domain in floating_driver_domain_list or
dns_domain.domain in instance_driver_domain_list):
domain_entry = self._prepare_domain_entry(context, dns_domain)
if domain_entry:
domains.append(domain_entry)
else:
LOG.warning('Database inconsistency: DNS domain |%s| is '
'registered in the Nova db but not visible to '
'either the floating or instance DNS driver. '
'It will be ignored.', dns_domain.domain)
return domains
def add_dns_entry(self, context, address, name, dns_type, domain):
self.floating_dns_manager.create_entry(name, address,
dns_type, domain)
def modify_dns_entry(self, context, address, name, domain):
self.floating_dns_manager.modify_address(name, address,
domain)
def delete_dns_entry(self, context, name, domain):
self.floating_dns_manager.delete_entry(name, domain)
def _delete_all_entries_for_ip(self, context, address):
domain_list = self.get_dns_domains(context)
for domain in domain_list:
names = self.get_dns_entries_by_address(context,
address,
domain['domain'])
for name in names:
self.delete_dns_entry(context, name, domain['domain'])
def get_dns_entries_by_address(self, context, address, domain):
return self.floating_dns_manager.get_entries_by_address(address,
domain)
def get_dns_entries_by_name(self, context, name, domain):
return self.floating_dns_manager.get_entries_by_name(name,
domain)
def create_private_dns_domain(self, context, domain, av_zone):
objects.DNSDomain.register_for_zone(context, domain, av_zone)
try:
self.instance_dns_manager.create_domain(domain)
except exception.FloatingIpDNSExists:
LOG.warning('Domain |%(domain)s| already exists, '
'changing zone to |%(av_zone)s|.',
{'domain': domain, 'av_zone': av_zone})
def create_public_dns_domain(self, context, domain, project):
objects.DNSDomain.register_for_project(context, domain, project)
try:
self.floating_dns_manager.create_domain(domain)
except exception.FloatingIpDNSExists:
LOG.warning('Domain |%(domain)s| already exists, '
'changing project to |%(project)s|.',
{'domain': domain, 'project': project})
def delete_dns_domain(self, context, domain):
objects.DNSDomain.delete_by_domain(context, domain)
self.floating_dns_manager.delete_domain(domain)
class LocalManager(base.Base, FloatingIP):
def __init__(self):
super(LocalManager, self).__init__()
# NOTE(vish): setting the host to none ensures that the actual
# l3driver commands for l3 are done via rpc.
self.host = None
self.servicegroup_api = servicegroup.API()
self.network_rpcapi = network_rpcapi.NetworkAPI()
self.floating_dns_manager = importutils.import_object(
CONF.floating_ip_dns_manager)
self.instance_dns_manager = importutils.import_object(
CONF.instance_dns_manager)
self.notifier = rpc.get_notifier('network', CONF.host)

View File

@ -1,179 +0,0 @@
# Copyright 2012 Nicira Networks, Inc
# 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 oslo_log import log as logging
from nova.network import linux_net
import nova.privsep.linux_net
from nova import utils
LOG = logging.getLogger(__name__)
class L3Driver(object):
"""Abstract class that defines a generic L3 API."""
def __init__(self, l3_lib=None):
raise NotImplementedError()
def initialize(self, **kwargs):
"""Set up basic L3 networking functionality."""
raise NotImplementedError()
def initialize_network(self, cidr, is_external):
"""Enable rules for a specific network."""
raise NotImplementedError()
def initialize_gateway(self, network_ref):
"""Set up a gateway on this network."""
raise NotImplementedError()
def remove_gateway(self, network_ref):
"""Remove an existing gateway on this network."""
raise NotImplementedError()
def is_initialized(self):
""":returns: True/False (whether the driver is initialized)."""
raise NotImplementedError()
def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
network=None):
"""Add a floating IP bound to the fixed IP with an optional
l3_interface_id. Some drivers won't care about the
l3_interface_id so just pass None in that case. Network
is also an optional parameter.
"""
raise NotImplementedError()
def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
network=None):
raise NotImplementedError()
def add_vpn(self, public_ip, port, private_ip):
raise NotImplementedError()
def remove_vpn(self, public_ip, port, private_ip):
raise NotImplementedError()
def clean_conntrack(self, fixed_ip):
raise NotImplementedError()
def teardown(self):
raise NotImplementedError()
class LinuxNetL3(L3Driver):
"""L3 driver that uses linux_net as the backend."""
def __init__(self):
self.initialized = False
def initialize(self, **kwargs):
if self.initialized:
return
LOG.debug("Initializing linux_net L3 driver")
fixed_range = kwargs.get('fixed_range', False)
networks = kwargs.get('networks', None)
if not fixed_range and networks is not None:
for network in networks:
if network['enable_dhcp']:
is_ext = (network['dhcp_server'] is not None and
network['dhcp_server'] != network['gateway'])
self.initialize_network(network['cidr'], is_ext)
linux_net.ensure_metadata_ip()
linux_net.metadata_forward()
self.initialized = True
def is_initialized(self):
return self.initialized
def initialize_network(self, cidr, is_external):
linux_net.init_host(cidr, is_external)
def initialize_gateway(self, network_ref):
mac_address = utils.generate_mac_address()
dev = linux_net.plug(network_ref, mac_address,
gateway=(network_ref['gateway'] is not None))
linux_net.initialize_gateway_device(dev, network_ref)
def remove_gateway(self, network_ref):
linux_net.unplug(network_ref)
def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
network=None):
linux_net.ensure_floating_forward(floating_ip, fixed_ip,
l3_interface_id, network)
linux_net.bind_floating_ip(floating_ip, l3_interface_id)
def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
network=None):
nova.privsep.linux_net.unbind_ip(l3_interface_id, floating_ip)
linux_net.remove_floating_forward(floating_ip, fixed_ip,
l3_interface_id, network)
nova.privsep.linux_net.clean_conntrack(fixed_ip)
def add_vpn(self, public_ip, port, private_ip):
linux_net.ensure_vpn_forward(public_ip, port, private_ip)
def remove_vpn(self, public_ip, port, private_ip):
# Linux net currently doesn't implement any way of removing
# the VPN forwarding rules
pass
def teardown(self):
pass
class NullL3(L3Driver):
"""The L3 driver that doesn't do anything. This class can be used when
nova-network should not manipulate L3 forwarding at all (e.g., in a Flat
or FlatDHCP scenario).
"""
def __init__(self):
pass
def initialize(self, **kwargs):
pass
def is_initialized(self):
return True
def initialize_network(self, cidr, is_external):
pass
def initialize_gateway(self, network_ref):
pass
def remove_gateway(self, network_ref):
pass
def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
network=None):
pass
def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
network=None):
pass
def add_vpn(self, public_ip, port, private_ip):
pass
def remove_vpn(self, public_ip, port, private_ip):
pass
def clean_conntrack(self, fixed_ip):
pass
def teardown(self):
pass

View File

@ -1,337 +0,0 @@
# Copyright 2012 Andrew Bogott for the Wikimedia Foundation
#
# 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.
try:
import ldap
except ImportError:
# This module needs to be importable despite ldap not being a requirement
ldap = None
import time
from oslo_log import log as logging
import nova.conf
from nova import exception
from nova.i18n import _
from nova.network import dns_driver
from nova import utils
CONF = nova.conf.CONF
LOG = logging.getLogger(__name__)
# Importing ldap.modlist breaks the tests for some reason,
# so this is an abbreviated version of a function from
# there.
def create_modlist(newattrs):
modlist = []
for attrtype in newattrs.keys():
utf8_vals = []
for val in newattrs[attrtype]:
utf8_vals.append(utils.utf8(val))
newattrs[attrtype] = utf8_vals
modlist.append((attrtype, newattrs[attrtype]))
return modlist
class DNSEntry(object):
def __init__(self, ldap_object):
"""ldap_object is an instance of ldap.LDAPObject.
It should already be initialized and bound before
getting passed in here.
"""
self.lobj = ldap_object
self.ldap_tuple = None
self.qualified_domain = None
@classmethod
def _get_tuple_for_domain(cls, lobj, domain):
entry = lobj.search_s(CONF.ldap_dns_base_dn, ldap.SCOPE_SUBTREE,
'(associatedDomain=%s)' % utils.utf8(domain))
if not entry:
return None
if len(entry) > 1:
LOG.warning("Found multiple matches for domain "
"%(domain)s.\n%(entry)s",
domain, entry)
return entry[0]
@classmethod
def _get_all_domains(cls, lobj):
entries = lobj.search_s(CONF.ldap_dns_base_dn,
ldap.SCOPE_SUBTREE, '(sOARecord=*)')
domains = []
for entry in entries:
domain = entry[1].get('associatedDomain')
if domain:
domains.append(domain[0])
return domains
def _set_tuple(self, tuple):
self.ldap_tuple = tuple
def _qualify(self, name):
return '%s.%s' % (name, self.qualified_domain)
def _dequalify(self, name):
z = ".%s" % self.qualified_domain
if name.endswith(z):
dequalified = name[0:name.rfind(z)]
else:
LOG.warning("Unable to dequalify. %(name)s is not in "
"%(domain)s.\n",
{'name': name,
'domain': self.qualified_domain})
dequalified = None
return dequalified
def _dn(self):
return self.ldap_tuple[0]
dn = property(_dn)
def _rdn(self):
return self.dn.partition(',')[0]
rdn = property(_rdn)
class DomainEntry(DNSEntry):
@classmethod
def _soa(cls):
date = time.strftime('%Y%m%d%H%M%S')
soa = '%s %s %s %d %d %d %d' % (
CONF.ldap_dns_servers[0],
CONF.ldap_dns_soa_hostmaster,
date,
CONF.ldap_dns_soa_refresh,
CONF.ldap_dns_soa_retry,
CONF.ldap_dns_soa_expiry,
CONF.ldap_dns_soa_minimum)
return utils.utf8(soa)
@classmethod
def create_domain(cls, lobj, domain):
"""Create a new domain entry, and return an object that wraps it."""
entry = cls._get_tuple_for_domain(lobj, domain)
if entry:
raise exception.FloatingIpDNSExists(name=domain, domain='')
newdn = 'dc=%s,%s' % (domain, CONF.ldap_dns_base_dn)
attrs = {'objectClass': ['domainrelatedobject', 'dnsdomain',
'domain', 'dcobject', 'top'],
'sOARecord': [cls._soa()],
'associatedDomain': [domain],
'dc': [domain]}
lobj.add_s(newdn, create_modlist(attrs))
return DomainEntry(lobj, domain)
def __init__(self, ldap_object, domain):
super(DomainEntry, self).__init__(ldap_object)
entry = self._get_tuple_for_domain(self.lobj, domain)
if not entry:
raise exception.NotFound()
self._set_tuple(entry)
assert(entry[1]['associatedDomain'][0] == domain)
self.qualified_domain = domain
def delete(self):
"""Delete the domain that this entry refers to."""
entries = self.lobj.search_s(self.dn,
ldap.SCOPE_SUBTREE,
'(aRecord=*)')
for entry in entries:
self.lobj.delete_s(entry[0])
self.lobj.delete_s(self.dn)
def update_soa(self):
mlist = [(ldap.MOD_REPLACE, 'sOARecord', self._soa())]
self.lobj.modify_s(self.dn, mlist)
def subentry_with_name(self, name):
entry = self.lobj.search_s(self.dn, ldap.SCOPE_SUBTREE,
'(associatedDomain=%s.%s)' %
(utils.utf8(name),
utils.utf8(self.qualified_domain)))
if entry:
return HostEntry(self, entry[0])
else:
return None
def subentries_with_ip(self, ip):
entries = self.lobj.search_s(self.dn, ldap.SCOPE_SUBTREE,
'(aRecord=%s)' % utils.utf8(ip))
objs = []
for entry in entries:
if 'associatedDomain' in entry[1]:
objs.append(HostEntry(self, entry))
return objs
def add_entry(self, name, address):
if self.subentry_with_name(name):
raise exception.FloatingIpDNSExists(name=name,
domain=self.qualified_domain)
entries = self.subentries_with_ip(address)
if entries:
# We already have an ldap entry for this IP, so we just
# need to add the new name.
existingdn = entries[0].dn
self.lobj.modify_s(existingdn, [(ldap.MOD_ADD,
'associatedDomain',
utils.utf8(self._qualify(name)))])
return self.subentry_with_name(name)
else:
# We need to create an entirely new entry.
newdn = 'dc=%s,%s' % (name, self.dn)
attrs = {'objectClass': ['domainrelatedobject', 'dnsdomain',
'domain', 'dcobject', 'top'],
'aRecord': [address],
'associatedDomain': [self._qualify(name)],
'dc': [name]}
self.lobj.add_s(newdn, create_modlist(attrs))
return self.subentry_with_name(name)
def remove_entry(self, name):
entry = self.subentry_with_name(name)
if not entry:
raise exception.NotFound()
entry.remove_name(name)
self.update_soa()
class HostEntry(DNSEntry):
def __init__(self, parent, tuple):
super(HostEntry, self).__init__(parent.lobj)
self.parent_entry = parent
self._set_tuple(tuple)
self.qualified_domain = parent.qualified_domain
def remove_name(self, name):
names = self.ldap_tuple[1]['associatedDomain']
if not names:
raise exception.NotFound()
if len(names) > 1:
# We just have to remove the requested domain.
self.lobj.modify_s(self.dn, [(ldap.MOD_DELETE, 'associatedDomain',
self._qualify(utils.utf8(name)))])
if (self.rdn[1] == name):
# We just removed the rdn, so we need to move this entry.
names.remove(self._qualify(name))
newrdn = 'dc=%s' % self._dequalify(names[0])
self.lobj.modrdn_s(self.dn, [newrdn])
else:
# We should delete the entire record.
self.lobj.delete_s(self.dn)
def modify_address(self, name, address):
names = self.ldap_tuple[1]['associatedDomain']
if not names:
raise exception.NotFound()
if len(names) == 1:
self.lobj.modify_s(self.dn, [(ldap.MOD_REPLACE, 'aRecord',
[utils.utf8(address)])])
else:
self.remove_name(name)
self.parent.add_entry(name, address)
def _names(self):
names = []
for domain in self.ldap_tuple[1]['associatedDomain']:
names.append(self._dequalify(domain))
return names
names = property(_names)
def _ip(self):
ip = self.ldap_tuple[1]['aRecord'][0]
return ip
ip = property(_ip)
def _parent(self):
return self.parent_entry
parent = property(_parent)
class LdapDNS(dns_driver.DNSDriver):
"""Driver for PowerDNS using ldap as a back end.
This driver assumes ldap-method=strict, with all domains
in the top-level, aRecords only.
"""
def __init__(self):
if not ldap:
raise ImportError(_('ldap not installed'))
self.lobj = ldap.initialize(CONF.ldap_dns_url)
self.lobj.simple_bind_s(CONF.ldap_dns_user,
CONF.ldap_dns_password)
def get_domains(self):
return DomainEntry._get_all_domains(self.lobj)
def create_entry(self, name, address, type, domain):
if type.lower() != 'a':
raise exception.InvalidInput(_("This driver only supports "
"type 'a' entries."))
dEntry = DomainEntry(self.lobj, domain)
dEntry.add_entry(name, address)
def delete_entry(self, name, domain):
dEntry = DomainEntry(self.lobj, domain)
dEntry.remove_entry(name)
def get_entries_by_address(self, address, domain):
try:
dEntry = DomainEntry(self.lobj, domain)
except exception.NotFound:
return []
entries = dEntry.subentries_with_ip(address)
names = []
for entry in entries:
names.extend(entry.names)
return names
def get_entries_by_name(self, name, domain):
try:
dEntry = DomainEntry(self.lobj, domain)
except exception.NotFound:
return []
nEntry = dEntry.subentry_with_name(name)
if nEntry:
return [nEntry.ip]
def modify_address(self, name, address, domain):
dEntry = DomainEntry(self.lobj, domain)
nEntry = dEntry.subentry_with_name(name)
nEntry.modify_address(name, address)
def create_domain(self, domain):
DomainEntry.create_domain(self.lobj, domain)
def delete_domain(self, domain):
dEntry = DomainEntry(self.lobj, domain)
dEntry.delete()
def delete_dns_file(self):
LOG.warning("This shouldn't be getting called except during testing.")
pass

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,206 +0,0 @@
# Copyright 2011 Andrew Bogott for the Wikimedia Foundation
#
# 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.
import os
from oslo_config import cfg
from oslo_log import log as logging
import six
from nova import exception
from nova.i18n import _
from nova.network import dns_driver
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class MiniDNS(dns_driver.DNSDriver):
"""Trivial DNS driver. This will read/write to either a local,
flat file or an in memory StringIO and have no effect on your actual
DNS system. This class is strictly for testing purposes, and should
keep you out of dependency hell.
A file is used when CONF.log_dir is set. This is relevant for when
two different DNS driver instances share the same data file.
Note that there is almost certainly a race condition here that
will manifest anytime instances are rapidly created and deleted.
A proper implementation will need some manner of locking.
"""
def __init__(self):
filename = None
if CONF.log_dir:
filename = os.path.join(CONF.log_dir, "dnstest.txt")
self.file = open(filename, 'w+')
else:
self.file = six.StringIO()
if not filename or not os.path.exists(filename):
self.file.write("# minidns\n\n\n")
self.file.flush()
def get_domains(self):
entries = []
self.file.seek(0)
for line in self.file:
entry = self.parse_line(line)
if entry and entry['address'] == 'domain':
entries.append(entry['name'])
return entries
def qualify(self, name, domain):
if domain:
qualified = "%s.%s" % (name, domain)
else:
qualified = name
return qualified.lower()
def create_entry(self, name, address, type, domain):
if name is None:
raise exception.InvalidInput(_("Invalid name"))
if type.lower() != 'a':
raise exception.InvalidInput(_("This driver only supports "
"type 'a'"))
if self.get_entries_by_name(name, domain):
raise exception.FloatingIpDNSExists(name=name, domain=domain)
self.file.seek(0, os.SEEK_END)
self.file.write("%s %s %s\n" %
(address, self.qualify(name, domain), type))
self.file.flush()
def parse_line(self, line):
vals = line.split()
if len(vals) < 3:
return None
else:
entry = {}
entry['address'] = vals[0].lower()
entry['name'] = vals[1].lower()
entry['type'] = vals[2].lower()
if entry['address'] == 'domain':
entry['domain'] = entry['name']
else:
entry['domain'] = entry['name'].partition('.')[2]
return entry
def delete_entry(self, name, domain):
if name is None:
raise exception.InvalidInput(_("Invalid name"))
deleted = False
keeps = []
self.file.seek(0)
for line in self.file:
entry = self.parse_line(line)
if (not entry or
entry['name'] != self.qualify(name, domain)):
keeps.append(line)
else:
deleted = True
self.file.truncate(0)
self.file.seek(0)
self.file.write(''.join(keeps))
self.file.flush()
if not deleted:
LOG.warning('Cannot delete entry |%s|', self.qualify(name, domain))
raise exception.NotFound
def modify_address(self, name, address, domain):
if not self.get_entries_by_name(name, domain):
raise exception.NotFound
lines = []
self.file.seek(0)
for line in self.file:
entry = self.parse_line(line)
if (entry and
entry['name'] == self.qualify(name, domain)):
lines.append("%s %s %s\n" %
(address, self.qualify(name, domain), entry['type']))
else:
lines.append(line)
self.file.truncate(0)
self.file.seek(0)
self.file.write(''.join(lines))
self.file.flush()
def get_entries_by_address(self, address, domain):
entries = []
self.file.seek(0)
for line in self.file:
entry = self.parse_line(line)
if entry and entry['address'] == address.lower():
if entry['name'].endswith(domain.lower()):
name = entry['name'].split(".")[0]
if name not in entries:
entries.append(name)
return entries
def get_entries_by_name(self, name, domain):
entries = []
self.file.seek(0)
for line in self.file:
entry = self.parse_line(line)
if (entry and
entry['name'] == self.qualify(name, domain)):
entries.append(entry['address'])
return entries
def delete_dns_file(self):
self.file.close()
try:
if os.path.exists(self.file.name):
try:
os.remove(self.file.name)
except OSError:
pass
except AttributeError:
# This was a BytesIO, which has no name.
pass
def create_domain(self, fqdomain):
if self.get_entries_by_name(fqdomain, ''):
raise exception.FloatingIpDNSExists(name=fqdomain, domain='')
self.file.seek(0, os.SEEK_END)
self.file.write("%s %s %s\n" % ('domain', fqdomain, 'domain'))
self.file.flush()
def delete_domain(self, fqdomain):
deleted = False
keeps = []
self.file.seek(0)
for line in self.file:
entry = self.parse_line(line)
if (not entry or
entry['domain'] != fqdomain.lower()):
keeps.append(line)
else:
LOG.info("deleted %s", entry)
deleted = True
self.file.truncate(0)
self.file.seek(0)
self.file.write(''.join(keeps))
self.file.flush()
if not deleted:
LOG.warning('Cannot delete domain |%s|', fqdomain)
raise exception.NotFound

View File

@ -2496,14 +2496,6 @@ class API(base_api.NetworkAPI):
uuid=network['id'])
return net_obj
def delete(self, context, network_uuid):
"""Delete a network for client."""
raise NotImplementedError()
def get_fixed_ip(self, context, id):
"""Get a fixed IP from the id."""
raise NotImplementedError()
def get_fixed_ip_by_address(self, context, address):
"""Return instance uuids given an address."""
uuid_maps = self._get_instance_uuids_by_ip(context, address)
@ -2563,8 +2555,6 @@ class API(base_api.NetworkAPI):
"""Return floating IP pool names."""
client = get_client(context)
pools = self._get_floating_ip_pools(client)
# Note(salv-orlando): Return a list of names to be consistent with
# nova.network.api.get_floating_ip_pools
return [n['name'] or n['id'] for n in pools]
def _make_floating_ip_obj(self, context, fip, pool_dict, port_dict):
@ -2639,9 +2629,6 @@ class API(base_api.NetworkAPI):
return objects.VirtualInterfaceList.get_by_instance_uuid(context,
instance.uuid)
def get_vif_by_mac_address(self, context, mac_address):
raise NotImplementedError()
def _get_floating_ip_pool_id_by_name_or_id(self, client, name_or_id):
search_opts = {constants.NET_EXTERNAL: True, 'fields': 'id'}
if uuidutils.is_uuid_like(name_or_id):
@ -2660,27 +2647,10 @@ class API(base_api.NetworkAPI):
% name_or_id)
raise exception.NovaException(message=msg)
def _get_default_floating_ip_pool_name(self):
"""Get default pool name from config.
TODO(stephenfin): Remove this helper function in Queens, opting to
use the [neutron] option only.
"""
if CONF.default_floating_pool != 'nova':
LOG.warning("Config option 'default_floating_pool' is set to "
"a non-default value. Falling back to this value "
"for now but this behavior will change in a "
"future release. You should unset this value "
"and set the '[neutron] default_floating_pool' "
"option instead.")
return CONF.default_floating_pool
return CONF.neutron.default_floating_pool
def allocate_floating_ip(self, context, pool=None):
"""Add a floating IP to a project from a pool."""
client = get_client(context)
pool = pool or self._get_default_floating_ip_pool_name()
pool = pool or CONF.neutron.default_floating_pool
pool_id = self._get_floating_ip_pool_id_by_name_or_id(client, pool)
param = {'floatingip': {'floating_network_id': pool_id}}
@ -3277,45 +3247,6 @@ class API(base_api.NetworkAPI):
subnets.append(subnet_object)
return subnets
def get_dns_domains(self, context):
"""Return a list of available dns domains.
These can be used to create DNS entries for floating IPs.
"""
raise NotImplementedError()
def add_dns_entry(self, context, address, name, dns_type, domain):
"""Create specified DNS entry for address."""
raise NotImplementedError()
def modify_dns_entry(self, context, name, address, domain):
"""Create specified DNS entry for address."""
raise NotImplementedError()
def delete_dns_entry(self, context, name, domain):
"""Delete the specified dns entry."""
raise NotImplementedError()
def delete_dns_domain(self, context, domain):
"""Delete the specified dns domain."""
raise NotImplementedError()
def get_dns_entries_by_address(self, context, address, domain):
"""Get entries for address and domain."""
raise NotImplementedError()
def get_dns_entries_by_name(self, context, name, domain):
"""Get entries for name and domain."""
raise NotImplementedError()
def create_private_dns_domain(self, context, domain, availability_zone):
"""Create a private DNS domain with nova availability zone."""
raise NotImplementedError()
def create_public_dns_domain(self, context, domain, project=None):
"""Create a private DNS domain with optional nova project."""
raise NotImplementedError()
def setup_instance_network_on_host(
self, context, instance, host, migration=None,
provider_mappings=None):

View File

@ -1,47 +0,0 @@
# Copyright 2012 Red Hat, Inc.
#
# 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 nova.network import dns_driver
class NoopDNSDriver(dns_driver.DNSDriver):
"""No-op DNS manager. Does nothing."""
def __init__(self):
pass
def get_domains(self):
return []
def create_entry(self, _name, _address, _type, _domain):
pass
def delete_entry(self, _name, _domain):
pass
def modify_address(self, _name, _address, _domain):
pass
def get_entries_by_address(self, _address, _domain):
return []
def get_entries_by_name(self, _name, _domain):
return []
def create_domain(self, _fqdomain):
pass
def delete_domain(self, _fqdomain):
pass

View File

@ -1,369 +0,0 @@
# Copyright 2013, Red Hat, Inc.
#
# 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.
"""
Client side of the network RPC API.
"""
import oslo_messaging as messaging
from oslo_serialization import jsonutils
import nova.conf
from nova import exception
from nova.objects import base as objects_base
from nova import profiler
from nova import rpc
CONF = nova.conf.CONF
RPC_TOPIC = 'network'
@profiler.trace_cls("rpc")
class NetworkAPI(object):
'''Client side of the network rpc API.
API version history:
* 1.0 - Initial version.
* 1.1 - Adds migrate_instance_[start|finish]
* 1.2 - Make migrate_instance_[start|finish] a little more flexible
* 1.3 - Adds fanout cast update_dns for multi_host networks
* 1.4 - Add get_backdoor_port()
* 1.5 - Adds associate
* 1.6 - Adds instance_uuid to _{dis,}associate_floating_ip
* 1.7 - Adds method get_floating_ip_pools to replace get_floating_pools
* 1.8 - Adds macs to allocate_for_instance
* 1.9 - Adds rxtx_factor to [add|remove]_fixed_ip, removes
instance_uuid from allocate_for_instance and
instance_get_nw_info
... Grizzly supports message version 1.9. So, any changes to existing
methods in 1.x after that point should be done such that they can
handle the version_cap being set to 1.9.
* 1.10- Adds (optional) requested_networks to deallocate_for_instance
... Havana supports message version 1.10. So, any changes to existing
methods in 1.x after that point should be done such that they can
handle the version_cap being set to 1.10.
* NOTE: remove unused method get_vifs_by_instance()
* NOTE: remove unused method get_vif_by_mac_address()
* NOTE: remove unused method get_network()
* NOTE: remove unused method get_all_networks()
* 1.11 - Add instance to deallocate_for_instance().
Remove instance_id, project_id, and host.
* 1.12 - Add instance to deallocate_fixed_ip()
... Icehouse supports message version 1.12. So, any changes to
existing methods in 1.x after that point should be done such that they
can handle the version_cap being set to 1.12.
* 1.13 - Convert allocate_for_instance()
to use NetworkRequestList objects
... Juno and Kilo supports message version 1.13. So, any changes to
existing methods in 1.x after that point should be done such that they
can handle the version_cap being set to 1.13.
* NOTE: remove unused method get_floating_ips_by_fixed_address()
* NOTE: remove unused method get_instance_uuids_by_ip_filter()
* NOTE: remove unused method disassociate_network()
* NOTE: remove unused method get_fixed_ip()
* NOTE: remove unused method get_fixed_ip_by_address()
* NOTE: remove unused method get_floating_ip()
* NOTE: remove unused method get_floating_ip_pools()
* NOTE: remove unused method get_floating_ip_by_address()
* NOTE: remove unused method get_floating_ips_by_project()
* NOTE: remove unused method get_instance_id_by_floating_address()
* NOTE: remove unused method allocate_floating_ip()
* NOTE: remove unused method deallocate_floating_ip()
* NOTE: remove unused method associate_floating_ip()
* NOTE: remove unused method disassociate_floating_ip()
* NOTE: remove unused method associate()
* 1.14 - Add mac parameter to release_fixed_ip().
* 1.15 - Convert set_network_host() to use Network objects.
... Liberty supports message version 1.15. So, any changes to
existing methods in 1.x after that point should be done such that they
can handle the version_cap being set to 1.15.
* 1.16 - Transfer instance in addition to instance_id in
setup_networks_on_host
... Mitaka supports message version 1.16. So, any changes to
existing methods in 1.x after that point should be done such that they
can handle the version_cap being set to 1.16.
* 1.17 - Add method release_dhcp()
... Newton and Ocata support message version 1.17. So, any changes to
existing methods in 1.x after that point should be done such that they
can handle the version_cap being set to 1.17.
'''
VERSION_ALIASES = {
'grizzly': '1.9',
'havana': '1.10',
'icehouse': '1.12',
'juno': '1.13',
'kilo': '1.13',
'liberty': '1.15',
'mitaka': '1.16',
'newton': '1.17',
'ocata': '1.17',
}
def __init__(self, topic=None):
super(NetworkAPI, self).__init__()
topic = topic or RPC_TOPIC
target = messaging.Target(topic=topic, version='1.0')
version_cap = self.VERSION_ALIASES.get(CONF.upgrade_levels.network,
CONF.upgrade_levels.network)
serializer = objects_base.NovaObjectSerializer()
self.client = rpc.get_client(target, version_cap, serializer)
# TODO(russellb): Convert this to named arguments. It's a pretty large
# list, so unwinding it all is probably best done in its own patch so it's
# easier to review.
def create_networks(self, ctxt, **kwargs):
return self.client.call(ctxt, 'create_networks', **kwargs)
def delete_network(self, ctxt, uuid, fixed_range):
return self.client.call(ctxt, 'delete_network',
uuid=uuid, fixed_range=fixed_range)
def allocate_for_instance(self, ctxt, instance_id, project_id, host,
rxtx_factor, vpn, requested_networks, macs=None,
dhcp_options=None):
# NOTE(mriedem): dhcp_options should be removed in version 2.0
version = '1.13'
if not self.client.can_send_version(version):
version = '1.9'
if requested_networks:
requested_networks = requested_networks.as_tuples()
if CONF.multi_host:
cctxt = self.client.prepare(version=version, server=host)
else:
cctxt = self.client.prepare(version=version)
return cctxt.call(ctxt, 'allocate_for_instance',
instance_id=instance_id, project_id=project_id,
host=host, rxtx_factor=rxtx_factor, vpn=vpn,
requested_networks=requested_networks,
macs=jsonutils.to_primitive(macs))
def deallocate_for_instance(self, ctxt, instance, requested_networks=None):
cctxt = self.client
kwargs = {}
if self.client.can_send_version('1.11'):
version = '1.11'
kwargs['instance'] = instance
kwargs['requested_networks'] = requested_networks
else:
if self.client.can_send_version('1.10'):
version = '1.10'
kwargs['requested_networks'] = requested_networks
else:
version = '1.0'
kwargs['host'] = instance.host
kwargs['instance_id'] = instance.uuid
kwargs['project_id'] = instance.project_id
if CONF.multi_host:
cctxt = cctxt.prepare(server=instance.host, version=version)
return cctxt.call(ctxt, 'deallocate_for_instance', **kwargs)
def release_dhcp(self, ctxt, host, dev, address, vif_address):
if self.client.can_send_version('1.17'):
cctxt = self.client.prepare(version='1.17', server=host)
return cctxt.call(ctxt, 'release_dhcp', dev=dev, address=address,
vif_address=vif_address)
else:
raise exception.RPCPinnedToOldVersion()
def add_fixed_ip_to_instance(self, ctxt, instance_id, rxtx_factor,
host, network_id):
cctxt = self.client.prepare(version='1.9')
return cctxt.call(ctxt, 'add_fixed_ip_to_instance',
instance_id=instance_id, rxtx_factor=rxtx_factor,
host=host, network_id=network_id)
def remove_fixed_ip_from_instance(self, ctxt, instance_id, rxtx_factor,
host, address):
cctxt = self.client.prepare(version='1.9')
return cctxt.call(ctxt, 'remove_fixed_ip_from_instance',
instance_id=instance_id, rxtx_factor=rxtx_factor,
host=host, address=address)
def get_instance_nw_info(self, ctxt, instance_id, rxtx_factor, host,
project_id):
cctxt = self.client.prepare(version='1.9')
return cctxt.call(ctxt, 'get_instance_nw_info',
instance_id=instance_id, rxtx_factor=rxtx_factor,
host=host, project_id=project_id)
def validate_networks(self, ctxt, networks):
return self.client.call(ctxt, 'validate_networks', networks=networks)
def get_dns_domains(self, ctxt):
return self.client.call(ctxt, 'get_dns_domains')
def add_dns_entry(self, ctxt, address, name, dns_type, domain):
return self.client.call(ctxt, 'add_dns_entry',
address=address, name=name,
dns_type=dns_type, domain=domain)
def modify_dns_entry(self, ctxt, address, name, domain):
return self.client.call(ctxt, 'modify_dns_entry',
address=address, name=name, domain=domain)
def delete_dns_entry(self, ctxt, name, domain):
return self.client.call(ctxt, 'delete_dns_entry',
name=name, domain=domain)
def delete_dns_domain(self, ctxt, domain):
return self.client.call(ctxt, 'delete_dns_domain', domain=domain)
def get_dns_entries_by_address(self, ctxt, address, domain):
return self.client.call(ctxt, 'get_dns_entries_by_address',
address=address, domain=domain)
def get_dns_entries_by_name(self, ctxt, name, domain):
return self.client.call(ctxt, 'get_dns_entries_by_name',
name=name, domain=domain)
def create_private_dns_domain(self, ctxt, domain, av_zone):
return self.client.call(ctxt, 'create_private_dns_domain',
domain=domain, av_zone=av_zone)
def create_public_dns_domain(self, ctxt, domain, project):
return self.client.call(ctxt, 'create_public_dns_domain',
domain=domain, project=project)
def setup_networks_on_host(self, ctxt, instance_id, host, teardown,
instance):
# NOTE(tr3buchet): the call is just to wait for completion
version = '1.16'
kwargs = {}
if not self.client.can_send_version(version):
version = '1.0'
else:
kwargs['instance'] = instance
cctxt = self.client.prepare(version=version)
return cctxt.call(ctxt, 'setup_networks_on_host',
instance_id=instance_id, host=host,
teardown=teardown, **kwargs)
def set_network_host(self, ctxt, network_ref):
version = '1.15'
if not self.client.can_send_version(version):
version = '1.0'
network_ref = objects_base.obj_to_primitive(network_ref)
cctxt = self.client.prepare(version=version)
return cctxt.call(ctxt, 'set_network_host', network_ref=network_ref)
def rpc_setup_network_on_host(self, ctxt, network_id, teardown, host):
# NOTE(tr3buchet): the call is just to wait for completion
cctxt = self.client.prepare(server=host)
return cctxt.call(ctxt, 'rpc_setup_network_on_host',
network_id=network_id, teardown=teardown)
# NOTE(russellb): Ideally this would not have a prefix of '_' since it is
# a part of the rpc API. However, this is how it was being called when the
# 1.0 API was being documented using this client proxy class. It should be
# changed if there was ever a 2.0.
def _rpc_allocate_fixed_ip(self, ctxt, instance_id, network_id, address,
vpn, host):
cctxt = self.client.prepare(server=host)
return cctxt.call(ctxt, '_rpc_allocate_fixed_ip',
instance_id=instance_id, network_id=network_id,
address=address, vpn=vpn)
def deallocate_fixed_ip(self, ctxt, address, host, instance):
kwargs = {}
if self.client.can_send_version('1.12'):
version = '1.12'
kwargs['instance'] = instance
else:
version = '1.0'
cctxt = self.client.prepare(server=host, version=version)
return cctxt.call(ctxt, 'deallocate_fixed_ip',
address=address, host=host, **kwargs)
def update_dns(self, ctxt, network_ids):
cctxt = self.client.prepare(fanout=True, version='1.3')
cctxt.cast(ctxt, 'update_dns', network_ids=network_ids)
# NOTE(russellb): Ideally this would not have a prefix of '_' since it is
# a part of the rpc API. However, this is how it was being called when the
# 1.0 API was being documented using this client proxy class. It should be
# changed if there was ever a 2.0.
def _associate_floating_ip(self, ctxt, floating_address, fixed_address,
interface, host, instance_uuid=None):
cctxt = self.client.prepare(server=host, version='1.6')
return cctxt.call(ctxt, '_associate_floating_ip',
floating_address=floating_address,
fixed_address=fixed_address,
interface=interface, instance_uuid=instance_uuid)
# NOTE(russellb): Ideally this would not have a prefix of '_' since it is
# a part of the rpc API. However, this is how it was being called when the
# 1.0 API was being documented using this client proxy class. It should be
# changed if there was ever a 2.0.
def _disassociate_floating_ip(self, ctxt, address, interface, host,
instance_uuid=None):
cctxt = self.client.prepare(server=host, version='1.6')
return cctxt.call(ctxt, '_disassociate_floating_ip',
address=address, interface=interface,
instance_uuid=instance_uuid)
def lease_fixed_ip(self, ctxt, address, host):
cctxt = self.client.prepare(server=host)
cctxt.cast(ctxt, 'lease_fixed_ip', address=address)
def release_fixed_ip(self, ctxt, address, host, mac):
kwargs = {}
if self.client.can_send_version('1.14'):
version = '1.14'
kwargs['mac'] = mac
else:
version = '1.0'
cctxt = self.client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'release_fixed_ip', address=address, **kwargs)
def migrate_instance_start(self, ctxt, instance_uuid, rxtx_factor,
project_id, source_compute, dest_compute,
floating_addresses, host=None):
cctxt = self.client.prepare(server=host, version='1.2')
return cctxt.call(ctxt, 'migrate_instance_start',
instance_uuid=instance_uuid,
rxtx_factor=rxtx_factor,
project_id=project_id,
source=source_compute,
dest=dest_compute,
floating_addresses=floating_addresses)
def migrate_instance_finish(self, ctxt, instance_uuid, rxtx_factor,
project_id, source_compute, dest_compute,
floating_addresses, host=None):
cctxt = self.client.prepare(server=host, version='1.2')
return cctxt.call(ctxt, 'migrate_instance_finish',
instance_uuid=instance_uuid,
rxtx_factor=rxtx_factor,
project_id=project_id,
source=source_compute,
dest=dest_compute,
floating_addresses=floating_addresses)

View File

@ -33,7 +33,6 @@ def register_all():
__import__('nova.objects.compute_node')
__import__('nova.objects.diagnostics')
__import__('nova.objects.console_auth_token')
__import__('nova.objects.dns_domain')
__import__('nova.objects.ec2')
__import__('nova.objects.external_event')
__import__('nova.objects.fixed_ip')

View File

@ -1,72 +0,0 @@
# Copyright (C) 2014, Red Hat, Inc.
#
# 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 nova.db import api as db
from nova import objects
from nova.objects import base
from nova.objects import fields
@base.NovaObjectRegistry.register
class DNSDomain(base.NovaPersistentObject, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'domain': fields.StringField(),
'scope': fields.StringField(nullable=True),
'availability_zone': fields.StringField(nullable=True),
'project_id': fields.StringField(nullable=True),
}
@staticmethod
def _from_db_object(context, vif, db_vif):
for field in vif.fields:
setattr(vif, field, db_vif[field])
vif._context = context
vif.obj_reset_changes()
return vif
@base.remotable_classmethod
def get_by_domain(cls, context, domain):
db_dnsd = db.dnsdomain_get(context, domain)
if db_dnsd:
return cls._from_db_object(context, cls(), db_dnsd)
@base.remotable_classmethod
def register_for_zone(cls, context, domain, zone):
db.dnsdomain_register_for_zone(context, domain, zone)
@base.remotable_classmethod
def register_for_project(cls, context, domain, project):
db.dnsdomain_register_for_project(context, domain, project)
@base.remotable_classmethod
def delete_by_domain(cls, context, domain):
db.dnsdomain_unregister(context, domain)
@base.NovaObjectRegistry.register
class DNSDomainList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'objects': fields.ListOfObjectsField('DNSDomain'),
}
@base.remotable_classmethod
def get_all(cls, context):
db_domains = db.dnsdomain_get_all(context)
return base.obj_make_list(context, cls(context), objects.DNSDomain,
db_domains)

View File

@ -105,10 +105,8 @@ class Network(obj_base.NovaPersistentObject, obj_base.NovaObject,
db_value = db_network[field]
if field == 'netmask_v6' and db_value is not None:
db_value = network._convert_legacy_ipv6_netmask(db_value)
if field == 'dhcp_server' and db_value is None:
elif field == 'dhcp_server' and db_value is None:
db_value = db_network['gateway']
if field == 'share_address' and CONF.share_dhcp_address:
db_value = CONF.share_dhcp_address
network[field] = db_value
network._context = context

View File

@ -16,7 +16,6 @@ from oslo_utils import versionutils
from nova.objects import base as obj_base
from nova.objects import fields
from nova import utils
# These are special case enums for the auto-allocate scenario. 'none' means
# do not allocate a network on server create. 'auto' means auto-allocate a
@ -49,24 +48,15 @@ class NetworkRequest(obj_base.NovaObject):
def obj_load_attr(self, attr):
setattr(self, attr, None)
# TODO(stephenfin): Drop the two item tuple case when we drop it entirely
def to_tuple(self):
address = str(self.address) if self.address is not None else None
if utils.is_neutron():
return self.network_id, address, self.port_id, self.pci_request_id
else:
return self.network_id, address
# TODO(stephenfin): Drop the two item tuple case when we drop it entirely
@classmethod
def from_tuple(cls, net_tuple):
if len(net_tuple) == 4:
network_id, address, port_id, pci_request_id = net_tuple
return cls(network_id=network_id, address=address,
port_id=port_id, pci_request_id=pci_request_id)
else:
network_id, address = net_tuple
return cls(network_id=network_id, address=address)
return cls(network_id=network_id, address=address, port_id=port_id,
pci_request_id=pci_request_id)
@property
def auto_allocate(self):

View File

@ -19,53 +19,17 @@ Linux network specific helpers.
import os
import six
from oslo_concurrency import processutils
from oslo_log import log as logging
from oslo_utils import excutils
from nova import exception
import nova.privsep.linux_net
LOG = logging.getLogger(__name__)
@nova.privsep.sys_admin_pctxt.entrypoint
def add_bridge(bridge):
"""Add a bridge.
:param bridge: the name of the bridge
"""
processutils.execute('brctl', 'addbr', bridge)
@nova.privsep.sys_admin_pctxt.entrypoint
def delete_bridge(bridge):
"""Delete a bridge.
:param bridge: the name of the bridge
"""
processutils.execute('brctl', 'delbr', bridge)
@nova.privsep.sys_admin_pctxt.entrypoint
def bridge_setfd(bridge):
processutils.execute('brctl', 'setfd', bridge, 0)
@nova.privsep.sys_admin_pctxt.entrypoint
def bridge_disable_stp(bridge):
processutils.execute('brctl', 'stp', bridge, 'off')
@nova.privsep.sys_admin_pctxt.entrypoint
def bridge_add_interface(bridge, interface):
return processutils.execute('brctl', 'addif', bridge, interface,
check_exit_code=False)
def device_exists(device):
"""Check if ethernet device exists."""
return os.path.exists('/sys/class/net/%s' % device)
@ -117,11 +81,6 @@ def _set_device_trust_inner(dev, vf_num, trusted):
check_exit_code=[0, 2, 254])
@nova.privsep.sys_admin_pctxt.entrypoint
def set_device_disabled(dev):
processutils.execute('ip', 'link', 'set', dev, 'down')
@nova.privsep.sys_admin_pctxt.entrypoint
def set_device_macaddr(dev, mac_addr, port_state=None):
_set_device_macaddr_inner(dev, mac_addr, port_state=port_state)
@ -146,80 +105,6 @@ def set_device_macaddr_and_vlan(dev, vf_num, mac_addr, vlan):
check_exit_code=[0, 2, 254])
@nova.privsep.sys_admin_pctxt.entrypoint
def bind_ip(device, ip, scope_is_link=False):
if not scope_is_link:
processutils.execute('ip', 'addr', 'add', str(ip) + '/32',
'dev', device, check_exit_code=[0, 2, 254])
else:
processutils.execute('ip', 'addr', 'add', str(ip) + '/32',
'scope', 'link', 'dev', device,
check_exit_code=[0, 2, 254])
@nova.privsep.sys_admin_pctxt.entrypoint
def unbind_ip(device, ip):
processutils.execute('ip', 'addr', 'del', str(ip) + '/32',
'dev', device, check_exit_code=[0, 2, 254])
def lookup_ip(device):
return processutils.execute('ip', 'addr', 'show', 'dev', device,
'scope', 'global')
@nova.privsep.sys_admin_pctxt.entrypoint
def change_ip(device, ip):
processutils.execute('ip', '-f', 'inet6', 'addr', 'change', ip,
'dev', device)
# TODO(mikal): this is horrid. The calling code takes arguments from an
# interface list and just regurgitates them here. This isn't good enough,
# but is outside the scope of the privsep transition. Mark it as bonkers and
# hope we clean it up later.
@nova.privsep.sys_admin_pctxt.entrypoint
def address_command_deprecated(device, action, params):
cmd = ['ip', 'addr', action]
cmd.extend(params)
cmd.extend(['dev', device])
processutils.execute(*cmd, check_exit_code=[0, 2, 254])
@nova.privsep.sys_admin_pctxt.entrypoint
def dhcp_release(dev, address, mac_address):
processutils.execute('dhcp_release', dev, address, mac_address)
def routes_show(dev):
# Format of output is:
# 192.168.1.0/24 proto kernel scope link src 192.168.1.6
return processutils.execute('ip', 'route', 'show', 'dev', dev)
# TODO(mikal): this is horrid. The calling code takes arguments from a route
# list and just regurgitates them into new routes. This isn't good enough,
# but is outside the scope of the privsep transition. Mark it as bonkers and
# hope we clean it up later.
@nova.privsep.sys_admin_pctxt.entrypoint
def route_add_deprecated(routes):
processutils.execute('ip', 'route', 'add', *routes)
@nova.privsep.sys_admin_pctxt.entrypoint
def route_delete(dev, route):
processutils.execute('ip', 'route', 'del', route, 'dev', dev)
# TODO(mikal): this is horrid. The calling code takes arguments from a route
# list and just regurgitates them into new routes. This isn't good enough,
# but is outside the scope of the privsep transition. Mark it as bonkers and
# hope we clean it up later.
@nova.privsep.sys_admin_pctxt.entrypoint
def route_delete_deprecated(dev, routes):
processutils.execute('ip', 'route', 'del', *routes)
@nova.privsep.sys_admin_pctxt.entrypoint
def create_tap_dev(dev, mac_address=None, multiqueue=False):
if not device_exists(dev):
@ -245,175 +130,8 @@ def create_tap_dev(dev, mac_address=None, multiqueue=False):
_set_device_enabled_inner(dev)
@nova.privsep.sys_admin_pctxt.entrypoint
def send_arp_for_ip(ip, device, count):
out, err = processutils.execute(
'arping', '-U', ip, '-A', '-I', device, '-c', str(count),
check_exit_code=False)
if err:
LOG.debug('arping error for IP %s', ip)
@nova.privsep.sys_admin_pctxt.entrypoint
def clean_conntrack(fixed_ip):
try:
processutils.execute('conntrack', '-D', '-r', fixed_ip,
check_exit_code=[0, 1])
except processutils.ProcessExecutionError:
LOG.exception('Error deleting conntrack entries for %s', fixed_ip)
def enable_ipv4_forwarding():
if not ipv4_forwarding_check():
_enable_ipv4_forwarding_inner()
def ipv4_forwarding_check():
with open('/proc/sys/net/ipv4/ip_forward', 'r') as f:
return f.readline().strip() == '1'
@nova.privsep.sys_admin_pctxt.entrypoint
def _enable_ipv4_forwarding_inner():
processutils.execute('sysctl', '-w', 'net.ipv4.ip_forward=1')
@nova.privsep.sys_admin_pctxt.entrypoint
def modify_ebtables(table, rule, insert_rule=True):
cmd = ['ebtables', '--concurrent', '-t', table]
if insert_rule:
cmd.append('-I')
else:
cmd.append('-D')
cmd.extend(rule)
processutils.execute(*cmd, check_exit_code=[0])
@nova.privsep.sys_admin_pctxt.entrypoint
def add_vlan(bridge_interface, interface, vlan_num):
processutils.execute('ip', 'link', 'add', 'link', bridge_interface,
'name', interface, 'type', 'vlan',
'id', vlan_num, check_exit_code=[0, 2, 254])
@nova.privsep.sys_admin_pctxt.entrypoint
def iptables_get_rules(ipv4=True):
if ipv4:
cmd = 'iptables'
else:
cmd = 'ip6tables'
return processutils.execute('%s-save' % cmd, '-c', attempts=5)
@nova.privsep.sys_admin_pctxt.entrypoint
def iptables_set_rules(rules, ipv4=True):
if ipv4:
cmd = 'iptables'
else:
cmd = 'ip6tables'
processutils.execute('%s-restore' % cmd, '-c',
process_input=six.b('\n'.join(rules)),
attempts=5)
@nova.privsep.sys_admin_pctxt.entrypoint
def restart_dnsmasq(flag_file, network_ref, config_file, pid_path, opts_path,
dhcp_lease_time, lease_max, conf_path, dhcp_bridge,
dhcp_domain, dns_servers, hosts_path):
_restart_dnsmasq_inner(flag_file, network_ref, config_file, pid_path,
opts_path, dhcp_lease_time, lease_max, conf_path,
dhcp_bridge, dhcp_domain, dns_servers, hosts_path)
# NOTE(mikal): this is done like this to enable unit testing
def _restart_dnsmasq_inner(flag_file, network_ref, config_file, pid_path,
opts_path, dhcp_lease_time, lease_max, conf_path,
dhcp_bridge, dhcp_domain, dns_servers, hosts_path):
cmd = ['env',
'CONFIG_FILE=%s' % flag_file,
'NETWORK_ID=%s' % str(network_ref['id']),
'dnsmasq',
'--strict-order',
'--bind-interfaces',
'--conf-file=%s' % config_file,
'--pid-file=%s' % pid_path,
'--dhcp-optsfile=%s' % opts_path,
'--listen-address=%s' % network_ref['dhcp_server'],
'--except-interface=lo',
'--dhcp-range=set:%s,%s,static,%s,%ss' %
(network_ref['label'],
network_ref['dhcp_start'],
network_ref['netmask'],
dhcp_lease_time),
'--dhcp-lease-max=%s' % lease_max,
'--dhcp-hostsfile=%s' % conf_path,
'--dhcp-script=%s' % dhcp_bridge,
'--no-hosts',
'--leasefile-ro']
# dnsmasq currently gives an error for an empty domain,
# rather than ignoring. So only specify it if defined.
if dhcp_domain:
cmd.append('--domain=%s' % dhcp_domain)
if dns_servers:
cmd.append('--no-resolv')
for dns_server in dns_servers:
cmd.append('--server=%s' % dns_server)
if network_ref['multi_host']:
cmd.append('--addn-hosts=%s' % hosts_path)
processutils.execute(*cmd)
@nova.privsep.sys_admin_pctxt.entrypoint
def start_ra(conf_path, pid_path):
cmd = ['radvd',
'-C', '%s' % conf_path,
'-p', '%s' % pid_path]
processutils.execute(*cmd)
@nova.privsep.sys_admin_pctxt.entrypoint
def ovs_plug(timeout, bridge, dev, mac_address):
cmd = ['ovs-vsctl', '--timeout=%s' % timeout,
'--', '--may-exist', 'add-port', bridge, dev,
'--', 'set', 'Interface', dev, 'type=internal',
'--', 'set', 'Interface', dev,
'external-ids:iface-id=%s' % dev,
'--', 'set', 'Interface', dev,
'external-ids:iface-status=active',
'--', 'set', 'Interface', dev,
'external-ids:attached-mac=%s' % mac_address]
try:
processutils.execute(*cmd)
except Exception as e:
LOG.error('Unable to execute %(cmd)s. Exception: %(exception)s',
{'cmd': cmd, 'exception': e})
raise exception.OVSConfigurationFailure(inner_exception=e)
@nova.privsep.sys_admin_pctxt.entrypoint
def ovs_drop_nondhcp(bridge, mac_address):
processutils.execute(
'ovs-ofctl', 'add-flow', bridge, 'priority=1,actions=drop')
processutils.execute(
'ovs-ofctl', 'add-flow', bridge,
'udp,tp_dst=67,dl_dst=%s,priority=2,actions=normal' % mac_address)
@nova.privsep.sys_admin_pctxt.entrypoint
def ovs_unplug(timeout, bridge, dev):
cmd = ['ovs-vsctl', '--timeout=%s' % timeout,
'--', '--if-exists', 'del-port', bridge, dev]
try:
processutils.execute(*cmd)
except Exception as e:
LOG.error('Unable to execute %(cmd)s. Exception: %(exception)s',
{'cmd': cmd, 'exception': e})
raise exception.OVSConfigurationFailure(inner_exception=e)

View File

@ -29,8 +29,6 @@ import sys
from oslo_log import log as logging
from oslo_utils import excutils
import nova.privsep
# NOTE(mriedem): Avoid importing nova.utils since that can cause a circular
# import with the privsep code. In fact, avoid importing anything outside
# of nova/privsep/ if possible.
@ -90,8 +88,3 @@ def supports_direct_io(dirpath):
pass
return hasDirectIO
@nova.privsep.sys_admin_pctxt.entrypoint
def kill(pid, signal):
os.kill(pid, signal)

View File

@ -48,16 +48,13 @@ from oslo_utils import timeutils
from oslo_versionedobjects import fixture as ovo_fixture
from oslotest import base
from oslotest import mock_fixture
from oslotest import moxstubout
import six
from six.moves import builtins
import testtools
from nova.compute import rpcapi as compute_rpcapi
from nova import context
from nova.db import api as db
from nova import exception
from nova.network import manager as network_manager
from nova.network.security_group import openstack_driver
from nova import objects
from nova.objects import base as objects_base
@ -89,36 +86,6 @@ CELL1_NAME = 'cell1'
nested = utils.nested_contexts
class SampleNetworks(fixtures.Fixture):
"""Create sample networks in the database."""
def __init__(self, host=None):
self.host = host
def setUp(self):
super(SampleNetworks, self).setUp()
ctxt = context.get_admin_context()
network = network_manager.VlanManager(host=self.host)
bridge_interface = CONF.flat_interface or CONF.vlan_interface
network.create_networks(ctxt,
label='test',
cidr='10.0.0.0/8',
multi_host=CONF.multi_host,
num_networks=CONF.num_networks,
network_size=CONF.network_size,
cidr_v6=CONF.fixed_range_v6,
gateway=CONF.gateway,
gateway_v6=CONF.gateway_v6,
bridge=CONF.flat_network_bridge,
bridge_interface=bridge_interface,
vpn_start=CONF.vpn_start,
vlan_start=CONF.vlan_start,
dns1=CONF.flat_network_dns)
for net in db.network_get_all(ctxt):
network.set_network_host(ctxt, net)
class TestingException(Exception):
pass
@ -257,28 +224,12 @@ class TestCase(base.BaseTestCase):
self.useFixture(ovo_fixture.StableObjectJsonFixture())
# NOTE(mnaser): All calls to utils.is_neutron() are cached in
# nova.utils._IS_NEUTRON. We set it to None to avoid any
# caching of that value.
utils._IS_NEUTRON = None
# Reset the global QEMU version flag.
images.QEMU_VERSION = None
# Reset the compute RPC API globals (mostly the _ROUTER).
compute_rpcapi.reset_globals()
# TODO(takashin): Remove MoxStubout fixture
# after removing tests which uses mox and are related to
# nova-network in the following files.
#
# - nova/tests/unit/api/openstack/compute/test_floating_ips.py
# - nova/tests/unit/api/openstack/compute/test_security_groups.py
# - nova/tests/unit/fake_network.py
# - nova/tests/unit/network/test_manager.py
mox_fixture = self.useFixture(moxstubout.MoxStubout())
self.mox = mox_fixture.mox
self.stubs = mox_fixture.stubs
self.addCleanup(self._clear_attrs)
self.useFixture(fixtures.EnvironmentVariable('http_proxy'))
self.policy = self.useFixture(policy_fixture.PolicyFixture())
@ -363,9 +314,6 @@ class TestCase(base.BaseTestCase):
Use the monkey patch fixture to replace a function for the
duration of a test. Useful when you want to provide fake
methods instead of mocks during testing.
This should be used instead of self.stubs.Set (which is based
on mox) going forward.
"""
self.useFixture(fixtures.MonkeyPatch(old, new))
@ -747,12 +695,9 @@ class BaseHookTestCase(NoDBTestCase):
class MatchType(object):
"""Matches any instance of a specified type
The MatchType class is a helper for use with the
mock.assert_called_with() method that lets you
assert that a particular parameter has a specific
data type. It enables strict check than the built
in mock.ANY helper, and is the equivalent of the
mox.IsA() function from the legacy mox library
The MatchType class is a helper for use with the mock.assert_called_with()
method that lets you assert that a particular parameter has a specific data
type. It enables stricter checking than the built in mock.ANY helper.
Example usage could be:
@ -794,11 +739,9 @@ class MatchObjPrims(object):
class ContainKeyValue(object):
"""Checks whether a key/value pair is in a dict parameter.
The ContainKeyValue class is a helper for use with the
mock.assert_*() method that lets you assert that a particular
dict contain a key/value pair. It enables strict check than
the built in mock.ANY helper, and is the equivalent of the
mox.ContainsKeyValue() function from the legacy mox library
The ContainKeyValue class is a helper for use with the mock.assert_*()
method that lets you assert that a particular dict contain a key/value
pair. It enables stricter checking than the built in mock.ANY helper.
Example usage could be:

View File

@ -96,11 +96,6 @@ class ServiceFixture(fixtures.Fixture):
if self.cell:
context.set_target_cell(self.ctxt, self.cell)
# NOTE(mikal): we don't have root to manipulate iptables, so just
# zero that bit out.
self.useFixture(fixtures.MockPatch(
'nova.network.linux_net.IptablesManager._apply'))
with mock.patch('nova.context.get_admin_context',
return_value=self.ctxt):
self.service = service.Service.create(**self.kwargs)
@ -791,18 +786,6 @@ class WarningsFixture(fixtures.Fixture):
message='Policy enforcement is depending on the value of is_admin.'
' This key is deprecated. Please update your policy '
'file to use the standard policy values.')
# TODO(takashin): Remove filtering warnings about mox
# after removing tests which uses mox and are related to
# nova-network in the following files.
#
# - nova/tests/unit/api/openstack/compute/test_floating_ips.py
# - nova/tests/unit/api/openstack/compute/test_security_groups.py
# - nova/tests/unit/fake_network.py
# - nova/tests/unit/network/test_manager.py
warnings.filterwarnings('ignore',
module='mox3.mox')
# NOTE(gibi): we can remove this once we get rid of Mox in nova
warnings.filterwarnings('ignore', message="Using class 'MoxStubout'")
# NOTE(mriedem): Ignore scope check UserWarnings from oslo.policy.
warnings.filterwarnings('ignore',
message="Policy .* failed scope check",
@ -990,12 +973,6 @@ class OSMetadataServer(fixtures.Fixture):
}
self.useFixture(ConfPatcher(**conf_overrides))
# NOTE(mikal): we don't have root to manipulate iptables, so just
# zero that bit out.
self.useFixture(fixtures.MonkeyPatch(
'nova.network.linux_net.IptablesManager._apply',
lambda _: None))
self.metadata = service.WSGIService("metadata")
self.metadata.start()
self.addCleanup(self.metadata.stop)

View File

@ -1,95 +0,0 @@
=====================================
OpenStack Nova Testing Infrastructure
=====================================
This README file attempts to provide current and prospective contributors with
everything they need to know in order to start creating unit tests for nova.
Note: the content for the rest of this file will be added as the work items in
the following blueprint are completed:
https://blueprints.launchpad.net/nova/+spec/consolidate-testing-infrastructure
Test Types: Unit vs. Functional vs. Integration
-----------------------------------------------
TBD
Writing Unit Tests
------------------
TBD
Using Fakes
~~~~~~~~~~~
TBD
test.TestCase
-------------
The TestCase class from nova.test (generally imported as test) will
automatically manage self.stubs using the stubout module and self.mox
using the mox module during the setUp step. They will automatically
verify and clean up during the tearDown step.
If using test.TestCase, calling the super class setUp is required and
calling the super class tearDown is required to be last if tearDown
is overridden.
Writing Functional Tests
------------------------
TBD
Writing Integration Tests
-------------------------
TBD
Tests and Exceptions
--------------------
A properly written test asserts that particular behavior occurs. This can
be a success condition or a failure condition, including an exception.
When asserting that a particular exception is raised, the most specific
exception possible should be used.
In particular, testing for Exception being raised is almost always a
mistake since it will match (almost) every exception, even those
unrelated to the exception intended to be tested.
This applies to catching exceptions manually with a try/except block,
or using assertRaises().
Example::
self.assertRaises(exception.InstanceNotFound, db.instance_get_by_uuid,
elevated, instance_uuid)
If a stubbed function/method needs a generic exception for testing
purposes, test.TestingException is available.
Example::
def stubbed_method(self):
raise test.TestingException()
self.stubs.Set(cls, 'inner_method', stubbed_method)
obj = cls()
self.assertRaises(test.TestingException, obj.outer_method)
Stubbing and Mocking
--------------------
Whenever possible, tests SHOULD NOT stub and mock out the same function.
If it's unavoidable, tests SHOULD define stubs before mocks since the
`TestCase` cleanup routine will un-mock before un-stubbing. Doing otherwise
results in a test that leaks stubbed functions, causing hard-to-debug
interference between tests [1]_.
If a mock must take place before a stub, any stubs after the mock call MUST be
manually unset using `self.cleanUp` calls within the test.
.. [1] https://bugs.launchpad.net/nova/+bug/1180671

View File

@ -19,11 +19,7 @@ from oslo_utils.fixture import uuidsentinel as uuids
import webob
from nova.api.openstack.compute import floating_ips as fips_v21
from nova import compute
from nova import context
from nova.db import api as db
from nova import exception
from nova import network
from nova import objects
from nova import test
from nova.tests.unit.api.openstack import fakes
@ -195,94 +191,6 @@ class FloatingIpTestV21(test.NoDBTestCase):
expected_exc)
class ExtendedFloatingIpTestV21(test.TestCase):
floating_ip = "10.10.10.10"
floating_ip_2 = "10.10.10.11"
floating_ips = fips_v21
def _create_floating_ips(self, floating_ips=None):
"""Create a floating IP object."""
if floating_ips is None:
floating_ips = [self.floating_ip]
elif not isinstance(floating_ips, (list, tuple)):
floating_ips = [floating_ips]
dict_ = {'pool': 'nova', 'host': 'fake_host'}
return db.floating_ip_bulk_create(
self.context, [dict(address=ip, **dict_) for ip in floating_ips],
)
def _delete_floating_ip(self):
db.floating_ip_destroy(self.context, self.floating_ip)
def setUp(self):
super(ExtendedFloatingIpTestV21, self).setUp()
self.stubs.Set(compute.api.API, "get",
compute_api_get)
self.stubs.Set(network.api.API, "get_floating_ip",
network_api_get_floating_ip)
self.stubs.Set(network.api.API, "get_floating_ip_by_address",
network_api_get_floating_ip_by_address)
self.stubs.Set(network.api.API, "get_floating_ips_by_project",
network_api_get_floating_ips_by_project)
self.stubs.Set(network.api.API, "release_floating_ip",
network_api_release)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
network_api_disassociate)
self.stubs.Set(network.api.API, "get_instance_id_by_floating_address",
get_instance_by_floating_ip_addr)
self.stubs.Set(objects.Instance, "get_network_info",
stub_nw_info(self))
fake_network.stub_out_nw_api_get_instance_nw_info(self)
self.stub_out('nova.db.api.instance_get',
fake_instance_get)
self.context = context.get_admin_context()
self._create_floating_ips()
self.controller = self.floating_ips.FloatingIPController()
self.manager = self.floating_ips.\
FloatingIPActionController()
self.fake_req = fakes.HTTPRequest.blank('')
def tearDown(self):
self._delete_floating_ip()
super(ExtendedFloatingIpTestV21, self).tearDown()
def test_extended_floating_ip_associate_fixed(self):
fixed_address = '192.168.1.100'
def fake_associate_floating_ip(*args, **kwargs):
self.assertEqual(fixed_address, kwargs['fixed_address'])
body = dict(addFloatingIp=dict(address=self.floating_ip,
fixed_address=fixed_address))
with mock.patch.object(self.manager.network_api,
'associate_floating_ip',
fake_associate_floating_ip):
rsp = self.manager._add_floating_ip(self.fake_req, TEST_INST,
body=body)
self.assertEqual(202, rsp.status_int)
def test_extended_floating_ip_associate_fixed_not_allocated(self):
def fake_associate_floating_ip(*args, **kwargs):
pass
self.stubs.Set(network.api.API, "associate_floating_ip",
fake_associate_floating_ip)
body = dict(addFloatingIp=dict(address=self.floating_ip,
fixed_address='11.11.11.11'))
ex = self.assertRaises(webob.exc.HTTPBadRequest,
self.manager._add_floating_ip,
self.fake_req, TEST_INST, body=body)
self.assertIn("Specified fixed address not assigned to instance",
ex.explanation)
class FloatingIPPolicyEnforcementV21(test.NoDBTestCase):
def setUp(self):

View File

@ -20,8 +20,6 @@ from oslo_policy import opts as policy_opts
from nova.conf import neutron
from nova.conf import paths
from nova import config
from nova import ipv6
from nova.tests.unit import utils
class ConfFixture(config_fixture.Config):
@ -31,19 +29,8 @@ class ConfFixture(config_fixture.Config):
# default group
self.conf.set_default('compute_driver', 'fake.SmallFakeDriver')
self.conf.set_default('fake_network', True)
self.conf.set_default('flat_network_bridge', 'br100')
self.conf.set_default('floating_ip_dns_manager',
'nova.tests.unit.utils.dns_manager')
self.conf.set_default('force_dhcp_release', False)
self.conf.set_default('host', 'fake-mini')
self.conf.set_default('instance_dns_manager',
'nova.tests.unit.utils.dns_manager')
self.conf.set_default('network_size', 8)
self.conf.set_default('num_networks', 2)
self.conf.set_default('periodic_enable', False)
self.conf.set_default('use_ipv6', True)
self.conf.set_default('vlan_interface', 'eth0')
# api_database group
self.conf.set_default('connection', "sqlite://", group='api_database')
@ -77,5 +64,3 @@ class ConfFixture(config_fixture.Config):
init_rpc=False)
policy_opts.set_defaults(self.conf)
neutron.register_dynamic_opts(self.conf)
self.addCleanup(utils.cleanup_dns_managers)
self.addCleanup(ipv6.api.reset_backend)

View File

@ -7854,44 +7854,6 @@ class CertificateTestCase(test.TestCase, ModelsObjectComparatorMixin):
self._assertEqualObjects(self.created[1], cert[0])
class DnsdomainTestCase(test.TestCase):
def setUp(self):
super(DnsdomainTestCase, self).setUp()
self.ctxt = context.get_admin_context()
self.domain = 'test.domain'
self.testzone = 'testzone'
self.project = 'fake'
def test_dnsdomain_register_for_zone(self):
db.dnsdomain_register_for_zone(self.ctxt, self.domain, self.testzone)
domain = db.dnsdomain_get(self.ctxt, self.domain)
self.assertEqual(domain['domain'], self.domain)
self.assertEqual(domain['availability_zone'], self.testzone)
self.assertEqual(domain['scope'], 'private')
def test_dnsdomain_register_for_project(self):
db.dnsdomain_register_for_project(self.ctxt, self.domain, self.project)
domain = db.dnsdomain_get(self.ctxt, self.domain)
self.assertEqual(domain['domain'], self.domain)
self.assertEqual(domain['project_id'], self.project)
self.assertEqual(domain['scope'], 'public')
def test_dnsdomain_unregister(self):
db.dnsdomain_register_for_zone(self.ctxt, self.domain, self.testzone)
db.dnsdomain_unregister(self.ctxt, self.domain)
domain = db.dnsdomain_get(self.ctxt, self.domain)
self.assertIsNone(domain)
def test_dnsdomain_get_all(self):
d_list = ['test.domain.one', 'test.domain.two']
db.dnsdomain_register_for_zone(self.ctxt, d_list[0], 'zone')
db.dnsdomain_register_for_zone(self.ctxt, d_list[1], 'zone')
db_list = db.dnsdomain_get_all(self.ctxt)
db_domain_list = [d.domain for d in db_list]
self.assertEqual(sorted(d_list), sorted(db_domain_list))
class BwUsageTestCase(test.TestCase, ModelsObjectComparatorMixin):
_ignored_keys = ['id', 'deleted', 'deleted_at', 'created_at', 'updated_at']
@ -8189,9 +8151,6 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin):
self.instance_id_mappings = models.InstanceIdMapping.__table__
self.shadow_instance_id_mappings = sqlalchemyutils.get_table(
self.engine, "shadow_instance_id_mappings")
self.dns_domains = models.DNSDomain.__table__
self.shadow_dns_domains = sqlalchemyutils.get_table(
self.engine, "shadow_dns_domains")
self.instances = models.Instance.__table__
self.shadow_instances = sqlalchemyutils.get_table(
self.engine, "shadow_instances")
@ -8473,31 +8432,6 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin):
self.assertEqual(len(rows), 4)
return 0
def test_archive_deleted_rows_no_id_column(self):
uuidstr0 = self.uuidstrs[0]
ins_stmt = self.dns_domains.insert().values(domain=uuidstr0)
self.conn.execute(ins_stmt)
update_statement = self.dns_domains.update().\
where(self.dns_domains.c.domain == uuidstr0).\
values(deleted=True, deleted_at=timeutils.utcnow())
self.conn.execute(update_statement)
qdd = sql.select([self.dns_domains], self.dns_domains.c.domain ==
uuidstr0)
rows = self.conn.execute(qdd).fetchall()
self.assertEqual(len(rows), 1)
qsdd = sql.select([self.shadow_dns_domains],
self.shadow_dns_domains.c.domain == uuidstr0)
rows = self.conn.execute(qsdd).fetchall()
self.assertEqual(len(rows), 0)
db.archive_deleted_rows(max_rows=1)
rows = self.conn.execute(qdd).fetchall()
self.assertEqual(len(rows), 0)
rows = self.conn.execute(qsdd).fetchall()
self.assertEqual(len(rows), 1)
self._assert_shadow_tables_empty_except(
'shadow_dns_domains',
)
def test_archive_deleted_rows_shadow_insertions_equals_deletions(self):
# Add 2 rows to table
for uuidstr in self.uuidstrs[:2]:

View File

@ -15,267 +15,16 @@
from oslo_serialization import jsonutils
from oslo_utils.fixture import uuidsentinel as uuids
from six.moves import range
from nova.compute import api as compute_api
from nova.compute import manager as compute_manager
import nova.conf
import nova.context
from nova.db import api as db
from nova import exception
from nova.network import manager as network_manager
from nova.network import model as network_model
from nova.network import rpcapi as network_rpcapi
from nova import objects
from nova.objects import base as obj_base
from nova.objects import network as network_obj
from nova.objects import virtual_interface as vif_obj
from nova.tests.unit.objects import test_fixed_ip
from nova.tests.unit.objects import test_instance_info_cache
from nova.tests.unit.objects import test_pci_device
from nova.tests.unit import utils
HOST = "testhost"
CONF = nova.conf.CONF
class FakeModel(dict):
"""Represent a model from the db."""
def __init__(self, *args, **kwargs):
self.update(kwargs)
class FakeNetworkManager(network_manager.NetworkManager):
"""This NetworkManager doesn't call the base class so we can bypass all
inherited service cruft and just perform unit tests.
"""
class FakeDB(object):
vifs = [{'id': 0,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'instance_uuid': uuids.instance_1,
'network_id': 1,
'uuid': uuids.vifs_1,
'address': 'DC:AD:BE:FF:EF:01',
'tag': 'fake-tag1'},
{'id': 1,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'instance_uuid': uuids.instance_2,
'network_id': 21,
'uuid': uuids.vifs_2,
'address': 'DC:AD:BE:FF:EF:02',
'tag': 'fake-tag2'},
{'id': 2,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'instance_uuid': uuids.instance_1,
'network_id': 31,
'uuid': uuids.vifs_3,
'address': 'DC:AD:BE:FF:EF:03',
'tag': None}]
floating_ips = [dict(address='172.16.1.1',
fixed_ip_id=100),
dict(address='172.16.1.2',
fixed_ip_id=200),
dict(address='173.16.1.2',
fixed_ip_id=210)]
fixed_ips = [dict(test_fixed_ip.fake_fixed_ip,
id=100,
address='172.16.0.1',
virtual_interface_id=0),
dict(test_fixed_ip.fake_fixed_ip,
id=200,
address='172.16.0.2',
virtual_interface_id=1),
dict(test_fixed_ip.fake_fixed_ip,
id=210,
address='173.16.0.2',
virtual_interface_id=2)]
def fixed_ip_get_by_instance(self, context, instance_uuid):
return [dict(address='10.0.0.0'), dict(address='10.0.0.1'),
dict(address='10.0.0.2')]
def network_get_by_cidr(self, context, cidr):
raise exception.NetworkNotFoundForCidr(cidr=cidr)
def network_create_safe(self, context, net):
fakenet = dict(net)
fakenet['id'] = 999
return fakenet
def network_get(self, context, network_id, project_only="allow_none"):
return {'cidr_v6': '2001:db8:69:%x::/64' % network_id}
def network_get_by_uuid(self, context, network_uuid):
raise exception.NetworkNotFoundForUUID(uuid=network_uuid)
def network_get_all(self, context):
raise exception.NoNetworksFound()
def network_get_all_by_uuids(self, context, project_only="allow_none"):
raise exception.NoNetworksFound()
def network_disassociate(self, context, network_id):
return True
def virtual_interface_get_all(self, context):
return self.vifs
def fixed_ips_by_virtual_interface(self, context, vif_id):
return [ip for ip in self.fixed_ips
if ip['virtual_interface_id'] == vif_id]
def fixed_ip_disassociate(self, context, address):
return True
def __init__(self, stubs=None):
self.db = self.FakeDB()
if stubs:
stubs.Set(vif_obj, 'db', self.db)
self.deallocate_called = None
self.deallocate_fixed_ip_calls = []
self.network_rpcapi = network_rpcapi.NetworkAPI()
# TODO(matelakat) method signature should align with the faked one's
def deallocate_fixed_ip(self, context, address=None, host=None,
instance=None):
self.deallocate_fixed_ip_calls.append((context, address, host))
# TODO(matelakat) use the deallocate_fixed_ip_calls instead
self.deallocate_called = address
def _create_fixed_ips(self, context, network_id, fixed_cidr=None,
extra_reserved=None, bottom_reserved=0,
top_reserved=0):
pass
def get_instance_nw_info(context, instance_id, rxtx_factor,
host, instance_uuid=None, **kwargs):
pass
def fake_network(network_id, ipv6=None):
if ipv6 is None:
ipv6 = CONF.use_ipv6
fake_network = {'id': network_id,
'uuid': getattr(uuids, 'network%i' % network_id),
'label': 'test%d' % network_id,
'injected': False,
'multi_host': False,
'cidr': '192.168.%d.0/24' % network_id,
'cidr_v6': None,
'netmask': '255.255.255.0',
'netmask_v6': None,
'bridge': 'fake_br%d' % network_id,
'bridge_interface': 'fake_eth%d' % network_id,
'gateway': '192.168.%d.1' % network_id,
'gateway_v6': None,
'broadcast': '192.168.%d.255' % network_id,
'dns1': '192.168.%d.3' % network_id,
'dns2': '192.168.%d.4' % network_id,
'dns3': '192.168.%d.3' % network_id,
'vlan': None,
'host': None,
'project_id': uuids.project,
'vpn_public_address': '192.168.%d.2' % network_id,
'vpn_public_port': None,
'vpn_private_address': None,
'dhcp_start': None,
'rxtx_base': network_id * 10,
'priority': None,
'deleted': False,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'mtu': None,
'dhcp_server': '192.168.%d.1' % network_id,
'enable_dhcp': True,
'share_address': False}
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 CONF.flat_injected:
fake_network['injected'] = True
return fake_network
def fake_network_obj(context, network_id=1, ipv6=None):
return network_obj.Network._from_db_object(
context, network_obj.Network(), fake_network(network_id, ipv6))
def fake_vif(x):
return {'id': x,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'address': 'DE:AD:BE:EF:00:%02x' % x,
'uuid': getattr(uuids, 'vif%i' % x),
'network_id': x,
'instance_uuid': uuids.vifs_1,
'tag': 'fake-tag'}
def floating_ip_ids():
for i in range(1, 100):
yield i
def fixed_ip_ids():
for i in range(1, 100):
yield i
floating_ip_id = floating_ip_ids()
fixed_ip_id = fixed_ip_ids()
def next_fixed_ip(network_id, num_floating_ips=0):
next_id = next(fixed_ip_id)
f_ips = [FakeModel(**next_floating_ip(next_id))
for i in range(num_floating_ips)]
return {'id': next_id,
'network_id': network_id,
'address': '192.168.%d.%03d' % (network_id, (next_id + 99)),
'instance_uuid': uuids.fixed_ip,
'allocated': False,
'reserved': False,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'leased': True,
'host': HOST,
'deleted': 0,
'network': fake_network(network_id),
'virtual_interface': fake_vif(network_id),
# and since network_id and vif_id happen to be equivalent
'virtual_interface_id': network_id,
'floating_ips': f_ips}
def next_floating_ip(fixed_ip_id):
next_id = next(floating_ip_id)
return {'id': next_id,
'address': '10.10.10.%03d' % (next_id + 99),
'fixed_ip_id': fixed_ip_id,
'project_id': None,
'auto_assigned': False}
def fake_get_instance_nw_info(test, num_networks=1):
def update_cache_fake(*args, **kwargs):
@ -380,16 +129,6 @@ def fake_get_instance_nw_info(test, num_networks=1):
return nw_model
def stub_out_nw_api_get_instance_nw_info(test, func=None):
def get_instance_nw_info(self, context, instance, conductor_api=None):
return fake_get_instance_nw_info(test)
if func is None:
func = get_instance_nw_info
test.stub_out('nova.network.api.API.get_instance_nw_info', func)
_real_functions = {}
@ -421,30 +160,6 @@ def unset_stub_network_methods(test):
_real_functions[name])
def stub_compute_with_ips(test):
orig_get = compute_api.API.get
orig_get_all = compute_api.API.get_all
orig_create = compute_api.API.create
def fake_get(*args, **kwargs):
return _get_instances_with_cached_ips(orig_get, *args, **kwargs)
def fake_get_all(*args, **kwargs):
return _get_instances_with_cached_ips(orig_get_all, *args, **kwargs)
def fake_create(*args, **kwargs):
return _create_instances_with_cached_ips(orig_create, *args, **kwargs)
def fake_pci_device_get_by_addr(context, node_id, dev_addr):
return test_pci_device.fake_db_dev
test.stub_out('nova.db.api.pci_device_get_by_addr',
fake_pci_device_get_by_addr)
test.stub_out('nova.compute.api.API.get', fake_get)
test.stub_out('nova.compute.api.API.get_all', fake_get_all)
test.stub_out('nova.compute.api.API.create', fake_create)
def _get_fake_cache():
def _ip(ip, fixed=True, floats=None):
ip_dict = {'address': ip, 'type': 'fixed'}
@ -461,7 +176,6 @@ def _get_fake_cache():
'label': 'private',
'subnets': [{'cidr': '192.168.0.0/24',
'ips': [_ip('192.168.0.3')]}]}}]
if CONF.use_ipv6:
ipv6_addr = 'fe80:b33f::a8bb:ccff:fedd:eeff'
info[0]['network']['subnets'].append({'cidr': 'fe80:b33f::/64',
'ips': [_ip(ipv6_addr)]})
@ -509,4 +223,4 @@ def _create_instances_with_cached_ips(orig_func, *args, **kwargs):
instance['info_cache'].network_info = fake_cache
db.instance_info_cache_update(args[1], instance['uuid'],
{'network_info': fake_cache})
return (instances, reservation_id)
return instances, reservation_id

View File

@ -1,570 +0,0 @@
# Copyright 2012 Red Hat, Inc.
# 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.
"""Tests for network API."""
import copy
import mock
from oslo_utils.fixture import uuidsentinel as uuids
from oslo_utils import uuidutils
from nova import context
from nova import exception
from nova import network
from nova.network import api
from nova.network import base_api
from nova.network import floating_ips
from nova.network import model as network_model
from nova import objects
from nova.objects import fields
from nova.objects import network_request as net_req_obj
from nova import test
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit import fake_instance
from nova.tests.unit.objects import test_fixed_ip
from nova.tests.unit.objects import test_virtual_interface
FAKE_UUID = 'a47ae74e-ab08-547f-9eee-ffd23fc46c16'
fake_info_cache = {
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': False,
'instance_uuid': uuids.instance,
'network_info': '[]',
}
class ApiTestCase(test.TestCase):
def setUp(self):
super(ApiTestCase, self).setUp()
self.flags(use_neutron=False)
self.network_api = network.API()
self.context = context.RequestContext('fake-user',
fakes.FAKE_PROJECT_ID)
@mock.patch('nova.objects.NetworkList.get_all')
def test_get_all(self, mock_get_all):
mock_get_all.return_value = mock.sentinel.get_all
self.assertEqual(mock.sentinel.get_all,
self.network_api.get_all(self.context))
mock_get_all.assert_called_once_with(self.context,
project_only=True)
@mock.patch('nova.objects.NetworkList.get_all')
def test_get_all_liberal(self, mock_get_all):
self.flags(network_manager='nova.network.manager.FlatDHCPManager')
mock_get_all.return_value = mock.sentinel.get_all
self.assertEqual(mock.sentinel.get_all,
self.network_api.get_all(self.context))
mock_get_all.assert_called_once_with(self.context,
project_only="allow_none")
@mock.patch('nova.objects.NetworkList.get_all')
def test_get_all_no_networks(self, mock_get_all):
mock_get_all.side_effect = exception.NoNetworksFound
self.assertEqual([], self.network_api.get_all(self.context))
mock_get_all.assert_called_once_with(self.context,
project_only=True)
@mock.patch('nova.objects.Network.get_by_uuid')
def test_get(self, mock_get):
mock_get.return_value = mock.sentinel.get_by_uuid
self.assertEqual(mock.sentinel.get_by_uuid,
self.network_api.get(self.context, uuids.instance))
@mock.patch('nova.objects.Network.get_by_id')
@mock.patch('nova.db.api.virtual_interface_get_by_instance')
def test_get_vifs_by_instance(self, mock_get_by_instance,
mock_get_by_id):
mock_get_by_instance.return_value = [
dict(test_virtual_interface.fake_vif,
network_id=123)]
mock_get_by_id.return_value = objects.Network()
mock_get_by_id.return_value.uuid = uuids.network_1
instance = objects.Instance(uuid=uuids.instance)
vifs = self.network_api.get_vifs_by_instance(self.context,
instance)
self.assertEqual(1, len(vifs))
self.assertEqual(123, vifs[0].network_id)
self.assertEqual(uuids.network_1, vifs[0].net_uuid)
mock_get_by_instance.assert_called_once_with(
self.context, uuids.instance)
mock_get_by_id.assert_called_once_with(self.context, 123,
project_only='allow_none')
@mock.patch('nova.objects.Network.get_by_id')
@mock.patch('nova.db.api.virtual_interface_get_by_address')
def test_get_vif_by_mac_address(self, mock_get_by_address,
mock_get_by_id):
mock_get_by_address.return_value = dict(
test_virtual_interface.fake_vif, network_id=123)
mock_get_by_id.return_value = objects.Network(
uuid=uuids.network_1)
vif = self.network_api.get_vif_by_mac_address(self.context,
mock.sentinel.mac)
self.assertEqual(123, vif.network_id)
self.assertEqual(uuids.network_1, vif.net_uuid)
mock_get_by_address.assert_called_once_with(self.context,
mock.sentinel.mac)
mock_get_by_id.assert_called_once_with(self.context, 123,
project_only='allow_none')
def _do_test_associate_floating_ip(self, orig_instance_uuid):
"""Test post-association logic."""
new_instance = objects.Instance(uuid=FAKE_UUID)
def fake_associate(*args, **kwargs):
return orig_instance_uuid
def fake_instance_get_by_uuid(context, instance_uuid,
columns_to_join=None,
use_slave=None):
if instance_uuid == orig_instance_uuid:
self.assertIn('extra.flavor', columns_to_join)
return fake_instance.fake_db_instance(uuid=instance_uuid)
def fake_get_nw_info(ctxt, instance):
class FakeNWInfo(object):
def json(self):
pass
return FakeNWInfo()
if orig_instance_uuid:
expected_updated_instances = [new_instance.uuid,
orig_instance_uuid]
else:
expected_updated_instances = [new_instance.uuid]
def fake_instance_info_cache_update(context, instance_uuid, cache):
self.assertEqual(instance_uuid,
expected_updated_instances.pop())
return fake_info_cache
def fake_update_instance_cache_with_nw_info(api, context, instance,
nw_info=None):
return
with test.nested(
mock.patch.object(floating_ips.FloatingIP, 'associate_floating_ip',
fake_associate),
mock.patch.object(self.network_api.db, 'instance_get_by_uuid',
fake_instance_get_by_uuid),
mock.patch.object(self.network_api, '_get_instance_nw_info',
fake_get_nw_info),
mock.patch.object(self.network_api.db,
'instance_info_cache_update',
fake_instance_info_cache_update),
mock.patch.object(base_api, "update_instance_cache_with_nw_info",
fake_update_instance_cache_with_nw_info)
):
self.network_api.associate_floating_ip(self.context,
new_instance,
'172.24.4.225',
'10.0.0.2')
def test_associate_preassociated_floating_ip(self):
self._do_test_associate_floating_ip(uuids.orig_uuid)
def test_associate_unassociated_floating_ip(self):
self._do_test_associate_floating_ip(None)
def test_get_floating_ip_invalid_id(self):
self.assertRaises(exception.InvalidID,
self.network_api.get_floating_ip,
self.context, '123zzz')
@mock.patch('nova.objects.FloatingIP.get_by_id')
def test_get_floating_ip(self, mock_get):
floating = mock.sentinel.floating
mock_get.return_value = floating
self.assertEqual(floating,
self.network_api.get_floating_ip(self.context, 123))
mock_get.assert_called_once_with(self.context, 123)
@mock.patch('nova.objects.FloatingIP.get_pool_names')
def test_get_floating_ip_pools(self, mock_get):
pools = ['foo', 'bar']
mock_get.return_value = pools
self.assertEqual(pools,
self.network_api.get_floating_ip_pools(
self.context))
@mock.patch('nova.objects.FloatingIP.get_by_address')
def test_get_floating_ip_by_address(self, mock_get):
floating = mock.sentinel.floating
mock_get.return_value = floating
self.assertEqual(floating,
self.network_api.get_floating_ip_by_address(
self.context, mock.sentinel.address))
mock_get.assert_called_once_with(self.context,
mock.sentinel.address)
@mock.patch('nova.objects.FloatingIPList.get_by_project')
def test_get_floating_ips_by_project(self, mock_get):
floatings = mock.sentinel.floating_ips
mock_get.return_value = floatings
self.assertEqual(floatings,
self.network_api.get_floating_ips_by_project(
self.context))
mock_get.assert_called_once_with(self.context,
self.context.project_id)
def _stub_migrate_instance_calls(self, method, multi_host, info):
fake_flavor = objects.Flavor.get_by_name(self.context, 'm1.small')
fake_flavor['rxtx_factor'] = 1.21
fake_instance = objects.Instance(
uuid=uuidutils.generate_uuid(dashed=False),
project_id='fake_project_id',
instance_type_id=fake_flavor['id'],
flavor=fake_flavor,
system_metadata={})
fake_migration = objects.Migration(
source_compute='fake_compute_source',
dest_compute='fake_compute_dest')
def fake_mig_inst_method(*args, **kwargs):
info['kwargs'] = kwargs
def fake_get_multi_addresses(*args, **kwargs):
return multi_host, ['fake_float1', 'fake_float2']
self.stub_out('nova.network.rpcapi.NetworkAPI.' + method,
fake_mig_inst_method)
self.stub_out('nova.network.api.API._get_multi_addresses',
fake_get_multi_addresses)
expected = {'instance_uuid': fake_instance.uuid,
'source_compute': 'fake_compute_source',
'dest_compute': 'fake_compute_dest',
'rxtx_factor': 1.21,
'project_id': 'fake_project_id',
'floating_addresses': None}
if multi_host:
expected['floating_addresses'] = ['fake_float1', 'fake_float2']
return fake_instance, fake_migration, expected
def test_migrate_instance_start_with_multihost(self):
info = {'kwargs': {}}
arg1, arg2, expected = self._stub_migrate_instance_calls(
'migrate_instance_start', True, info)
expected['host'] = 'fake_compute_source'
self.network_api.migrate_instance_start(self.context, arg1, arg2)
self.assertEqual(info['kwargs'], expected)
def test_migrate_instance_start_without_multihost(self):
info = {'kwargs': {}}
arg1, arg2, expected = self._stub_migrate_instance_calls(
'migrate_instance_start', False, info)
self.network_api.migrate_instance_start(self.context, arg1, arg2)
self.assertEqual(info['kwargs'], expected)
def test_migrate_instance_finish_with_multihost(self):
info = {'kwargs': {}}
arg1, arg2, expected = self._stub_migrate_instance_calls(
'migrate_instance_finish', True, info)
expected['host'] = 'fake_compute_dest'
self.network_api.migrate_instance_finish(self.context, arg1, arg2, {})
self.assertEqual(info['kwargs'], expected)
def test_migrate_instance_finish_without_multihost(self):
info = {'kwargs': {}}
arg1, arg2, expected = self._stub_migrate_instance_calls(
'migrate_instance_finish', False, info)
self.network_api.migrate_instance_finish(self.context, arg1, arg2, {})
self.assertEqual(info['kwargs'], expected)
def test_is_multi_host_instance_has_no_fixed_ip(self):
with mock.patch.object(self.network_api.db, 'fixed_ip_get_by_instance',
side_effect=exception.FixedIpNotFoundForInstance(
instance_uuid=FAKE_UUID)):
instance = objects.Instance(uuid=FAKE_UUID)
result, floats = (
self.network_api._get_multi_addresses(self.context, instance))
self.assertFalse(result)
@mock.patch('nova.objects.fixed_ip.FixedIPList.get_by_instance_uuid')
def _test_is_multi_host_network_has_no_project_id(self, is_multi_host,
fip_get):
network = objects.Network(
id=123, project_id=None,
multi_host=is_multi_host)
fip_get.return_value = [
objects.FixedIP(instance_uuid=FAKE_UUID, network=network,
floating_ips=objects.FloatingIPList())]
instance = objects.Instance(uuid=FAKE_UUID)
result, floats = self.network_api._get_multi_addresses(self.context,
instance)
self.assertEqual(is_multi_host, result)
def test_is_multi_host_network_has_no_project_id_multi(self):
self._test_is_multi_host_network_has_no_project_id(True)
def test_is_multi_host_network_has_no_project_id_non_multi(self):
self._test_is_multi_host_network_has_no_project_id(False)
@mock.patch('nova.objects.fixed_ip.FixedIPList.get_by_instance_uuid')
def _test_is_multi_host_network_has_project_id(self, is_multi_host,
fip_get):
network = objects.Network(
id=123, project_id=self.context.project_id,
multi_host=is_multi_host)
fip_get.return_value = [
objects.FixedIP(instance_uuid=FAKE_UUID, network=network,
floating_ips=objects.FloatingIPList())]
instance = objects.Instance(uuid=FAKE_UUID)
result, floats = self.network_api._get_multi_addresses(self.context,
instance)
self.assertEqual(is_multi_host, result)
def test_is_multi_host_network_has_project_id_multi(self):
self._test_is_multi_host_network_has_project_id(True)
def test_is_multi_host_network_has_project_id_non_multi(self):
self._test_is_multi_host_network_has_project_id(False)
def _test_refresh_cache(self, method, *args, **kwargs):
# This test verifies that no call to get_instance_nw_info() is made
# from the @refresh_cache decorator for the tested method.
with test.nested(
mock.patch.object(self.network_api.network_rpcapi, method),
mock.patch.object(self.network_api.network_rpcapi,
'get_instance_nw_info'),
mock.patch.object(network_model.NetworkInfo, 'hydrate'),
mock.patch.object(objects.InstanceInfoCache, 'save'),
) as (
method_mock, nwinfo_mock, hydrate_mock, save_mock
):
nw_info = network_model.NetworkInfo([])
method_mock.return_value = nw_info
hydrate_mock.return_value = nw_info
getattr(self.network_api, method)(*args, **kwargs)
hydrate_mock.assert_called_once_with(nw_info)
self.assertFalse(nwinfo_mock.called)
def test_allocate_for_instance_refresh_cache(self):
instance = fake_instance.fake_instance_obj(self.context)
vpn = 'fake-vpn'
requested_networks = [('fake-networks', None)]
self._test_refresh_cache('allocate_for_instance', self.context,
instance, vpn, requested_networks)
@mock.patch('nova.network.rpcapi.NetworkAPI.allocate_for_instance')
def test_allocate_for_instance_no_nets_no_auto(self, mock_rpc_alloc):
# Tests that nothing fails if no networks are returned and auto
# allocation wasn't requested.
mock_rpc_alloc.return_value = []
instance = fake_instance.fake_instance_obj(self.context)
nw_info = self.network_api.allocate_for_instance(
self.context, instance, mock.sentinel.vpn, requested_networks=None)
self.assertEqual(0, len(nw_info))
@mock.patch('nova.network.rpcapi.NetworkAPI.allocate_for_instance')
def test_allocate_for_instance_no_nets_auto_allocate(self, mock_rpc_alloc):
# Tests that we fail when no networks are allocated and auto-allocation
# was requested.
def fake_rpc_allocate(context, *args, **kwargs):
# assert that requested_networks is nulled out
self.assertIn('requested_networks', kwargs)
self.assertIsNone(kwargs['requested_networks'])
return []
mock_rpc_alloc.side_effect = fake_rpc_allocate
instance = fake_instance.fake_instance_obj(self.context)
self.assertRaises(exception.UnableToAutoAllocateNetwork,
self.network_api.allocate_for_instance,
self.context, instance, mock.sentinel.vpn,
[(net_req_obj.NETWORK_ID_AUTO, None)])
self.assertEqual(1, mock_rpc_alloc.call_count)
@mock.patch('nova.network.rpcapi.NetworkAPI.deallocate_for_instance')
def test_deallocate_for_instance_auto_allocate(self, mock_rpc_dealloc):
# Tests that we pass requested_networks=None to the RPC API when
# we're auto-allocating.
instance = fake_instance.fake_instance_obj(self.context)
req_net = objects.NetworkRequest(
network_id=net_req_obj.NETWORK_ID_AUTO)
requested_networks = objects.NetworkRequestList(objects=[req_net])
self.network_api.deallocate_for_instance(
self.context, instance, requested_networks)
mock_rpc_dealloc.assert_called_once_with(self.context,
instance=instance,
requested_networks=None)
def test_add_fixed_ip_to_instance_refresh_cache(self):
instance = fake_instance.fake_instance_obj(self.context)
network_id = 'fake-network-id'
self._test_refresh_cache('add_fixed_ip_to_instance', self.context,
instance, network_id)
def test_remove_fixed_ip_from_instance_refresh_cache(self):
instance = fake_instance.fake_instance_obj(self.context)
address = 'fake-address'
self._test_refresh_cache('remove_fixed_ip_from_instance', self.context,
instance, address)
@mock.patch('nova.db.api.fixed_ip_get_by_address')
def test_get_fixed_ip_by_address(self, fip_get):
fip_get.return_value = test_fixed_ip.fake_fixed_ip
fip = self.network_api.get_fixed_ip_by_address(self.context,
'fake-addr')
self.assertIsInstance(fip, objects.FixedIP)
@mock.patch('nova.objects.FixedIP.get_by_id')
def test_get_fixed_ip(self, mock_get_by_id):
mock_get_by_id.return_value = mock.sentinel.fixed_ip
self.assertEqual(mock.sentinel.fixed_ip,
self.network_api.get_fixed_ip(self.context,
mock.sentinel.id))
mock_get_by_id.assert_called_once_with(self.context, mock.sentinel.id)
@mock.patch('nova.objects.FixedIP.get_by_floating_address')
def test_get_instance_by_floating_address(self, mock_get_by_floating):
mock_get_by_floating.return_value = objects.FixedIP(
instance_uuid = uuids.instance)
self.assertEqual(uuids.instance,
self.network_api.get_instance_id_by_floating_address(
self.context, mock.sentinel.floating))
mock_get_by_floating.assert_called_once_with(self.context,
mock.sentinel.floating)
@mock.patch('nova.objects.FixedIP.get_by_floating_address')
def test_get_instance_by_floating_address_none(self, mock_get_by_floating):
mock_get_by_floating.return_value = None
self.assertIsNone(
self.network_api.get_instance_id_by_floating_address(
self.context, mock.sentinel.floating))
mock_get_by_floating.assert_called_once_with(self.context,
mock.sentinel.floating)
@mock.patch('nova.network.api.API.migrate_instance_start')
def test_cleanup_instance_network_on_host(self, fake_migrate_start):
instance = fake_instance.fake_instance_obj(self.context)
self.network_api.cleanup_instance_network_on_host(
self.context, instance, 'fake_compute_source')
fake_migrate_start.assert_called_once_with(
self.context, instance,
{'source_compute': 'fake_compute_source', 'dest_compute': None})
@mock.patch('nova.network.api.API.migrate_instance_finish')
def test_setup_instance_network_on_host(self, fake_migrate_finish):
instance = fake_instance.fake_instance_obj(self.context)
self.network_api.setup_instance_network_on_host(
self.context, instance, 'fake_compute_source')
fake_migrate_finish.assert_called_once_with(
self.context, instance,
{'source_compute': None, 'dest_compute': 'fake_compute_source'},
None)
@mock.patch('oslo_concurrency.lockutils.lock')
@mock.patch.object(api.API, '_get_instance_nw_info')
@mock.patch('nova.network.base_api.update_instance_cache_with_nw_info')
def test_get_instance_nw_info(self, mock_update, mock_get, mock_lock):
fake_result = mock.sentinel.get_nw_info_result
mock_get.return_value = fake_result
instance = fake_instance.fake_instance_obj(self.context)
result = self.network_api.get_instance_nw_info(self.context, instance)
mock_get.assert_called_once_with(self.context, instance)
mock_update.assert_called_once_with(self.network_api, self.context,
instance, nw_info=fake_result)
self.assertEqual(fake_result, result)
@mock.patch('nova.network.api.API')
@mock.patch('nova.db.api.instance_info_cache_update')
class TestUpdateInstanceCache(test.NoDBTestCase):
def setUp(self):
super(TestUpdateInstanceCache, self).setUp()
self.context = context.get_admin_context()
self.instance = objects.Instance(uuid=FAKE_UUID, deleted=False)
vifs = [network_model.VIF(id='super_vif')]
self.nw_info = network_model.NetworkInfo(vifs)
self.nw_json = fields.NetworkModel.to_primitive(self, 'network_info',
self.nw_info)
def test_update_nw_info_none(self, db_mock, api_mock):
api_mock._get_instance_nw_info.return_value = self.nw_info
info_cache = copy.deepcopy(fake_info_cache)
info_cache.update({'network_info': self.nw_json})
db_mock.return_value = info_cache
base_api.update_instance_cache_with_nw_info(api_mock, self.context,
self.instance, None)
api_mock._get_instance_nw_info.assert_called_once_with(self.context,
self.instance)
db_mock.assert_called_once_with(self.context, self.instance.uuid,
{'network_info': self.nw_json})
self.assertEqual(self.nw_info, self.instance.info_cache.network_info)
def test_update_nw_info_none_instance_deleted(self, db_mock, api_mock):
instance = objects.Instance(uuid=FAKE_UUID, deleted=True)
base_api.update_instance_cache_with_nw_info(
api_mock, self.context, instance)
self.assertFalse(api_mock.called)
def test_update_nw_info_one_network(self, db_mock, api_mock):
info_cache = copy.deepcopy(fake_info_cache)
info_cache.update({'network_info': self.nw_json})
db_mock.return_value = info_cache
base_api.update_instance_cache_with_nw_info(api_mock, self.context,
self.instance, self.nw_info)
self.assertFalse(api_mock._get_instance_nw_info.called)
db_mock.assert_called_once_with(self.context, self.instance.uuid,
{'network_info': self.nw_json})
self.assertEqual(self.nw_info, self.instance.info_cache.network_info)
def test_update_nw_info_empty_list(self, db_mock, api_mock):
new_nw_info = network_model.NetworkInfo([])
db_mock.return_value = fake_info_cache
base_api.update_instance_cache_with_nw_info(api_mock, self.context,
self.instance, new_nw_info)
self.assertFalse(api_mock._get_instance_nw_info.called)
db_mock.assert_called_once_with(self.context, self.instance.uuid,
{'network_info': '[]'})
self.assertEqual(new_nw_info, self.instance.info_cache.network_info)
def test_decorator_return_object(self, db_mock, api_mock):
db_mock.return_value = fake_info_cache
@base_api.refresh_cache
def func(self, context, instance):
return network_model.NetworkInfo([])
func(api_mock, self.context, self.instance)
self.assertFalse(api_mock._get_instance_nw_info.called)
db_mock.assert_called_once_with(self.context, self.instance.uuid,
{'network_info': '[]'})
def test_decorator_return_none(self, db_mock, api_mock):
db_mock.return_value = fake_info_cache
@base_api.refresh_cache
def func(self, context, instance):
pass
api_mock._get_instance_nw_info.return_value = self.nw_info
func(api_mock, self.context, self.instance)
api_mock._get_instance_nw_info.assert_called_once_with(self.context,
self.instance)
db_mock.assert_called_once_with(self.context, self.instance.uuid,
{'network_info': self.nw_json})
class NetworkHooksTestCase(test.BaseHookTestCase):
def test_instance_network_info_hook(self):
info_func = base_api.update_instance_cache_with_nw_info
self.assert_has_hook('instance_network_info', info_func)

View File

@ -1,26 +0,0 @@
# Copyright 2015 OpenStack Foundation
# 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 nova.network import l3
from nova import test
class L3DriverTestCase(test.NoDBTestCase):
def test_linuxnetl3_driver_signatures(self):
self.assertPublicAPISignatures(l3.L3Driver, l3.LinuxNetL3)
def test_nulll3_driver_signatures(self):
self.assertPublicAPISignatures(l3.L3Driver, l3.NullL3)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,417 +0,0 @@
# Copyright 2013 Red Hat, Inc.
#
# 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.
"""
Unit Tests for nova.network.rpcapi
"""
import collections
import mock
from oslo_config import cfg
from nova import context
from nova import exception
from nova.network import rpcapi as network_rpcapi
from nova.objects import base as objects_base
from nova import test
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_network
CONF = cfg.CONF
class NetworkRpcAPITestCase(test.NoDBTestCase):
def setUp(self):
super(NetworkRpcAPITestCase, self).setUp()
self.flags(multi_host=True)
# Used to specify the default value expected if no real value is passed
DefaultArg = collections.namedtuple('DefaultArg', ['value'])
def _test_network_api(self, method, rpc_method, **kwargs):
ctxt = context.RequestContext('fake_user', 'fake_project')
rpcapi = network_rpcapi.NetworkAPI()
self.assertIsNotNone(rpcapi.client)
self.assertEqual(network_rpcapi.RPC_TOPIC,
rpcapi.client.target.topic)
expected_retval = 'foo' if rpc_method == 'call' else None
expected_version = kwargs.pop('version', None)
expected_fanout = kwargs.pop('fanout', None)
expected_kwargs = kwargs.copy()
for k, v in expected_kwargs.items():
if isinstance(v, self.DefaultArg):
expected_kwargs[k] = v.value
kwargs.pop(k)
prepare_kwargs = {}
if expected_version:
prepare_kwargs['version'] = expected_version
if expected_fanout:
prepare_kwargs['fanout'] = True
if 'source_compute' in expected_kwargs:
# Fix up for migrate_instance_* calls.
expected_kwargs['source'] = expected_kwargs.pop('source_compute')
expected_kwargs['dest'] = expected_kwargs.pop('dest_compute')
targeted_methods = [
'lease_fixed_ip', 'release_fixed_ip', 'rpc_setup_network_on_host',
'_rpc_allocate_fixed_ip', 'deallocate_fixed_ip', 'update_dns',
'_associate_floating_ip', '_disassociate_floating_ip',
'lease_fixed_ip', 'release_fixed_ip', 'migrate_instance_start',
'migrate_instance_finish',
'allocate_for_instance', 'deallocate_for_instance',
]
targeted_by_instance = ['deallocate_for_instance']
if method in targeted_methods and ('host' in expected_kwargs or
'instance' in expected_kwargs):
if method in targeted_by_instance:
host = expected_kwargs['instance']['host']
else:
host = expected_kwargs['host']
if method not in ['allocate_for_instance',
'deallocate_fixed_ip']:
expected_kwargs.pop('host')
if CONF.multi_host:
prepare_kwargs['server'] = host
with test.nested(
mock.patch.object(rpcapi.client, rpc_method),
mock.patch.object(rpcapi.client, 'prepare'),
mock.patch.object(rpcapi.client, 'can_send_version'),
) as (
rpc_mock, prepare_mock, csv_mock
):
version_check = [
'deallocate_for_instance', 'deallocate_fixed_ip',
'allocate_for_instance', 'release_fixed_ip',
'set_network_host', 'setup_networks_on_host'
]
if method in version_check:
csv_mock.return_value = True
if prepare_kwargs:
prepare_mock.return_value = rpcapi.client
if rpc_method == 'call':
rpc_mock.return_value = 'foo'
else:
rpc_mock.return_value = None
retval = getattr(rpcapi, method)(ctxt, **kwargs)
self.assertEqual(expected_retval, retval)
if method in version_check:
csv_mock.assert_called_once_with(mock.ANY)
if prepare_kwargs:
prepare_mock.assert_called_once_with(**prepare_kwargs)
rpc_mock.assert_called_once_with(ctxt, method, **expected_kwargs)
def test_create_networks(self):
self._test_network_api('create_networks', rpc_method='call',
arg1='arg', arg2='arg')
def test_delete_network(self):
self._test_network_api('delete_network', rpc_method='call',
uuid='fake_uuid', fixed_range='range')
def test_allocate_for_instance(self):
self._test_network_api('allocate_for_instance', rpc_method='call',
instance_id='fake_id', project_id='fake_id', host='fake_host',
rxtx_factor='fake_factor', vpn=False, requested_networks={},
macs=[], version='1.13')
def test_deallocate_for_instance(self):
instance = fake_instance.fake_instance_obj(context.get_admin_context())
self._test_network_api('deallocate_for_instance', rpc_method='call',
requested_networks=self.DefaultArg(None), instance=instance,
version='1.11')
def test_deallocate_for_instance_with_expected_networks(self):
instance = fake_instance.fake_instance_obj(context.get_admin_context())
self._test_network_api('deallocate_for_instance', rpc_method='call',
instance=instance, requested_networks={}, version='1.11')
def test_release_dhcp(self):
ctxt = context.RequestContext('fake_user', 'fake_project')
dev = 'eth0'
address = '192.168.65.158'
vif_address = '00:0c:29:2c:b2:64'
host = 'fake-host'
rpcapi = network_rpcapi.NetworkAPI()
call_mock = mock.Mock()
cctxt_mock = mock.Mock(call=call_mock)
with test.nested(
mock.patch.object(rpcapi.client, 'can_send_version',
return_value=True),
mock.patch.object(rpcapi.client, 'prepare',
return_value=cctxt_mock)
) as (
can_send_mock, prepare_mock
):
rpcapi.release_dhcp(ctxt, host, dev, address, vif_address)
can_send_mock.assert_called_once_with('1.17')
prepare_mock.assert_called_once_with(server=host, version='1.17')
call_mock.assert_called_once_with(ctxt, 'release_dhcp', dev=dev,
address=address,
vif_address=vif_address)
def test_release_dhcp_v116(self):
ctxt = context.RequestContext('fake_user', 'fake_project')
dev = 'eth0'
address = '192.168.65.158'
vif_address = '00:0c:29:2c:b2:64'
host = 'fake-host'
rpcapi = network_rpcapi.NetworkAPI()
with mock.patch.object(rpcapi.client, 'can_send_version',
return_value=False) as can_send_mock:
self.assertRaises(exception.RPCPinnedToOldVersion,
rpcapi.release_dhcp, ctxt, host, dev, address,
vif_address)
can_send_mock.assert_called_once_with('1.17')
def test_add_fixed_ip_to_instance(self):
self._test_network_api('add_fixed_ip_to_instance', rpc_method='call',
instance_id='fake_id', rxtx_factor='fake_factor',
host='fake_host', network_id='fake_id', version='1.9')
def test_remove_fixed_ip_from_instance(self):
self._test_network_api('remove_fixed_ip_from_instance',
rpc_method='call', instance_id='fake_id',
rxtx_factor='fake_factor', host='fake_host',
address='fake_address', version='1.9')
def test_get_instance_nw_info(self):
self._test_network_api('get_instance_nw_info', rpc_method='call',
instance_id='fake_id', rxtx_factor='fake_factor',
host='fake_host', project_id='fake_id', version='1.9')
def test_validate_networks(self):
self._test_network_api('validate_networks', rpc_method='call',
networks={})
def test_get_dns_domains(self):
self._test_network_api('get_dns_domains', rpc_method='call')
def test_add_dns_entry(self):
self._test_network_api('add_dns_entry', rpc_method='call',
address='addr', name='name', dns_type='foo', domain='domain')
def test_modify_dns_entry(self):
self._test_network_api('modify_dns_entry', rpc_method='call',
address='addr', name='name', domain='domain')
def test_delete_dns_entry(self):
self._test_network_api('delete_dns_entry', rpc_method='call',
name='name', domain='domain')
def test_delete_dns_domain(self):
self._test_network_api('delete_dns_domain', rpc_method='call',
domain='fake_domain')
def test_get_dns_entries_by_address(self):
self._test_network_api('get_dns_entries_by_address', rpc_method='call',
address='fake_address', domain='fake_domain')
def test_get_dns_entries_by_name(self):
self._test_network_api('get_dns_entries_by_name', rpc_method='call',
name='fake_name', domain='fake_domain')
def test_create_private_dns_domain(self):
self._test_network_api('create_private_dns_domain', rpc_method='call',
domain='fake_domain', av_zone='fake_zone')
def test_create_public_dns_domain(self):
self._test_network_api('create_public_dns_domain', rpc_method='call',
domain='fake_domain', project='fake_project')
def test_setup_networks_on_host(self):
ctxt = context.RequestContext('fake_user', 'fake_project')
instance = fake_instance.fake_instance_obj(ctxt)
self._test_network_api('setup_networks_on_host', rpc_method='call',
instance_id=instance.id, host='fake_host', teardown=False,
instance=instance, version='1.16')
def test_setup_networks_on_host_v1_0(self):
ctxt = context.RequestContext('fake_user', 'fake_project')
instance = fake_instance.fake_instance_obj(ctxt)
host = 'fake_host'
teardown = True
rpcapi = network_rpcapi.NetworkAPI()
call_mock = mock.Mock()
cctxt_mock = mock.Mock(call=call_mock)
with test.nested(
mock.patch.object(rpcapi.client, 'can_send_version',
return_value=False),
mock.patch.object(rpcapi.client, 'prepare',
return_value=cctxt_mock)
) as (
can_send_mock, prepare_mock
):
rpcapi.setup_networks_on_host(ctxt, instance.id, host, teardown,
instance)
# assert our mocks were called as expected
can_send_mock.assert_called_once_with('1.16')
prepare_mock.assert_called_once_with(version='1.0')
call_mock.assert_called_once_with(ctxt, 'setup_networks_on_host',
host=host, teardown=teardown,
instance_id=instance.id)
def test_lease_fixed_ip(self):
self._test_network_api('lease_fixed_ip', rpc_method='cast',
host='fake_host', address='fake_addr')
def test_release_fixed_ip(self):
self._test_network_api('release_fixed_ip', rpc_method='cast',
host='fake_host', address='fake_addr', mac='fake_mac',
version='1.14')
def test_release_fixed_ip_no_mac_support(self):
# Tests that the mac kwarg is not passed when we can't send version
# 1.14 to the network manager.
ctxt = context.RequestContext('fake_user', 'fake_project')
address = '192.168.65.158'
host = 'fake-host'
mac = '00:0c:29:2c:b2:64'
rpcapi = network_rpcapi.NetworkAPI()
cast_mock = mock.Mock()
cctxt_mock = mock.Mock(cast=cast_mock)
with test.nested(
mock.patch.object(rpcapi.client, 'can_send_version',
return_value=False),
mock.patch.object(rpcapi.client, 'prepare',
return_value=cctxt_mock)
) as (
can_send_mock, prepare_mock
):
rpcapi.release_fixed_ip(ctxt, address, host, mac)
# assert our mocks were called as expected 232
can_send_mock.assert_called_once_with('1.14')
prepare_mock.assert_called_once_with(server=host, version='1.0')
cast_mock.assert_called_once_with(ctxt, 'release_fixed_ip',
address=address)
def test_set_network_host(self):
network = fake_network.fake_network_obj(context.get_admin_context())
self._test_network_api('set_network_host', rpc_method='call',
network_ref=network, version='1.15')
def test_set_network_host_network_object_to_primitive(self):
# Tests that the network object is converted to a primitive if it
# can't send version 1.15.
ctxt = context.RequestContext('fake_user', 'fake_project')
network = fake_network.fake_network_obj(ctxt)
network_dict = objects_base.obj_to_primitive(network)
rpcapi = network_rpcapi.NetworkAPI()
call_mock = mock.Mock()
cctxt_mock = mock.Mock(call=call_mock)
with test.nested(
mock.patch.object(rpcapi.client, 'can_send_version',
return_value=False),
mock.patch.object(rpcapi.client, 'prepare',
return_value=cctxt_mock)
) as (
can_send_mock, prepare_mock
):
rpcapi.set_network_host(ctxt, network)
# assert our mocks were called as expected
can_send_mock.assert_called_once_with('1.15')
prepare_mock.assert_called_once_with(version='1.0')
call_mock.assert_called_once_with(ctxt, 'set_network_host',
network_ref=network_dict)
def test_rpc_setup_network_on_host(self):
self._test_network_api('rpc_setup_network_on_host', rpc_method='call',
network_id='fake_id', teardown=False, host='fake_host')
def test_rpc_allocate_fixed_ip(self):
self._test_network_api('_rpc_allocate_fixed_ip', rpc_method='call',
instance_id='fake_id', network_id='fake_id', address='addr',
vpn=True, host='fake_host')
def test_deallocate_fixed_ip(self):
instance = fake_instance.fake_db_instance()
self._test_network_api('deallocate_fixed_ip', rpc_method='call',
address='fake_addr', host='fake_host', instance=instance,
version='1.12')
def test_update_dns(self):
self._test_network_api('update_dns', rpc_method='cast', fanout=True,
network_ids='fake_id', version='1.3')
def test__associate_floating_ip(self):
self._test_network_api('_associate_floating_ip', rpc_method='call',
floating_address='fake_addr', fixed_address='fixed_address',
interface='fake_interface', host='fake_host',
instance_uuid='fake_uuid', version='1.6')
def test__disassociate_floating_ip(self):
self._test_network_api('_disassociate_floating_ip', rpc_method='call',
address='fake_addr', interface='fake_interface',
host='fake_host', instance_uuid='fake_uuid', version='1.6')
def test_migrate_instance_start(self):
self._test_network_api('migrate_instance_start', rpc_method='call',
instance_uuid='fake_instance_uuid',
rxtx_factor='fake_factor',
project_id='fake_project',
source_compute='fake_src_compute',
dest_compute='fake_dest_compute',
floating_addresses='fake_floating_addresses',
host=self.DefaultArg(None),
version='1.2')
def test_migrate_instance_start_multi_host(self):
self._test_network_api('migrate_instance_start', rpc_method='call',
instance_uuid='fake_instance_uuid',
rxtx_factor='fake_factor',
project_id='fake_project',
source_compute='fake_src_compute',
dest_compute='fake_dest_compute',
floating_addresses='fake_floating_addresses',
host='fake_host',
version='1.2')
def test_migrate_instance_finish(self):
self._test_network_api('migrate_instance_finish', rpc_method='call',
instance_uuid='fake_instance_uuid',
rxtx_factor='fake_factor',
project_id='fake_project',
source_compute='fake_src_compute',
dest_compute='fake_dest_compute',
floating_addresses='fake_floating_addresses',
host=self.DefaultArg(None),
version='1.2')
def test_migrate_instance_finish_multi_host(self):
self._test_network_api('migrate_instance_finish', rpc_method='call',
instance_uuid='fake_instance_uuid',
rxtx_factor='fake_factor',
project_id='fake_project',
source_compute='fake_src_compute',
dest_compute='fake_dest_compute',
floating_addresses='fake_floating_addresses',
host='fake_host',
version='1.2')

View File

@ -1,85 +0,0 @@
# Copyright (C) 2014, Red Hat, Inc.
#
# 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.
import mock
from nova.db import api as db
from nova.objects import dns_domain
from nova.tests.unit.objects import test_objects
fake_dnsd = {
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'domain': 'blah.example.com',
'scope': 'private',
'availability_zone': 'overthere',
'project_id': '867530niner',
}
class _TestDNSDomain(object):
@staticmethod
def _compare(test, db, obj):
for field, value in db.items():
test.assertEqual(db[field], getattr(obj, field))
def test_get_by_domain(self):
with mock.patch.object(db, 'dnsdomain_get') as get:
get.return_value = fake_dnsd
dnsd = dns_domain.DNSDomain.get_by_domain(self.context, 'domain')
self._compare(self, fake_dnsd, dnsd)
def test_register_for_zone(self):
dns_domain.DNSDomain.register_for_zone(self.context.elevated(),
'domain', 'zone')
dnsd = dns_domain.DNSDomain.get_by_domain(self.context, 'domain')
self.assertEqual('domain', dnsd.domain)
self.assertEqual('zone', dnsd.availability_zone)
def test_register_for_project(self):
dns_domain.DNSDomain.register_for_project(self.context.elevated(),
'domain', 'project')
dnsd = dns_domain.DNSDomain.get_by_domain(self.context, 'domain')
self.assertEqual('domain', dnsd.domain)
self.assertEqual('project', dnsd.project_id)
def test_delete_by_domain(self):
dns_domain.DNSDomain.register_for_zone(self.context.elevated(),
'domain', 'zone')
dnsd = dns_domain.DNSDomain.get_by_domain(self.context, 'domain')
self.assertEqual('domain', dnsd.domain)
self.assertEqual('zone', dnsd.availability_zone)
dns_domain.DNSDomain.delete_by_domain(self.context.elevated(),
'domain')
dnsd = dns_domain.DNSDomain.get_by_domain(self.context, 'domain')
self.assertIsNone(dnsd)
def test_get_all(self):
with mock.patch.object(db, 'dnsdomain_get_all') as get:
get.return_value = [fake_dnsd]
dns_domain.DNSDomainList.get_all(self.context)
class TestDNSDomainObject(test_objects._LocalTest,
_TestDNSDomain):
pass
class TestRemoteDNSDomainObject(test_objects._RemoteTest,
_TestDNSDomain):
pass

View File

@ -1047,8 +1047,6 @@ object_data = {
'ComputeNodeList': '1.17-52f3b0962b1c86b98590144463ebb192',
'ConsoleAuthToken': '1.1-8da320fb065080eb4d3c2e5c59f8bf52',
'CpuDiagnostics': '1.0-d256f2e442d1b837735fd17dfe8e3d47',
'DNSDomain': '1.0-7b0b2dab778454b6a7b6c66afe163a1a',
'DNSDomainList': '1.0-4ee0d9efdfd681fed822da88376e04d2',
'Destination': '1.4-3b440d29459e2c98987ad5b25ad1cb2c',
'DeviceBus': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d',
'DeviceMetadata': '1.0-04eb8fd218a49cbc3b1e54b774d179f7',

View File

@ -16,9 +16,7 @@
import mock
from oslo_concurrency import processutils
import six
from nova import exception
import nova.privsep.linux_net
from nova import test
from nova.tests import fixtures
@ -32,11 +30,6 @@ class LinuxNetTestCase(test.NoDBTestCase):
super(LinuxNetTestCase, self).setUp()
self.useFixture(fixtures.PrivsepFixture())
def test_bridge_add_interface(self, mock_execute):
nova.privsep.linux_net.bridge_add_interface('br0', 'eth0')
cmd = ['brctl', 'addif', 'br0', 'eth0']
mock_execute.assert_called_once_with(*cmd, check_exit_code=False)
@mock.patch('os.path.exists')
def test_device_exists(self, mock_exists, mock_execute):
nova.privsep.linux_net.device_exists('eth0')
@ -123,115 +116,8 @@ class LinuxNetTestCase(test.NoDBTestCase):
nova.privsep.linux_net.create_tap_dev,
'tap42', multiqueue=True)
@mock.patch('nova.privsep.linux_net.ipv4_forwarding_check',
return_value=False)
def test_enable_ipv4_forwarding_required(self, mock_check, mock_execute):
nova.privsep.linux_net.enable_ipv4_forwarding()
mock_check.assert_called_once()
mock_execute.assert_called_once_with(
'sysctl', '-w', 'net.ipv4.ip_forward=1')
@mock.patch('nova.privsep.linux_net.ipv4_forwarding_check',
return_value=True)
def test_enable_ipv4_forwarding_redundant(self, mock_check, mock_execute):
nova.privsep.linux_net.enable_ipv4_forwarding()
mock_check.assert_called_once()
mock_execute.assert_not_called()
def test_modify_ebtables_insert_rule(self, mock_execute):
table = 'filter'
rule = 'INPUT -p ARP -i %s --arp-ip-dst %s -j DROP'.split()
nova.privsep.linux_net.modify_ebtables(table, rule, insert_rule=True)
cmd = ['ebtables', '--concurrent', '-t', table] + ['-I'] + rule
mock_execute.assert_called_once_with(*cmd, check_exit_code=[0])
def test_modify_ebtables_remove_rule(self, mock_execute):
table = 'filter'
rule = 'INPUT -p ARP -i %s --arp-ip-dst %s -j DROP'.split()
nova.privsep.linux_net.modify_ebtables(table, rule, insert_rule=False)
cmd = ['ebtables', '--concurrent', '-t', table] + ['-D'] + rule
mock_execute.assert_called_once_with(*cmd, check_exit_code=[0])
def test_add_vlan(self, mock_execute):
nova.privsep.linux_net.add_vlan('eth0', 'vlan_name', 1)
cmd = ['ip', 'link', 'add', 'link', 'eth0', 'name', 'vlan_name',
'type', 'vlan', 'id', 1]
mock_execute.assert_called_once_with(*cmd, check_exit_code=[0, 2, 254])
def test_iptables_get_rules(self, mock_execute):
nova.privsep.linux_net.iptables_get_rules()
cmd = ['iptables-save', '-c']
mock_execute.assert_called_once_with(*cmd, attempts=5)
def test_iptables_get_rules_ipv6(self, mock_execute):
nova.privsep.linux_net.iptables_get_rules(ipv4=False)
cmd = ['ip6tables-save', '-c']
mock_execute.assert_called_once_with(*cmd, attempts=5)
def test_iptables_set_rules(self, mock_execute):
rules = [
"# Generated by iptables-save v1.8.2 on Mon Aug 19 11:25:48 2019",
"*security",
":INPUT ACCEPT [508089:729290563]",
":FORWARD ACCEPT [247333:239588306]",
":OUTPUT ACCEPT [340769:25538424]",
":FORWARD_direct - [0:0]",
":INPUT_direct - [0:0]",
":OUTPUT_direct - [0:0]",
"-A INPUT -j INPUT_direct",
"-A FORWARD -j FORWARD_direct",
"-A OUTPUT -j OUTPUT_direct",
"COMMIT",
"# Completed on Mon Aug 19 11:25:48 2019",
]
rules_str = six.b('\n'.join(rules))
nova.privsep.linux_net.iptables_set_rules(rules)
cmd = ['iptables-restore', '-c']
mock_execute.assert_called_once_with(*cmd, process_input=rules_str,
attempts=5)
def test_iptables_set_rules_ipv6(self, mock_execute):
rules = [
"# Generated by ip6tables-save v1.8.2 on Mon Aug 19 12:00:29 2019",
"*security",
":INPUT ACCEPT [56:10115]",
":FORWARD ACCEPT [0:0]",
":OUTPUT ACCEPT [147:15301]",
":FORWARD_direct - [0:0]",
":INPUT_direct - [0:0]",
":OUTPUT_direct - [0:0]",
"-A INPUT -j INPUT_direct",
"-A FORWARD -j FORWARD_direct",
"-A OUTPUT -j OUTPUT_direct",
"COMMIT",
"# Completed on Mon Aug 19 12:00:29 2019",
]
rules_str = six.b('\n'.join(rules))
nova.privsep.linux_net.iptables_set_rules(rules, ipv4=False)
cmd = ['ip6tables-restore', '-c']
mock_execute.assert_called_once_with(*cmd, process_input=rules_str,
attempts=5)
def test_ovs_plug__fail(self, mock_execute):
mock_execute.side_effect = processutils.ProcessExecutionError
exc = self.assertRaises(exception.OVSConfigurationFailure,
nova.privsep.linux_net.ovs_plug,
60, 'int-br', 'eth0', '00:14:22:01:23:45')
self.assertIsInstance(exc.kwargs['inner_exception'],
processutils.ProcessExecutionError)
def test_ovs_unplug__fail(self, mock_execute):
mock_execute.side_effect = processutils.ProcessExecutionError
exc = self.assertRaises(exception.OVSConfigurationFailure,
nova.privsep.linux_net.ovs_unplug,
60, 'int-br', 'eth0')
self.assertIsInstance(exc.kwargs['inner_exception'],
processutils.ProcessExecutionError)

View File

@ -18,7 +18,6 @@ import os
import nova.privsep.utils
from nova import test
from nova.tests import fixtures
class SupportDirectIOTestCase(test.NoDBTestCase):
@ -126,14 +125,3 @@ class SupportDirectIOTestCase(test.NoDBTestCase):
self.mock_write.assert_not_called()
self.mock_close.assert_not_called()
self.mock_unlink.assert_called_once_with(self.test_path)
class UtilsTestCase(test.NoDBTestCase):
def setUp(self):
super(UtilsTestCase, self).setUp()
self.useFixture(fixtures.PrivsepFixture())
@mock.patch('os.kill')
def test_kill(self, mock_kill):
nova.privsep.utils.kill(42, -9)
mock_kill.assert_called_with(42, -9)

View File

@ -47,48 +47,6 @@ from nova import utils
CONF = cfg.CONF
class TestConfFixture(testtools.TestCase):
"""Test the Conf fixtures in Nova.
This is a basic test that this fixture works like we expect.
Expectations:
1. before using the fixture, a default value (api_paste_config)
comes through untouched.
2. before using the fixture, a known default value that we
override is correct.
3. after using the fixture a known value that we override is the
new value.
4. after using the fixture we can set a default value to something
random, and it will be reset once we are done.
There are 2 copies of this test so that you can verify they do the
right thing with:
tox -e py27 test_fixtures -- --concurrency=1
As regardless of run order, their initial asserts would be
impacted if the reset behavior isn't working correctly.
"""
def _test_override(self):
self.assertEqual('api-paste.ini', CONF.wsgi.api_paste_config)
self.assertFalse(CONF.fake_network)
self.useFixture(conf_fixture.ConfFixture())
CONF.set_default('api_paste_config', 'foo', group='wsgi')
self.assertTrue(CONF.fake_network)
def test_override1(self):
self._test_override()
def test_override2(self):
self._test_override()
class TestLogging(testtools.TestCase):
def test_default_logging(self):
stdlog = self.useFixture(fixtures.StandardLogging())

View File

@ -1,276 +0,0 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
"""Unit Tests for network code."""
import mock
import six
from nova.network import linux_net
from nova import test
class IptablesManagerTestCase(test.NoDBTestCase):
binary_name = linux_net.get_binary_name()
sample_filter = ['#Generated by iptables-save on Fri Feb 18 15:17:05 2011',
'*filter',
':INPUT ACCEPT [2223527:305688874]',
':FORWARD ACCEPT [0:0]',
':OUTPUT ACCEPT [2172501:140856656]',
':iptables-top-rule - [0:0]',
':iptables-bottom-rule - [0:0]',
':%s-FORWARD - [0:0]' % (binary_name),
':%s-INPUT - [0:0]' % (binary_name),
':%s-OUTPUT - [0:0]' % (binary_name),
':%s-local - [0:0]' % (binary_name),
':nova-filter-top - [0:0]',
'[0:0] -A FORWARD -j nova-filter-top',
'[0:0] -A OUTPUT -j nova-filter-top',
'[0:0] -A nova-filter-top -j %s-local' % (binary_name),
'[0:0] -A INPUT -j %s-INPUT' % (binary_name),
'[0:0] -A OUTPUT -j %s-OUTPUT' % (binary_name),
'[0:0] -A FORWARD -j %s-FORWARD' % (binary_name),
'[0:0] -A INPUT -i virbr0 -p udp -m udp --dport 53 '
'-j ACCEPT',
'[0:0] -A INPUT -i virbr0 -p tcp -m tcp --dport 53 '
'-j ACCEPT',
'[0:0] -A INPUT -i virbr0 -p udp -m udp --dport 67 '
'-j ACCEPT',
'[0:0] -A INPUT -i virbr0 -p tcp -m tcp --dport 67 '
'-j ACCEPT',
'[0:0] -A FORWARD -s 192.168.122.0/24 -i virbr0 '
'-j ACCEPT',
'[0:0] -A FORWARD -i virbr0 -o virbr0 -j ACCEPT',
'[0:0] -A FORWARD -o virbr0 -j REJECT --reject-with '
'icmp-port-unreachable',
'[0:0] -A FORWARD -i virbr0 -j REJECT --reject-with '
'icmp-port-unreachable',
'COMMIT',
'# Completed on Fri Feb 18 15:17:05 2011']
sample_nat = ['# Generated by iptables-save on Fri Feb 18 15:17:05 2011',
'*nat',
':PREROUTING ACCEPT [3936:762355]',
':INPUT ACCEPT [2447:225266]',
':OUTPUT ACCEPT [63491:4191863]',
':POSTROUTING ACCEPT [63112:4108641]',
':%s-OUTPUT - [0:0]' % (binary_name),
':%s-POSTROUTING - [0:0]' % (binary_name),
':%s-PREROUTING - [0:0]' % (binary_name),
':%s-float-snat - [0:0]' % (binary_name),
':%s-snat - [0:0]' % (binary_name),
':nova-postrouting-bottom - [0:0]',
'[0:0] -A PREROUTING -j %s-PREROUTING' % (binary_name),
'[0:0] -A OUTPUT -j %s-OUTPUT' % (binary_name),
'[0:0] -A POSTROUTING -j %s-POSTROUTING' % (binary_name),
'[0:0] -A nova-postrouting-bottom '
'-j %s-snat' % (binary_name),
'[0:0] -A %s-snat '
'-j %s-float-snat' % (binary_name, binary_name),
'[0:0] -A POSTROUTING -j nova-postrouting-bottom',
'COMMIT',
'# Completed on Fri Feb 18 15:17:05 2011']
def setUp(self):
super(IptablesManagerTestCase, self).setUp()
self.manager = linux_net.IptablesManager()
def test_duplicate_rules_no_dirty(self):
table = self.manager.ipv4['filter']
table.dirty = False
num_rules = len(table.rules)
table.add_rule('FORWARD', '-s 1.2.3.4/5 -j DROP')
self.assertEqual(len(table.rules), num_rules + 1)
self.assertTrue(table.dirty)
table.dirty = False
num_rules = len(table.rules)
table.add_rule('FORWARD', '-s 1.2.3.4/5 -j DROP')
self.assertEqual(len(table.rules), num_rules)
self.assertFalse(table.dirty)
def test_clean_tables_no_apply(self):
for table in six.itervalues(self.manager.ipv4):
table.dirty = False
for table in six.itervalues(self.manager.ipv6):
table.dirty = False
with mock.patch.object(self.manager, '_apply') as mock_apply:
self.manager.apply()
self.assertFalse(mock_apply.called)
def test_filter_rules_are_wrapped(self):
current_lines = self.sample_filter
table = self.manager.ipv4['filter']
table.add_rule('FORWARD', '-s 1.2.3.4/5 -j DROP')
new_lines = self.manager._modify_rules(current_lines, table, 'filter')
self.assertIn('[0:0] -A %s-FORWARD '
'-s 1.2.3.4/5 -j DROP' % self.binary_name, new_lines)
table.remove_rule('FORWARD', '-s 1.2.3.4/5 -j DROP')
new_lines = self.manager._modify_rules(current_lines, table, 'filter')
self.assertNotIn('[0:0] -A %s-FORWARD '
'-s 1.2.3.4/5 -j DROP' % self.binary_name, new_lines)
def test_remove_rules_regex(self):
current_lines = self.sample_nat
table = self.manager.ipv4['nat']
table.add_rule('float-snat', '-s 10.0.0.1 -j SNAT --to 10.10.10.10'
' -d 10.0.0.1')
table.add_rule('float-snat', '-s 10.0.0.1 -j SNAT --to 10.10.10.10'
' -o eth0')
table.add_rule('PREROUTING', '-d 10.10.10.10 -j DNAT --to 10.0.0.1')
table.add_rule('OUTPUT', '-d 10.10.10.10 -j DNAT --to 10.0.0.1')
table.add_rule('float-snat', '-s 10.0.0.10 -j SNAT --to 10.10.10.11'
' -d 10.0.0.10')
table.add_rule('float-snat', '-s 10.0.0.10 -j SNAT --to 10.10.10.11'
' -o eth0')
table.add_rule('PREROUTING', '-d 10.10.10.11 -j DNAT --to 10.0.0.10')
table.add_rule('OUTPUT', '-d 10.10.10.11 -j DNAT --to 10.0.0.10')
new_lines = self.manager._modify_rules(current_lines, table, 'nat')
self.assertEqual(len(new_lines) - len(current_lines), 8)
regex = r'.*\s+%s(/32|\s+|$)'
num_removed = table.remove_rules_regex(regex % '10.10.10.10')
self.assertEqual(num_removed, 4)
new_lines = self.manager._modify_rules(current_lines, table, 'nat')
self.assertEqual(len(new_lines) - len(current_lines), 4)
num_removed = table.remove_rules_regex(regex % '10.10.10.11')
self.assertEqual(num_removed, 4)
new_lines = self.manager._modify_rules(current_lines, table, 'nat')
self.assertEqual(current_lines, new_lines)
def test_nat_rules(self):
current_lines = self.sample_nat
new_lines = self.manager._modify_rules(current_lines,
self.manager.ipv4['nat'],
'nat')
for line in [':%s-OUTPUT - [0:0]' % (self.binary_name),
':%s-float-snat - [0:0]' % (self.binary_name),
':%s-snat - [0:0]' % (self.binary_name),
':%s-PREROUTING - [0:0]' % (self.binary_name),
':%s-POSTROUTING - [0:0]' % (self.binary_name)]:
self.assertIn(line, new_lines, "One of our chains went"
" missing.")
seen_lines = set()
for line in new_lines:
line = line.strip()
self.assertNotIn(line, seen_lines, "Duplicate line: %s" % line)
seen_lines.add(line)
last_postrouting_line = ''
for line in new_lines:
if line.startswith('[0:0] -A POSTROUTING'):
last_postrouting_line = line
self.assertIn('-j nova-postrouting-bottom', last_postrouting_line,
"Last POSTROUTING rule does not jump to "
"nova-postouting-bottom: %s" % last_postrouting_line)
for chain in ['POSTROUTING', 'PREROUTING', 'OUTPUT']:
self.assertTrue('[0:0] -A %s -j %s-%s' %
(chain, self.binary_name, chain) in new_lines,
"Built-in chain %s not wrapped" % (chain,))
def test_filter_rules(self):
current_lines = self.sample_filter
new_lines = self.manager._modify_rules(current_lines,
self.manager.ipv4['filter'],
'nat')
for line in [':%s-FORWARD - [0:0]' % (self.binary_name),
':%s-INPUT - [0:0]' % (self.binary_name),
':%s-local - [0:0]' % (self.binary_name),
':%s-OUTPUT - [0:0]' % (self.binary_name)]:
self.assertIn(line, new_lines, "One of our chains went"
" missing.")
seen_lines = set()
for line in new_lines:
line = line.strip()
self.assertNotIn(line, seen_lines, "Duplicate line: %s" % line)
seen_lines.add(line)
for chain in ['FORWARD', 'OUTPUT']:
for line in new_lines:
if line.startswith('[0:0] -A %s' % chain):
self.assertIn('-j nova-filter-top', line,
"First %s rule does not "
"jump to nova-filter-top" % chain)
break
self.assertTrue('[0:0] -A nova-filter-top '
'-j %s-local' % self.binary_name in new_lines,
"nova-filter-top does not jump to wrapped local chain")
for chain in ['INPUT', 'OUTPUT', 'FORWARD']:
self.assertTrue('[0:0] -A %s -j %s-%s' %
(chain, self.binary_name, chain) in new_lines,
"Built-in chain %s not wrapped" % (chain,))
def test_missing_table(self):
current_lines = []
new_lines = self.manager._modify_rules(current_lines,
self.manager.ipv4['filter'],
'filter')
for line in ['*filter',
'COMMIT']:
self.assertIn(line, new_lines, "One of iptables key lines "
"went missing.")
self.assertGreater(len(new_lines), 4, "No iptables rules added")
msg = "iptables rules not generated in the correct order"
self.assertEqual("#Generated by nova", new_lines[0], msg)
self.assertEqual("*filter", new_lines[1], msg)
self.assertEqual("COMMIT", new_lines[-2], msg)
self.assertEqual("#Completed by nova", new_lines[-1], msg)
def test_iptables_top_order(self):
# Test iptables_top_regex
current_lines = list(self.sample_filter)
current_lines[12:12] = ['[0:0] -A FORWARD -j iptables-top-rule']
self.flags(iptables_top_regex='-j iptables-top-rule')
new_lines = self.manager._modify_rules(current_lines,
self.manager.ipv4['filter'],
'filter')
self.assertEqual(current_lines, new_lines)
def test_iptables_bottom_order(self):
# Test iptables_bottom_regex
current_lines = list(self.sample_filter)
current_lines[26:26] = ['[0:0] -A FORWARD -j iptables-bottom-rule']
self.flags(iptables_bottom_regex='-j iptables-bottom-rule')
new_lines = self.manager._modify_rules(current_lines,
self.manager.ipv4['filter'],
'filter')
self.assertEqual(current_lines, new_lines)
def test_iptables_preserve_order(self):
# Test both iptables_top_regex and iptables_bottom_regex
current_lines = list(self.sample_filter)
current_lines[12:12] = ['[0:0] -A FORWARD -j iptables-top-rule']
current_lines[27:27] = ['[0:0] -A FORWARD -j iptables-bottom-rule']
self.flags(iptables_top_regex='-j iptables-top-rule')
self.flags(iptables_bottom_regex='-j iptables-bottom-rule')
new_lines = self.manager._modify_rules(current_lines,
self.manager.ipv4['filter'],
'filter')
self.assertEqual(current_lines, new_lines)

View File

@ -1,82 +0,0 @@
# Copyright (c) 2011 OpenStack Foundation
#
# 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.
"""Test suite for IPv6."""
from nova import ipv6
from nova import test
class IPv6RFC2462TestCase(test.NoDBTestCase):
"""Unit tests for IPv6 rfc2462 backend operations."""
def setUp(self):
super(IPv6RFC2462TestCase, self).setUp()
self.flags(ipv6_backend='rfc2462')
ipv6.reset_backend()
def test_to_global(self):
addr = ipv6.to_global('2001:db8::', '02:16:3e:33:44:55', 'test')
self.assertEqual(addr, '2001:db8::16:3eff:fe33:4455')
def test_to_mac(self):
mac = ipv6.to_mac('2001:db8::216:3eff:fe33:4455')
self.assertEqual(mac, '00:16:3e:33:44:55')
def test_to_global_with_bad_mac(self):
bad_mac = '02:16:3e:33:44:5Z'
expected_msg = 'Bad mac for to_global_ipv6: %s' % bad_mac
err = self.assertRaises(TypeError, ipv6.to_global,
'2001:db8::', bad_mac, 'test')
self.assertEqual(expected_msg, str(err))
def test_to_global_with_bad_prefix(self):
bad_prefix = '2001::1::2'
expected_msg = 'Bad prefix for to_global_ipv6: %s' % bad_prefix
err = self.assertRaises(TypeError, ipv6.to_global,
bad_prefix,
'02:16:3e:33:44:55',
'test')
self.assertEqual(expected_msg, str(err))
class IPv6AccountIdentiferTestCase(test.NoDBTestCase):
"""Unit tests for IPv6 account_identifier backend operations."""
def setUp(self):
super(IPv6AccountIdentiferTestCase, self).setUp()
self.flags(ipv6_backend='account_identifier')
ipv6.reset_backend()
def test_to_global(self):
addr = ipv6.to_global('2001:db8::', '02:16:3e:33:44:55', 'test')
self.assertEqual(addr, '2001:db8::a94a:8fe5:ff33:4455')
def test_to_mac(self):
mac = ipv6.to_mac('2001:db8::a94a:8fe5:ff33:4455')
self.assertEqual(mac, '02:16:3e:33:44:55')
def test_to_global_with_bad_mac(self):
bad_mac = '02:16:3e:33:44:5Z'
expected_msg = 'Bad mac for to_global_ipv6: %s' % bad_mac
err = self.assertRaises(TypeError, ipv6.to_global,
'2001:db8::', bad_mac, 'test')
self.assertEqual(expected_msg, str(err))
def test_to_global_with_bad_prefix(self):
bad_prefix = '2001::1::2'
expected_msg = 'Bad prefix for to_global_ipv6: %s' % bad_prefix
err = self.assertRaises(TypeError, ipv6.to_global,
bad_prefix,
'02:16:3e:33:44:55',
'test')
self.assertEqual(expected_msg, str(err))

View File

@ -55,12 +55,7 @@ class TestProfiler(test.NoDBTestCase):
'nova.conductor.rpcapi.ComputeTaskAPI',
'nova.conductor.rpcapi.ConductorAPI',
'nova.image.api.API',
'nova.network.api.API',
'nova.network.manager.FlatDHCPManager',
'nova.network.manager.FlatManager',
'nova.network.manager.VlanManager',
'nova.network.neutronv2.api.ClientWrapper',
'nova.network.rpcapi.NetworkAPI',
'nova.scheduler.manager.SchedulerManager',
'nova.scheduler.rpcapi.SchedulerAPI',
'nova.virt.libvirt.vif.LibvirtGenericVIFDriver',

View File

@ -27,7 +27,6 @@ import nova.context
from nova.db import api as db
from nova import exception
from nova.image import glance
from nova.network import minidns
from nova.network import model as network_model
from nova import objects
from nova.objects import base as obj_base
@ -135,8 +134,6 @@ FAKE_VIF_MAC = 'de:ad:be:ef:ca:fe'
def get_test_network_info(count=1):
ipv6 = CONF.use_ipv6
def current():
subnet_4 = network_model.Subnet(
cidr=FAKE_NETWORK_IP4_CIDR,
@ -155,9 +152,7 @@ def get_test_network_info(count=1):
network_model.IP(FAKE_NETWORK_IP6_ADDR3)],
routes=None,
version=6)
subnets = [subnet_4]
if ipv6:
subnets.append(subnet_6)
subnets = [subnet_4, subnet_6]
network = network_model.Network(
id=FAKE_NETWORK_UUID,
bridge=FAKE_NETWORK_BRIDGE,
@ -187,23 +182,6 @@ def is_linux():
return platform.system() == 'Linux'
test_dns_managers = []
def dns_manager():
global test_dns_managers
manager = minidns.MiniDNS()
test_dns_managers.append(manager)
return manager
def cleanup_dns_managers():
global test_dns_managers
for manager in test_dns_managers:
manager.delete_dns_file()
test_dns_managers = []
def killer_xml_body():
return (("""<!DOCTYPE x [
<!ENTITY a "%(a)s">

View File

@ -53,7 +53,6 @@ from six.moves import range
import nova.conf
from nova import exception
from nova.i18n import _, _LE, _LW
import nova.network
from nova import safe_utils
profiler = importutils.try_import('osprofiler.profiler')
@ -63,8 +62,6 @@ CONF = nova.conf.CONF
LOG = logging.getLogger(__name__)
_IS_NEUTRON = None
synchronized = lockutils.synchronized_with_prefix('nova-')
SM_IMAGE_PROP_PREFIX = "image_"
@ -709,16 +706,6 @@ def is_none_string(val):
return val.lower() == 'none'
def is_neutron():
global _IS_NEUTRON
if _IS_NEUTRON is not None:
return _IS_NEUTRON
_IS_NEUTRON = nova.network.is_neutron()
return _IS_NEUTRON
def is_auto_disk_config_disabled(auto_disk_config_raw):
auto_disk_config_disabled = False
if auto_disk_config_raw is not None:

View File

@ -61,4 +61,76 @@ upgrade:
* ``[DEFAULT] firewall_driver``
* ``[DEFAULT] allow_same_net_traffic``
* ``[DEFAULT] flat_network_bridge``
* ``[DEFAULT] flat_network_dns``
* ``[DEFAULT] flat_interface``
* ``[DEFAULT] vlan_interface``
* ``[DEFAULT] vlan_start``
* ``[DEFAULT] num_networks``
* ``[DEFAULT] vpn_ip``
* ``[DEFAULT] vpn_start``
* ``[DEFAULT] network_size``
* ``[DEFAULT] fixed_range_v6``
* ``[DEFAULT] gateway``
* ``[DEFAULT] gateway_v6``
* ``[DEFAULT] cnt_vpn_clients``
* ``[DEFAULT] fixed_ip_disassociate_timeout``
* ``[DEFAULT] create_unique_mac_address_attempts``
* ``[DEFAULT] teardown_unused_network_gateway``
* ``[DEFAULT] l3_lib``
* ``[DEFAULT] network_driver``
* ``[DEFAULT] network_manager``
* ``[DEFAULT] multi_host``
* ``[DEFAULT] force_dhcp_release``
* ``[DEFAULT] update_dns_entries``
* ``[DEFAULT] dns_update_periodic_interval``
* ``[DEFAULT] dhcp_domain``
* ``[DEFAULT] use_neutron``
* ``[DEFAULT] auto_assign_floating_ip``
* ``[DEFAULT] floating_ip_dns_manager``
* ``[DEFAULT] instance_dns_manager``
* ``[DEFAULT] instance_dns_domain``
* ``[DEFAULT] default_floating_pool``
* ``[DEFAULT] ipv6_backend``
* ``[DEFAULT] metadata_host``
* ``[DEFAULT] metadata_port``
* ``[DEFAULT] iptables_top_regex``
* ``[DEFAULT] iptables_bottom_regex``
* ``[DEFAULT] iptables_drop_action``
* ``[DEFAULT] ldap_dns_url``
* ``[DEFAULT] ldap_dns_user``
* ``[DEFAULT] ldap_dns_password``
* ``[DEFAULT] ldap_dns_soa_hostmaster``
* ``[DEFAULT] ldap_dns_servers``
* ``[DEFAULT] ldap_dns_base_dn``
* ``[DEFAULT] ldap_dns_soa_refresh``
* ``[DEFAULT] ldap_dns_soa_retry``
* ``[DEFAULT] ldap_dns_soa_expiry``
* ``[DEFAULT] ldap_dns_soa_minimum``
* ``[DEFAULT] dhcpbridge_flagfile``
* ``[DEFAULT] dhcpbridge``
* ``[DEFAULT] dhcp_lease_time``
* ``[DEFAULT] dns_server``
* ``[DEFAULT] use_network_dns_servers``
* ``[DEFAULT] dnsmasq_config_file``
* ``[DEFAULT] ebtables_exec_attempts``
* ``[DEFAULT] ebtables_retry_interval``
* ``[DEFAULT] fake_network``
* ``[DEFAULT] send_arp_for_ha``
* ``[DEFAULT] send_arp_for_ha_count``
* ``[DEFAULT] dmz_cidr``
* ``[DEFAULT] force_snat_range``
* ``[DEFAULT] linuxnet_interface_driver``
* ``[DEFAULT] linuxnet_ovs_integration_bridge``
* ``[DEFAULT] use_single_default_gateway``
* ``[DEFAULT] forward_bridge_interface``
* ``[DEFAULT] ovs_vsctl_timeout``
* ``[DEFAULT] networks_path``
* ``[DEFAULT] public_interface``
* ``[DEFAULT] routing_source_ip``
* ``[DEFAULT] use_ipv6``
* ``[DEFAULT] allow_same_net_traffic``
* ``[DEFAULT] defer_iptables_apply``
* ``[DEFAULT] share_dhcp_address``
* ``[upgrade_levels] network``
* ``[vmware] vlan_interface``

View File

@ -36,31 +36,21 @@ packages =
[entry_points]
oslo.config.opts =
nova.conf = nova.conf.opts:list_opts
oslo.config.opts.defaults =
nova.conf = nova.middleware:set_defaults
oslo.policy.enforcer =
nova = nova.policy:get_enforcer
oslo.policy.policies =
# The sample policies will be ordered by entry point and then by list
# returned from that entry point. If more control is desired split out each
# list_rules method into a separate entry point rather than using the
# aggregate method.
nova = nova.policies:list_rules
nova.compute.monitors.cpu =
virt_driver = nova.compute.monitors.cpu.virt_driver:Monitor
nova.ipv6_backend =
rfc2462 = nova.ipv6.rfc2462
account_identifier = nova.ipv6.account_identifier
nova.scheduler.driver =
filter_scheduler = nova.scheduler.filter_scheduler:FilterScheduler
fake_scheduler = nova.tests.unit.scheduler.fakes:FakeScheduler
console_scripts =
nova-api = nova.cmd.api:main
nova-api-metadata = nova.cmd.api_metadata:main
@ -76,7 +66,6 @@ console_scripts =
nova-serialproxy = nova.cmd.serialproxy:main
nova-spicehtml5proxy = nova.cmd.spicehtml5proxy:main
nova-status = nova.cmd.status:main
wsgi_scripts =
nova-api-wsgi = nova.api.openstack.compute.wsgi:init_application
nova-metadata-wsgi = nova.api.metadata.wsgi:init_application

View File

@ -7,7 +7,6 @@ coverage!=4.4,>=4.0 # Apache-2.0
ddt>=1.0.1 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD
mock>=3.0.0 # BSD
mox3>=0.20.0 # Apache-2.0
psycopg2>=2.7 # LGPL/ZPL
PyMySQL>=0.7.6 # MIT License
pycodestyle>=2.0.0 # MIT License