diff --git a/etc/nova/rootwrap.d/api-metadata.filters b/etc/nova/rootwrap.d/api-metadata.filters deleted file mode 100644 index 1aa6f83e68df..000000000000 --- a/etc/nova/rootwrap.d/api-metadata.filters +++ /dev/null @@ -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 diff --git a/etc/nova/rootwrap.d/network.filters b/etc/nova/rootwrap.d/network.filters deleted file mode 100644 index 52b7130ea89d..000000000000 --- a/etc/nova/rootwrap.d/network.filters +++ /dev/null @@ -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 diff --git a/lower-constraints.txt b/lower-constraints.txt index b59125dd95c2..898b81fce5a4 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -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 diff --git a/nova/conf/__init__.py b/nova/conf/__init__.py index fc64ceccac3c..fb6752c8e2fc 100644 --- a/nova/conf/__init__.py +++ b/nova/conf/__init__.py @@ -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) diff --git a/nova/conf/netconf.py b/nova/conf/netconf.py index 064bb5f5f134..5fe0f909d7f4 100644 --- a/nova/conf/netconf.py +++ b/nova/conf/netconf.py @@ -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. """), ] diff --git a/nova/conf/network.py b/nova/conf/network.py deleted file mode 100644 index 62beb4cb05f7..000000000000 --- a/nova/conf/network.py +++ /dev/null @@ -1,1336 +0,0 @@ -# Copyright 2016 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. - -"""Config options for the nova-network service and related services.""" - -# NOTE(sfinucan): Don't make any non-bugfix changes to this file, as every -# single option found here will be removed in a future release. - -from oslo_config import cfg - -from nova.conf import paths - -network_opts = [ - cfg.BoolOpt('use_neutron', - default=True, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Enable neutron as the backend for networking. - -Determine whether to use Neutron or Nova Network as the back end. Set to true -to use neutron. -"""), - # 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. -"""), - cfg.StrOpt("flat_network_bridge", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the bridge used for simple network interfaces when no -bridge is specified in the VM creation request. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any string representing a valid network bridge, such as 'br100' - -Related options: - -* ``use_neutron`` -"""), - cfg.StrOpt("flat_network_dns", - default="8.8.4.4", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the address of the DNS server for a simple network. If this option is -not specified, the default of '8.8.4.4' is used. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any valid IP address. - -Related options: - -* ``use_neutron`` -"""), - cfg.StrOpt("flat_interface", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option is the name of the virtual interface of the VM on which the bridge -will be built. While it was originally designed to be used only by -nova-network, it is also used by libvirt for the bridge interface name. - -Possible values: - -* Any valid virtual interface name, such as 'eth0' -"""), - cfg.IntOpt("vlan_start", - default=100, - min=1, - max=4094, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the VLAN number used for private networks. Note that the when creating -the networks, if the specified number has already been assigned, nova-network -will increment this number until it finds an available VLAN. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. It also will be ignored if the configuration option -for `network_manager` is not set to the default of -'nova.network.manager.VlanManager'. - -Possible values: - -* Any integer between 1 and 4094. Values outside of that range will raise a - ValueError exception. - -Related options: - -* ``network_manager`` -* ``use_neutron`` -"""), - cfg.StrOpt("vlan_interface", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. While -this option has an effect when using neutron, it incorrectly override the value -provided by neutron and should therefore not be used. -""", - help=""" -This option is the name of the virtual interface of the VM on which the VLAN -bridge will be built. While it was originally designed to be used only by -nova-network, it is also used by libvirt and xenapi for the bridge interface -name. - -Please note that this setting will be ignored in nova-network if the -configuration option for `network_manager` is not set to the default of -'nova.network.manager.VlanManager'. - -Possible values: - -* Any valid virtual interface name, such as 'eth0' -"""), - cfg.IntOpt("num_networks", - default=1, - min=1, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option represents the number of networks to create if not explicitly -specified when the network is created. The only time this is used is if a CIDR -is specified, but an explicit network_size is not. In that case, the subnets -are created by diving the IP address space of the CIDR by num_networks. The -resulting subnet sizes cannot be larger than the configuration option -`network_size`; in that event, they are reduced to `network_size`, and a -warning is logged. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any positive integer is technically valid, although there are practical - limits based upon available IP address space and virtual interfaces. - -Related options: - -* ``use_neutron`` -* ``network_size`` -"""), - cfg.StrOpt("vpn_ip", - default="$my_ip", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option is no longer used since the /os-cloudpipe API was removed in the -16.0.0 Pike release. This is the public IP address for the cloudpipe VPN -servers. It defaults to the IP address of the host. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. It also will be ignored if the configuration option -for `network_manager` is not set to the default of -'nova.network.manager.VlanManager'. - -Possible values: - -* Any valid IP address. The default is ``$my_ip``, the IP address of the VM. - -Related options: - -* ``network_manager`` -* ``use_neutron`` -* ``vpn_start`` -"""), - cfg.PortOpt("vpn_start", - default=1000, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the port number to use as the first VPN port for private networks. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. It also will be ignored if the configuration option -for `network_manager` is not set to the default of -'nova.network.manager.VlanManager', or if you specify a value the 'vpn_start' -parameter when creating a network. - -Possible values: - -* Any integer representing a valid port number. The default is 1000. - -Related options: - -* ``use_neutron`` -* ``vpn_ip`` -* ``network_manager`` -"""), - cfg.IntOpt("network_size", - default=256, - min=1, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the number of addresses in each private subnet. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any positive integer that is less than or equal to the available network - size. Note that if you are creating multiple networks, they must all fit in - the available IP address space. The default is 256. - -Related options: - -* ``use_neutron`` -* ``num_networks`` -"""), - cfg.StrOpt("fixed_range_v6", - default="fd00::/48", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the fixed IPv6 address block when creating a network. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any valid IPv6 CIDR - -Related options: - -* ``use_neutron`` -"""), - cfg.StrOpt("gateway", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the default IPv4 gateway. It is used only in the testing suite. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any valid IP address. - -Related options: - -* ``use_neutron`` -* ``gateway_v6`` -"""), - cfg.StrOpt("gateway_v6", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the default IPv6 gateway. It is used only in the testing suite. - -Please note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Possible values: - -* Any valid IP address. - -Related options: - -* ``use_neutron`` -* ``gateway`` -"""), - cfg.IntOpt("cnt_vpn_clients", - default=0, - min=0, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option represents the number of IP addresses to reserve at the top of the -address range for VPN clients. It also will be ignored if the configuration -option for `network_manager` is not set to the default of -'nova.network.manager.VlanManager'. - -Possible values: - -* Any integer, 0 or greater. - -Related options: - -* ``use_neutron`` -* ``network_manager`` -"""), - cfg.IntOpt("fixed_ip_disassociate_timeout", - default=600, - min=0, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the number of seconds to wait before disassociating a deallocated fixed -IP address. This is only used with the nova-network service, and has no effect -when using neutron for networking. - -Possible values: - -* Any integer, zero or greater. - -Related options: - -* ``use_neutron`` -"""), - cfg.IntOpt("create_unique_mac_address_attempts", - default=5, - min=1, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines how many times nova-network will attempt to create a -unique MAC address before giving up and raising a -`VirtualInterfaceMacAddressException` error. - -Possible values: - -* Any positive integer. The default is 5. - -Related options: - -* ``use_neutron`` -"""), - cfg.BoolOpt("teardown_unused_network_gateway", - default=False, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Determines whether unused gateway devices, both VLAN and bridge, are deleted if -the network is in nova-network VLAN mode and is multi-hosted. - -Related options: - -* ``use_neutron`` -* ``vpn_ip`` -* ``fake_network`` -"""), - cfg.BoolOpt("force_dhcp_release", - default=True, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -When this option is True, a call is made to release the DHCP for the instance -when that instance is terminated. - -Related options: - -* ``use_neutron`` -"""), - cfg.BoolOpt("update_dns_entries", - default=False, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -When this option is True, whenever a DNS entry must be updated, a fanout cast -message is sent to all network hosts to update their DNS entries in multi-host -mode. - -Related options: - -* ``use_neutron`` -"""), - cfg.IntOpt("dns_update_periodic_interval", - default=-1, - min=-1, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the time, in seconds, to wait between refreshing DNS -entries for the network. - -Possible values: - -* A positive integer -* -1 to disable updates - -Related options: - -* ``use_neutron`` -"""), - cfg.StrOpt("l3_lib", - default="nova.network.l3.LinuxNetL3", - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option allows you to specify the L3 management library to be used. - -Possible values: - -* Any dot-separated string that represents the import path to an L3 networking - library. - -Related options: - -* ``use_neutron`` -"""), - cfg.BoolOpt("share_dhcp_address", - default=False, - deprecated_for_removal=True, - deprecated_since='2014.2', - help=""" -THIS VALUE SHOULD BE SET WHEN CREATING THE NETWORK. - -If True in multi_host mode, all compute hosts share the same dhcp address. The -same IP address used for DHCP will be added on each nova-network node which is -only visible to the VMs on the same host. - -The use of this configuration has been deprecated and may be removed in any -release after Mitaka. It is recommended that instead of relying on this option, -an explicit value should be passed to 'create_networks()' as a keyword argument -with the name 'share_address'. -"""), -] - -linux_net_opts = [ - cfg.MultiStrOpt('dhcpbridge_flagfile', - default=['/etc/nova/nova-dhcpbridge.conf'], - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option is a list of full paths to one or more configuration files for -dhcpbridge. In most cases the default path of '/etc/nova/nova-dhcpbridge.conf' -should be sufficient, but if you have special needs for configuring dhcpbridge, -you can change or add to this list. - -Possible values - -* A list of strings, where each string is the full path to a dhcpbridge - configuration file. -"""), - cfg.StrOpt('networks_path', - default=paths.state_path_def('networks'), - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -The location where the network configuration files will be kept. The default is -the 'networks' directory off of the location where nova's Python module is -installed. - -Possible values - -* A string containing the full path to the desired configuration directory -"""), - cfg.StrOpt('public_interface', - default='eth0', - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the name of the network interface for public IP addresses. The default -is 'eth0'. - -Possible values: - -* Any string representing a network interface name -"""), - cfg.StrOpt('dhcpbridge', - default=paths.bindir_def('nova-dhcpbridge'), - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -The location of the binary nova-dhcpbridge. By default it is the binary named -'nova-dhcpbridge' that is installed with all the other nova binaries. - -Possible values: - -* Any string representing the full path to the binary for dhcpbridge -"""), - cfg.StrOpt('routing_source_ip', - default='$my_ip', - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -The public IP address of the network host. - -This is used when creating an SNAT rule. - -Possible values: - -* Any valid IP address - -Related options: - -* ``force_snat_range`` -"""), - cfg.IntOpt('dhcp_lease_time', - default=86400, - min=1, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -The lifetime of a DHCP lease, in seconds. The default is 86400 (one day). - -Possible values: - -* Any positive integer value. -"""), - cfg.MultiStrOpt("dns_server", - default=[], - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Despite the singular form of the name of this option, it is actually a list of -zero or more server addresses that dnsmasq will use for DNS nameservers. If -this is not empty, dnsmasq will not read /etc/resolv.conf, but will only use -the servers specified in this option. If the option use_network_dns_servers is -True, the dns1 and dns2 servers from the network will be appended to this list, -and will be used as DNS servers, too. - -Possible values: - -* A list of strings, where each string is either an IP address or a FQDN. - -Related options: - -* ``use_network_dns_servers`` -"""), - cfg.BoolOpt("use_network_dns_servers", - default=False, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -When this option is set to True, the dns1 and dns2 servers for the network -specified by the user on boot will be used for DNS, as well as any specified in -the `dns_server` option. - -Related options: - -* ``dns_server`` -"""), - cfg.ListOpt("dmz_cidr", - default=[], - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option is a list of zero or more IP address ranges in your network's DMZ -that should be accepted. - -Possible values: - -* A list of strings, each of which should be a valid CIDR. -"""), - cfg.MultiStrOpt("force_snat_range", - default=[], - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is a list of zero or more IP ranges that traffic from the -`routing_source_ip` will be SNATted to. If the list is empty, then no SNAT -rules are created. - -Possible values: - -* A list of strings, each of which should be a valid CIDR. - -Related options: - -* ``routing_source_ip`` -"""), - cfg.StrOpt("dnsmasq_config_file", - default="", - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -The path to the custom dnsmasq configuration file, if any. - -Possible values: - -* The full path to the configuration file, or an empty string if there is no - custom dnsmasq configuration file. -"""), - cfg.StrOpt("linuxnet_interface_driver", - default="nova.network.linux_net.LinuxBridgeInterfaceDriver", - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This is the class used as the ethernet device driver for linuxnet bridge -operations. The default value should be all you need for most cases, but if you -wish to use a customized class, set this option to the full dot-separated -import path for that class. - -Possible values: - -* Any string representing a dot-separated class path that Nova can import. -"""), - cfg.StrOpt("linuxnet_ovs_integration_bridge", - default="br-int", - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -The name of the Open vSwitch bridge that is used with linuxnet when connecting -with Open vSwitch." - -Possible values: - -* Any string representing a valid bridge name. -"""), - cfg.BoolOpt("send_arp_for_ha", - default=False, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -When True, when a device starts up, and upon binding floating IP addresses, arp -messages will be sent to ensure that the arp caches on the compute hosts are -up-to-date. - -Related options: - -* ``send_arp_for_ha_count`` -"""), - cfg.IntOpt("send_arp_for_ha_count", - default=3, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -When arp messages are configured to be sent, they will be sent with the count -set to the value of this option. Of course, if this is set to zero, no arp -messages will be sent. - -Possible values: - -* Any integer greater than or equal to 0 - -Related options: - -* ``send_arp_for_ha`` -"""), - cfg.BoolOpt("use_single_default_gateway", - default=False, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -When set to True, only the firt nic of a VM will get its default gateway from -the DHCP server. -"""), - cfg.MultiStrOpt("forward_bridge_interface", - default=["all"], - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -One or more interfaces that bridges can forward traffic to. If any of the items -in this list is the special keyword 'all', then all traffic will be forwarded. - -Possible values: - -* A list of zero or more interface names, or the word 'all'. -"""), - cfg.StrOpt("metadata_host", - default="$my_ip", - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the IP address for the network metadata API server. - -This is really the client side of the metadata host equation that allows -nova-network to find the metadata server when doing a default multi host -networking. - -Possible values: - -* Any valid IP address. The default is the address of the Nova API server. - -Related options: - -* ``metadata_port`` -"""), - cfg.PortOpt("metadata_port", - default=8775, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the port used for the metadata API server. - -Related options: - -* ``metadata_host`` -"""), - cfg.StrOpt("iptables_top_regex", - default="", - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This expression, if defined, will select any matching iptables rules and place -them at the top when applying metadata changes to the rules. - -Possible values: - -* Any string representing a valid regular expression, or an empty string - -Related options: - -* ``iptables_bottom_regex`` -"""), - cfg.StrOpt("iptables_bottom_regex", - default="", - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This expression, if defined, will select any matching iptables rules and place -them at the bottom when applying metadata changes to the rules. - -Possible values: - -* Any string representing a valid regular expression, or an empty string - -Related options: - -* iptables_top_regex -"""), - cfg.StrOpt("iptables_drop_action", - default="DROP", - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -By default, packets that do not pass the firewall are DROPped. In many cases, -though, an operator may find it more useful to change this from DROP to REJECT, -so that the user issuing those packets may have a better idea as to what's -going on, or LOGDROP in order to record the blocked traffic before DROPping. - -Possible values: - -* A string representing an iptables chain. The default is DROP. -"""), - cfg.BoolOpt('defer_iptables_apply', - default=False, - deprecated_for_removal=True, - deprecated_since="19.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Defer application of IPTables rules until after init phase. - -When a compute service is restarted each instance running on the host has its -iptables rules built and applied sequentially during the host init stage. The -impact of this, especially on a host running many instances, can be observed as -a period where some instances are not accessible as the existing iptables rules -have been torn down and not yet re-applied. - -This is a workaround that prevents the application of the iptables rules until -all instances on the host had been initialised then the rules for all instances -are applied all at once preventing a 'blackout' period. -"""), - cfg.IntOpt("ovs_vsctl_timeout", - default=120, - min=0, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option represents the period of time, in seconds, that the ovs_vsctl calls -will wait for a response from the database before timing out. A setting of 0 -means that the utility should wait forever for a response. - -Possible values: - -* Any positive integer if a limited timeout is desired, or zero if the calls - should wait forever for a response. -"""), - cfg.BoolOpt("fake_network", - default=False, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option is used mainly in testing to avoid calls to the underlying network -utilities. -"""), - cfg.IntOpt("ebtables_exec_attempts", - default=3, - min=1, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the number of times to retry ebtables commands before -giving up. The minimum number of retries is 1. - -Possible values: - -* Any positive integer - -Related options: - -* ``ebtables_retry_interval`` -"""), - cfg.FloatOpt("ebtables_retry_interval", - default=1.0, - deprecated_for_removal=True, - deprecated_since="16.0.0", - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -This option determines the time, in seconds, that the system will sleep in -between ebtables retries. Note that each successive retry waits a multiple of -this value, so for example, if this is set to the default of 1.0 seconds, and -ebtables_exec_attempts is 4, after the first failure, the system will sleep for -1 * 1.0 seconds, after the second failure it will sleep 2 * 1.0 seconds, and -after the third failure it will sleep 3 * 1.0 seconds. - -Possible values: - -* Any non-negative float or integer. Setting this to zero will result in no - waiting between attempts. - -Related options: - -* ebtables_exec_attempts -"""), -] - -ldap_dns_opts = [ - cfg.URIOpt('ldap_dns_url', - default='ldap://ldap.example.com:389', - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -URL for LDAP server which will store DNS entries - -Possible values: - -* A valid LDAP URL representing the server -"""), - cfg.StrOpt('ldap_dns_user', - default='uid=admin,ou=people,dc=example,dc=org', - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help='Bind user for LDAP server'), - cfg.StrOpt('ldap_dns_password', - default='password', - secret=True, - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help="Bind user's password for LDAP server"), - cfg.StrOpt('ldap_dns_soa_hostmaster', - default='hostmaster@example.org', - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Hostmaster for LDAP DNS driver Statement of Authority - -Possible values: - -* Any valid string representing LDAP DNS hostmaster. -"""), - cfg.MultiStrOpt('ldap_dns_servers', - default=['dns.example.org'], - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -DNS Servers for LDAP DNS driver - -Possible values: - -* A valid URL representing a DNS server -"""), - cfg.StrOpt('ldap_dns_base_dn', - default='ou=hosts,dc=example,dc=org', - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Base distinguished name for the LDAP search query - -This option helps to decide where to look up the host in LDAP. -"""), - cfg.IntOpt('ldap_dns_soa_refresh', - default=1800, - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Refresh interval (in seconds) for LDAP DNS driver Start of Authority - -Time interval, a secondary/slave DNS server waits before requesting for -primary DNS server's current SOA record. If the records are different, -secondary DNS server will request a zone transfer from primary. - -NOTE: Lower values would cause more traffic. -"""), - cfg.IntOpt('ldap_dns_soa_retry', - default=3600, - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Retry interval (in seconds) for LDAP DNS driver Start of Authority - -Time interval, a secondary/slave DNS server should wait, if an -attempt to transfer zone failed during the previous refresh interval. -"""), - cfg.IntOpt('ldap_dns_soa_expiry', - default=86400, - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Expiry interval (in seconds) for LDAP DNS driver Start of Authority - -Time interval, a secondary/slave DNS server holds the information -before it is no longer considered authoritative. -"""), - cfg.IntOpt('ldap_dns_soa_minimum', - default=7200, - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Minimum interval (in seconds) for LDAP DNS driver Start of Authority - -It is Minimum time-to-live applies for all resource records in the -zone file. This value is supplied to other servers how long they -should keep the data in cache. -"""), -] - -driver_opts = [ - cfg.StrOpt('network_driver', - default='nova.network.linux_net', - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Driver to use for network creation. - -Network driver initializes (creates bridges and so on) only when the -first VM lands on a host node. All network managers configure the -network using network drivers. The driver is not tied to any particular -network manager. - -The default Linux driver implements vlans, bridges, and iptables rules -using linux utilities. - -Note that this option is only used when using nova-network instead -of Neutron in your deployment. - -Related options: - -* ``use_neutron`` -"""), -] - -rpcapi_opts = [ - cfg.BoolOpt('multi_host', - default=False, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Default value for multi_host in networks. - -nova-network service can operate in a multi-host or single-host mode. -In multi-host mode each compute node runs a copy of nova-network and the -instances on that compute node use the compute node as a gateway to the -Internet. Where as in single-host mode, a central server runs the nova-network -service. All compute nodes forward traffic from the instances to the -cloud controller which then forwards traffic to the Internet. - -If this options is set to true, some rpc network calls will be sent directly -to host. - -Note that this option is only used when using nova-network instead of -Neutron in your deployment. - -Related options: - -* ``use_neutron`` -""") -] - -floating_ip_opts = [ - cfg.StrOpt('default_floating_pool', - default='nova', - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -This option was used for two purposes: to set the floating IP pool name for -nova-network and to do the same for neutron. nova-network is deprecated, as are -any related configuration options. Users of neutron, meanwhile, should use the -'default_floating_pool' option in the '[neutron]' group. -""", - help=""" -Default pool for floating IPs. - -This option specifies the default floating IP pool for allocating floating IPs. - -While allocating a floating ip, users can optionally pass in the name of the -pool they want to allocate from, otherwise it will be pulled from the -default pool. - -If this option is not set, then 'nova' is used as default floating pool. - -Possible values: - -* Any string representing a floating IP pool name -"""), - cfg.BoolOpt('auto_assign_floating_ip', - default=False, - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Autoassigning floating IP to VM - -When set to True, floating IP is auto allocated and associated -to the VM upon creation. - -Related options: - -* use_neutron: this options only works with nova-network. -"""), - cfg.StrOpt('floating_ip_dns_manager', - default='nova.network.noop_dns_driver.NoopDNSDriver', - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Full class name for the DNS Manager for floating IPs. - -This option specifies the class of the driver that provides functionality -to manage DNS entries associated with floating IPs. - -When a user adds a DNS entry for a specified domain to a floating IP, -nova will add a DNS entry using the specified floating DNS driver. -When a floating IP is deallocated, its DNS entry will automatically be deleted. - -Possible values: - -* Full Python path to the class to be used - -Related options: - -* use_neutron: this options only works with nova-network. -"""), - cfg.StrOpt('instance_dns_manager', - default='nova.network.noop_dns_driver.NoopDNSDriver', - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Full class name for the DNS Manager for instance IPs. - -This option specifies the class of the driver that provides functionality -to manage DNS entries for instances. - -On instance creation, nova will add DNS entries for the instance name and -id, using the specified instance DNS driver and domain. On instance deletion, -nova will remove the DNS entries. - -Possible values: - -* Full Python path to the class to be used - -Related options: - -* use_neutron: this options only works with nova-network. -"""), - cfg.StrOpt('instance_dns_domain', - default='', - deprecated_for_removal=True, - deprecated_since='15.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -If specified, Nova checks if the availability_zone of every instance matches -what the database says the availability_zone should be for the specified -dns_domain. - -Related options: - -* use_neutron: this options only works with nova-network. -""") -] - -ipv6_opts = [ - cfg.BoolOpt('use_ipv6', - default=False, - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Assign IPv6 and IPv4 addresses when creating instances. - -Related options: - -* use_neutron: this only works with nova-network. -"""), - cfg.StrOpt('ipv6_backend', - default='rfc2462', - choices=('rfc2462', 'account_identifier'), - deprecated_for_removal=True, - deprecated_since='16.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help=""" -Abstracts out IPv6 address generation to pluggable backends. - -nova-network can be put into dual-stack mode, so that it uses -both IPv4 and IPv6 addresses. In dual-stack mode, by default, instances -acquire IPv6 global unicast addresses with the help of stateless address -auto-configuration mechanism. - -Related options: - -* use_neutron: this option only works with nova-network. -* use_ipv6: this option only works if ipv6 is enabled for nova-network. -"""), -] - - -service_opts = [ - cfg.StrOpt('network_manager', - choices=[ - 'nova.network.manager.FlatManager', - 'nova.network.manager.FlatDHCPManager', - 'nova.network.manager.VlanManager', - ], - default='nova.network.manager.VlanManager', - deprecated_for_removal=True, - deprecated_since='18.0.0', - deprecated_reason=""" -nova-network is deprecated, as are any related configuration options. -""", - help='Full class name for the Manager for network'), -] - - -ALL_DEFAULT_OPTS = (linux_net_opts + network_opts + ldap_dns_opts + - rpcapi_opts + driver_opts + floating_ip_opts + - ipv6_opts + service_opts) - - -def register_opts(conf): - conf.register_opts(ALL_DEFAULT_OPTS) - - -def list_opts(): - return {"DEFAULT": ALL_DEFAULT_OPTS} diff --git a/nova/conf/upgrade_levels.py b/nova/conf/upgrade_levels.py index 19cc5e23b3b6..b15f5b0ee1f4 100644 --- a/nova/conf/upgrade_levels.py +++ b/nova/conf/upgrade_levels.py @@ -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'. diff --git a/nova/db/api.py b/nova/db/api.py index 4f3c8e99821b..a6845810febb 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -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) - - #################### diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 3e52b30d3970..4009b9042569 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -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" diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index c6f43ef7637b..8ae941514597 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -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' diff --git a/nova/ipv6/__init__.py b/nova/ipv6/__init__.py deleted file mode 100644 index 05bd0358a75f..000000000000 --- a/nova/ipv6/__init__.py +++ /dev/null @@ -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 diff --git a/nova/ipv6/account_identifier.py b/nova/ipv6/account_identifier.py deleted file mode 100644 index a8da65764feb..000000000000 --- a/nova/ipv6/account_identifier.py +++ /dev/null @@ -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]]) diff --git a/nova/ipv6/api.py b/nova/ipv6/api.py deleted file mode 100644 index 478fc1f1417c..000000000000 --- a/nova/ipv6/api.py +++ /dev/null @@ -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() diff --git a/nova/ipv6/rfc2462.py b/nova/ipv6/rfc2462.py deleted file mode 100644 index 9d62f24423a1..000000000000 --- a/nova/ipv6/rfc2462.py +++ /dev/null @@ -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]]) diff --git a/nova/network/__init__.py b/nova/network/__init__.py index 73835e2a9f10..5df62405441e 100644 --- a/nova/network/__init__.py +++ b/nova/network/__init__.py @@ -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() diff --git a/nova/network/api.py b/nova/network/api.py deleted file mode 100644 index ba2ef9ea14e4..000000000000 --- a/nova/network/api.py +++ /dev/null @@ -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}) diff --git a/nova/network/base_api.py b/nova/network/base_api.py index 27c366f48d70..573bf9abcb77 100644 --- a/nova/network/base_api.py +++ b/nova/network/base_api.py @@ -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 diff --git a/nova/network/dns_driver.py b/nova/network/dns_driver.py deleted file mode 100644 index 07b690b91f01..000000000000 --- a/nova/network/dns_driver.py +++ /dev/null @@ -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() diff --git a/nova/network/driver.py b/nova/network/driver.py deleted file mode 100644 index f984389c8612..000000000000 --- a/nova/network/driver.py +++ /dev/null @@ -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) diff --git a/nova/network/floating_ips.py b/nova/network/floating_ips.py deleted file mode 100644 index 04064e6060bb..000000000000 --- a/nova/network/floating_ips.py +++ /dev/null @@ -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) diff --git a/nova/network/l3.py b/nova/network/l3.py deleted file mode 100644 index abf3a9b18551..000000000000 --- a/nova/network/l3.py +++ /dev/null @@ -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 diff --git a/nova/network/ldapdns.py b/nova/network/ldapdns.py deleted file mode 100644 index 047d0042acfd..000000000000 --- a/nova/network/ldapdns.py +++ /dev/null @@ -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 diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py deleted file mode 100644 index 233005f38153..000000000000 --- a/nova/network/linux_net.py +++ /dev/null @@ -1,1632 +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. - -"""Implements vlans, bridges, and iptables rules using linux utilities.""" - -import calendar -import inspect -import os -import re -import signal -import time - -import netaddr -import netifaces -from oslo_concurrency import processutils -from oslo_log import log as logging -from oslo_serialization import jsonutils -from oslo_utils import excutils -from oslo_utils import fileutils -from oslo_utils import importutils -from oslo_utils import timeutils -import six - -import nova.conf -from nova import exception -from nova.i18n import _ -from nova import objects -from nova.pci import utils as pci_utils -import nova.privsep.linux_net -from nova import utils - -LOG = logging.getLogger(__name__) - - -CONF = nova.conf.CONF - - -# NOTE(vish): Iptables supports chain names of up to 28 characters, and we -# add up to 12 characters to binary_name which is used as a prefix, -# so we limit it to 16 characters. -# (max_chain_name_length - len('-POSTROUTING') == 16) -def get_binary_name(): - """Grab the name of the binary we're running in.""" - return os.path.basename(inspect.stack()[-1][1])[:16] - - -binary_name = get_binary_name() - - -class IptablesRule(object): - """An iptables rule. - - You shouldn't need to use this class directly, it's only used by - IptablesManager. - - """ - - def __init__(self, chain, rule, wrap=True, top=False): - self.chain = chain - self.rule = rule - self.wrap = wrap - self.top = top - - def __eq__(self, other): - return ((self.chain == other.chain) and - (self.rule == other.rule) and - (self.top == other.top) and - (self.wrap == other.wrap)) - - def __ne__(self, other): - return not self == other - - def __repr__(self): - if self.wrap: - chain = '%s-%s' % (binary_name, self.chain) - else: - chain = self.chain - # new rules should have a zero [packet: byte] count - return '[0:0] -A %s %s' % (chain, self.rule) - - -class IptablesTable(object): - """An iptables table.""" - - def __init__(self): - self.rules = [] - self.remove_rules = [] - self.chains = set() - self.unwrapped_chains = set() - self.remove_chains = set() - self.dirty = True - - def has_chain(self, name, wrap=True): - if wrap: - return name in self.chains - else: - return name in self.unwrapped_chains - - def add_chain(self, name, wrap=True): - """Adds a named chain to the table. - - The chain name is wrapped to be unique for the component creating - it, so different components of Nova can safely create identically - named chains without interfering with one another. - - At the moment, its wrapped name is -, - so if nova-compute creates a chain named 'OUTPUT', it'll actually - end up named 'nova-compute-OUTPUT'. - - """ - if wrap: - self.chains.add(name) - else: - self.unwrapped_chains.add(name) - self.dirty = True - - def remove_chain(self, name, wrap=True): - """Remove named chain. - - This removal "cascades". All rule in the chain are removed, as are - all rules in other chains that jump to it. - - If the chain is not found, this is merely logged. - - """ - if wrap: - chain_set = self.chains - else: - chain_set = self.unwrapped_chains - - if name not in chain_set: - LOG.warning('Attempted to remove chain %s which does not exist', - name) - return - self.dirty = True - - # non-wrapped chains and rules need to be dealt with specially, - # so we keep a list of them to be iterated over in apply() - if not wrap: - self.remove_chains.add(name) - chain_set.remove(name) - if not wrap: - self.remove_rules += [r for r in self.rules if r.chain == name] - self.rules = [r for r in self.rules if r.chain != name] - - if wrap: - jump_snippet = '-j %s-%s' % (binary_name, name) - else: - jump_snippet = '-j %s' % (name,) - - if not wrap: - self.remove_rules += [r for r in self.rules - if jump_snippet in r.rule] - self.rules = [r for r in self.rules if jump_snippet not in r.rule] - - def add_rule(self, chain, rule, wrap=True, top=False): - """Add a rule to the table. - - This is just like what you'd feed to iptables, just without - the '-A ' bit at the start. - - However, if you need to jump to one of your wrapped chains, - prepend its name with a '$' which will ensure the wrapping - is applied correctly. - - """ - if wrap and chain not in self.chains: - raise ValueError(_('Unknown chain: %r') % chain) - - if '$' in rule: - rule = ' '.join(map(self._wrap_target_chain, rule.split(' '))) - - rule_obj = IptablesRule(chain, rule, wrap, top) - if rule_obj in self.rules: - LOG.debug("Skipping duplicate iptables rule addition. " - "%(rule)r already in %(rules)r", - {'rule': rule_obj, 'rules': self.rules}) - else: - self.rules.append(IptablesRule(chain, rule, wrap, top)) - self.dirty = True - - def _wrap_target_chain(self, s): - if s.startswith('$'): - return '%s-%s' % (binary_name, s[1:]) - return s - - def remove_rule(self, chain, rule, wrap=True, top=False): - """Remove a rule from a chain. - - Note: The rule must be exactly identical to the one that was added. - You cannot switch arguments around like you can with the iptables - CLI tool. - - """ - try: - self.rules.remove(IptablesRule(chain, rule, wrap, top)) - if not wrap: - self.remove_rules.append(IptablesRule(chain, rule, wrap, top)) - self.dirty = True - except ValueError: - LOG.warning('Tried to remove rule that was not there:' - ' %(chain)r %(rule)r %(wrap)r %(top)r', - {'chain': chain, 'rule': rule, - 'top': top, 'wrap': wrap}) - - def remove_rules_regex(self, regex): - """Remove all rules matching regex.""" - if isinstance(regex, six.string_types): - regex = re.compile(regex) - num_rules = len(self.rules) - self.rules = [r for r in self.rules if not regex.match(str(r))] - removed = num_rules - len(self.rules) - if removed > 0: - self.dirty = True - return removed - - def empty_chain(self, chain, wrap=True): - """Remove all rules from a chain.""" - chained_rules = [rule for rule in self.rules - if rule.chain == chain and rule.wrap == wrap] - if chained_rules: - self.dirty = True - for rule in chained_rules: - self.rules.remove(rule) - - -class IptablesManager(object): - """Wrapper for iptables. - - See IptablesTable for some usage docs - - A number of chains are set up to begin with. - - First, nova-filter-top. It's added at the top of FORWARD and OUTPUT. Its - name is not wrapped, so it's shared between the various nova workers. It's - intended for rules that need to live at the top of the FORWARD and OUTPUT - chains. It's in both the ipv4 and ipv6 set of tables. - - For ipv4 and ipv6, the built-in INPUT, OUTPUT, and FORWARD filter chains - are wrapped, meaning that the "real" INPUT chain has a rule that jumps to - the wrapped INPUT chain, etc. Additionally, there's a wrapped chain named - "local" which is jumped to from nova-filter-top. - - For ipv4, the built-in PREROUTING, OUTPUT, and POSTROUTING nat chains are - wrapped in the same was as the built-in filter chains. Additionally, - there's a snat chain that is applied after the POSTROUTING chain. - - """ - - def __init__(self, redirect_privsep_calls_to=None): - # NOTE(mikal): This is only used by the xenapi hypervisor driver, - # which wants to intercept our calls to iptables and redirect them - # to an agent running in dom0. - # TODO(mikal): We really should make the dom0 agent feel more like - # privsep. They really are the same thing, just one is from a simpler - # time in our past. - self.redirect_privsep = redirect_privsep_calls_to - - self.ipv4 = {'filter': IptablesTable(), - 'nat': IptablesTable(), - 'mangle': IptablesTable()} - self.ipv6 = {'filter': IptablesTable()} - - self.iptables_apply_deferred = False - - # Add a nova-filter-top chain. It's intended to be shared - # among the various nova components. It sits at the very top - # of FORWARD and OUTPUT. - for tables in [self.ipv4, self.ipv6]: - tables['filter'].add_chain('nova-filter-top', wrap=False) - tables['filter'].add_rule('FORWARD', '-j nova-filter-top', - wrap=False, top=True) - tables['filter'].add_rule('OUTPUT', '-j nova-filter-top', - wrap=False, top=True) - - tables['filter'].add_chain('local') - tables['filter'].add_rule('nova-filter-top', '-j $local', - wrap=False) - - # Wrap the built-in chains - builtin_chains = {4: {'filter': ['INPUT', 'OUTPUT', 'FORWARD'], - 'nat': ['PREROUTING', 'OUTPUT', 'POSTROUTING'], - 'mangle': ['POSTROUTING']}, - 6: {'filter': ['INPUT', 'OUTPUT', 'FORWARD']}} - - for ip_version in builtin_chains: - if ip_version == 4: - tables = self.ipv4 - elif ip_version == 6: - tables = self.ipv6 - - for table, chains in builtin_chains[ip_version].items(): - for chain in chains: - tables[table].add_chain(chain) - tables[table].add_rule(chain, '-j $%s' % (chain,), - wrap=False) - - # Add a nova-postrouting-bottom chain. It's intended to be shared - # among the various nova components. We set it as the last chain - # of POSTROUTING chain. - self.ipv4['nat'].add_chain('nova-postrouting-bottom', wrap=False) - self.ipv4['nat'].add_rule('POSTROUTING', '-j nova-postrouting-bottom', - wrap=False) - - # We add a snat chain to the shared nova-postrouting-bottom chain - # so that it's applied last. - self.ipv4['nat'].add_chain('snat') - self.ipv4['nat'].add_rule('nova-postrouting-bottom', '-j $snat', - wrap=False) - - # And then we add a float-snat chain and jump to first thing in - # the snat chain. - self.ipv4['nat'].add_chain('float-snat') - self.ipv4['nat'].add_rule('snat', '-j $float-snat') - - def defer_apply_on(self): - self.iptables_apply_deferred = True - - def defer_apply_off(self): - self.iptables_apply_deferred = False - self.apply() - - def dirty(self): - for table in six.itervalues(self.ipv4): - if table.dirty: - return True - if CONF.use_ipv6: - for table in six.itervalues(self.ipv6): - if table.dirty: - return True - return False - - def apply(self): - if self.iptables_apply_deferred: - return - if self.dirty(): - self._apply() - else: - LOG.debug("Skipping apply due to lack of new rules") - - @utils.synchronized('iptables', external=True) - def _apply(self): - """Apply the current in-memory set of iptables rules. - - This will blow away any rules left over from previous runs of the - same component of Nova, and replace them with our current set of - rules. This happens atomically, thanks to iptables-restore. - - """ - s = [(True, self.ipv4)] - if CONF.use_ipv6: - s += [(False, self.ipv6)] - - for is_ipv4, tables in s: - if not self.redirect_privsep: - all_tables, _err = nova.privsep.linux_net.iptables_get_rules( - ipv4=is_ipv4) - else: - if is_ipv4: - cmd = 'iptables-save' - else: - cmd = 'ip6tables-save' - all_tables, _err = self.redirect_privsep( - cmd, '-c', run_as_root=True, attempts=5) - - all_lines = all_tables.split('\n') - for table_name, table in tables.items(): - start, end = self._find_table(all_lines, table_name) - all_lines[start:end] = self._modify_rules( - all_lines[start:end], table, table_name) - table.dirty = False - - if not self.redirect_privsep: - nova.privsep.linux_net.iptables_set_rules(all_lines, - ipv4=is_ipv4) - else: - if is_ipv4: - cmd = 'iptables-restore' - else: - cmd = 'ip6tables-restore' - self.redirect_privsep( - cmd, '-c', run_as_root=True, - process_input=six.b('\n'.join(all_lines)), - attempts=5) - - LOG.debug("IPTablesManager.apply completed with success") - - def _find_table(self, lines, table_name): - if len(lines) < 3: - # length only <2 when fake iptables - return (0, 0) - try: - start = lines.index('*%s' % table_name) - 1 - except ValueError: - # Couldn't find table_name - return (0, 0) - end = lines[start:].index('COMMIT') + start + 2 - return (start, end) - - @staticmethod - def create_rules_from_regexp(criterion, new_filter): - if not criterion: - return [], new_filter - regex = re.compile(criterion) - temp_filter = [line for line in new_filter if regex.search(line)] - for rule_str in temp_filter: - new_filter = [s for s in new_filter - if s.strip() != rule_str.strip()] - return temp_filter, new_filter - - def _modify_rules(self, current_lines, table, table_name): - unwrapped_chains = table.unwrapped_chains - chains = sorted(table.chains) - remove_chains = table.remove_chains - rules = table.rules - remove_rules = table.remove_rules - - if not current_lines: - fake_table = ['#Generated by nova', - '*' + table_name, 'COMMIT', - '#Completed by nova'] - current_lines = fake_table - - # Remove any trace of our rules - new_filter = [line for line in current_lines - if binary_name not in line] - - top_rules, new_filter = self.create_rules_from_regexp( - CONF.iptables_top_regex, new_filter) - bottom_rules, new_filter = self.create_rules_from_regexp( - CONF.iptables_bottom_regex, new_filter) - - seen_chains = False - rules_index = 0 - for rules_index, rule in enumerate(new_filter): - if not seen_chains: - if rule.startswith(':'): - seen_chains = True - else: - if not rule.startswith(':'): - break - - if not seen_chains: - rules_index = 2 - - our_rules = top_rules - bot_rules = [] - for rule in rules: - rule_str = str(rule) - if rule.top: - # rule.top == True means we want this rule to be at the top. - # Further down, we weed out duplicates from the bottom of the - # list, so here we remove the dupes ahead of time. - - # We don't want to remove an entry if it has non-zero - # [packet:byte] counts and replace it with [0:0], so let's - # go look for a duplicate, and over-ride our table rule if - # found. - - # ignore [packet:byte] counts at beginning of line - if rule_str.startswith('['): - rule_str = rule_str.split(']', 1)[1] - dup_filter = [s for s in new_filter - if rule_str.strip() in s.strip()] - - new_filter = [s for s in new_filter - if rule_str.strip() not in s.strip()] - # if no duplicates, use original rule - if dup_filter: - # grab the last entry, if there is one - dup = list(dup_filter)[-1] - rule_str = str(dup) - else: - rule_str = str(rule) - rule_str.strip() - - our_rules += [rule_str] - else: - bot_rules += [rule_str] - - our_rules += bot_rules - - new_filter = list(new_filter) - new_filter[rules_index:rules_index] = our_rules - - new_filter[rules_index:rules_index] = [':%s - [0:0]' % (name,) - for name in unwrapped_chains] - new_filter[rules_index:rules_index] = [':%s-%s - [0:0]' % - (binary_name, name,) - for name in chains] - - commit_index = new_filter.index('COMMIT') - new_filter[commit_index:commit_index] = bottom_rules - seen_lines = set() - - def _weed_out_duplicates(line): - # ignore [packet:byte] counts at beginning of lines - if line.startswith('['): - line = line.split(']', 1)[1] - line = line.strip() - if line in seen_lines: - return False - else: - seen_lines.add(line) - return True - - def _weed_out_removes(line): - # We need to find exact matches here - if line.startswith(':'): - # it's a chain, for example, ":nova-billing - [0:0]" - # strip off everything except the chain name - line = line.split(':')[1] - line = line.split('- [')[0] - line = line.strip() - for chain in remove_chains: - if chain == line: - remove_chains.remove(chain) - return False - elif line.startswith('['): - # it's a rule - # ignore [packet:byte] counts at beginning of lines - line = line.split(']', 1)[1] - line = line.strip() - for rule in remove_rules: - # ignore [packet:byte] counts at beginning of rules - rule_str = str(rule) - rule_str = rule_str.split(' ', 1)[1] - rule_str = rule_str.strip() - if rule_str == line: - remove_rules.remove(rule) - return False - - # Leave it alone - return True - - # We filter duplicates, letting the *last* occurrence take - # precedence. We also filter out anything in the "remove" - # lists. - new_filter = list(new_filter) - new_filter.reverse() - new_filter = filter(_weed_out_duplicates, new_filter) - new_filter = filter(_weed_out_removes, new_filter) - new_filter = list(new_filter) - new_filter.reverse() - - # flush lists, just in case we didn't find something - remove_chains.clear() - for rule in remove_rules: - remove_rules.remove(rule) - - return new_filter - - -# NOTE(jkoelker) This is just a nice little stub point since mocking -# builtins with mox is a nightmare -def write_to_file(file, data, mode='w'): - with open(file, mode) as f: - f.write(data) - - -def is_pid_cmdline_correct(pid, match): - """Ensure that the cmdline for a pid seems sane - - Because pids are recycled, blindly killing by pid is something to - avoid. This provides the ability to include a substring that is - expected in the cmdline as a safety check. - """ - try: - with open('/proc/%d/cmdline' % pid) as f: - cmdline = f.read() - return match in cmdline - except EnvironmentError: - return False - - -def metadata_forward(): - """Create forwarding rule for metadata.""" - if CONF.metadata_host != '127.0.0.1': - iptables_manager.ipv4['nat'].add_rule('PREROUTING', - '-s 0.0.0.0/0 -d 169.254.169.254/32 ' - '-p tcp -m tcp --dport 80 -j DNAT ' - '--to-destination %s:%s' % - (CONF.metadata_host, - CONF.metadata_port)) - else: - iptables_manager.ipv4['nat'].add_rule('PREROUTING', - '-s 0.0.0.0/0 -d 169.254.169.254/32 ' - '-p tcp -m tcp --dport 80 ' - '-j REDIRECT --to-ports %s' % - CONF.metadata_port) - iptables_manager.apply() - - -def _iptables_dest(ip): - if ((netaddr.IPAddress(ip).version == 4 and ip == '127.0.0.1') or - ip == '::1'): - return '-m addrtype --dst-type LOCAL' - else: - return '-d %s' % ip - - -def metadata_accept(): - """Create the filter accept rule for metadata.""" - - rule = ('-p tcp -m tcp --dport %s %s -j ACCEPT' % - (CONF.metadata_port, _iptables_dest(CONF.metadata_host))) - - if netaddr.IPAddress(CONF.metadata_host).version == 4: - iptables_manager.ipv4['filter'].add_rule('INPUT', rule) - else: - iptables_manager.ipv6['filter'].add_rule('INPUT', rule) - - iptables_manager.apply() - - -def add_snat_rule(ip_range, is_external=False): - if CONF.routing_source_ip: - if is_external: - if CONF.force_snat_range: - snat_range = CONF.force_snat_range - else: - snat_range = [] - else: - snat_range = ['0.0.0.0/0'] - for dest_range in snat_range: - rule = ('-s %s -d %s -j SNAT --to-source %s' - % (ip_range, dest_range, CONF.routing_source_ip)) - if not is_external and CONF.public_interface: - rule += ' -o %s' % CONF.public_interface - iptables_manager.ipv4['nat'].add_rule('snat', rule) - iptables_manager.apply() - - -def init_host(ip_range, is_external=False): - """Basic networking setup goes here.""" - # NOTE(devcamcar): Cloud public SNAT entries and the default - # SNAT rule for outbound traffic. - - add_snat_rule(ip_range, is_external) - - rules = [] - if is_external: - for snat_range in CONF.force_snat_range: - rules.append('PREROUTING -p ipv4 --ip-src %s --ip-dst %s ' - '-j redirect --redirect-target ACCEPT' % - (ip_range, snat_range)) - if rules: - ensure_ebtables_rules(rules, 'nat') - - iptables_manager.ipv4['nat'].add_rule('POSTROUTING', - '-s %s -d %s/32 -j ACCEPT' % - (ip_range, CONF.metadata_host)) - - for dmz in CONF.dmz_cidr: - iptables_manager.ipv4['nat'].add_rule('POSTROUTING', - '-s %s -d %s -j ACCEPT' % - (ip_range, dmz)) - - iptables_manager.ipv4['nat'].add_rule('POSTROUTING', - '-s %(range)s -d %(range)s ' - '-m conntrack ! --ctstate DNAT ' - '-j ACCEPT' % - {'range': ip_range}) - iptables_manager.apply() - - -def bind_floating_ip(floating_ip, device): - """Bind IP to public interface.""" - nova.privsep.linux_net.bind_ip(device, floating_ip) - if CONF.send_arp_for_ha and CONF.send_arp_for_ha_count > 0: - nova.privsep.linux_net.send_arp_for_ip( - floating_ip, device, CONF.send_arp_for_ha_count) - - -def ensure_metadata_ip(): - """Sets up local metadata IP.""" - nova.privsep.linux_net.bind_ip('lo', '169.254.169.254', - scope_is_link=True) - - -def ensure_vpn_forward(public_ip, port, private_ip): - """Sets up forwarding rules for vlan.""" - iptables_manager.ipv4['filter'].add_rule('FORWARD', - '-d %s -p udp ' - '--dport 1194 ' - '-j ACCEPT' % private_ip) - iptables_manager.ipv4['nat'].add_rule('PREROUTING', - '-d %s -p udp ' - '--dport %s -j DNAT --to %s:1194' % - (public_ip, port, private_ip)) - iptables_manager.ipv4['nat'].add_rule('OUTPUT', - '-d %s -p udp ' - '--dport %s -j DNAT --to %s:1194' % - (public_ip, port, private_ip)) - iptables_manager.apply() - - -def ensure_floating_forward(floating_ip, fixed_ip, device, network): - """Ensure floating IP forwarding rule.""" - # NOTE(vish): Make sure we never have duplicate rules for the same ip - regex = r'.*\s+%s(/32|\s+|$)' % floating_ip - num_rules = iptables_manager.ipv4['nat'].remove_rules_regex(regex) - if num_rules: - LOG.warning('Removed %(num)d duplicate rules for floating IP ' - '%(float)s', {'num': num_rules, 'float': floating_ip}) - for chain, rule in floating_forward_rules(floating_ip, fixed_ip, device): - iptables_manager.ipv4['nat'].add_rule(chain, rule) - iptables_manager.apply() - if device != network['bridge']: - ensure_ebtables_rules(*floating_ebtables_rules(fixed_ip, network)) - - -def remove_floating_forward(floating_ip, fixed_ip, device, network): - """Remove forwarding for floating IP.""" - for chain, rule in floating_forward_rules(floating_ip, fixed_ip, device): - iptables_manager.ipv4['nat'].remove_rule(chain, rule) - iptables_manager.apply() - if device != network['bridge']: - remove_ebtables_rules(*floating_ebtables_rules(fixed_ip, network)) - - -def floating_ebtables_rules(fixed_ip, network): - """Makes sure only in-network traffic is bridged.""" - return (['PREROUTING --logical-in %s -p ipv4 --ip-src %s ' - '! --ip-dst %s -j redirect --redirect-target ACCEPT' % - (network['bridge'], fixed_ip, network['cidr'])], 'nat') - - -def floating_forward_rules(floating_ip, fixed_ip, device): - rules = [] - rule = '-s %s -j SNAT --to %s' % (fixed_ip, floating_ip) - if device: - rules.append(('float-snat', rule + ' -d %s' % fixed_ip)) - rules.append(('float-snat', rule + ' -o %s' % device)) - else: - rules.append(('float-snat', rule)) - rules.append( - ('PREROUTING', '-d %s -j DNAT --to %s' % (floating_ip, fixed_ip))) - rules.append( - ('OUTPUT', '-d %s -j DNAT --to %s' % (floating_ip, fixed_ip))) - rules.append(('POSTROUTING', '-s %s -m conntrack --ctstate DNAT -j SNAT ' - '--to-source %s' % - (fixed_ip, floating_ip))) - return rules - - -@utils.synchronized('lock_gateway', external=True) -def initialize_gateway_device(dev, network_ref): - if not network_ref: - return - - nova.privsep.linux_net.enable_ipv4_forwarding() - - # NOTE(vish): The ip for dnsmasq has to be the first address on the - # bridge for it to respond to requests properly - try: - prefix = network_ref.cidr.prefixlen - except AttributeError: - prefix = network_ref['cidr'].rpartition('/')[2] - - full_ip = '%s/%s' % (network_ref['dhcp_server'], prefix) - new_ip_params = [[full_ip, 'brd', network_ref['broadcast']]] - old_ip_params = [] - out, err = nova.privsep.linux_net.lookup_ip(dev) - for line in out.split('\n'): - fields = line.split() - if fields and fields[0] == 'inet': - if fields[-2] in ('secondary', 'dynamic'): - ip_params = fields[1:-2] - else: - ip_params = fields[1:-1] - old_ip_params.append(ip_params) - if ip_params[0] != full_ip: - new_ip_params.append(ip_params) - if not old_ip_params or old_ip_params[0][0] != full_ip: - old_routes = [] - result = nova.privsep.linux_net.routes_show(dev) - if result: - out, err = result - for line in out.split('\n'): - fields = line.split() - if fields and 'via' in fields: - old_routes.append(fields) - nova.privsep.linux_net.route_delete(dev, fields[0]) - for ip_params in old_ip_params: - nova.privsep.linux_net.address_command_deprecated( - dev, 'del', ip_params) - for ip_params in new_ip_params: - nova.privsep.linux_net.address_command_deprecated( - dev, 'add', ip_params) - - for fields in old_routes: - # TODO(mikal): this is horrible and should be re-written - nova.privsep.linux_net.route_add_deprecated(fields) - if CONF.send_arp_for_ha and CONF.send_arp_for_ha_count > 0: - nova.privsep.linux_net.send_arp_for_ip( - network_ref['dhcp_server'], dev, - CONF.send_arp_for_ha_count) - if CONF.use_ipv6: - nova.privsep.linux_net.change_ip(dev, network_ref['cidr_v6']) - - -def get_dhcp_leases(context, network_ref): - """Return a network's hosts config in dnsmasq leasefile format.""" - hosts = [] - host = None - if network_ref['multi_host']: - host = CONF.host - for fixedip in objects.FixedIPList.get_by_network(context, - network_ref, - host=host): - # NOTE(cfb): Don't return a lease entry if the IP isn't - # already leased - if fixedip.leased: - hosts.append(_host_lease(fixedip)) - - return '\n'.join(hosts) - - -def get_dhcp_hosts(context, network_ref, fixedips): - """Get network's hosts config in dhcp-host format.""" - hosts = [] - macs = set() - for fixedip in fixedips: - if fixedip.allocated: - if fixedip.virtual_interface.address not in macs: - hosts.append(_host_dhcp(fixedip)) - macs.add(fixedip.virtual_interface.address) - return '\n'.join(hosts) - - -def get_dns_hosts(context, network_ref): - """Get network's DNS hosts in hosts format.""" - hosts = [] - for fixedip in objects.FixedIPList.get_by_network(context, network_ref): - if fixedip.allocated: - hosts.append(_host_dns(fixedip)) - return '\n'.join(hosts) - - -def _add_dnsmasq_accept_rules(dev): - """Allow DHCP and DNS traffic through to dnsmasq.""" - table = iptables_manager.ipv4['filter'] - for port in [67, 53]: - for proto in ['udp', 'tcp']: - args = {'dev': dev, 'port': port, 'proto': proto} - table.add_rule('INPUT', - '-i %(dev)s -p %(proto)s -m %(proto)s ' - '--dport %(port)s -j ACCEPT' % args) - iptables_manager.apply() - - -def _remove_dnsmasq_accept_rules(dev): - """Remove DHCP and DNS traffic allowed through to dnsmasq.""" - table = iptables_manager.ipv4['filter'] - for port in [67, 53]: - for proto in ['udp', 'tcp']: - args = {'dev': dev, 'port': port, 'proto': proto} - table.remove_rule('INPUT', - '-i %(dev)s -p %(proto)s -m %(proto)s ' - '--dport %(port)s -j ACCEPT' % args) - iptables_manager.apply() - - -# NOTE(russellb) Curious why this is needed? Check out this explanation from -# markmc: https://bugzilla.redhat.com/show_bug.cgi?id=910619#c6 -def _add_dhcp_mangle_rule(dev): - table = iptables_manager.ipv4['mangle'] - table.add_rule('POSTROUTING', - '-o %s -p udp -m udp --dport 68 -j CHECKSUM ' - '--checksum-fill' % dev) - iptables_manager.apply() - - -def _remove_dhcp_mangle_rule(dev): - table = iptables_manager.ipv4['mangle'] - table.remove_rule('POSTROUTING', - '-o %s -p udp -m udp --dport 68 -j CHECKSUM ' - '--checksum-fill' % dev) - iptables_manager.apply() - - -def get_dhcp_opts(context, network_ref, fixedips): - """Get network's hosts config in dhcp-opts format.""" - gateway = network_ref['gateway'] - # NOTE(vish): if we are in multi-host mode and we are not sharing - # addresses, then we actually need to hand out the - # dhcp server address as the gateway. - if network_ref['multi_host'] and not (network_ref['share_address'] or - CONF.share_dhcp_address): - gateway = network_ref['dhcp_server'] - hosts = [] - if CONF.use_single_default_gateway: - for fixedip in fixedips: - if fixedip.allocated: - vif_id = fixedip.virtual_interface_id - if fixedip.default_route: - hosts.append(_host_dhcp_opts(vif_id, gateway)) - else: - hosts.append(_host_dhcp_opts(vif_id)) - else: - hosts.append(_host_dhcp_opts(None, gateway)) - return '\n'.join(hosts) - - -def release_dhcp(dev, address, mac_address): - if nova.privsep.linux_net.device_exists(dev): - try: - nova.privsep.linux_net.dhcp_release(dev, address, mac_address) - except processutils.ProcessExecutionError: - raise exception.NetworkDhcpReleaseFailed(address=address, - mac_address=mac_address) - - -def update_dhcp(context, dev, network_ref): - conffile = _dhcp_file(dev, 'conf') - host = None - if network_ref['multi_host']: - host = CONF.host - fixedips = objects.FixedIPList.get_by_network(context, - network_ref, - host=host) - write_to_file(conffile, get_dhcp_hosts(context, network_ref, fixedips)) - restart_dhcp(context, dev, network_ref, fixedips) - - -def update_dns(context, dev, network_ref): - hostsfile = _dhcp_file(dev, 'hosts') - host = None - if network_ref['multi_host']: - host = CONF.host - fixedips = objects.FixedIPList.get_by_network(context, - network_ref, - host=host) - write_to_file(hostsfile, get_dns_hosts(context, network_ref)) - restart_dhcp(context, dev, network_ref, fixedips) - - -def kill_dhcp(dev): - pid = _dnsmasq_pid_for(dev) - if pid: - # Check that the process exists and looks like a dnsmasq process - conffile = _dhcp_file(dev, 'conf') - if is_pid_cmdline_correct(pid, conffile.split('/')[-1]): - nova.privsep.utils.kill(pid, signal.SIGKILL) - else: - LOG.debug('Pid %d is stale, skip killing dnsmasq', pid) - _remove_dnsmasq_accept_rules(dev) - _remove_dhcp_mangle_rule(dev) - - -# NOTE(ja): Sending a HUP only reloads the hostfile, so any -# configuration options (like dchp-range, vlan, ...) -# aren't reloaded. -@utils.synchronized('dnsmasq_start') -def restart_dhcp(context, dev, network_ref, fixedips): - """(Re)starts a dnsmasq server for a given network. - - If a dnsmasq instance is already running then send a HUP - signal causing it to reload, otherwise spawn a new instance. - - """ - conffile = _dhcp_file(dev, 'conf') - - optsfile = _dhcp_file(dev, 'opts') - write_to_file(optsfile, get_dhcp_opts(context, network_ref, fixedips)) - os.chmod(optsfile, 0o644) - - _add_dhcp_mangle_rule(dev) - - # Make sure dnsmasq can actually read it (it setuid()s to "nobody") - os.chmod(conffile, 0o644) - - pid = _dnsmasq_pid_for(dev) - - # if dnsmasq is already running, then tell it to reload - if pid: - if is_pid_cmdline_correct(pid, conffile.split('/')[-1]): - try: - nova.privsep.utils.kill(pid, signal.SIGHUP) - _add_dnsmasq_accept_rules(dev) - return - except Exception as exc: - LOG.error('kill -HUP dnsmasq threw %s', exc) - else: - LOG.debug('Pid %d is stale, relaunching dnsmasq', pid) - - dns_servers = CONF.dns_server - if CONF.use_network_dns_servers: - if network_ref.get('dns1'): - dns_servers.append(network_ref.get('dns1')) - if network_ref.get('dns2'): - dns_servers.append(network_ref.get('dns2')) - - hosts_path = None - if network_ref['multi_host']: - hosts_path = _dhcp_file(dev, 'hosts') - - nova.privsep.linux_net.restart_dnsmasq( - jsonutils.dumps(CONF.dhcpbridge_flagfile), - network_ref, - CONF.dnsmasq_config_file, - _dhcp_file(dev, 'pid'), - _dhcp_file(dev, 'opts'), - CONF.dhcp_lease_time, - len(netaddr.IPNetwork(network_ref['cidr'])), - _dhcp_file(dev, 'conf'), - CONF.dhcpbridge, - CONF.api.dhcp_domain, - dns_servers, - hosts_path) - - _add_dnsmasq_accept_rules(dev) - - -@utils.synchronized('radvd_start') -def update_ra(context, dev, network_ref): - conffile = _ra_file(dev, 'conf') - conf_str = """ -interface %s -{ - AdvSendAdvert on; - MinRtrAdvInterval 3; - MaxRtrAdvInterval 10; - prefix %s - { - AdvOnLink on; - AdvAutonomous on; - }; -}; -""" % (dev, network_ref['cidr_v6']) - write_to_file(conffile, conf_str) - - # Make sure radvd can actually read it (it setuid()s to "nobody") - os.chmod(conffile, 0o644) - - pid = _ra_pid_for(dev) - - # if radvd is already running, then tell it to reload - if pid: - if is_pid_cmdline_correct(pid, conffile): - try: - nova.privsep.utils.kill(pid, signal.SIGTERM) - except Exception as exc: - LOG.error('killing radvd threw %s', exc) - else: - LOG.debug('Pid %d is stale, relaunching radvd', pid) - - nova.privsep.linux_net.start_ra(_ra_file(dev, 'conf'), - _ra_file(dev, 'pid')) - - -def _host_lease(fixedip): - """Return a host string for an address in leasefile format.""" - timestamp = timeutils.utcnow() - seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) - return '%d %s %s %s *' % (seconds_since_epoch + CONF.dhcp_lease_time, - fixedip.virtual_interface.address, - fixedip.address, - fixedip.instance.hostname or '*') - - -def _host_dhcp_network(vif_id): - return 'NW-%s' % vif_id - - -def _host_dhcp(fixedip): - """Return a host string for an address in dhcp-host format.""" - # NOTE(cfb): dnsmasq on linux only supports 64 characters in the hostname - # field (LP #1238910). Since the . counts as a character we need - # to truncate the hostname to only 63 characters. - hostname = fixedip.instance.hostname - if len(hostname) > 63: - LOG.warning('hostname %s too long, truncating.', hostname) - hostname = fixedip.instance.hostname[:2] + '-' +\ - fixedip.instance.hostname[-60:] - if CONF.use_single_default_gateway: - net = _host_dhcp_network(fixedip.virtual_interface_id) - return '%s,%s.%s,%s,net:%s' % (fixedip.virtual_interface.address, - hostname, - CONF.api.dhcp_domain, - fixedip.address, - net) - else: - return '%s,%s.%s,%s' % (fixedip.virtual_interface.address, - hostname, - CONF.api.dhcp_domain, - fixedip.address) - - -def _host_dns(fixedip): - return '%s\t%s.%s' % (fixedip.address, - fixedip.instance.hostname, - CONF.api.dhcp_domain) - - -def _host_dhcp_opts(vif_id=None, gateway=None): - """Return an empty gateway option.""" - values = [] - if vif_id is not None: - values.append(_host_dhcp_network(vif_id)) - # NOTE(vish): 3 is the dhcp option for gateway. - values.append('3') - if gateway: - values.append('%s' % gateway) - return ','.join(values) - - -def _dhcp_file(dev, kind): - """Return path to a pid, leases, hosts or conf file for a bridge/device.""" - fileutils.ensure_tree(CONF.networks_path) - return os.path.abspath('%s/nova-%s.%s' % (CONF.networks_path, - dev, - kind)) - - -def _ra_file(dev, kind): - """Return path to a pid or conf file for a bridge/device.""" - fileutils.ensure_tree(CONF.networks_path) - return os.path.abspath('%s/nova-ra-%s.%s' % (CONF.networks_path, - dev, - kind)) - - -def _dnsmasq_pid_for(dev): - """Returns the pid for prior dnsmasq instance for a bridge/device. - - Returns None if no pid file exists. - - If machine has rebooted pid might be incorrect (caller should check). - - """ - pid_file = _dhcp_file(dev, 'pid') - - if os.path.exists(pid_file): - try: - with open(pid_file, 'r') as f: - return int(f.read()) - except (ValueError, IOError): - return None - - -def _ra_pid_for(dev): - """Returns the pid for prior radvd instance for a bridge/device. - - Returns None if no pid file exists. - - If machine has rebooted pid might be incorrect (caller should check). - - """ - pid_file = _ra_file(dev, 'pid') - - if os.path.exists(pid_file): - with open(pid_file, 'r') as f: - return int(f.read()) - - -def delete_bridge_dev(dev): - """Delete a network bridge.""" - if nova.privsep.linux_net.device_exists(dev): - try: - nova.privsep.linux_net.set_device_disabled(dev) - nova.privsep.linux_net.delete_bridge(dev) - except processutils.ProcessExecutionError: - with excutils.save_and_reraise_exception(): - LOG.error("Failed removing bridge device: '%s'", dev) - - -# Similar to compute virt layers, the Linux network node -# code uses a flexible driver model to support different ways -# of creating ethernet interfaces and attaching them to the network. -# In the case of a network host, these interfaces -# act as gateway/dhcp/vpn/etc. endpoints not VM interfaces. -interface_driver = None - - -def _get_interface_driver(): - global interface_driver - if not interface_driver: - interface_driver = importutils.import_object( - CONF.linuxnet_interface_driver) - return interface_driver - - -def plug(network, mac_address, gateway=True): - return _get_interface_driver().plug(network, mac_address, gateway) - - -def unplug(network): - return _get_interface_driver().unplug(network) - - -def get_dev(network): - return _get_interface_driver().get_dev(network) - - -class LinuxNetInterfaceDriver(object): - """Abstract class that defines generic network host API - for all Linux interface drivers. - """ - - def plug(self, network, mac_address): - """Create Linux device, return device name.""" - raise NotImplementedError() - - def unplug(self, network): - """Destroy Linux device, return device name.""" - raise NotImplementedError() - - def get_dev(self, network): - """Get device name.""" - raise NotImplementedError() - - -# plugs interfaces using Linux Bridge -class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver): - - def plug(self, network, mac_address, gateway=True): - vlan = network.get('vlan') - if vlan is not None: - iface = CONF.vlan_interface or network['bridge_interface'] - LinuxBridgeInterfaceDriver.ensure_vlan_bridge( - vlan, - network['bridge'], - iface, - network, - mac_address, - network.get('mtu')) - iface = 'vlan%s' % vlan - else: - iface = CONF.flat_interface or network['bridge_interface'] - LinuxBridgeInterfaceDriver.ensure_bridge( - network['bridge'], - iface, - network, gateway) - - if network['share_address'] or CONF.share_dhcp_address: - isolate_dhcp_address(iface, network['dhcp_server']) - # NOTE(vish): applying here so we don't get a lock conflict - iptables_manager.apply() - return network['bridge'] - - def unplug(self, network, gateway=True): - vlan = network.get('vlan') - if vlan is not None: - iface = 'vlan%s' % vlan - LinuxBridgeInterfaceDriver.remove_vlan_bridge(vlan, - network['bridge']) - else: - iface = CONF.flat_interface or network['bridge_interface'] - LinuxBridgeInterfaceDriver.remove_bridge(network['bridge'], - gateway) - - if network['share_address'] or CONF.share_dhcp_address: - remove_isolate_dhcp_address(iface, network['dhcp_server']) - - iptables_manager.apply() - return self.get_dev(network) - - def get_dev(self, network): - return network['bridge'] - - @staticmethod - def ensure_vlan_bridge(vlan_num, bridge, bridge_interface, - net_attrs=None, mac_address=None, - mtu=None): - """Create a vlan and bridge unless they already exist.""" - interface = LinuxBridgeInterfaceDriver.ensure_vlan(vlan_num, - bridge_interface, mac_address, - mtu) - LinuxBridgeInterfaceDriver.ensure_bridge(bridge, interface, net_attrs) - return interface - - @staticmethod - def remove_vlan_bridge(vlan_num, bridge): - """Delete a bridge and vlan.""" - LinuxBridgeInterfaceDriver.remove_bridge(bridge) - LinuxBridgeInterfaceDriver.remove_vlan(vlan_num) - - @staticmethod - @utils.synchronized('lock_vlan', external=True) - def ensure_vlan(vlan_num, bridge_interface, mac_address=None, mtu=None, - interface=None): - """Create a vlan unless it already exists.""" - if interface is None: - interface = 'vlan%s' % vlan_num - if not nova.privsep.linux_net.device_exists(interface): - LOG.debug('Starting VLAN interface %s', interface) - nova.privsep.linux_net.add_vlan(bridge_interface, interface, - vlan_num) - # (danwent) the bridge will inherit this address, so we want to - # make sure it is the value set from the NetworkManager - if mac_address: - nova.privsep.linux_net.set_device_macaddr( - interface, mac_address) - nova.privsep.linux_net.set_device_enabled(interface) - # NOTE(vish): set mtu every time to ensure that changes to mtu get - # propagated - nova.privsep.linux_net.set_device_mtu(interface, mtu) - return interface - - @staticmethod - @utils.synchronized('lock_vlan', external=True) - def remove_vlan(vlan_num): - """Delete a vlan.""" - vlan_interface = 'vlan%s' % vlan_num - nova.privsep.linux_net.delete_net_dev(vlan_interface) - - @staticmethod - @utils.synchronized('lock_bridge', external=True) - def ensure_bridge(bridge, interface, net_attrs=None, gateway=True, - filtering=True): - """Create a bridge unless it already exists. - - :param interface: the interface to create the bridge on. - :param net_attrs: dictionary with attributes used to create bridge. - :param gateway: whether or not the bridge is a gateway. - :param filtering: whether or not to create filters on the bridge. - - If net_attrs is set, it will add the net_attrs['gateway'] to the bridge - using net_attrs['broadcast'] and net_attrs['cidr']. It will also add - the ip_v6 address specified in net_attrs['cidr_v6'] if use_ipv6 is set. - - The code will attempt to move any IPs that already exist on the - interface onto the bridge and reset the default gateway if necessary. - - """ - if not nova.privsep.linux_net.device_exists(bridge): - LOG.debug('Starting Bridge %s', bridge) - out, err = nova.privsep.linux_net.add_bridge(bridge) - if (err and err != "device %s already exists; can't create " - "bridge with the same name\n" % (bridge)): - msg = _('Failed to add bridge: %s') % err - raise exception.NovaException(msg) - - nova.privsep.linux_net.bridge_setfd(bridge) - nova.privsep.linux_net.bridge_disable_stp(bridge) - nova.privsep.linux_net.set_device_enabled(bridge) - - if interface: - LOG.debug('Adding interface %(interface)s to bridge %(bridge)s', - {'interface': interface, 'bridge': bridge}) - out, err = nova.privsep.linux_net.bridge_add_interface( - bridge, interface) - if (err and err != "device %s is already a member of a bridge; " - "can't enslave it to bridge %s.\n" % (interface, bridge)): - msg = _('Failed to add interface: %s') % err - raise exception.NovaException(msg) - - # NOTE(apmelton): Linux bridge's default behavior is to use the - # lowest mac of all plugged interfaces. This isn't a problem when - # it is first created and the only interface is the bridged - # interface. But, as instance interfaces are plugged, there is a - # chance for the mac to change. So, set it here so that it won't - # change in the future. - if not CONF.fake_network: - interface_addrs = netifaces.ifaddresses(interface) - interface_mac = interface_addrs[netifaces.AF_LINK][0]['addr'] - nova.privsep.linux_net.set_device_macaddr( - bridge, interface_mac) - - nova.privsep.linux_net.set_device_enabled(interface) - - # NOTE(vish): This will break if there is already an ip on the - # interface, so we move any ips to the bridge - # NOTE(danms): We also need to copy routes to the bridge so as - # not to break existing connectivity on the interface - old_routes = [] - out, err = nova.privsep.linux_net.routes_show(interface) - for line in out.split('\n'): - fields = line.split() - if fields and 'via' in fields: - old_routes.append(fields) - nova.privsep.linux_net.route_delete_deprecated(fields) - out, err = nova.privsep.linux_net.lookup_ip(interface) - for line in out.split('\n'): - fields = line.split() - if fields and fields[0] == 'inet': - if fields[-2] in ('secondary', 'dynamic', ): - params = fields[1:-2] - else: - params = fields[1:-1] - nova.privsep.linux_net.address_command_deprecated( - fields[-1], 'del', params) - nova.privsep.linux_net.address_command_deprecated( - bridge, 'add', params) - for fields in old_routes: - nova.privsep.linux_net.route_add_deprecated(fields) - - if filtering: - # Don't forward traffic unless we were told to be a gateway - ipv4_filter = iptables_manager.ipv4['filter'] - if gateway: - for rule in get_gateway_rules(bridge): - ipv4_filter.add_rule(*rule) - else: - ipv4_filter.add_rule('FORWARD', - ('--in-interface %s -j %s' - % (bridge, CONF.iptables_drop_action))) - ipv4_filter.add_rule('FORWARD', - ('--out-interface %s -j %s' - % (bridge, CONF.iptables_drop_action))) - - @staticmethod - @utils.synchronized('lock_bridge', external=True) - def remove_bridge(bridge, gateway=True, filtering=True): - """Delete a bridge.""" - if not nova.privsep.linux_net.device_exists(bridge): - return - else: - if filtering: - ipv4_filter = iptables_manager.ipv4['filter'] - if gateway: - for rule in get_gateway_rules(bridge): - ipv4_filter.remove_rule(*rule) - else: - drop_actions = ['DROP'] - if CONF.iptables_drop_action != 'DROP': - drop_actions.append(CONF.iptables_drop_action) - - for drop_action in drop_actions: - ipv4_filter.remove_rule('FORWARD', - ('--in-interface %s -j %s' - % (bridge, drop_action))) - ipv4_filter.remove_rule('FORWARD', - ('--out-interface %s -j %s' - % (bridge, drop_action))) - delete_bridge_dev(bridge) - - -# NOTE(cfb): Fix for LP #1316621, #1501366. -# We call ebtables with --concurrent which causes ebtables to -# use a lock file to deal with concurrent calls. Since we can't -# be sure the libvirt also uses --concurrent we retry in a loop -# to be sure. -# -# ebtables doesn't implement a timeout and doesn't gracefully -# handle cleaning up a lock file if someone sends a SIGKILL to -# ebtables while its holding a lock. As a result we want to add -# a timeout to the ebtables calls but we first need to teach -# oslo_concurrency how to do that. -def _exec_ebtables(table, rule, insert_rule=True, check_exit_code=True): - # List of error strings to re-try. - retry_strings = ( - 'Multiple ebtables programs', - ) - - # We always try at least once - attempts = CONF.ebtables_exec_attempts - count = 1 - while count <= attempts: - # Updated our counters if needed - sleep = CONF.ebtables_retry_interval * count - count += 1 - # NOTE(cfb): ebtables reports all errors with a return code of 255. - # As such we can't know if we hit a locking error, or some - # other error (like a rule doesn't exist) so we have to - # to parse stderr. - try: - nova.privsep.linux_net.modify_ebtables(table, rule, - insert_rule=insert_rule) - except processutils.ProcessExecutionError as exc: - # See if we can retry the error. - if any(error in exc.stderr for error in retry_strings): - if count > attempts and check_exit_code: - LOG.warning('Rule edit for %s failed. Not Retrying.', - table) - raise - else: - # We need to sleep a bit before retrying - LOG.warning('Rule edit for %(table)s failed. ' - 'Sleeping %(time)s seconds before retry.', - {'table': table, 'time': sleep}) - time.sleep(sleep) - else: - # Not eligible for retry - if check_exit_code: - LOG.warning('Rule edit for %s failed and not eligible ' - 'for retry.', - table) - raise - else: - return - else: - # Success - return - - -@utils.synchronized('ebtables', external=True) -def ensure_ebtables_rules(rules, table='filter'): - for rule in rules: - _exec_ebtables(table, rule.split(), insert_rule=False, - check_exit_code=False) - _exec_ebtables(table, rule.split()) - - -@utils.synchronized('ebtables', external=True) -def remove_ebtables_rules(rules, table='filter'): - for rule in rules: - _exec_ebtables(table, rule.split(), insert_rule=False, - check_exit_code=False) - - -def isolate_dhcp_address(interface, address): - # block arp traffic to address across the interface - rules = [] - rules.append('INPUT -p ARP -i %s --arp-ip-dst %s -j DROP' - % (interface, address)) - rules.append('OUTPUT -p ARP -o %s --arp-ip-src %s -j DROP' - % (interface, address)) - rules.append('FORWARD -p IPv4 -i %s --ip-protocol udp ' - '--ip-destination-port 67:68 -j DROP' - % interface) - rules.append('FORWARD -p IPv4 -o %s --ip-protocol udp ' - '--ip-destination-port 67:68 -j DROP' - % interface) - # NOTE(vish): the above is not possible with iptables/arptables - ensure_ebtables_rules(rules) - - -def remove_isolate_dhcp_address(interface, address): - # block arp traffic to address across the interface - rules = [] - rules.append('INPUT -p ARP -i %s --arp-ip-dst %s -j DROP' - % (interface, address)) - rules.append('OUTPUT -p ARP -o %s --arp-ip-src %s -j DROP' - % (interface, address)) - rules.append('FORWARD -p IPv4 -i %s --ip-protocol udp ' - '--ip-destination-port 67:68 -j DROP' - % interface) - rules.append('FORWARD -p IPv4 -o %s --ip-protocol udp ' - '--ip-destination-port 67:68 -j DROP' - % interface) - remove_ebtables_rules(rules) - # NOTE(vish): the above is not possible with iptables/arptables - - -def get_gateway_rules(bridge): - interfaces = CONF.forward_bridge_interface - if 'all' in interfaces: - return [('FORWARD', '-i %s -j ACCEPT' % bridge), - ('FORWARD', '-o %s -j ACCEPT' % bridge)] - rules = [] - for iface in CONF.forward_bridge_interface: - if iface: - rules.append(('FORWARD', '-i %s -o %s -j ACCEPT' % (bridge, - iface))) - rules.append(('FORWARD', '-i %s -o %s -j ACCEPT' % (iface, - bridge))) - rules.append(('FORWARD', '-i %s -o %s -j ACCEPT' % (bridge, bridge))) - rules.append(('FORWARD', '-i %s -j %s' % (bridge, - CONF.iptables_drop_action))) - rules.append(('FORWARD', '-o %s -j %s' % (bridge, - CONF.iptables_drop_action))) - return rules - - -# plugs interfaces using Open vSwitch -class LinuxOVSInterfaceDriver(LinuxNetInterfaceDriver): - - def plug(self, network, mac_address, gateway=True): - dev = self.get_dev(network) - if not nova.privsep.linux_net.device_exists(dev): - bridge = CONF.linuxnet_ovs_integration_bridge - - nova.privsep.linux_net.ovs_plug(CONF.ovs_vsctl_timeout, - bridge, dev, mac_address) - nova.privsep.linux_net.set_device_macaddr( - dev, mac_address) - nova.privsep.linux_net.set_device_mtu(dev, network.get('mtu')) - nova.privsep.linux_net.set_device_enabled(dev) - if not gateway: - # If we weren't instructed to act as a gateway then add the - # appropriate flows to block all non-dhcp traffic. - nova.privsep.linux_net.ovs_drop_nondhcp( - bridge, mac_address) - - # .. and make sure iptbles won't forward it as well. - iptables_manager.ipv4['filter'].add_rule('FORWARD', - '--in-interface %s -j %s' % (bridge, - CONF.iptables_drop_action)) - iptables_manager.ipv4['filter'].add_rule('FORWARD', - '--out-interface %s -j %s' % (bridge, - CONF.iptables_drop_action)) - else: - for rule in get_gateway_rules(bridge): - iptables_manager.ipv4['filter'].add_rule(*rule) - - return dev - - def unplug(self, network): - dev = self.get_dev(network) - bridge = CONF.linuxnet_ovs_integration_bridge - - nova.privsep.linux_net.ovs_unplug(CONF.ovs_vsctl_timeout, bridge, dev) - - return dev - - def get_dev(self, network): - dev = 'gw-' + str(network['uuid'][0:11]) - return dev - - -iptables_manager = IptablesManager() - - -def set_vf_trusted(pci_addr, trusted): - """Configures the VF to be trusted or not - - :param pci_addr: PCI slot of the device - :param trusted: Boolean value to indicate whether to - enable/disable 'trusted' capability - """ - pf_ifname = pci_utils.get_ifname_by_pci_address(pci_addr, - pf_interface=True) - vf_num = pci_utils.get_vf_num_by_pci_address(pci_addr) - nova.privsep.linux_net.set_device_trust( - pf_ifname, vf_num, trusted) diff --git a/nova/network/manager.py b/nova/network/manager.py deleted file mode 100644 index 9b995f0eefa2..000000000000 --- a/nova/network/manager.py +++ /dev/null @@ -1,2165 +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. -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Network Hosts are responsible for allocating IPs and setting up network. - -There are multiple backend drivers that handle specific types of networking -topologies. All of the network commands are issued to a subclass of -:class:`NetworkManager`. - -""" - -import collections -import datetime -import functools -import math -import re - -import netaddr -from oslo_concurrency import processutils -from oslo_log import log as logging -import oslo_messaging as messaging -from oslo_service import periodic_task -from oslo_utils import excutils -from oslo_utils import importutils -from oslo_utils import netutils -from oslo_utils import strutils -from oslo_utils import timeutils -from oslo_utils import uuidutils -import six - -import nova.conf -from nova import context -from nova import exception -from nova.i18n import _ -from nova import ipv6 -from nova import manager -from nova.network import api as network_api -from nova.network import driver -from nova.network import floating_ips -from nova.network import model as network_model -from nova.network import rpcapi as network_rpcapi -from nova.network.security_group import openstack_driver -from nova import objects -from nova.objects import base as obj_base -from nova.objects import quotas as quotas_obj -from nova import servicegroup -from nova import utils - -LOG = logging.getLogger(__name__) - -CONF = nova.conf.CONF - - -def get_my_linklocal(interface): - try: - if_str = processutils.execute( - 'ip', '-f', 'inet6', '-o', 'addr', 'show', interface) - condition = r'\s+inet6\s+([0-9a-f:]+)/\d+\s+scope\s+link' - links = [re.search(condition, x) for x in if_str[0].split('\n')] - address = [w.group(1) for w in links if w is not None] - if address[0] is not None: - return address[0] - else: - msg = _('Link Local address is not found.:%s') % if_str - raise exception.NovaException(msg) - except Exception as ex: - msg = _("Couldn't get Link Local IP of %(interface)s" - " :%(ex)s") % {'interface': interface, 'ex': ex} - raise exception.NovaException(msg) - - -class RPCAllocateFixedIP(object): - """Mixin class originally for FlatDCHP and VLAN network managers. - - used since they share code to RPC.call allocate_fixed_ip on the - correct network host to configure dnsmasq - """ - - servicegroup_api = None - - def _allocate_fixed_ips(self, context, instance_id, host, networks, - **kwargs): - """Calls allocate_fixed_ip once for each network.""" - green_threads = [] - - vpn = kwargs.get('vpn') - requested_networks = kwargs.get('requested_networks') - addresses_by_network = {} - if requested_networks is not None: - for request in requested_networks: - addresses_by_network[request.network_id] = request.address - - for network in networks: - if 'uuid' in network and network['uuid'] in addresses_by_network: - address = addresses_by_network[network['uuid']] - else: - address = None - # NOTE(vish): if we are not multi_host pass to the network host - # NOTE(tr3buchet): but if we are, host came from instance.host - if not network['multi_host']: - host = network['host'] - # NOTE(vish): if there is no network host, set one - if host is None: - host = self.network_rpcapi.set_network_host(context, - network) - if host != self.host: - # need to call allocate_fixed_ip to correct network host - green_threads.append(utils.spawn( - self.network_rpcapi._rpc_allocate_fixed_ip, - context, instance_id, network['id'], address, vpn, - host)) - else: - # i am the correct host, run here - self.allocate_fixed_ip(context, instance_id, network, - vpn=vpn, address=address) - - # wait for all of the allocates (if any) to finish - for gt in green_threads: - gt.wait() - - def _rpc_allocate_fixed_ip(self, context, instance_id, network_id, - **kwargs): - """Sits in between _allocate_fixed_ips and allocate_fixed_ip to - perform network lookup on the far side of rpc. - """ - network = self._get_network_by_id(context, network_id) - return self.allocate_fixed_ip(context, instance_id, network, **kwargs) - - def deallocate_fixed_ip(self, context, address, host=None, teardown=True, - instance=None): - """Call the superclass deallocate_fixed_ip if i'm the correct host - otherwise call to the correct host - """ - fixed_ip = objects.FixedIP.get_by_address( - context, address, expected_attrs=['network']) - network = fixed_ip.network - - # NOTE(vish): if we are not multi_host pass to the network host - # NOTE(tr3buchet): but if we are, host came from instance.host - if not network.multi_host: - host = network.host - if host == self.host: - # NOTE(vish): deallocate the fixed ip locally - return super(RPCAllocateFixedIP, self).deallocate_fixed_ip(context, - address, instance=instance) - - if network.multi_host: - service = objects.Service.get_by_host_and_binary( - context, host, 'nova-network') - if not service or not self.servicegroup_api.service_is_up(service): - # NOTE(vish): deallocate the fixed ip locally but don't - # teardown network devices - return super(RPCAllocateFixedIP, self).deallocate_fixed_ip( - context, address, teardown=False, instance=instance) - - self.network_rpcapi.deallocate_fixed_ip(context, address, host, - instance) - - -class NetworkManager(manager.Manager): - """Implements common network manager functionality. - - This class must be subclassed to support specific topologies. - - host management: - hosts configure themselves for networks they are assigned to in the - table upon startup. If there are networks in the table which do not - have hosts, those will be filled in and have hosts configured - as the hosts pick them up one at time during their periodic task. - The one at a time part is to flatten the layout to help scale - """ - - target = messaging.Target(version='1.17') - - # If True, this manager requires VIF to create a bridge. - SHOULD_CREATE_BRIDGE = False - - # If True, this manager requires VIF to create VLAN tag. - SHOULD_CREATE_VLAN = False - - # if True, this manager leverages DHCP - DHCP = False - - timeout_fixed_ips = True - - required_create_args = [] - - def __init__(self, network_driver=None, *args, **kwargs): - self.driver = driver.load_network_driver(network_driver) - self.instance_dns_manager = importutils.import_object( - CONF.instance_dns_manager) - self.instance_dns_domain = CONF.instance_dns_domain - self.floating_dns_manager = importutils.import_object( - CONF.floating_ip_dns_manager) - self.network_api = network_api.API() - self.network_rpcapi = network_rpcapi.NetworkAPI() - self.security_group_api = ( - openstack_driver.get_openstack_security_group_driver()) - - self.servicegroup_api = servicegroup.API() - - l3_lib = kwargs.get("l3_lib", CONF.l3_lib) - self.l3driver = importutils.import_object(l3_lib) - - self.quotas_cls = objects.Quotas - - super(NetworkManager, self).__init__(service_name='network', - *args, **kwargs) - - @staticmethod - def _uses_shared_ip(network): - shared = network.get('share_address') or CONF.share_dhcp_address - return not network.get('multi_host') or shared - - @utils.synchronized('get_dhcp') - def _get_dhcp_ip(self, context, network_ref, host=None): - """Get the proper dhcp address to listen on.""" - # NOTE(vish): If we are sharing the dhcp_address then we can just - # return the dhcp_server from the database. - if self._uses_shared_ip(network_ref): - return network_ref.get('dhcp_server') or network_ref['gateway'] - - if not host: - host = self.host - network_id = network_ref['id'] - try: - fip = objects.FixedIP.get_by_network_and_host(context, - network_id, - host) - return fip.address - except exception.FixedIpNotFoundForNetworkHost: - elevated = context.elevated() - fip = objects.FixedIP.associate_pool(elevated, - network_id, - host=host) - return fip.address - - def get_dhcp_leases(self, ctxt, network_ref): - """Broker the request to the driver to fetch the dhcp leases.""" - LOG.debug('Get DHCP leases for network %s', network_ref['uuid']) - return self.driver.get_dhcp_leases(ctxt, network_ref) - - def init_host(self): - """Do any initialization that needs to be run if this is a - standalone service. - """ - # NOTE(vish): Set up networks for which this host already has - # an ip address. - ctxt = context.get_admin_context() - for network in objects.NetworkList.get_by_host(ctxt, self.host): - self._setup_network_on_host(ctxt, network) - if CONF.update_dns_entries: - LOG.debug('Update DNS on network %s for host %s', - network['uuid'], self.host) - dev = self.driver.get_dev(network) - self.driver.update_dns(ctxt, dev, network) - LOG.info('Configured network %(network)s on host %(host)s', - {'network': network['uuid'], 'host': self.host}) - - @periodic_task.periodic_task - def _disassociate_stale_fixed_ips(self, context): - if self.timeout_fixed_ips: - now = timeutils.utcnow() - timeout = CONF.fixed_ip_disassociate_timeout - time = now - datetime.timedelta(seconds=timeout) - num = objects.FixedIP.disassociate_all_by_timeout(context, - self.host, - time) - if num: - LOG.debug('Disassociated %s stale fixed IP(s)', num) - - def set_network_host(self, context, network_ref): - """Safely sets the host of the network.""" - # TODO(mriedem): Remove this compat shim when network RPC API version - # 1.0 is dropped. - if not isinstance(network_ref, obj_base.NovaObject): - network_ref = objects.Network._from_db_object( - context, objects.Network(), network_ref) - LOG.debug('Setting host %s for network %s', self.host, - network_ref.uuid) - network_ref.host = self.host - network_ref.save() - return self.host - - def _do_trigger_security_group_members_refresh_for_instance(self, - instance_id): - # NOTE(francois.charlier): the instance may have been deleted already - # thus enabling `read_deleted` - admin_context = context.get_admin_context(read_deleted='yes') - instance = objects.Instance.get_by_uuid(admin_context, instance_id) - - try: - # NOTE(vish): We need to make sure the instance info cache has been - # updated with new ip info before we trigger the - # security group refresh. This is somewhat inefficient - # but avoids doing some dangerous refactoring for a - # bug fix. - nw_info = self.get_instance_nw_info(admin_context, instance_id, - None, None) - ic = objects.InstanceInfoCache.new(admin_context, instance_id) - ic.network_info = nw_info - ic.save() - except exception.InstanceInfoCacheNotFound: - pass - groups = instance.security_groups - group_ids = [group.id for group in groups] - - self.security_group_api.trigger_members_refresh(admin_context, - group_ids) - - # NOTE(hanlind): This method can be removed in version 2.0 of the RPC API - def get_instance_uuids_by_ip_filter(self, context, filters): - fixed_ip_filter = filters.get('fixed_ip') - ip_filter = re.compile(str(filters.get('ip'))) - ipv6_filter = re.compile(str(filters.get('ip6'))) - LOG.debug('Get instance uuids by IP filters. Fixed IP filter: %s. ' - 'IP filter: %s. IPv6 filter: %s', fixed_ip_filter, - str(filters.get('ip')), str(filters.get('ip6'))) - - # NOTE(jkoelker) Should probably figure out a better way to do - # this. But for now it "works", this could suck on - # large installs. - - vifs = objects.VirtualInterfaceList.get_all(context) - results = [] - - for vif in vifs: - if vif.instance_uuid is None: - continue - - network = self._get_network_by_id(context, vif.network_id) - fixed_ipv6 = None - if network['cidr_v6'] is not None: - fixed_ipv6 = ipv6.to_global(network['cidr_v6'], - vif.address, - context.project_id) - - if fixed_ipv6 and ipv6_filter.match(fixed_ipv6): - results.append({'instance_uuid': vif.instance_uuid, - 'ip': fixed_ipv6}) - - fixed_ips = objects.FixedIPList.get_by_virtual_interface_id( - context, vif.id) - for fixed_ip in fixed_ips: - if not fixed_ip or not fixed_ip.address: - continue - if str(fixed_ip.address) == fixed_ip_filter: - results.append({'instance_uuid': vif.instance_uuid, - 'ip': fixed_ip.address}) - continue - if ip_filter.match(str(fixed_ip.address)): - results.append({'instance_uuid': vif.instance_uuid, - 'ip': fixed_ip.address}) - continue - for floating_ip in fixed_ip.floating_ips: - if not floating_ip or not floating_ip.address: - continue - if ip_filter.match(str(floating_ip.address)): - results.append({'instance_uuid': vif.instance_uuid, - 'ip': floating_ip.address}) - continue - - return results - - def _get_networks_for_instance(self, context, instance_id, project_id, - requested_networks=None): - """Determine & return which networks an instance should connect to.""" - # TODO(tr3buchet) maybe this needs to be updated in the future if - # there is a better way to determine which networks - # a non-vlan instance should connect to - if requested_networks is not None and len(requested_networks) != 0: - network_uuids = [request.network_id - for request in requested_networks] - networks = self._get_networks_by_uuids(context, network_uuids) - else: - try: - networks = objects.NetworkList.get_all(context) - except exception.NoNetworksFound: - return [] - # return only networks which are not vlan networks - return [network for network in networks if not network.vlan] - - def allocate_for_instance(self, context, **kwargs): - """Handles allocating the various network resources for an instance. - - rpc.called by network_api - """ - instance_uuid = kwargs['instance_id'] - if not uuidutils.is_uuid_like(instance_uuid): - instance_uuid = kwargs.get('instance_uuid') - host = kwargs['host'] - project_id = kwargs['project_id'] - rxtx_factor = kwargs['rxtx_factor'] - requested_networks = kwargs.get('requested_networks') - if (requested_networks and - not isinstance(requested_networks, - objects.NetworkRequestList)): - requested_networks = objects.NetworkRequestList.from_tuples( - requested_networks) - vpn = kwargs['vpn'] - macs = kwargs['macs'] - admin_context = context.elevated() - networks = self._get_networks_for_instance(context, - instance_uuid, project_id, - requested_networks=requested_networks) - networks_list = [self._get_network_dict(network) - for network in networks] - LOG.debug('Networks retrieved for instance: |%s|', - networks_list, instance_uuid=instance_uuid) - - try: - self._allocate_mac_addresses(admin_context, instance_uuid, - networks, macs, requested_networks) - except Exception: - with excutils.save_and_reraise_exception(): - # If we fail to allocate any one mac address, clean up all - # allocated VIFs - objects.VirtualInterface.delete_by_instance_uuid( - context, instance_uuid) - - self._allocate_fixed_ips(admin_context, instance_uuid, - host, networks, vpn=vpn, - requested_networks=requested_networks) - - if CONF.update_dns_entries: - network_ids = [network['id'] for network in networks] - self.network_rpcapi.update_dns(context, network_ids) - - net_info = self.get_instance_nw_info(admin_context, instance_uuid, - rxtx_factor, host) - LOG.info("Allocated network: '%s' for instance", net_info, - instance_uuid=instance_uuid) - return net_info - - def deallocate_for_instance(self, context, **kwargs): - """Handles deallocating various network resources for an instance. - - rpc.called by network_api - kwargs can contain fixed_ips to circumvent another db lookup - """ - # NOTE(francois.charlier): in some cases the instance might be - # deleted before the IPs are released, so we need to get deleted - # instances too - read_deleted_context = context.elevated(read_deleted='yes') - if 'instance' in kwargs: - instance = kwargs['instance'] - instance_uuid = instance.uuid - host = instance.host - else: - instance_id = kwargs['instance_id'] - if uuidutils.is_uuid_like(instance_id): - instance = objects.Instance.get_by_uuid( - read_deleted_context, instance_id) - else: - instance = objects.Instance.get_by_id( - read_deleted_context, instance_id) - # NOTE(russellb) in case instance_id was an ID and not UUID - instance_uuid = instance.uuid - host = kwargs.get('host') - - try: - requested_networks = kwargs.get('requested_networks') - if requested_networks: - # NOTE(obondarev): Temporary and transitional - if isinstance(requested_networks, objects.NetworkRequestList): - requested_networks = requested_networks.as_tuples() - - network_ids = set([net_id for (net_id, ip) - in requested_networks]) - fixed_ips = [ip for (net_id, ip) in requested_networks if ip] - else: - fixed_ip_list = objects.FixedIPList.get_by_instance_uuid( - read_deleted_context, instance_uuid) - network_ids = set([str(fixed_ip.network_id) for fixed_ip - in fixed_ip_list]) - fixed_ips = [str(ip.address) for ip in fixed_ip_list] - except exception.FixedIpNotFoundForInstance: - network_ids = set([]) - fixed_ips = [] - LOG.debug("Network deallocation for instance", - instance_uuid=instance_uuid) - # deallocate fixed ips - for fixed_ip in fixed_ips: - self.deallocate_fixed_ip(context, fixed_ip, host=host, - instance=instance) - - if CONF.update_dns_entries: - self.network_rpcapi.update_dns(context, list(network_ids)) - - # deallocate vifs (mac addresses) - objects.VirtualInterface.delete_by_instance_uuid( - read_deleted_context, instance_uuid) - LOG.info("Network deallocated for instance (fixed IPs: '%s')", - fixed_ips, instance_uuid=instance_uuid) - - @messaging.expected_exceptions(exception.InstanceNotFound) - def get_instance_nw_info(self, context, instance_id, rxtx_factor, - host, instance_uuid=None, **kwargs): - """Creates network info list for instance. - - called by allocate_for_instance and network_api - context needs to be elevated - :returns: network info list [(network,info),(network,info)...] - where network = dict containing pertinent data from a network db object - and info = dict containing pertinent networking data - """ - if not uuidutils.is_uuid_like(instance_id): - instance_id = instance_uuid - instance_uuid = instance_id - LOG.debug('Get instance network info', instance_uuid=instance_uuid) - - try: - fixed_ips = objects.FixedIPList.get_by_instance_uuid( - context, instance_uuid) - except exception.FixedIpNotFoundForInstance: - fixed_ips = [] - - LOG.debug('Found %d fixed IPs associated to the instance in the ' - 'database.', - len(fixed_ips), instance_uuid=instance_uuid) - - nw_info = network_model.NetworkInfo() - - vifs = collections.OrderedDict() - for fixed_ip in fixed_ips: - vif = fixed_ip.virtual_interface - if not vif: - LOG.warning('No VirtualInterface for FixedIP: %s', - str(fixed_ip.address), instance_uuid=instance_uuid) - continue - - if not fixed_ip.network: - LOG.warning('No Network for FixedIP: %s', - str(fixed_ip.address), instance_uuid=instance_uuid) - continue - - if vif.uuid in vifs: - current = vifs[vif.uuid] - else: - current = { - 'id': vif.uuid, - 'type': network_model.VIF_TYPE_BRIDGE, - 'address': vif.address, - } - vifs[vif.uuid] = current - - net_dict = self._get_network_dict(fixed_ip.network) - network = network_model.Network(**net_dict) - subnets = self._get_subnets_from_network(context, - fixed_ip.network, - host) - network['subnets'] = subnets - current['network'] = network - try: - current['rxtx_cap'] = (fixed_ip.network['rxtx_base'] * - rxtx_factor) - except (TypeError, KeyError): - pass - if fixed_ip.network.cidr_v6 and vif.address: - # NOTE(vish): I strongly suspect the v6 subnet is not used - # anywhere, but support it just in case - # add the v6 address to the v6 subnet - address = ipv6.to_global(fixed_ip.network.cidr_v6, - vif.address, - fixed_ip.network.project_id) - model_ip = network_model.FixedIP(address=address) - current['network']['subnets'][1]['ips'].append(model_ip) - - # add the v4 address to the v4 subnet - model_ip = network_model.FixedIP(address=str(fixed_ip.address)) - for ip in fixed_ip.floating_ips: - floating_ip = network_model.IP(address=str(ip['address']), - type='floating') - model_ip.add_floating_ip(floating_ip) - current['network']['subnets'][0]['ips'].append(model_ip) - - for vif in vifs.values(): - nw_info.append(network_model.VIF(**vif)) - - LOG.debug('Built network info: |%s|', nw_info, - instance_uuid=instance_uuid) - return nw_info - - @staticmethod - def _get_network_dict(network): - """Returns the dict representing necessary and meta network fields.""" - # get generic network fields - network_dict = {'id': network['uuid'], - 'bridge': network['bridge'], - 'label': network['label'], - 'tenant_id': network['project_id']} - - # get extra information - if network.get('injected'): - network_dict['injected'] = network['injected'] - - return network_dict - - @staticmethod - def _extract_subnets(network): - """Returns information about the IPv4 and IPv6 subnets - associated with a Neutron Network UUID. - """ - subnet_v4 = { - 'network_id': network.uuid, - 'cidr': network.cidr, - 'gateway': network.gateway, - 'dhcp_server': getattr(network, 'dhcp_server'), - 'broadcast': network.broadcast, - 'netmask': network.netmask, - 'version': 4, - 'dns1': network.dns1, - 'dns2': network.dns2} - # TODO(tr3buchet): I'm noticing we've assumed here that all dns is v4. - # this is probably bad as there is no way to add v6 - # dns to nova - subnet_v6 = { - 'network_id': network.uuid, - 'cidr': network.cidr_v6, - 'gateway': network.gateway_v6, - 'dhcp_server': None, - 'broadcast': None, - 'netmask': network.netmask_v6, - 'version': 6, - 'dns1': None, - 'dns2': None} - - def ips_to_strs(net): - for key, value in net.items(): - if isinstance(value, netaddr.ip.BaseIP): - net[key] = str(value) - return net - - return [ips_to_strs(subnet_v4), ips_to_strs(subnet_v6)] - - def _get_subnets_from_network(self, context, network, instance_host=None): - """Returns the 1 or 2 possible subnets for a nova network.""" - extracted_subnets = self._extract_subnets(network) - subnets = [] - for subnet in extracted_subnets: - subnet_dict = {'cidr': subnet['cidr'], - 'gateway': network_model.IP( - address=subnet['gateway'], - type='gateway')} - # deal with dhcp - if self.DHCP: - if network.get('multi_host'): - dhcp_server = self._get_dhcp_ip(context, network, - instance_host) - else: - dhcp_server = self._get_dhcp_ip(context, subnet) - subnet_dict['dhcp_server'] = dhcp_server - - subnet_object = network_model.Subnet(**subnet_dict) - - # add dns info - for k in ['dns1', 'dns2']: - if subnet.get(k): - subnet_object.add_dns( - network_model.IP(address=subnet[k], type='dns')) - - subnet_object['ips'] = [] - - subnets.append(subnet_object) - - return subnets - - def _allocate_mac_addresses(self, context, instance_uuid, networks, macs, - requested_networks): - """Generates mac addresses and creates vif rows in db for them.""" - # make a copy we can mutate - if macs is not None: - available_macs = set(macs) - - if requested_networks: - tags_by_network = { - network.network_id: network.tag if 'tag' in network else None - for network in requested_networks} - else: - tags_by_network = {} - - for network in networks: - if macs is None: - self._add_virtual_interface( - context, instance_uuid, - network['id'], - tag=tags_by_network.get(network['uuid'])) - else: - try: - mac = available_macs.pop() - except KeyError: - raise exception.VirtualInterfaceCreateException() - self._add_virtual_interface( - context, instance_uuid, - network['id'], mac, - tag=tags_by_network.get(network['uuid'])) - - def _add_virtual_interface(self, context, instance_uuid, network_id, - mac=None, tag=None): - attempts = 1 if mac else CONF.create_unique_mac_address_attempts - for i in range(attempts): - try: - vif = objects.VirtualInterface(context) - vif.address = mac or utils.generate_mac_address() - vif.instance_uuid = instance_uuid - vif.network_id = network_id - vif.uuid = uuidutils.generate_uuid() - vif.tag = tag - vif.create() - return vif - except exception.VirtualInterfaceCreateException: - # Try again up to max number of attempts - pass - - raise exception.VirtualInterfaceMacAddressException() - - def add_fixed_ip_to_instance(self, context, instance_id, host, network_id, - rxtx_factor=None): - """Adds a fixed IP to an instance from specified network.""" - if uuidutils.is_uuid_like(network_id): - network = self.get_network(context, network_id) - else: - network = self._get_network_by_id(context, network_id) - LOG.debug('Add fixed IP on network %s', network['uuid'], - instance_uuid=instance_id) - self._allocate_fixed_ips(context, instance_id, host, [network]) - return self.get_instance_nw_info(context, instance_id, rxtx_factor, - host) - - # NOTE(russellb) This method can be removed in 2.0 of this API. It is - # deprecated in favor of the method in the base API. - def get_backdoor_port(self, context): - """Return backdoor port for eventlet_backdoor.""" - return self.backdoor_port - - def remove_fixed_ip_from_instance(self, context, instance_id, host, - address, rxtx_factor=None): - """Removes a fixed IP from an instance from specified network.""" - LOG.debug('Remove fixed IP %s', address, instance_uuid=instance_id) - fixed_ips = objects.FixedIPList.get_by_instance_uuid(context, - instance_id) - for fixed_ip in fixed_ips: - if str(fixed_ip.address) == address: - self.deallocate_fixed_ip(context, address, host) - # NOTE(vish): this probably isn't a dhcp ip so just - # deallocate it now. In the extremely rare - # case that this is a race condition, we - # will just get a warn in lease or release. - if not fixed_ip.leased: - fixed_ip.disassociate() - return self.get_instance_nw_info(context, instance_id, - rxtx_factor, host) - raise exception.FixedIpNotFoundForSpecificInstance( - instance_uuid=instance_id, ip=address) - - def _validate_instance_zone_for_dns_domain(self, context, instance): - if not self.instance_dns_domain: - return True - instance_domain = self.instance_dns_domain - - domainref = objects.DNSDomain.get_by_domain(context, instance_domain) - if domainref is None: - LOG.warning('instance-dns-zone not found |%s|.', - instance_domain, instance=instance) - return True - dns_zone = domainref.availability_zone - - instance_zone = instance.get('availability_zone') - if dns_zone and (dns_zone != instance_zone): - LOG.warning('instance-dns-zone is |%(domain)s|, ' - 'which is in availability zone |%(zone)s|. ' - 'Instance is in zone |%(zone2)s|. ' - 'No DNS record will be created.', - {'domain': instance_domain, - 'zone': dns_zone, - 'zone2': instance_zone}, - instance=instance) - return False - else: - return True - - def allocate_fixed_ip(self, context, instance_id, network, **kwargs): - """Gets a fixed IP from the pool.""" - # TODO(vish): when this is called by compute, we can associate compute - # with a network, or a cluster of computes with a network - # and use that network here with a method like - # network_get_by_compute_host - address = None - - # NOTE(vish) This db query could be removed if we pass az and name - # (or the whole instance object). - instance = objects.Instance.get_by_uuid(context, instance_id) - LOG.debug('Allocate fixed IP on network %s', network['uuid'], - instance=instance) - - # A list of cleanup functions to call on error - cleanup = [] - - # Check the quota; can't put this in the API because we get - # called into from other places - quotas = self.quotas_cls(context=context) - quota_project, quota_user = quotas_obj.ids_from_instance(context, - instance) - try: - quotas.check_deltas(context, {'fixed_ips': 1}, quota_project) - except exception.OverQuota as exc: - count = exc.kwargs['usages']['fixed_ips'] - LOG.warning("Quota exceeded for project %(pid)s, tried to " - "allocate fixed IP. %(used)s of %(allowed)s are " - "in use or are already reserved.", - {'pid': quota_project, 'used': count, - 'allowed': exc.kwargs['quotas']['fixed_ips']}, - instance_uuid=instance_id) - raise exception.FixedIpLimitExceeded() - - try: - if network['cidr']: - - # NOTE(mriedem): allocate the vif before associating the - # instance to reduce a race window where a previous instance - # was associated with the fixed IP and has released it, because - # release_fixed_ip will disassociate if allocated is False. - vif = objects.VirtualInterface.get_by_instance_and_network( - context, instance_id, network['id']) - if vif is None: - LOG.debug('vif for network %(network)s is used up, ' - 'trying to create new vif', - {'network': network['id']}, instance=instance) - vif = self._add_virtual_interface(context, - instance_id, network['id']) - - address = kwargs.get('address', None) - if address: - LOG.debug('Associating instance with specified fixed IP ' - '%(address)s in network %(network)s on subnet ' - '%(cidr)s.', - {'address': address, 'network': network['id'], - 'cidr': network['cidr']}, - instance=instance) - fip = objects.FixedIP.associate( - context, str(address), instance_id, network['id'], - vif_id=vif.id) - else: - LOG.debug('Associating instance with fixed IP from pool ' - 'in network %(network)s on subnet %(cidr)s.', - {'network': network['id'], - 'cidr': network['cidr']}, - instance=instance) - fip = objects.FixedIP.associate_pool( - context.elevated(), network['id'], instance_id, - vif_id=vif.id) - LOG.debug('Associated instance with fixed IP: %s', fip, - instance=instance) - address = str(fip.address) - - cleanup.append(fip.disassociate) - - # 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: - try: - quotas.check_deltas(context, {'fixed_ips': 0}, - quota_project) - except exception.OverQuota as exc: - # Cleanup of the fixed IP allocation occurs in the - # outermost catch-all except block. - count = exc.kwargs['usages']['fixed_ips'] - allowed = exc.kwargs['quotas']['fixed_ips'] - LOG.warning("Quota exceeded for project %(pid)s, " - "tried to allocate fixed IP. %(used)s " - "of %(allowed)s are in use or are " - "already reserved.", - {'pid': quota_project, 'used': count, - 'allowed': allowed}, - instance_uuid=instance_id) - raise exception.FixedIpLimitExceeded() - - LOG.debug('Refreshing security group members for instance.', - instance=instance) - self._do_trigger_security_group_members_refresh_for_instance( - instance_id) - cleanup.append(functools.partial( - self._do_trigger_security_group_members_refresh_for_instance, # noqa - instance_id)) - - name = instance.display_name - - if self._validate_instance_zone_for_dns_domain(context, instance): - self.instance_dns_manager.create_entry( - name, str(fip.address), "A", self.instance_dns_domain) - cleanup.append(functools.partial( - self.instance_dns_manager.delete_entry, - name, self.instance_dns_domain)) - - self.instance_dns_manager.create_entry( - instance_id, str(fip.address), "A", - self.instance_dns_domain) - cleanup.append(functools.partial( - self.instance_dns_manager.delete_entry, - instance_id, self.instance_dns_domain)) - - LOG.debug('Setting up network %(network)s on host %(host)s.', - {'network': network['id'], 'host': self.host}, - instance=instance) - self._setup_network_on_host(context, network) - cleanup.append(functools.partial( - self._teardown_network_on_host, - context, network)) - - if address is None: - # TODO(mriedem): should _setup_network_on_host return the addr? - LOG.debug('Fixed IP is setup on network %s but not returning ' - 'the specific IP from the base network manager.', - network['uuid'], instance=instance) - else: - LOG.debug('Allocated fixed IP %s on network %s', address, - network['uuid'], instance=instance) - return address - - except Exception: - with excutils.save_and_reraise_exception(): - for f in cleanup: - try: - f() - except Exception: - LOG.warning('Error cleaning up fixed IP ' - 'allocation. Manual cleanup may ' - 'be required.', exc_info=True) - - def deallocate_fixed_ip(self, context, address, host=None, teardown=True, - instance=None): - """Returns a fixed IP to the pool.""" - fixed_ip_ref = objects.FixedIP.get_by_address( - context, address, expected_attrs=['network']) - instance_uuid = fixed_ip_ref.instance_uuid - vif_id = fixed_ip_ref.virtual_interface_id - LOG.debug('Deallocate fixed IP %s', address, - instance_uuid=instance_uuid) - - if not instance: - # NOTE(vish) This db query could be removed if we pass az and name - # (or the whole instance object). - # NOTE(danms) We can't use fixed_ip_ref.instance because - # instance may be deleted and the relationship - # doesn't extend to deleted instances - instance = objects.Instance.get_by_uuid( - context.elevated(read_deleted='yes'), instance_uuid) - - self._do_trigger_security_group_members_refresh_for_instance( - instance_uuid) - - if self._validate_instance_zone_for_dns_domain(context, instance): - for n in self.instance_dns_manager.get_entries_by_address( - address, self.instance_dns_domain): - self.instance_dns_manager.delete_entry(n, - self.instance_dns_domain) - - fixed_ip_ref.allocated = False - fixed_ip_ref.save() - - if teardown: - network = fixed_ip_ref.network - - if CONF.force_dhcp_release: - dev = self.driver.get_dev(network) - # NOTE(vish): The below errors should never happen, but - # there may be a race condition that is causing - # them per - # https://code.launchpad.net/bugs/968457, - # so we log a message to help track down - # the possible race. - if not vif_id: - LOG.info("Unable to release %s because vif doesn't exist", - address) - return - - vif = objects.VirtualInterface.get_by_id(context, vif_id) - - if not vif: - LOG.info("Unable to release %s because vif " - "object doesn't exist", address) - return - - # NOTE(cfb): Call teardown before release_dhcp to ensure - # that the IP can't be re-leased after a release - # packet is sent. - self._teardown_network_on_host(context, network) - # NOTE(vish): This forces a packet so that the - # release_fixed_ip callback will - # get called by nova-dhcpbridge. - try: - self.network_rpcapi.release_dhcp(context, - instance.launched_on, - dev, address, - vif.address) - except exception.RPCPinnedToOldVersion: - # Fall back on previous behaviour of calling - # release_dhcp on the local driver - self.driver.release_dhcp(dev, address, vif.address) - except exception.NetworkDhcpReleaseFailed: - LOG.error("Error releasing DHCP for IP %(address)s" - " with MAC %(mac_address)s", - {'address': address, - 'mac_address': vif.address}, - instance=instance) - - # NOTE(yufang521247): This is probably a failed dhcp fixed - # ip. DHCPRELEASE packet sent to dnsmasq would not trigger - # dhcp-bridge to run. Thus it is better to disassociate - # such fixed ip here. - fixed_ip_ref = objects.FixedIP.get_by_address( - context, address) - if (instance_uuid == fixed_ip_ref.instance_uuid and - not fixed_ip_ref.leased): - LOG.debug('Explicitly disassociating fixed IP %s from ' - 'instance.', address, - instance_uuid=instance_uuid) - fixed_ip_ref.disassociate() - else: - # We can't try to free the IP address so just call teardown - self._teardown_network_on_host(context, network) - - def release_dhcp(self, context, dev, address, vif_address): - self.driver.release_dhcp(dev, address, vif_address) - - def lease_fixed_ip(self, context, address): - """Called by dhcp-bridge when IP is leased.""" - LOG.debug('Leased IP |%s|', address) - fixed_ip = objects.FixedIP.get_by_address(context, address) - - if fixed_ip.instance_uuid is None: - LOG.warning('IP %s leased that is not associated', fixed_ip) - return - fixed_ip.leased = True - fixed_ip.save() - if not fixed_ip.allocated: - LOG.warning('IP |%s| leased that isn\'t allocated', fixed_ip, - instance_uuid=fixed_ip.instance_uuid) - - def release_fixed_ip(self, context, address, mac=None): - """Called by dhcp-bridge when IP is released.""" - LOG.debug('Released IP |%s|', address) - fixed_ip = objects.FixedIP.get_by_address(context, address) - - if fixed_ip.instance_uuid is None: - LOG.warning('IP %s released that is not associated', fixed_ip) - return - if not fixed_ip.leased: - LOG.warning('IP %s released that was not leased', fixed_ip, - instance_uuid=fixed_ip.instance_uuid) - else: - fixed_ip.leased = False - fixed_ip.save() - if not fixed_ip.allocated: - # NOTE(mriedem): Sometimes allocate_fixed_ip will associate the - # fixed IP to a new instance while an old associated instance is - # being deallocated. So we check to see if the mac is for the VIF - # that is associated to the instance that is currently associated - # with the fixed IP because if it's not, we hit this race and - # should ignore the request so we don't disassociate the fixed IP - # from the wrong instance. - if mac: - LOG.debug('Checking to see if virtual interface with MAC ' - '%(mac)s is still associated to instance.', - {'mac': mac}, instance_uuid=fixed_ip.instance_uuid) - vif = objects.VirtualInterface.get_by_address(context, mac) - if vif: - LOG.debug('Found VIF: %s', vif, - instance_uuid=fixed_ip.instance_uuid) - if vif.instance_uuid != fixed_ip.instance_uuid: - LOG.info("Ignoring request to release fixed IP " - "%(address)s with MAC %(mac)s since it " - "is now associated with a new instance " - "that is in the process of allocating " - "it's network.", - {'address': address, 'mac': mac}, - instance_uuid=fixed_ip.instance_uuid) - return - else: - LOG.debug('No VIF was found for MAC: %s', mac, - instance_uuid=fixed_ip.instance_uuid) - - LOG.debug('Disassociating fixed IP %s from instance.', address, - instance_uuid=fixed_ip.instance_uuid) - fixed_ip.disassociate() - - @staticmethod - def _convert_int_args(kwargs): - int_args = ("network_size", "num_networks", - "vlan_start", "vpn_start") - for key in int_args: - try: - value = kwargs.get(key) - if value is None: - continue - kwargs[key] = int(value) - except ValueError: - raise exception.InvalidIntValue(key=key) - - def create_networks(self, context, - label, cidr=None, multi_host=None, num_networks=None, - network_size=None, cidr_v6=None, - gateway=None, gateway_v6=None, bridge=None, - bridge_interface=None, dns1=None, dns2=None, - fixed_cidr=None, allowed_start=None, - allowed_end=None, **kwargs): - if 'dhcp_server' not in kwargs: - kwargs['dhcp_server'] = gateway - if 'enable_dhcp' not in kwargs: - kwargs['enable_dhcp'] = True - if 'share_address' not in kwargs: - kwargs['share_address'] = CONF.share_dhcp_address - kwargs.update({ - 'label': label, - 'cidr': cidr, - 'multi_host': multi_host, - 'num_networks': num_networks, - 'network_size': network_size, - 'cidr_v6': cidr_v6, - 'gateway': gateway, - 'gateway_v6': gateway_v6, - 'bridge': bridge, - 'bridge_interface': bridge_interface, - 'dns1': dns1, - 'dns2': dns2, - 'fixed_cidr': fixed_cidr, - 'allowed_start': allowed_start, - 'allowed_end': allowed_end, - }) - self._convert_int_args(kwargs) - - kwargs["bridge"] = kwargs["bridge"] or CONF.flat_network_bridge - kwargs["bridge_interface"] = (kwargs["bridge_interface"] or - CONF.flat_interface) - - for fld in self.required_create_args: - if not kwargs[fld]: - raise exception.NetworkNotCreated(req=fld) - - if kwargs["cidr_v6"]: - # NOTE(vish): just for validation - try: - netaddr.IPNetwork(kwargs["cidr_v6"]) - except netaddr.AddrFormatError: - raise exception.InvalidCidr(cidr=kwargs["cidr_v6"]) - - if kwargs["cidr"]: - try: - fixnet = netaddr.IPNetwork(kwargs["cidr"]) - except netaddr.AddrFormatError: - raise exception.InvalidCidr(cidr=kwargs["cidr"]) - - kwargs["num_networks"] = kwargs["num_networks"] or CONF.num_networks - if not kwargs["network_size"]: - if kwargs["cidr"]: - each_subnet_size = fixnet.size / kwargs["num_networks"] - if each_subnet_size > CONF.network_size: - subnet = 32 - int(math.log(CONF.network_size, 2)) - LOG.warning( - 'Subnet(s) too large, defaulting to /%s.' - ' To override, specify network_size flag.', subnet) - kwargs["network_size"] = CONF.network_size - else: - kwargs["network_size"] = fixnet.size - else: - kwargs["network_size"] = CONF.network_size - - kwargs["multi_host"] = ( - CONF.multi_host - if kwargs["multi_host"] is None - else strutils.bool_from_string(kwargs["multi_host"])) - - kwargs["vlan_start"] = kwargs.get("vlan_start") or CONF.vlan_start - kwargs["vpn_start"] = kwargs.get("vpn_start") or CONF.vpn_start - kwargs["dns1"] = kwargs["dns1"] or CONF.flat_network_dns - - if kwargs["fixed_cidr"]: - try: - kwargs["fixed_cidr"] = netaddr.IPNetwork(kwargs["fixed_cidr"]) - except netaddr.AddrFormatError: - raise exception.InvalidCidr(cidr=kwargs["fixed_cidr"]) - - # Subnet of fixed IPs must fall within fixed range - if kwargs["fixed_cidr"] not in fixnet: - raise exception.AddressOutOfRange( - address=kwargs["fixed_cidr"].network, cidr=fixnet) - - LOG.debug('Create network: |%s|', kwargs) - return self._do_create_networks(context, **kwargs) - - @staticmethod - def _index_of(subnet, ip): - try: - start = netaddr.IPAddress(ip) - except netaddr.AddrFormatError: - raise exception.InvalidAddress(address=ip) - index = start.value - subnet.value - if index < 0 or index >= subnet.size: - raise exception.AddressOutOfRange(address=ip, cidr=str(subnet)) - return index - - def _validate_cidr(self, context, nets, subnets_v4, fixed_net_v4): - used_subnets = [net.cidr for net in nets] - - def find_next(subnet): - next_subnet = subnet.next() - while next_subnet in subnets_v4: - next_subnet = next_subnet.next() - if next_subnet in fixed_net_v4: - return next_subnet - - for subnet in list(subnets_v4): - if subnet in used_subnets: - next_subnet = find_next(subnet) - if next_subnet: - subnets_v4.remove(subnet) - subnets_v4.append(next_subnet) - subnet = next_subnet - else: - raise exception.CidrConflict(cidr=subnet, - other=subnet) - for used_subnet in used_subnets: - if subnet in used_subnet: - raise exception.CidrConflict(cidr=subnet, - other=used_subnet) - if used_subnet in subnet: - next_subnet = find_next(subnet) - if next_subnet: - subnets_v4.remove(subnet) - subnets_v4.append(next_subnet) - subnet = next_subnet - else: - raise exception.CidrConflict(cidr=subnet, - other=used_subnet) - - def _do_create_networks(self, context, - label, cidr, multi_host, num_networks, - network_size, cidr_v6, gateway, gateway_v6, bridge, - bridge_interface, dns1=None, dns2=None, - fixed_cidr=None, mtu=None, dhcp_server=None, - enable_dhcp=None, share_address=None, - allowed_start=None, allowed_end=None, **kwargs): - """Create networks based on parameters.""" - # NOTE(jkoelker): these are dummy values to make sure iter works - # TODO(tr3buchet): disallow carving up networks - fixed_net_v4 = netaddr.IPNetwork('0/32') - fixed_net_v6 = netaddr.IPNetwork('::0/128') - subnets_v4 = [] - subnets_v6 = [] - - if kwargs.get('ipam'): - if cidr_v6: - subnets_v6 = [netaddr.IPNetwork(cidr_v6)] - if cidr: - subnets_v4 = [netaddr.IPNetwork(cidr)] - else: - subnet_bits = int(math.ceil(math.log(network_size, 2))) - if cidr_v6: - fixed_net_v6 = netaddr.IPNetwork(cidr_v6) - prefixlen_v6 = 128 - subnet_bits - # smallest subnet in IPv6 ethernet network is /64 - if prefixlen_v6 > 64: - prefixlen_v6 = 64 - subnets_v6 = fixed_net_v6.subnet(prefixlen_v6, - count=num_networks) - if cidr: - fixed_net_v4 = netaddr.IPNetwork(cidr) - prefixlen_v4 = 32 - subnet_bits - subnets_v4 = list(fixed_net_v4.subnet(prefixlen_v4, - count=num_networks)) - - if cidr: - # NOTE(jkoelker): This replaces the _validate_cidrs call and - # prevents looping multiple times - try: - nets = objects.NetworkList.get_all(context) - except exception.NoNetworksFound: - nets = [] - num_used_nets = len(nets) - self._validate_cidr(context, nets, subnets_v4, fixed_net_v4) - - networks = objects.NetworkList(context=context, objects=[]) - subnets = six.moves.zip_longest(subnets_v4, subnets_v6) - for index, (subnet_v4, subnet_v6) in enumerate(subnets): - net = objects.Network(context=context) - uuid = kwargs.get('uuid') - if uuid: - net.uuid = uuid - net.bridge = bridge - net.bridge_interface = bridge_interface - net.multi_host = multi_host - - net.dns1 = dns1 - net.dns2 = dns2 - net.mtu = mtu - net.enable_dhcp = enable_dhcp - net.share_address = share_address - - net.project_id = kwargs.get('project_id') - - if num_networks > 1: - net.label = '%s_%d' % (label, index) - else: - net.label = label - - bottom_reserved = self._bottom_reserved_ips - top_reserved = self._top_reserved_ips - extra_reserved = [] - if cidr and subnet_v4: - current = subnet_v4[1] - if allowed_start: - val = self._index_of(subnet_v4, allowed_start) - current = netaddr.IPAddress(allowed_start) - bottom_reserved = val - if allowed_end: - val = self._index_of(subnet_v4, allowed_end) - top_reserved = subnet_v4.size - 1 - val - net.cidr = str(subnet_v4) - net.netmask = str(subnet_v4.netmask) - net.broadcast = str(subnet_v4.broadcast) - if gateway: - net.gateway = gateway - else: - net.gateway = current - current += 1 - net.dhcp_server = dhcp_server or net.gateway - net.dhcp_start = current - current += 1 - if net.dhcp_start == net.dhcp_server: - net.dhcp_start = current - extra_reserved.append(str(net.dhcp_server)) - extra_reserved.append(str(net.gateway)) - - if cidr_v6 and subnet_v6: - net.cidr_v6 = str(subnet_v6) - if gateway_v6: - # use a pre-defined gateway if one is provided - net.gateway_v6 = str(gateway_v6) - else: - net.gateway_v6 = str(subnet_v6[1]) - - net.netmask_v6 = str(subnet_v6.netmask) - - if CONF.network_manager == 'nova.network.manager.VlanManager': - vlan = kwargs.get('vlan', None) - if not vlan: - index_vlan = index + num_used_nets - vlan = kwargs['vlan_start'] + index_vlan - used_vlans = [x.vlan for x in nets] - if vlan in used_vlans: - # That vlan is used, try to get another one - used_vlans.sort() - vlan = used_vlans[-1] + 1 - - net.vpn_private_address = net.dhcp_start - extra_reserved.append(str(net.vpn_private_address)) - net.dhcp_start = net.dhcp_start + 1 - net.vlan = vlan - net.bridge = 'br%s' % vlan - - # NOTE(vish): This makes ports unique across the cloud, a more - # robust solution would be to make them uniq per ip - index_vpn = index + num_used_nets - net.vpn_public_port = kwargs['vpn_start'] + index_vpn - - net.create() - networks.objects.append(net) - - if cidr and subnet_v4: - self._create_fixed_ips(context, net.id, fixed_cidr, - extra_reserved, bottom_reserved, - top_reserved) - # NOTE(danms): Remove this in RPC API v2.0 - return obj_base.obj_to_primitive(networks) - - def delete_network(self, context, fixed_range, uuid, - require_disassociated=True): - - # Prefer uuid but we'll also take cidr for backwards compatibility - elevated = context.elevated() - if uuid: - network = objects.Network.get_by_uuid(elevated, uuid) - elif fixed_range: - network = objects.Network.get_by_cidr(elevated, fixed_range) - LOG.debug('Delete network %s', network['uuid']) - - if require_disassociated and network.project_id is not None: - raise exception.NetworkHasProject(project_id=network.project_id) - network.destroy() - - @property - def _bottom_reserved_ips(self): - """Number of reserved IPs at the bottom of the range.""" - return 2 # network, gateway - - @property - def _top_reserved_ips(self): - """Number of reserved IPs at the top of the range.""" - return 1 # broadcast - - def _create_fixed_ips(self, context, network_id, fixed_cidr=None, - extra_reserved=None, bottom_reserved=0, - top_reserved=0): - """Create all fixed IPs for network.""" - network = self._get_network_by_id(context, network_id) - if extra_reserved is None: - extra_reserved = [] - if not fixed_cidr: - fixed_cidr = netaddr.IPNetwork(network['cidr']) - num_ips = len(fixed_cidr) - ips = [] - for index in range(num_ips): - address = str(fixed_cidr[index]) - if (index < bottom_reserved or num_ips - index <= top_reserved or - address in extra_reserved): - reserved = True - else: - reserved = False - - ips.append({'network_id': network_id, - 'address': address, - 'reserved': reserved}) - objects.FixedIPList.bulk_create(context, ips) - - def _allocate_fixed_ips(self, context, instance_id, host, networks, - **kwargs): - """Calls allocate_fixed_ip once for each network.""" - raise NotImplementedError() - - def setup_networks_on_host(self, context, instance_id, host, instance=None, - teardown=False): - """calls setup/teardown on network hosts for an instance.""" - green_threads = [] - - if teardown: - call_func = self._teardown_network_on_host - else: - call_func = self._setup_network_on_host - if instance is None: - instance = objects.Instance.get_by_id(context, instance_id) - vifs = objects.VirtualInterfaceList.get_by_instance_uuid( - context, instance.uuid) - LOG.debug('Setup networks on host', instance=instance) - for vif in vifs: - network = objects.Network.get_by_id(context, vif.network_id) - if not network.multi_host: - # NOTE (tr3buchet): if using multi_host, host is instance.host - host = network['host'] - if self.host == host or host is None: - # at this point i am the correct host, or host doesn't - # matter -> FlatManager - call_func(context, network) - else: - # i'm not the right host, run call on correct host - green_threads.append(utils.spawn( - self.network_rpcapi.rpc_setup_network_on_host, context, - network.id, teardown, host)) - - # wait for all of the setups (if any) to finish - for gt in green_threads: - gt.wait() - - def rpc_setup_network_on_host(self, context, network_id, teardown): - if teardown: - call_func = self._teardown_network_on_host - else: - call_func = self._setup_network_on_host - - # subcall from original setup_networks_on_host - network = objects.Network.get_by_id(context, network_id) - call_func(context, network) - - def _initialize_network(self, network): - if network.enable_dhcp: - is_ext = (network.dhcp_server is not None and - network.dhcp_server != network.gateway) - self.l3driver.initialize_network(network.cidr, is_ext) - self.l3driver.initialize_gateway(network) - - def _setup_network_on_host(self, context, network): - """Sets up network on this host.""" - raise NotImplementedError() - - def _teardown_network_on_host(self, context, network): - """Sets up network on this host.""" - raise NotImplementedError() - - def validate_networks(self, context, networks): - """check if the networks exists and host - is set to each network. - """ - LOG.debug('Validate networks') - if networks is None or len(networks) == 0: - return - - for network_uuid, address in networks: - # check if the fixed IP address is valid and - # it actually belongs to the network - if address is not None: - if not netutils.is_valid_ip(address): - raise exception.FixedIpInvalid(address=address) - - fixed_ip_ref = objects.FixedIP.get_by_address( - context, address, expected_attrs=['network']) - network = fixed_ip_ref.network - if network.uuid != network_uuid: - raise exception.FixedIpNotFoundForNetwork( - address=address, network_uuid=network_uuid) - if fixed_ip_ref.instance_uuid is not None: - raise exception.FixedIpAlreadyInUse( - address=address, - instance_uuid=fixed_ip_ref.instance_uuid) - - def _get_network_by_id(self, context, network_id): - return objects.Network.get_by_id(context, network_id, - project_only='allow_none') - - def _get_networks_by_uuids(self, context, network_uuids): - networks = objects.NetworkList.get_by_uuids( - context, network_uuids, project_only="allow_none") - networks.sort(key=lambda x: network_uuids.index(x.uuid)) - return networks - - def get_vifs_by_instance(self, context, instance_id): - """Returns the vifs associated with an instance.""" - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - instance = objects.Instance.get_by_id(context, instance_id) - LOG.debug('Get VIFs for instance', instance=instance) - - # NOTE(russellb) No need to object-ify this since - # get_vifs_by_instance() is unused and set to be removed. - vifs = objects.VirtualInterfaceList.get_by_instance_uuid(context, - instance.uuid) - for vif in vifs: - if vif.network_id is not None: - network = self._get_network_by_id(context, vif.network_id) - vif.net_uuid = network.uuid - return [dict(vif) for vif in vifs] - - def get_instance_id_by_floating_address(self, context, address): - """Returns the instance id a floating IP's fixed IP is allocated to.""" - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - LOG.debug('Get instance for floating address %s', 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_network(self, context, network_uuid): - # NOTE(vish): used locally - - return objects.Network.get_by_uuid(context.elevated(), network_uuid) - - def get_all_networks(self, context): - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - try: - return obj_base.obj_to_primitive( - objects.NetworkList.get_all(context)) - except exception.NoNetworksFound: - return [] - - def disassociate_network(self, context, network_uuid): - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - network = self.get_network(context, network_uuid) - network.disassociate(context, network.id) - - def get_fixed_ip(self, context, id): - """Return a fixed IP.""" - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - return objects.FixedIP.get_by_id(context, id) - - def get_fixed_ip_by_address(self, context, address): - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - return objects.FixedIP.get_by_address(context, address) - - def get_vif_by_mac_address(self, context, mac_address): - """Returns the vifs record for the mac_address.""" - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - # NOTE(russellb) No need to object-ify this since - # get_vifs_by_instance() is unused and set to be removed. - vif = objects.VirtualInterface.get_by_address(context, mac_address) - if vif.network_id is not None: - network = self._get_network_by_id(context, vif.network_id) - vif.net_uuid = network.uuid - return vif - - @periodic_task.periodic_task( - spacing=CONF.dns_update_periodic_interval) - def _periodic_update_dns(self, context): - """Update local DNS entries of all networks on this host.""" - networks = objects.NetworkList.get_by_host(context, self.host) - for network in networks: - dev = self.driver.get_dev(network) - self.driver.update_dns(context, dev, network) - - def update_dns(self, context, network_ids): - """Called when fixed IP is allocated or deallocated.""" - if CONF.fake_network: - return - - LOG.debug('Update DNS for network ids: %s', network_ids) - networks = [network for network in - objects.NetworkList.get_by_host(context, self.host) - if network.multi_host and network.id in network_ids] - for network in networks: - dev = self.driver.get_dev(network) - self.driver.update_dns(context, dev, network) - - def add_network_to_project(self, ctxt, project_id, network_uuid): - raise NotImplementedError() - - -class FlatManager(NetworkManager): - """Basic network where no vlans are used. - - FlatManager does not do any bridge or vlan creation. The user is - responsible for setting up whatever bridges are specified when creating - networks through nova-manage. This bridge needs to be created on all - compute hosts. - - The idea is to create a single network for the host with a command like: - nova-manage network create 192.168.0.0/24 1 256. Creating multiple - networks for one manager is currently not supported, but could be - added by modifying allocate_fixed_ip and get_network to get the network - with new logic. Arbitrary lists of addresses in a single network can - be accomplished with manual db editing. - - If flat_injected is True, the compute host will attempt to inject network - config into the guest. It attempts to modify /etc/network/interfaces and - currently only works on debian based systems. To support a wider range of - OSes, some other method may need to be devised to let the guest know which - IP it should be using so that it can configure itself. Perhaps an attached - disk or serial device with configuration info. - - Metadata forwarding must be handled by the gateway, and since nova does - not do any setup in this mode, it must be done manually. Requests to - 169.254.169.254 port 80 will need to be forwarded to the api server. - - """ - - timeout_fixed_ips = False - - required_create_args = ['bridge'] - - def _allocate_fixed_ips(self, context, instance_id, host, networks, - **kwargs): - """Calls allocate_fixed_ip once for each network.""" - requested_networks = kwargs.get('requested_networks') - addresses_by_network = {} - if requested_networks is not None: - for request in requested_networks: - addresses_by_network[request.network_id] = request.address - for network in networks: - if network['uuid'] in addresses_by_network: - address = addresses_by_network[network['uuid']] - else: - address = None - self.allocate_fixed_ip(context, instance_id, - network, address=address) - - def deallocate_fixed_ip(self, context, address, host=None, teardown=True, - instance=None): - """Returns a fixed IP to the pool.""" - super(FlatManager, self).deallocate_fixed_ip(context, address, host, - teardown, - instance=instance) - objects.FixedIP.disassociate_by_address(context, address) - - def _setup_network_on_host(self, context, network): - """Setup Network on this host.""" - # NOTE(tr3buchet): this does not need to happen on every ip - # allocation, this functionality makes more sense in create_network - # but we'd have to move the flat_injected flag to compute - network.injected = CONF.flat_injected - network.save() - - def _teardown_network_on_host(self, context, network): - """Tear down network on this host.""" - pass - - # NOTE(justinsb): The floating ip functions are stub-implemented. - # We were throwing an exception, but this was messing up horizon. - # Timing makes it difficult to implement floating ips here, in Essex. - - 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 to 2.0. - return None - - 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 {} - - 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 to 2.0. - return {} - - 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 to 2.0. - return None - - 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 to 2.0. - return [] - - 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 to 2.0. - return [] - - # NOTE(hanlind): This method can be removed in version 2.0 of the RPC API - def allocate_floating_ip(self, context, project_id, pool): - """Gets a floating IP from the pool.""" - return None - - # NOTE(hanlind): This method can be removed in version 2.0 of the RPC API - def deallocate_floating_ip(self, context, address, - affect_auto_assigned): - """Returns a floating IP to the pool.""" - return None - - # NOTE(hanlind): This method can be removed in version 2.0 of the RPC API - 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. - """ - return None - - # NOTE(hanlind): This method can be removed in version 2.0 of the RPC API - 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. - """ - return None - - def migrate_instance_start(self, context, instance_uuid, - floating_addresses, - rxtx_factor=None, project_id=None, - source=None, dest=None): - pass - - def migrate_instance_finish(self, context, instance_uuid, - floating_addresses, host=None, - rxtx_factor=None, project_id=None, - source=None, dest=None): - pass - - def update_dns(self, context, network_ids): - """Called when fixed IP is allocated or deallocated.""" - pass - - -class FlatDHCPManager(RPCAllocateFixedIP, floating_ips.FloatingIP, - NetworkManager): - """Flat networking with dhcp. - - FlatDHCPManager will start up one dhcp server to give out addresses. - It never injects network settings into the guest. It also manages bridges. - Otherwise it behaves like FlatManager. - - """ - - SHOULD_CREATE_BRIDGE = True - DHCP = True - required_create_args = ['bridge'] - - def init_host(self): - """Do any initialization that needs to be run if this is a - standalone service. - """ - ctxt = context.get_admin_context() - networks = objects.NetworkList.get_by_host(ctxt, self.host) - - self.driver.iptables_manager.defer_apply_on() - - self.l3driver.initialize(fixed_range=False, networks=networks) - super(FlatDHCPManager, self).init_host() - self.init_host_floating_ips() - - self.driver.iptables_manager.defer_apply_off() - - def _setup_network_on_host(self, context, network): - """Sets up network on this host.""" - network.dhcp_server = self._get_dhcp_ip(context, network) - - self._initialize_network(network) - - # NOTE(vish): if dhcp server is not set then don't dhcp - if not CONF.fake_network and network.enable_dhcp: - dev = self.driver.get_dev(network) - # NOTE(dprince): dhcp DB queries require elevated context - elevated = context.elevated() - self.driver.update_dhcp(elevated, dev, network) - if CONF.use_ipv6: - self.driver.update_ra(context, dev, network) - gateway = get_my_linklocal(dev) - network.gateway_v6 = gateway - network.save() - - def _teardown_network_on_host(self, context, network): - # NOTE(vish): if dhcp server is not set then don't dhcp - if not CONF.fake_network and network.enable_dhcp: - network['dhcp_server'] = self._get_dhcp_ip(context, network) - dev = self.driver.get_dev(network) - # NOTE(dprince): dhcp DB queries require elevated context - elevated = context.elevated() - self.driver.update_dhcp(elevated, dev, network) - - def _get_network_dict(self, network): - """Returns the dict representing necessary and meta network fields.""" - - # get generic network fields - network_dict = super(FlatDHCPManager, self)._get_network_dict(network) - - # get flat dhcp specific fields - if self.SHOULD_CREATE_BRIDGE: - network_dict['should_create_bridge'] = self.SHOULD_CREATE_BRIDGE - if network.get('bridge_interface'): - network_dict['bridge_interface'] = network['bridge_interface'] - if network.get('multi_host'): - network_dict['multi_host'] = network['multi_host'] - - return network_dict - - -class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager): - """Vlan network with dhcp. - - VlanManager is the most complicated. It will create a host-managed - vlan for each project. Each project gets its own subnet. The networks - and associated subnets are created with nova-manage using a command like: - nova-manage network create 10.0.0.0/8 3 16. This will create 3 networks - of 16 addresses from the beginning of the 10.0.0.0 range. - - A dhcp server is run for each subnet, so each project will have its own. - For this mode to be useful, each project will need a vpn to access the - instances in its subnet. - - """ - - SHOULD_CREATE_BRIDGE = True - SHOULD_CREATE_VLAN = True - DHCP = True - required_create_args = ['bridge_interface'] - - def __init__(self, network_driver=None, *args, **kwargs): - super(VlanManager, self).__init__(network_driver=network_driver, - *args, **kwargs) - # NOTE(cfb) VlanManager doesn't enforce quotas on fixed IP addresses - # because a project is assigned an entire network. - self.quotas_cls = objects.QuotasNoOp - - def init_host(self): - """Do any initialization that needs to be run if this is a - standalone service. - """ - - LOG.debug('Setup network on host %s', self.host) - ctxt = context.get_admin_context() - networks = objects.NetworkList.get_by_host(ctxt, self.host) - - self.driver.iptables_manager.defer_apply_on() - - self.l3driver.initialize(fixed_range=False, networks=networks) - NetworkManager.init_host(self) - self.init_host_floating_ips() - - self.driver.iptables_manager.defer_apply_off() - - def allocate_fixed_ip(self, context, instance_id, network, **kwargs): - """Gets a fixed IP from the pool.""" - - LOG.debug('Allocate fixed IP on network %s', network['uuid'], - instance_uuid=instance_id) - - # NOTE(mriedem): allocate the vif before associating the - # instance to reduce a race window where a previous instance - # was associated with the fixed IP and has released it, because - # release_fixed_ip will disassociate if allocated is False. - vif = objects.VirtualInterface.get_by_instance_and_network( - context, instance_id, network['id']) - if vif is None: - LOG.debug('vif for network %(network)s and instance ' - '%(instance_id)s is used up, ' - 'trying to create new vif', - {'network': network['id'], - 'instance_id': instance_id}) - vif = self._add_virtual_interface(context, - instance_id, network['id']) - - if kwargs.get('vpn', None): - address = network['vpn_private_address'] - fip = objects.FixedIP.associate(context, str(address), - instance_id, network['id'], - reserved=True, - vif_id=vif.id) - else: - address = kwargs.get('address', None) - if address: - fip = objects.FixedIP.associate(context, str(address), - instance_id, - network['id'], - vif_id=vif.id) - else: - fip = objects.FixedIP.associate_pool( - context, network['id'], instance_id, - vif_id=vif.id) - address = fip.address - - if not kwargs.get('vpn', None): - self._do_trigger_security_group_members_refresh_for_instance( - instance_id) - - # NOTE(vish) This db query could be removed if we pass az and name - # (or the whole instance object). - instance = objects.Instance.get_by_uuid(context, instance_id) - - name = instance.display_name - if self._validate_instance_zone_for_dns_domain(context, instance): - self.instance_dns_manager.create_entry(name, address, - "A", - self.instance_dns_domain) - self.instance_dns_manager.create_entry(instance_id, address, - "A", - self.instance_dns_domain) - - self._setup_network_on_host(context, network) - LOG.debug('Allocated fixed IP %s on network %s', address, - network['uuid'], instance=instance) - return address - - def add_network_to_project(self, context, project_id, network_uuid=None): - """Force adds another network to a project.""" - LOG.debug('Add network %s to project %s', network_uuid, project_id) - if network_uuid is not None: - network_id = self.get_network(context, network_uuid).id - else: - network_id = None - objects.Network.associate(context, project_id, network_id, force=True) - - def associate(self, context, network_uuid, associations): - """Associate or disassociate host or project to network.""" - # NOTE(vish): This is no longer used but can't be removed until - # we major version the network_rpcapi to 2.0. - LOG.debug('Associate network %s: |%s|', network_uuid, associations) - network = self.get_network(context, network_uuid) - network_id = network.id - if 'host' in associations: - host = associations['host'] - if host is None: - network.disassociate(context, network_id, - host=True, project=False) - else: - network.host = self.host - network.save() - if 'project' in associations: - project = associations['project'] - if project is None: - network.disassociate(context, network_id, - host=False, project=True) - else: - network.associate(context, project, network_id, force=True) - - def _get_network_by_id(self, context, network_id): - # NOTE(vish): Don't allow access to networks with project_id=None as - # these are networks that haven't been allocated to a - # project yet. - return objects.Network.get_by_id(context, network_id, - project_only=True) - - def _get_networks_by_uuids(self, context, network_uuids): - # NOTE(vish): Don't allow access to networks with project_id=None as - # these are networks that haven't been allocated to a - # project yet. - networks = objects.NetworkList.get_by_uuids( - context, network_uuids, project_only=True) - networks.sort(key=lambda x: network_uuids.index(x.uuid)) - return networks - - def _get_networks_for_instance(self, context, instance_id, project_id, - requested_networks=None): - """Determine which networks an instance should connect to.""" - # get networks associated with project - if requested_networks is not None and len(requested_networks) != 0: - network_uuids = [request.network_id - for request in requested_networks] - networks = self._get_networks_by_uuids(context, network_uuids) - else: - # NOTE(vish): Allocates network on demand so requires admin. - networks = objects.NetworkList.get_by_project( - context.elevated(), project_id) - return networks - - def create_networks(self, context, **kwargs): - """Create networks based on parameters.""" - self._convert_int_args(kwargs) - - kwargs["vlan_start"] = kwargs.get("vlan_start") or CONF.vlan_start - kwargs["num_networks"] = (kwargs.get("num_networks") or - CONF.num_networks) - kwargs["network_size"] = (kwargs.get("network_size") or - CONF.network_size) - # Check that num_networks + vlan_start is not > 4094, fixes lp708025 - if kwargs["num_networks"] + kwargs["vlan_start"] > 4094: - raise ValueError(_('The sum between the number of networks and' - ' the vlan start cannot be greater' - ' than 4094')) - - # Check that vlan is not greater than 4094 or less then 1 - vlan_num = kwargs.get("vlan", None) - if vlan_num is not None: - try: - vlan_num = int(vlan_num) - except ValueError: - raise ValueError(_("vlan must be an integer")) - if vlan_num > 4094: - raise ValueError(_('The vlan number cannot be greater than' - ' 4094')) - if vlan_num < 1: - raise ValueError(_('The vlan number cannot be less than 1')) - - # check that num networks and network size fits in fixed_net - fixed_net = netaddr.IPNetwork(kwargs['cidr']) - if fixed_net.size < kwargs['num_networks'] * kwargs['network_size']: - raise ValueError(_('The network range is not ' - 'big enough to fit %(num_networks)s networks. Network ' - 'size is %(network_size)s') % kwargs) - - kwargs['bridge_interface'] = (kwargs.get('bridge_interface') or - CONF.vlan_interface) - LOG.debug('Create network: |%s|', kwargs) - return NetworkManager.create_networks( - self, context, vpn=True, **kwargs) - - @utils.synchronized('setup_network', external=True) - def _setup_network_on_host(self, context, network): - """Sets up network on this host.""" - if not network.vpn_public_address: - address = CONF.vpn_ip - network.vpn_public_address = address - network.save() - else: - address = network.vpn_public_address - network.dhcp_server = self._get_dhcp_ip(context, network) - - self._initialize_network(network) - - # NOTE(vish): only ensure this forward if the address hasn't been set - # manually. - if address == CONF.vpn_ip and hasattr(self.driver, - "ensure_vpn_forward"): - self.l3driver.add_vpn(CONF.vpn_ip, - network.vpn_public_port, - network.vpn_private_address) - if not CONF.fake_network: - dev = self.driver.get_dev(network) - # NOTE(dprince): dhcp DB queries require elevated context - if network.enable_dhcp: - elevated = context.elevated() - self.driver.update_dhcp(elevated, dev, network) - if CONF.use_ipv6: - self.driver.update_ra(context, dev, network) - gateway = get_my_linklocal(dev) - network.gateway_v6 = gateway - network.save() - - @utils.synchronized('setup_network', external=True) - def _teardown_network_on_host(self, context, network): - if not CONF.fake_network: - network['dhcp_server'] = self._get_dhcp_ip(context, network) - dev = self.driver.get_dev(network) - - # NOTE(ethuleau): For multi hosted networks, if the network is no - # more used on this host and if VPN forwarding rule aren't handed - # by the host, we delete the network gateway. - vpn_address = network['vpn_public_address'] - if (CONF.teardown_unused_network_gateway and - network['multi_host'] and vpn_address != CONF.vpn_ip and - not objects.Network.in_use_on_host(context, network['id'], - self.host)): - LOG.debug("Remove unused gateway %s", network['bridge']) - if network.enable_dhcp: - self.driver.kill_dhcp(dev) - self.l3driver.remove_gateway(network) - if not self._uses_shared_ip(network): - fip = objects.FixedIP.get_by_address(context, - network.dhcp_server) - fip.allocated = False - fip.host = None - fip.save() - # NOTE(vish): if dhcp server is not set then don't dhcp - elif network.enable_dhcp: - # NOTE(dprince): dhcp DB queries require elevated context - elevated = context.elevated() - self.driver.update_dhcp(elevated, dev, network) - - def _get_network_dict(self, network): - """Returns the dict representing necessary and meta network fields.""" - - # get generic network fields - network_dict = super(VlanManager, self)._get_network_dict(network) - - # get vlan specific network fields - if self.SHOULD_CREATE_BRIDGE: - network_dict['should_create_bridge'] = self.SHOULD_CREATE_BRIDGE - if self.SHOULD_CREATE_VLAN: - network_dict['should_create_vlan'] = self.SHOULD_CREATE_VLAN - for k in ['vlan', 'bridge_interface', 'multi_host']: - if network.get(k): - network_dict[k] = network[k] - - return network_dict - - @property - def _bottom_reserved_ips(self): - """Number of reserved IPs at the bottom of the range.""" - return super(VlanManager, self)._bottom_reserved_ips + 1 # vpn server - - @property - def _top_reserved_ips(self): - """Number of reserved IPs at the top of the range.""" - parent_reserved = super(VlanManager, self)._top_reserved_ips - return parent_reserved + CONF.cnt_vpn_clients diff --git a/nova/network/minidns.py b/nova/network/minidns.py deleted file mode 100644 index 5da77a53e58c..000000000000 --- a/nova/network/minidns.py +++ /dev/null @@ -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 diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index 5c579c178662..17a0fe4c31b3 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -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): diff --git a/nova/network/noop_dns_driver.py b/nova/network/noop_dns_driver.py deleted file mode 100644 index d6f2783eab9c..000000000000 --- a/nova/network/noop_dns_driver.py +++ /dev/null @@ -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 diff --git a/nova/network/rpcapi.py b/nova/network/rpcapi.py deleted file mode 100644 index ad8f2dc7a4fc..000000000000 --- a/nova/network/rpcapi.py +++ /dev/null @@ -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) diff --git a/nova/objects/__init__.py b/nova/objects/__init__.py index 621c2d2ca630..8ce1514f6f34 100644 --- a/nova/objects/__init__.py +++ b/nova/objects/__init__.py @@ -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') diff --git a/nova/objects/dns_domain.py b/nova/objects/dns_domain.py deleted file mode 100644 index b517c7ec6943..000000000000 --- a/nova/objects/dns_domain.py +++ /dev/null @@ -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) diff --git a/nova/objects/network.py b/nova/objects/network.py index ea35f938a36a..eae7824ee96b 100644 --- a/nova/objects/network.py +++ b/nova/objects/network.py @@ -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 diff --git a/nova/objects/network_request.py b/nova/objects/network_request.py index ff182195ccb8..ef07d62bf60a 100644 --- a/nova/objects/network_request.py +++ b/nova/objects/network_request.py @@ -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 + return self.network_id, address, self.port_id, self.pci_request_id - # 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) + 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) @property def auto_allocate(self): diff --git a/nova/privsep/linux_net.py b/nova/privsep/linux_net.py index 8e378b8ac8bb..12a3b11c1740 100644 --- a/nova/privsep/linux_net.py +++ b/nova/privsep/linux_net.py @@ -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) diff --git a/nova/privsep/utils.py b/nova/privsep/utils.py index 0b98a10ad493..b51bcf5926ed 100644 --- a/nova/privsep/utils.py +++ b/nova/privsep/utils.py @@ -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) diff --git a/nova/test.py b/nova/test.py index bb0010912e4d..9b7e1d7db336 100644 --- a/nova/test.py +++ b/nova/test.py @@ -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: diff --git a/nova/tests/fixtures.py b/nova/tests/fixtures.py index 86cfbbd17fe7..dd4e5c5c8a2b 100644 --- a/nova/tests/fixtures.py +++ b/nova/tests/fixtures.py @@ -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) diff --git a/nova/tests/unit/README.rst b/nova/tests/unit/README.rst deleted file mode 100644 index 8ac999c7406f..000000000000 --- a/nova/tests/unit/README.rst +++ /dev/null @@ -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 diff --git a/nova/tests/unit/api/openstack/compute/test_floating_ips.py b/nova/tests/unit/api/openstack/compute/test_floating_ips.py index 869129ab9069..751ad8b369c6 100644 --- a/nova/tests/unit/api/openstack/compute/test_floating_ips.py +++ b/nova/tests/unit/api/openstack/compute/test_floating_ips.py @@ -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): diff --git a/nova/tests/unit/conf_fixture.py b/nova/tests/unit/conf_fixture.py index 6f601fe1af05..b02d73b39e77 100644 --- a/nova/tests/unit/conf_fixture.py +++ b/nova/tests/unit/conf_fixture.py @@ -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) diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index db41157e1e4f..c05014c35e24 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -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]: diff --git a/nova/tests/unit/fake_network.py b/nova/tests/unit/fake_network.py index 62ad95e0b99d..9725b52cacf6 100644 --- a/nova/tests/unit/fake_network.py +++ b/nova/tests/unit/fake_network.py @@ -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,10 +176,9 @@ 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)]}) + ipv6_addr = 'fe80:b33f::a8bb:ccff:fedd:eeff' + info[0]['network']['subnets'].append({'cidr': 'fe80:b33f::/64', + 'ips': [_ip(ipv6_addr)]}) return jsonutils.dumps(info) @@ -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 diff --git a/nova/tests/unit/network/test_api.py b/nova/tests/unit/network/test_api.py deleted file mode 100644 index 428a0aebf55d..000000000000 --- a/nova/tests/unit/network/test_api.py +++ /dev/null @@ -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) diff --git a/nova/tests/unit/network/test_l3.py b/nova/tests/unit/network/test_l3.py deleted file mode 100644 index 9df8f49e7836..000000000000 --- a/nova/tests/unit/network/test_l3.py +++ /dev/null @@ -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) diff --git a/nova/tests/unit/network/test_linux_net.py b/nova/tests/unit/network/test_linux_net.py deleted file mode 100644 index 5aae8281b505..000000000000 --- a/nova/tests/unit/network/test_linux_net.py +++ /dev/null @@ -1,1417 +0,0 @@ -# Copyright 2011 NTT -# 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. - -import calendar -import datetime -import os - -import mock -import netifaces -from oslo_concurrency import processutils -from oslo_serialization import jsonutils -from oslo_utils import fileutils -from oslo_utils.fixture import uuidsentinel as uuids -from oslo_utils import timeutils - -import nova.conf -from nova import context -from nova.db import api as db -from nova import exception -from nova.network import driver -from nova.network import linux_net -from nova import objects -from nova import test - - -CONF = nova.conf.CONF - -instances = {uuids.instance_1: - {'id': 0, - 'uuid': uuids.instance_1, - 'host': 'fake_instance00', - 'created_at': datetime.datetime(1955, 11, 5, 0, 0, 0), - 'updated_at': datetime.datetime(1985, 10, 26, 1, 35, 0), - 'hostname': 'fake_instance00'}, - uuids.instance_2: - {'id': 1, - 'uuid': uuids.instance_2, - 'host': 'fake_instance01', - 'created_at': datetime.datetime(1955, 11, 5, 0, 0, 0), - 'updated_at': datetime.datetime(1985, 10, 26, 1, 35, 0), - 'hostname': 'fake_instance01'}, - uuids.instance_3: - {'id': 2, - 'uuid': uuids.instance_3, - 'host': 'fake_instance02', - 'created_at': datetime.datetime(1955, 11, 5, 0, 0, 0), - 'updated_at': datetime.datetime(1985, 10, 26, 1, 35, 0), - 'hostname': 'really_long_fake_instance02_to_test_hostname_' - 'truncation_when_too_long'}} - - -addresses = [{"address": "10.0.0.1"}, - {"address": "10.0.0.2"}, - {"address": "10.0.0.3"}, - {"address": "10.0.0.4"}, - {"address": "10.0.0.5"}, - {"address": "10.0.0.6"}] - - -networks = [{'id': 0, - 'uuid': "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", - 'label': 'test0', - 'injected': False, - 'multi_host': False, - 'cidr': '192.168.0.0/24', - 'cidr_v6': '2001:db8::/64', - 'gateway_v6': '2001:db8::1', - 'netmask_v6': '64', - 'netmask': '255.255.255.0', - 'bridge': 'fa0', - 'bridge_interface': 'fake_fa0', - 'gateway': '192.168.0.1', - 'broadcast': '192.168.0.255', - 'dns1': '192.168.0.1', - 'dns2': '192.168.0.2', - 'dhcp_server': '192.168.0.1', - 'dhcp_start': '192.168.100.1', - 'vlan': None, - 'host': None, - 'project_id': 'fake_project', - 'vpn_public_address': '192.168.0.2', - 'mtu': None, - 'enable_dhcp': True, - 'share_address': False}, - {'id': 1, - 'uuid': "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", - 'label': 'test1', - 'injected': False, - 'multi_host': True, - 'cidr': '192.168.1.0/24', - 'cidr_v6': '2001:db9::/64', - 'gateway_v6': '2001:db9::1', - 'netmask_v6': '64', - 'netmask': '255.255.255.0', - 'bridge': 'fa1', - 'bridge_interface': 'fake_fa1', - 'gateway': '192.168.1.1', - 'broadcast': '192.168.1.255', - 'dns1': '192.168.0.1', - 'dns2': '192.168.0.2', - 'dhcp_server': '192.168.1.1', - 'dhcp_start': '192.168.100.1', - 'vlan': None, - 'host': None, - 'project_id': 'fake_project', - 'vpn_public_address': '192.168.1.2', - 'mtu': None, - 'enable_dhcp': True, - 'share_address': False}] - - -fixed_ips = [{'id': 0, - 'network_id': 0, - 'address': '192.168.0.100', - 'instance_id': 0, - 'allocated': True, - 'leased': True, - 'virtual_interface_id': 0, - 'default_route': True, - 'instance_uuid': uuids.instance_1, - 'floating_ips': []}, - {'id': 1, - 'network_id': 1, - 'address': '192.168.1.100', - 'instance_id': 0, - 'allocated': True, - 'leased': True, - 'virtual_interface_id': 1, - 'default_route': False, - 'instance_uuid': uuids.instance_1, - 'floating_ips': []}, - {'id': 2, - 'network_id': 1, - 'address': '192.168.0.101', - 'instance_id': 1, - 'allocated': True, - 'leased': True, - 'virtual_interface_id': 2, - 'default_route': True, - 'instance_uuid': uuids.instance_2, - 'floating_ips': []}, - {'id': 3, - 'network_id': 0, - 'address': '192.168.1.101', - 'instance_id': 1, - 'allocated': True, - 'leased': True, - 'virtual_interface_id': 3, - 'default_route': False, - 'instance_uuid': uuids.instance_2, - 'floating_ips': []}, - {'id': 4, - 'network_id': 0, - 'address': '192.168.0.102', - 'instance_id': 0, - 'allocated': True, - 'leased': False, - 'virtual_interface_id': 4, - 'default_route': False, - 'instance_uuid': uuids.instance_1, - 'floating_ips': []}, - {'id': 5, - 'network_id': 1, - 'address': '192.168.1.102', - 'instance_id': 1, - 'allocated': True, - 'leased': False, - 'virtual_interface_id': 5, - 'default_route': False, - 'instance_uuid': uuids.instance_2, - 'floating_ips': []}, - {'id': 6, - 'network_id': 1, - 'address': '192.168.1.103', - 'instance_id': 1, - 'allocated': False, - 'leased': True, - 'virtual_interface_id': 6, - 'default_route': False, - 'instance_uuid': uuids.instance_2, - 'floating_ips': []}, - {'id': 7, - 'network_id': 2, - 'address': '192.168.2.100', - 'instance_id': 2, - 'allocated': True, - 'leased': False, - 'virtual_interface_id': 7, - 'default_route': False, - 'instance_uuid': uuids.instance_3, - 'floating_ips': []}] - - -vifs = [{'id': 0, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:00', - 'uuid': '00000000-0000-0000-0000-0000000000000000', - 'network_id': 0, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000000'}, - {'id': 1, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:01', - 'uuid': '00000000-0000-0000-0000-0000000000000001', - 'network_id': 1, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000000'}, - {'id': 2, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:02', - 'uuid': '00000000-0000-0000-0000-0000000000000002', - 'network_id': 1, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000001'}, - {'id': 3, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:03', - 'uuid': '00000000-0000-0000-0000-0000000000000003', - 'network_id': 0, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000001'}, - {'id': 4, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:04', - 'uuid': '00000000-0000-0000-0000-0000000000000004', - 'network_id': 0, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000000'}, - {'id': 5, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:05', - 'uuid': '00000000-0000-0000-0000-0000000000000005', - 'network_id': 1, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000001'}, - {'id': 6, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:06', - 'uuid': '00000000-0000-0000-0000-0000000000000006', - 'network_id': 1, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000001'}, - {'id': 7, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:07', - 'uuid': '00000000-0000-0000-0000-0000000000000007', - 'network_id': 2, - 'instance_uuid': '00000000-0000-0000-0000-0000000000000002'}] - - -def get_associated(context, network_id, host=None, address=None): - result = [] - for datum in fixed_ips: - if (datum['network_id'] == network_id and - datum['instance_uuid'] is not None and - datum['virtual_interface_id'] is not None): - instance = instances[datum['instance_uuid']] - if host and host != instance['host']: - continue - if address and address != datum['address']: - continue - cleaned = {} - cleaned['address'] = datum['address'] - cleaned['instance_uuid'] = datum['instance_uuid'] - cleaned['network_id'] = datum['network_id'] - cleaned['vif_id'] = datum['virtual_interface_id'] - vif = vifs[datum['virtual_interface_id']] - cleaned['vif_address'] = vif['address'] - cleaned['instance_hostname'] = instance['hostname'] - cleaned['instance_updated'] = instance['updated_at'] - cleaned['instance_created'] = instance['created_at'] - cleaned['allocated'] = datum['allocated'] - cleaned['leased'] = datum['leased'] - cleaned['default_route'] = datum['default_route'] - result.append(cleaned) - return result - - -class LinuxNetworkUtilsTestCase(test.NoDBTestCase): - def test_is_pid_cmdline_correct(self): - # Negative general case - fake_open = mock.mock_open(read_data='no-such-process') - with mock.patch.object(linux_net, 'open', fake_open, create=True): - self.assertFalse(linux_net.is_pid_cmdline_correct(1, "foo"), - "foo should not be in 'no-such-process'") - - # Negative case that would be a thing we would want to skip - fake_open = mock.mock_open( - read_data=('/usr/sbin/dnsmasq ' - '--conf-file=/var/run/NetworkManager/dnsmasq.conf')) - with mock.patch.object(linux_net, 'open', fake_open, create=True): - self.assertFalse( - linux_net.is_pid_cmdline_correct(1, "nova-br100.conf"), - "nova-br100.conf should not have been found") - - # Positive matching case - fake_open = mock.mock_open( - read_data=('/usr/sbin/dnsmasq ' - '--dhcp-hostsfile=' - '/opt/stack/data/nova/networks/nova-br100.conf')) - with mock.patch.object(linux_net, 'open', fake_open, create=True): - self.assertTrue( - linux_net.is_pid_cmdline_correct(1, "nova-br100.conf"), - 'nova-br100.conf should have been found') - - # Negative case. This would match except we throw an IOError/OSError - # because the file couldn't be read or opened, this should then fail. - for err in (IOError, OSError): - fake_open = mock.mock_open( - read_data=('/usr/sbin/dnsmasq ' - '--dhcp-hostsfile=' - '/opt/stack/data/nova/networks/nova-br100.conf')) - fake_open.side_effect = err - with mock.patch.object(linux_net, 'open', fake_open, create=True): - self.assertFalse( - linux_net.is_pid_cmdline_correct(1, "nova-br100.conf"), - 'nova-br100.conf should not have been found') - - -class LinuxNetworkTestCase(test.NoDBTestCase): - - REQUIRES_LOCKING = True - - def setUp(self): - super(LinuxNetworkTestCase, self).setUp() - self.driver = driver.load_network_driver() - self.driver.db = db - self.context = context.RequestContext('testuser', 'testproject', - is_admin=True) - - def get_vifs(_context, instance_uuid, use_slave): - return [vif for vif in vifs if vif['instance_uuid'] == - instance_uuid] - - def get_instance(_context, instance_id): - return instances[instance_id] - - self.stub_out('nova.db.api.virtual_interface_get_by_instance', - get_vifs) - self.stub_out('nova.db.api.instance_get', get_instance) - self.stub_out('nova.db.api.network_get_associated_fixed_ips', - get_associated) - - @mock.patch.object(linux_net.iptables_manager.ipv4['nat'], 'add_rule') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def _test_add_snat_rule(self, expected, is_external, - mock_iptables_set_rules, mock_iptables_get_rules, - mock_add_rule): - - def verify_add_rule(chain, rule): - self.assertEqual('snat', chain) - self.assertEqual(expected, rule) - self.called = True - - mock_add_rule.side_effect = verify_add_rule - - self.called = False - linux_net.add_snat_rule('10.0.0.0/24', is_external) - if expected: - mock_add_rule.assert_called_once_with('snat', expected) - self.assertTrue(self.called) - - def test_add_snat_rule_no_ext(self): - self.flags(routing_source_ip='10.10.10.1') - expected = ('-s 10.0.0.0/24 -d 0.0.0.0/0 ' - '-j SNAT --to-source 10.10.10.1 -o eth0') - self._test_add_snat_rule(expected, False) - - def test_add_snat_rule_ext(self): - self.flags(routing_source_ip='10.10.10.1') - expected = () - self._test_add_snat_rule(expected, True) - - def test_add_snat_rule_snat_range_no_ext(self): - self.flags(routing_source_ip='10.10.10.1', - force_snat_range=['10.10.10.0/24']) - expected = ('-s 10.0.0.0/24 -d 0.0.0.0/0 ' - '-j SNAT --to-source 10.10.10.1 -o eth0') - self._test_add_snat_rule(expected, False) - - def test_add_snat_rule_snat_range_ext(self): - self.flags(routing_source_ip='10.10.10.1', - force_snat_range=['10.10.10.0/24']) - expected = ('-s 10.0.0.0/24 -d 10.10.10.0/24 ' - '-j SNAT --to-source 10.10.10.1') - self._test_add_snat_rule(expected, True) - - @mock.patch.object(fileutils, 'ensure_tree') - @mock.patch.object(os, 'chmod') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.restart_dnsmasq') - def test_update_dhcp_for_nw00(self, mock_restart_dnsmasq, - mock_iptables_set_rules, - mock_iptables_get_rules, mock_chmod, - mock_ensure_tree): - with mock.patch.object(self.driver, 'write_to_file') \ - as mock_write_to_file: - self.flags(use_single_default_gateway=True) - - self.driver.update_dhcp(self.context, "eth0", networks[0]) - - self.assertEqual(mock_write_to_file.call_count, 2) - self.assertEqual(mock_ensure_tree.call_count, 7) - self.assertEqual(mock_chmod.call_count, 2) - self.assertEqual(mock_restart_dnsmasq.call_count, 1) - - @mock.patch.object(fileutils, 'ensure_tree') - @mock.patch.object(os, 'chmod') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.restart_dnsmasq') - def test_update_dhcp_for_nw01(self, mock_restart_dnsmasq, - mock_iptables_set_rules, - mock_iptables_get_rules, mock_chmod, - mock_ensure_tree): - with mock.patch.object(self.driver, 'write_to_file') \ - as mock_write_to_file: - self.flags(use_single_default_gateway=True) - - self.driver.update_dhcp(self.context, "eth0", networks[0]) - - self.assertEqual(mock_write_to_file.call_count, 2) - self.assertEqual(mock_ensure_tree.call_count, 7) - self.assertEqual(mock_chmod.call_count, 2) - self.assertEqual(mock_restart_dnsmasq.call_count, 1) - - def _get_fixedips(self, network, host=None): - return objects.FixedIPList.get_by_network(self.context, - network, - host=host) - - def test_get_dhcp_hosts_for_nw00(self): - self.flags(use_single_default_gateway=True) - - expected = ( - "DE:AD:BE:EF:00:00,fake_instance00.novalocal," - "192.168.0.100,net:NW-0\n" - "DE:AD:BE:EF:00:03,fake_instance01.novalocal," - "192.168.1.101,net:NW-3\n" - "DE:AD:BE:EF:00:04,fake_instance00.novalocal," - "192.168.0.102,net:NW-4" - ) - fixedips = self._get_fixedips(networks[0]) - actual_hosts = self.driver.get_dhcp_hosts(self.context, networks[0], - fixedips) - - self.assertEqual(expected, actual_hosts) - - def test_get_dhcp_hosts_for_nw01(self): - self.flags(use_single_default_gateway=True) - - expected = ( - "DE:AD:BE:EF:00:02,fake_instance01.novalocal," - "192.168.0.101,net:NW-2\n" - "DE:AD:BE:EF:00:05,fake_instance01.novalocal," - "192.168.1.102,net:NW-5" - ) - fixedips = self._get_fixedips(networks[1], host='fake_instance01') - actual_hosts = self.driver.get_dhcp_hosts(self.context, networks[1], - fixedips) - self.assertEqual(expected, actual_hosts) - - def test_get_dns_hosts_for_nw00(self): - expected = ( - "192.168.0.100\tfake_instance00.novalocal\n" - "192.168.1.101\tfake_instance01.novalocal\n" - "192.168.0.102\tfake_instance00.novalocal" - ) - actual_hosts = self.driver.get_dns_hosts(self.context, networks[0]) - self.assertEqual(expected, actual_hosts) - - def test_get_dns_hosts_for_nw01(self): - expected = ( - "192.168.1.100\tfake_instance00.novalocal\n" - "192.168.0.101\tfake_instance01.novalocal\n" - "192.168.1.102\tfake_instance01.novalocal" - ) - actual_hosts = self.driver.get_dns_hosts(self.context, networks[1]) - self.assertEqual(expected, actual_hosts) - - def test_get_dhcp_opts_for_nw00(self): - self.flags(use_single_default_gateway=True) - expected_opts = 'NW-0,3,192.168.0.1\nNW-3,3\nNW-4,3' - fixedips = self._get_fixedips(networks[0]) - actual_opts = self.driver.get_dhcp_opts(self.context, networks[0], - fixedips) - - self.assertEqual(expected_opts, actual_opts) - - def test_get_dhcp_opts_for_nw00_no_single_default_gateway(self): - self.flags(use_single_default_gateway=False) - expected_opts = '3,192.168.0.1' - fixedips = self._get_fixedips(networks[0]) - actual_opts = self.driver.get_dhcp_opts(self.context, networks[0], - fixedips) - - self.assertEqual(expected_opts, actual_opts) - - def test_get_dhcp_opts_for_nw01(self): - self.flags(use_single_default_gateway=True) - expected_opts = "NW-2,3,192.168.1.1\nNW-5,3" - fixedips = self._get_fixedips(networks[1], 'fake_instance01') - actual_opts = self.driver.get_dhcp_opts(self.context, networks[1], - fixedips) - - self.assertEqual(expected_opts, actual_opts) - - def test_get_dhcp_leases_for_nw00(self): - timestamp = timeutils.utcnow() - seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) - - leases = self.driver.get_dhcp_leases(self.context, networks[0]) - leases = leases.split('\n') - for lease in leases: - lease = lease.split(' ') - data = get_associated(self.context, 0, address=lease[2])[0] - self.assertTrue(data['allocated']) - self.assertTrue(data['leased']) - self.assertGreater(int(lease[0]), seconds_since_epoch) - self.assertEqual(data['vif_address'], lease[1]) - self.assertEqual(data['address'], lease[2]) - self.assertEqual(data['instance_hostname'], lease[3]) - self.assertEqual('*', lease[4]) - - def test_get_dhcp_leases_for_nw01(self): - self.flags(host='fake_instance01') - timestamp = timeutils.utcnow() - seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) - - leases = self.driver.get_dhcp_leases(self.context, networks[1]) - leases = leases.split('\n') - for lease in leases: - lease = lease.split(' ') - data = get_associated(self.context, 1, address=lease[2])[0] - self.assertTrue(data['leased']) - self.assertGreater(int(lease[0]), seconds_since_epoch) - self.assertEqual(data['vif_address'], lease[1]) - self.assertEqual(data['address'], lease[2]) - self.assertEqual(data['instance_hostname'], lease[3]) - self.assertEqual('*', lease[4]) - - def test_dhcp_opts_not_default_gateway_network(self): - expected = "NW-0,3" - fixedip = objects.FixedIPList.get_by_network(self.context, - {'id': 0})[0] - actual = self.driver._host_dhcp_opts(fixedip.virtual_interface_id) - self.assertEqual(expected, actual) - - def test_host_dhcp_without_default_gateway_network(self): - expected = ','.join(['DE:AD:BE:EF:00:00', - 'fake_instance00.novalocal', - '192.168.0.100']) - fixedip = objects.FixedIPList.get_by_network(self.context, - {'id': 0})[0] - actual = self.driver._host_dhcp(fixedip) - self.assertEqual(expected, actual) - - def test_host_dhcp_truncated_hostname(self): - expected = ','.join(['DE:AD:BE:EF:00:07', - 're-ng_fake_instance02_to_test_hostname_' - 'truncation_when_too_long.novalocal', - '192.168.2.100']) - fixedip = objects.FixedIPList.get_by_network(self.context, - {'id': 2})[0] - actual = self.driver._host_dhcp(fixedip) - self.assertEqual(expected, actual) - - def test_host_dns_without_default_gateway_network(self): - expected = "192.168.0.100\tfake_instance00.novalocal" - fixedip = objects.FixedIPList.get_by_network(self.context, - {'id': 0})[0] - actual = self.driver._host_dns(fixedip) - self.assertEqual(expected, actual) - - @mock.patch.object(linux_net.iptables_manager.ipv4['filter'], 'add_rule') - @mock.patch('nova.privsep.linux_net.add_bridge', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.routes_show', - return_value=('fake', 0)) - @mock.patch('nova.privsep.linux_net.lookup_ip', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - @mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')) - def test_linux_bridge_driver_plug( - self, mock_bridge_add_interface, mock_bridge_disable_stp, - mock_bridge_setfd, mock_iptables_set_rules, - mock_iptables_get_rules, mock_lookup_ip, mock_routes_show, - mock_enabled, mock_add_bridge, mock_add_rule): - """Makes sure plug doesn't drop FORWARD by default. - - Ensures bug 890195 doesn't reappear. - """ - - def verify_add_rule(chain, rule): - self.assertEqual('FORWARD', chain) - self.assertIn('ACCEPT', rule) - - mock_add_rule.side_effect = verify_add_rule - - driver = linux_net.LinuxBridgeInterfaceDriver() - driver.plug({"bridge": "br100", "bridge_interface": "eth0", - "share_address": False}, "fakemac") - self.assertEqual(2, mock_add_rule.call_count) - - @mock.patch('nova.privsep.linux_net.device_exists', - return_value=False) - @mock.patch('nova.privsep.linux_net.ovs_plug', - side_effect=exception.OVSConfigurationFailure('foo')) - def test_linux_ovs_driver_plug_exception(self, mock_plug, - mock_device_exists): - self.flags(fake_network=False) - - driver = linux_net.LinuxOVSInterfaceDriver() - - self.assertRaises(exception.OVSConfigurationFailure, - driver.plug, {'uuid': 'fake_network_uuid'}, - 'fake_mac') - mock_plug.assert_called_once() - mock_device_exists.assert_called_once() - - @mock.patch.object(linux_net.LinuxBridgeInterfaceDriver, - 'ensure_vlan_bridge') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_vlan_override(self, mock_iptables_set_rules, - mock_iptables_get_rules, mock_ensure_vlan_bridge): - """Makes sure vlan_interface flag overrides network bridge_interface. - - Allows heterogeneous networks a la bug 833426 - """ - - driver = linux_net.LinuxBridgeInterfaceDriver() - - info = {} - - def test_ensure(vlan, bridge, interface, network, mac_address, mtu): - info['passed_interface'] = interface - - mock_ensure_vlan_bridge.side_effect = test_ensure - - network = { - "bridge": "br100", - "bridge_interface": "base_interface", - "share_address": False, - "vlan": "fake" - } - self.flags(vlan_interface="") - driver.plug(network, "fakemac") - self.assertEqual("base_interface", info['passed_interface']) - self.flags(vlan_interface="override_interface") - driver.plug(network, "fakemac") - self.assertEqual("override_interface", info['passed_interface']) - driver.plug(network, "fakemac") - self.assertEqual(3, mock_ensure_vlan_bridge.call_count) - - @mock.patch.object(linux_net.LinuxBridgeInterfaceDriver, 'ensure_bridge') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_flat_override(self, mock_iptables_set_rules, - mock_iptables_get_rules, mock_ensure_bridge): - """Makes sure flat_interface flag overrides network bridge_interface. - - Allows heterogeneous networks a la bug 833426 - """ - - driver = linux_net.LinuxBridgeInterfaceDriver() - - info = {} - - def test_ensure(bridge, interface, network, gateway): - info['passed_interface'] = interface - - mock_ensure_bridge.side_effect = test_ensure - - network = { - "bridge": "br100", - "bridge_interface": "base_interface", - "share_address": False, - } - driver.plug(network, "fakemac") - self.assertEqual("base_interface", info['passed_interface']) - self.flags(flat_interface="override_interface") - driver.plug(network, "fakemac") - self.assertEqual("override_interface", info['passed_interface']) - self.assertEqual(2, mock_ensure_bridge.call_count) - - @mock.patch.object(linux_net, '_dnsmasq_pid_for') - @mock.patch.object(linux_net, 'write_to_file') - @mock.patch('os.chmod') - @mock.patch.object(linux_net, '_add_dhcp_mangle_rule') - @mock.patch('oslo_concurrency.processutils.execute') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.restart_dnsmasq', - side_effect=nova.privsep.linux_net._restart_dnsmasq_inner) - def _test_dnsmasq_execute(self, mock_restart_dnsmasq, - mock_iptables_set_rules, - mock_iptables_get_rules, mock_execute, - mock_add_dhcp_mangle_rule, - mock_chmod, mock_write_to_file, - mock_dnsmasq_pid_for, extra_expected=None): - network_ref = {'id': 'fake', - 'label': 'fake', - 'gateway': '10.0.0.1', - 'multi_host': False, - 'cidr': '10.0.0.0/24', - 'netmask': '255.255.255.0', - 'dns1': '8.8.4.4', - 'dhcp_start': '1.0.0.2', - 'dhcp_server': '10.0.0.1', - 'share_address': False} - - def fake_execute(*args, **kwargs): - executes.append(args) - return "", "" - - def fake_add_dhcp_mangle_rule(*args, **kwargs): - executes.append(args) - - mock_execute.side_effect = fake_execute - mock_add_dhcp_mangle_rule.side_effect = fake_add_dhcp_mangle_rule - - dev = 'br100' - - default_domain = CONF.api.dhcp_domain - for domain in ('', default_domain): - executes = [] - self.flags(dhcp_domain=domain, group='api') - fixedips = self._get_fixedips(network_ref) - linux_net.restart_dhcp(self.context, dev, network_ref, fixedips) - expected = ['env', - 'CONFIG_FILE=%s' % jsonutils.dumps(CONF.dhcpbridge_flagfile), - 'NETWORK_ID=fake', - 'dnsmasq', - '--strict-order', - '--bind-interfaces', - '--conf-file=%s' % CONF.dnsmasq_config_file, - '--pid-file=%s' % linux_net._dhcp_file(dev, 'pid'), - '--dhcp-optsfile=%s' % linux_net._dhcp_file(dev, 'opts'), - '--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'], - CONF.dhcp_lease_time), - '--dhcp-lease-max=256', - '--dhcp-hostsfile=%s' % linux_net._dhcp_file(dev, 'conf'), - '--dhcp-script=%s' % CONF.dhcpbridge, - '--no-hosts', - '--leasefile-ro'] - - if CONF.api.dhcp_domain: - expected.append('--domain=%s' % CONF.api.dhcp_domain) - - if extra_expected: - expected += extra_expected - self.assertEqual([(dev,), tuple(expected)], executes) - self.assertEqual(2, mock_execute.call_count) - self.assertEqual(2, mock_add_dhcp_mangle_rule.call_count) - self.assertEqual(4, mock_chmod.call_count) - self.assertEqual(2, mock_write_to_file.call_count) - self.assertEqual(2, mock_dnsmasq_pid_for.call_count) - - def test_dnsmasq_execute(self): - self._test_dnsmasq_execute() - - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_dnsmasq_execute_dns_servers(self, mock_iptables_set_rules, - mock_iptables_get_rules): - self.flags(dns_server=['1.1.1.1', '2.2.2.2']) - expected = [ - '--no-resolv', - '--server=1.1.1.1', - '--server=2.2.2.2', - ] - self._test_dnsmasq_execute(extra_expected=expected) - - def test_dnsmasq_execute_use_network_dns_servers(self): - self.flags(use_network_dns_servers=True) - expected = [ - '--no-resolv', - '--server=8.8.4.4', - ] - self._test_dnsmasq_execute(extra_expected=expected) - - @mock.patch('nova.privsep.linux_net.modify_ebtables') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_isolated_host(self, mock_iptables_set_rules, - mock_iptables_get_rules, mock_modify_ebtables): - self.flags(fake_network=False, - share_dhcp_address=True) - driver = linux_net.LinuxBridgeInterfaceDriver() - - def fake_ensure(bridge, interface, network, gateway): - return bridge - - self.stub_out('nova.network.linux_net.iptables_manager', - linux_net.IptablesManager()) - self.stub_out('nova.network.linux_net.binary_name', 'test') - self.stub_out( - 'nova.network.linux_net.LinuxBridgeInterfaceDriver.ensure_bridge', - fake_ensure) - - iface = 'eth0' - dhcp = '192.168.1.1' - network = {'dhcp_server': dhcp, - 'share_address': False, - 'bridge': 'br100', - 'bridge_interface': iface} - driver.plug(network, 'fakemac') - - mock_iptables_get_rules.assert_has_calls([ - mock.call(ipv4=True), - mock.call(ipv4=False)]) - mock_iptables_set_rules.assert_has_calls([ - mock.call(mock.ANY, ipv4=True), - mock.call(mock.ANY, ipv4=False)]) - mock_modify_ebtables.assert_has_calls([ - mock.call('filter', - ['INPUT', '-p', 'ARP', '-i', iface, '--arp-ip-dst', - dhcp, '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['INPUT', '-p', 'ARP', '-i', iface, '--arp-ip-dst', - dhcp, '-j', 'DROP'], - insert_rule=True), - mock.call('filter', - ['OUTPUT', '-p', 'ARP', '-o', iface, '--arp-ip-src', - dhcp, '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['OUTPUT', '-p', 'ARP', '-o', iface, '--arp-ip-src', - dhcp, '-j', 'DROP'], - insert_rule=True), - mock.call('filter', - ['FORWARD', '-p', 'IPv4', '-i', iface, '--ip-protocol', - 'udp', '--ip-destination-port', '67:68', '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['FORWARD', '-p', 'IPv4', '-i', iface, '--ip-protocol', - 'udp', '--ip-destination-port', '67:68', '-j', 'DROP'], - insert_rule=True), - mock.call('filter', - ['FORWARD', '-p', 'IPv4', '-o', iface, '--ip-protocol', - 'udp', '--ip-destination-port', '67:68', '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['FORWARD', '-p', 'IPv4', '-o', iface, '--ip-protocol', - 'udp', '--ip-destination-port', '67:68', '-j', 'DROP'], - insert_rule=True)]) - - mock_modify_ebtables.reset_mock() - - def fake_remove(bridge, gateway): - return - - self.stub_out( - 'nova.network.linux_net.LinuxBridgeInterfaceDriver.remove_bridge', - fake_remove) - - driver.unplug(network) - mock_modify_ebtables.assert_has_calls([ - mock.call('filter', - ['INPUT', '-p', 'ARP', '-i', iface, '--arp-ip-dst', - dhcp, '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['OUTPUT', '-p', 'ARP', '-o', iface, '--arp-ip-src', - dhcp, '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['FORWARD', '-p', 'IPv4', '-i', iface, '--ip-protocol', - 'udp', '--ip-destination-port', '67:68', '-j', 'DROP'], - insert_rule=False), - mock.call('filter', - ['FORWARD', '-p', 'IPv4', '-o', iface, '--ip-protocol', - 'udp', '--ip-destination-port', '67:68', '-j', 'DROP'], - insert_rule=False)]) - - @mock.patch('nova.privsep.linux_net.routes_show') - @mock.patch('nova.privsep.linux_net.route_delete') - @mock.patch('nova.privsep.linux_net.route_add_deprecated') - @mock.patch('nova.privsep.linux_net.lookup_ip') - @mock.patch('nova.privsep.linux_net.change_ip') - @mock.patch('nova.privsep.linux_net.address_command_deprecated') - def _test_initialize_gateway(self, existing, - mock_address_command, mock_change_ip, - mock_lookup_ip, mock_route_add, - mock_route_delete, mock_routes, - routes='', - routes_show_called=True, deleted_routes=None, - added_routes=None, changed_interfaces=None, - address_commands=None): - self.flags(fake_network=False) - mock_lookup_ip.return_value = (existing, '') - - mock_routes.return_value = (routes, '') - mock_lookup_ip.return_value = (existing, '') - - network = {'dhcp_server': '192.168.1.1', - 'cidr': '192.168.1.0/24', - 'broadcast': '192.168.1.255', - 'cidr_v6': '2001:db8::/64'} - self.driver.initialize_gateway_device('eth0', network) - self.assertTrue(mock_lookup_ip.called) - - if routes_show_called: - mock_routes.assert_called_once_with('eth0') - if deleted_routes: - mock_route_delete.assert_has_calls(deleted_routes) - if added_routes: - mock_route_add.assert_has_calls(added_routes) - if changed_interfaces: - mock_change_ip.assert_has_calls(changed_interfaces) - if address_commands: - mock_address_command.assert_has_calls(address_commands) - - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=True) - def test_initialize_gateway_moves_wrong_ip(self, mock_forwarding_check): - existing = ("2: eth0: " - " mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n" - " link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n" - " inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\n" - " inet6 dead::beef:dead:beef:dead/64 scope link\n" - " valid_lft forever preferred_lft forever\n") - self._test_initialize_gateway( - existing, - changed_interfaces=[mock.call('eth0', '2001:db8::/64')], - address_commands=[ - mock.call('eth0', 'del', ['192.168.0.1/24', 'brd', - '192.168.0.255', - 'scope', 'global']), - mock.call('eth0', 'add', ['192.168.1.1/24', 'brd', - '192.168.1.255']), - mock.call('eth0', 'add', ['192.168.0.1/24', 'brd', - '192.168.0.255', - 'scope', 'global'])] - ) - - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=True) - def test_initialize_gateway_ip_with_dynamic_flag(self, - mock_forwarding_check): - existing = ("2: eth0: " - " mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n" - " link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n" - " inet 192.168.0.1/24 brd 192.168.0.255 scope global " - "dynamic eth0\n" - " inet6 dead::beef:dead:beef:dead/64 scope link\n" - " valid_lft forever preferred_lft forever\n") - self._test_initialize_gateway( - existing, - changed_interfaces=[mock.call('eth0', '2001:db8::/64')], - address_commands=[ - mock.call('eth0', 'del', - ['192.168.0.1/24', 'brd', '192.168.0.255', - 'scope', 'global']), - mock.call('eth0', 'add', - ['192.168.1.1/24', 'brd', '192.168.1.255']), - mock.call('eth0', 'add', - ['192.168.0.1/24', 'brd', '192.168.0.255', - 'scope', 'global'])] - ) - - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=True) - def test_initialize_gateway_resets_route(self, mock_forwarding_check): - routes = ("default via 192.168.0.1 dev eth0\n" - "192.168.100.0/24 via 192.168.0.254 dev eth0 proto static\n") - existing = ("2: eth0: " - " mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n" - " link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n" - " inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\n" - " inet6 dead::beef:dead:beef:dead/64 scope link\n" - " valid_lft forever preferred_lft forever\n") - self._test_initialize_gateway( - existing, routes=routes, - deleted_routes=[mock.call('eth0', 'default'), - mock.call('eth0', '192.168.100.0/24')], - added_routes=[mock.call(['default', 'via', '192.168.0.1', - 'dev', 'eth0']), - mock.call(['192.168.100.0/24', 'via', - '192.168.0.254', - 'dev', 'eth0', 'proto', 'static'])], - changed_interfaces=[mock.call('eth0', '2001:db8::/64')], - address_commands=[ - mock.call('eth0', 'del', - ['192.168.0.1/24', 'brd', '192.168.0.255', - 'scope', 'global']), - mock.call('eth0', 'add', - ['192.168.1.1/24', 'brd', '192.168.1.255']), - mock.call('eth0', 'add', - ['192.168.0.1/24', 'brd', '192.168.0.255', - 'scope', 'global'])] - ) - - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=True) - def test_initialize_gateway_no_move_right_ip(self, mock_forwarding_check): - existing = ("2: eth0: " - " mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n" - " link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n" - " inet 192.168.1.1/24 brd 192.168.1.255 scope global eth0\n" - " inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\n" - " inet6 dead::beef:dead:beef:dead/64 scope link\n" - " valid_lft forever preferred_lft forever\n") - self._test_initialize_gateway( - existing, routes_show_called=False, - changed_interfaces=[mock.call('eth0', '2001:db8::/64')]) - mock_forwarding_check.assert_called() - - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=True) - def test_initialize_gateway_add_if_blank(self, mock_forwarding_check): - existing = ("2: eth0: " - " mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n" - " link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n" - " inet6 dead::beef:dead:beef:dead/64 scope link\n" - " valid_lft forever preferred_lft forever\n") - self._test_initialize_gateway( - existing, - changed_interfaces=[mock.call('eth0', '2001:db8::/64')], - address_commands=[ - mock.call('eth0', 'add', - ['192.168.1.1/24', 'brd', '192.168.1.255'])] - ) - - @mock.patch.object(linux_net, 'ensure_ebtables_rules') - @mock.patch.object(linux_net.iptables_manager, 'apply') - def test_ensure_floating_no_duplicate_forwards(self, mock_apply, - mock_ensure_ebtables_rules): - ln = linux_net - - mock_apply.side_effect = lambda: None - mock_ensure_ebtables_rules.side_effect = lambda *a, **kw: None - - net = {'bridge': 'br100', 'cidr': '10.0.0.0/24'} - ln.ensure_floating_forward('10.10.10.10', '10.0.0.1', 'eth0', net) - ln.ensure_floating_forward('10.10.10.11', '10.0.0.10', 'eth0', net) - two_forward_rules = len(linux_net.iptables_manager.ipv4['nat'].rules) - ln.ensure_floating_forward('10.10.10.10', '10.0.0.3', 'eth0', net) - dup_forward_rules = len(linux_net.iptables_manager.ipv4['nat'].rules) - self.assertEqual(two_forward_rules, dup_forward_rules) - self.assertEqual(3, mock_apply.call_count) - self.assertEqual(3, mock_ensure_ebtables_rules.call_count) - - def test_apply_ran(self): - manager = linux_net.IptablesManager() - manager.iptables_apply_deferred = False - with mock.patch.object(manager, '_apply') as mock_apply: - empty_ret = manager.apply() - mock_apply.assert_called_once() - self.assertIsNone(empty_ret) - - def test_apply_not_run(self): - manager = linux_net.IptablesManager() - manager.iptables_apply_deferred = True - with mock.patch.object(manager, '_apply') as mock_apply: - manager.apply() - mock_apply.assert_not_called() - - def test_deferred_unset_apply_ran(self): - manager = linux_net.IptablesManager() - manager.iptables_apply_deferred = True - with mock.patch.object(manager, '_apply') as mock_apply: - manager.defer_apply_off() - mock_apply.assert_called_once() - self.assertFalse(manager.iptables_apply_deferred) - - @mock.patch.object(linux_net.iptables_manager.ipv4['filter'], 'add_rule') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def _test_add_metadata_accept_rule(self, expected, mock_iptables_set_rules, - mock_iptables_get_rules, mock_add_rule): - def verify_add_rule(chain, rule): - self.assertEqual('INPUT', chain) - self.assertEqual(expected, rule) - - mock_add_rule.side_effect = verify_add_rule - linux_net.metadata_accept() - mock_add_rule.assert_called_once() - - @mock.patch.object(linux_net.iptables_manager.ipv6['filter'], 'add_rule') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def _test_add_metadata_accept_ipv6_rule(self, expected, - mock_iptables_set_rules, - mock_iptables_get_rules, - mock_add_rule): - def verify_add_rule(chain, rule): - self.assertEqual('INPUT', chain) - self.assertEqual(expected, rule) - - mock_add_rule.side_effect = verify_add_rule - linux_net.metadata_accept() - mock_add_rule.assert_called_once() - - def test_metadata_accept(self): - self.flags(metadata_port='8775') - self.flags(metadata_host='10.10.10.1') - expected = ('-p tcp -m tcp --dport 8775 ' - '-d 10.10.10.1 -j ACCEPT') - self._test_add_metadata_accept_rule(expected) - - def test_metadata_accept_ipv6(self): - self.flags(metadata_port='8775') - self.flags(metadata_host='2600::') - expected = ('-p tcp -m tcp --dport 8775 ' - '-d 2600:: -j ACCEPT') - self._test_add_metadata_accept_ipv6_rule(expected) - - def test_metadata_accept_localhost(self): - self.flags(metadata_port='8775') - self.flags(metadata_host='127.0.0.1') - expected = ('-p tcp -m tcp --dport 8775 ' - '-m addrtype --dst-type LOCAL -j ACCEPT') - self._test_add_metadata_accept_rule(expected) - - def test_metadata_accept_ipv6_localhost(self): - self.flags(metadata_port='8775') - self.flags(metadata_host='::1') - expected = ('-p tcp -m tcp --dport 8775 ' - '-m addrtype --dst-type LOCAL -j ACCEPT') - self._test_add_metadata_accept_ipv6_rule(expected) - - @mock.patch.object(linux_net.iptables_manager.ipv4['nat'], 'add_rule') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def _test_add_metadata_forward_rule(self, expected, - mock_iptables_set_rules, - mock_iptables_get_rules, - mock_add_rule): - def verify_add_rule(chain, rule): - self.assertEqual('PREROUTING', chain) - self.assertEqual(expected, rule) - - mock_add_rule.side_effect = verify_add_rule - linux_net.metadata_forward() - mock_add_rule.assert_called_once() - - def test_metadata_forward(self): - self.flags(metadata_port='8775') - self.flags(metadata_host='10.10.10.1') - expected = ('-s 0.0.0.0/0 -d 169.254.169.254/32 -p tcp -m tcp ' - '--dport 80 -j DNAT --to-destination 10.10.10.1:8775') - self._test_add_metadata_forward_rule(expected) - - def test_metadata_forward_localhost(self): - self.flags(metadata_port='8775') - self.flags(metadata_host='127.0.0.1') - expected = ('-s 0.0.0.0/0 -d 169.254.169.254/32 -p tcp -m tcp ' - '--dport 80 -j REDIRECT --to-ports 8775') - self._test_add_metadata_forward_rule(expected) - - def test_ensure_bridge_brings_up_interface(self): - # We have to bypass the CONF.fake_network check so that netifaces - # is actually called. - self.flags(fake_network=False) - fake_mac = 'aa:bb:cc:00:11:22' - fake_ifaces = { - netifaces.AF_LINK: [{'addr': fake_mac}] - } - with test.nested( - mock.patch('nova.privsep.linux_net.lookup_ip', - return_value=('', '')), - mock.patch('nova.privsep.linux_net.device_exists', - return_value=True), - mock.patch('nova.privsep.linux_net.set_device_enabled'), - mock.patch('nova.privsep.linux_net.set_device_macaddr'), - mock.patch('nova.privsep.linux_net.routes_show', - return_value=('fake', '')), - mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')), - mock.patch.object(netifaces, 'ifaddresses') - ) as (lookup_ip, device_exists, device_enabled, set_device_macaddr, - routes_show, add_interface, ifaddresses): - ifaddresses.return_value = fake_ifaces - driver = linux_net.LinuxBridgeInterfaceDriver() - driver.ensure_bridge('bridge', 'eth0') - device_exists.assert_has_calls( - [mock.call('bridge')]) - add_interface.assert_has_calls( - [mock.call('bridge', 'eth0')]) - ifaddresses.assert_called_once_with('eth0') - device_enabled.assert_called_once_with('eth0') - set_device_macaddr.assert_called_once_with('bridge', fake_mac) - lookup_ip.assert_called_once_with('eth0') - - def test_ensure_bridge_brclt_addif_exception(self): - with test.nested( - mock.patch('nova.privsep.linux_net.device_exists', - return_value=True), - mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', 'some error happens')) - ) as (device_exists, _): - driver = linux_net.LinuxBridgeInterfaceDriver() - self.assertRaises(exception.NovaException, - driver.ensure_bridge, 'bridge', 'eth0') - device_exists.assert_called_once_with('bridge') - - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - def test_ensure_bridge_brclt_addbr_neutron_race( - self, mock_bridge_disable_stp, mock_bridge_setfd, mock_enabled): - def fake_execute(*cmd, **kwargs): - if ('brctl', 'addbr', 'brq1234567-89') == cmd: - return ('', "device brq1234567-89 already exists; " - "can't create bridge with the same name\n") - else: - return ('', '') - - with test.nested( - mock.patch('nova.privsep.linux_net.device_exists', - return_value=False), - mock.patch('nova.privsep.linux_net.add_bridge', fake_execute) - ) as (device_exists, _): - driver = linux_net.LinuxBridgeInterfaceDriver() - driver.ensure_bridge('brq1234567-89', '') - device_exists.assert_called_once_with('brq1234567-89') - - @mock.patch('nova.privsep.linux_net.modify_ebtables', - return_value=('', '')) - def test_exec_ebtables_success(self, mock_modify_ebtables): - self.driver._exec_ebtables('fake', 'fake') - mock_modify_ebtables.assert_called() - - @mock.patch('nova.privsep.linux_net.modify_ebtables', - side_effect=processutils.ProcessExecutionError( - 'error', - stderr=(u'Unable to update the kernel. Two possible ' - 'causes:\n1. Multiple ebtables programs were ' - 'executing simultaneously. The ebtables\n ' - 'userspace tool doesn\'t by default support ' - 'multiple ebtables programs running\n ' - 'concurrently. The ebtables option --concurrent ' - 'or a tool like flock can be\n used to support ' - 'concurrent scripts that update the ebtables ' - 'kernel tables.\n2. The kernel doesn\'t support ' - 'a certain ebtables extension, consider\n ' - 'recompiling your kernel or insmod the ' - 'extension.\n.\n'))) - @mock.patch('time.sleep') - def test_exec_ebtables_fail_all(self, mock_sleep, mock_modify_ebtables): - self.flags(ebtables_exec_attempts=5) - self.assertRaises(processutils.ProcessExecutionError, - self.driver._exec_ebtables, 'fake', 'fake') - self.assertEqual(5, mock_modify_ebtables.call_count) - - @mock.patch('nova.privsep.linux_net.modify_ebtables', - side_effect=processutils.ProcessExecutionError( - 'error', - stderr=(u'Sorry, rule does not exist'))) - @mock.patch('time.sleep') - def test_exec_ebtables_fail_no_retry(self, mock_sleep, - mock_modify_ebtables): - self.assertRaises(processutils.ProcessExecutionError, - self.driver._exec_ebtables, 'fake', 'fake') - mock_modify_ebtables.assert_called() - - @mock.patch('nova.privsep.linux_net.modify_ebtables', - side_effect=[ - processutils.ProcessExecutionError( - 'error', - stderr=(u'Unable to update the kernel. Two possible ' - 'causes:\n1. Multiple ebtables programs were ' - 'executing simultaneously. The ebtables\n ' - 'userspace tool doesn\'t by default support ' - 'multiple ebtables programs running\n ' - 'concurrently. The ebtables option ' - '--concurrent or a tool like flock can be\n ' - 'used to support concurrent scripts that ' - 'update the ebtables kernel tables.\n2. The ' - 'kernel doesn\'t support a certain ebtables ' - 'extension, consider\n recompiling your ' - 'kernel or insmod the extension.\n.\n')), - ('', '')]) - @mock.patch('time.sleep') - def test_exec_ebtables_fail_once(self, mock_sleep, mock_modify_ebtables): - self.driver._exec_ebtables('fake', 'fake') - self.assertEqual(2, mock_modify_ebtables.call_count) - - @mock.patch('os.path.exists', return_value=True) - @mock.patch('nova.privsep.linux_net.set_device_disabled') - @mock.patch('nova.privsep.linux_net.delete_bridge') - def test_remove_bridge(self, mock_delete, mock_disabled, mock_exists): - linux_net.LinuxBridgeInterfaceDriver.remove_bridge('fake-bridge') - - self.assertIn(mock.call('/sys/class/net/fake-bridge'), - mock_exists.mock_calls) - mock_disabled.assert_called_once_with('fake-bridge') - mock_delete.assert_called_once_with('fake-bridge') - - @mock.patch('nova.privsep.linux_net.device_exists', return_value=False) - @mock.patch('nova.privsep.linux_net.set_device_mtu') - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.set_device_macaddr') - @mock.patch('nova.privsep.linux_net.add_vlan') - def test_ensure_vlan(self, mock_add_vlan, mock_set_macaddr, - mock_set_enabled, mock_set_device_mtu, - mock_device_exists): - interface = linux_net.LinuxBridgeInterfaceDriver.ensure_vlan( - 1, 'eth0', 'MAC', 'MTU', "vlan_name") - self.assertEqual("vlan_name", interface) - mock_device_exists.assert_called_once_with('vlan_name') - - mock_add_vlan.assert_called_once_with('eth0', 'vlan_name', 1) - mock_set_device_mtu.assert_called_once_with('vlan_name', 'MTU') - mock_set_enabled.assert_called_once_with('vlan_name') - mock_set_macaddr.assert_called_once_with('vlan_name', 'MAC') - - @mock.patch('nova.privsep.linux_net.device_exists', return_value=True) - @mock.patch('nova.privsep.linux_net.set_device_mtu') - def test_ensure_vlan_device_exists(self, mock_set_device_mtu, - mock_device_exists): - interface = linux_net.LinuxBridgeInterfaceDriver.ensure_vlan(1, 'eth0') - self.assertEqual("vlan1", interface) - mock_device_exists.assert_called_once_with('vlan1') - mock_set_device_mtu.assert_called_once_with('vlan1', None) - - @mock.patch('os.path.exists', return_value=True) - @mock.patch('nova.privsep.linux_net.set_device_disabled', - side_effect=processutils.ProcessExecutionError()) - def test_remove_bridge_negative(self, mock_device_disabled, mock_exists): - self.assertRaises(processutils.ProcessExecutionError, - linux_net.LinuxBridgeInterfaceDriver.remove_bridge, - 'fake-bridge') - - @mock.patch('nova.pci.utils.get_vf_num_by_pci_address') - @mock.patch('nova.pci.utils.get_ifname_by_pci_address') - @mock.patch('nova.privsep.linux_net.set_device_trust', - side_effect=nova.privsep.linux_net._set_device_trust_inner) - @mock.patch('oslo_concurrency.processutils.execute') - def test_set_vf_trusted_on(self, mexecute, mtrust, mget_ifname, - mget_vfnum): - mget_ifname.return_value = 'eth0' - mget_vfnum.return_value = 2 - linux_net.set_vf_trusted('PCI_ADDR', True) - mexecute.assert_called_once_with( - 'ip', 'link', 'set', 'eth0', 'vf', 2, 'trust', 'on', - check_exit_code=[0, 2, 254]) - - @mock.patch('nova.pci.utils.get_vf_num_by_pci_address') - @mock.patch('nova.pci.utils.get_ifname_by_pci_address') - @mock.patch('nova.privsep.linux_net.set_device_trust', - side_effect=nova.privsep.linux_net._set_device_trust_inner) - @mock.patch('oslo_concurrency.processutils.execute') - def test_set_vf_trusted_off(self, mexecute, mtrust, mget_ifname, - mget_vfnum): - mget_ifname.return_value = 'eth0' - mget_vfnum.return_value = 2 - linux_net.set_vf_trusted('PCI_ADDR', False) - mexecute.assert_called_once_with( - 'ip', 'link', 'set', 'eth0', 'vf', 2, 'trust', 'off', - check_exit_code=[0, 2, 254]) diff --git a/nova/tests/unit/network/test_manager.py b/nova/tests/unit/network/test_manager.py deleted file mode 100644 index eb498ac50840..000000000000 --- a/nova/tests/unit/network/test_manager.py +++ /dev/null @@ -1,3823 +0,0 @@ -# Copyright 2011 Rackspace -# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. -# 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. - -import fixtures -import mock -from mox3 import mox -import netaddr -from oslo_concurrency import processutils -from oslo_config import cfg -from oslo_db import exception as db_exc -from oslo_log import log as logging -import oslo_messaging as messaging -from oslo_utils.fixture import uuidsentinel as uuids -from oslo_utils import importutils -from oslo_utils import netutils -import six -import testtools - -from nova import context -from nova.db import api as db -from nova.db.sqlalchemy import models -from nova import exception -from nova import ipv6 -from nova.network import floating_ips -from nova.network import linux_net -from nova.network import manager as network_manager -from nova.network import rpcapi as network_rpcapi -from nova import objects -from nova.objects import network as network_obj -from nova.objects import virtual_interface as vif_obj -from nova import test -from nova.tests.unit.api.openstack import fakes -from nova.tests.unit import fake_instance -from nova.tests.unit import fake_ldap -from nova.tests.unit import fake_network -from nova.tests.unit.objects import test_fixed_ip -from nova.tests.unit.objects import test_floating_ip -from nova.tests.unit.objects import test_network -from nova.tests.unit.objects import test_service -from nova import utils - - -CONF = cfg.CONF -LOG = logging.getLogger(__name__) - - -HOST = "testhost" -FAKEUUID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" - - -fake_inst = fake_instance.fake_db_instance - - -networks = [{'id': 0, - 'uuid': FAKEUUID, - 'label': 'test0', - 'injected': False, - 'multi_host': False, - 'cidr': '192.168.0.0/24', - 'cidr_v6': '2001:db8::/64', - 'gateway_v6': '2001:db8::1', - 'netmask_v6': '64', - 'netmask': '255.255.255.0', - 'bridge': 'fa0', - 'bridge_interface': 'fake_fa0', - 'gateway': '192.168.0.1', - 'dhcp_server': '192.168.0.1', - 'broadcast': '192.168.0.255', - 'dns1': '192.168.0.1', - 'dns2': '192.168.0.2', - 'vlan': None, - 'host': HOST, - 'project_id': fakes.FAKE_PROJECT_ID, - 'vpn_public_address': '192.168.0.2', - 'vpn_public_port': '22', - 'vpn_private_address': '10.0.0.2'}, - {'id': 1, - 'uuid': 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - 'label': 'test1', - 'injected': False, - 'multi_host': False, - 'cidr': '192.168.1.0/24', - 'cidr_v6': '2001:db9::/64', - 'gateway_v6': '2001:db9::1', - 'netmask_v6': '64', - 'netmask': '255.255.255.0', - 'bridge': 'fa1', - 'bridge_interface': 'fake_fa1', - 'gateway': '192.168.1.1', - 'dhcp_server': '192.168.1.1', - 'broadcast': '192.168.1.255', - 'dns1': '192.168.0.1', - 'dns2': '192.168.0.2', - 'vlan': None, - 'host': HOST, - 'project_id': fakes.FAKE_PROJECT_ID, - 'vpn_public_address': '192.168.1.2', - 'vpn_public_port': '22', - 'vpn_private_address': '10.0.0.2'}] - -fixed_ips = [{'id': 0, - 'network_id': 0, - 'address': '192.168.0.100', - 'instance_uuid': 0, - 'allocated': False, - 'virtual_interface_id': 0, - 'floating_ips': []}, - {'id': 0, - 'network_id': 1, - 'address': '192.168.1.100', - 'instance_uuid': 0, - 'allocated': False, - 'virtual_interface_id': 0, - 'floating_ips': []}, - {'id': 0, - 'network_id': 1, - 'address': '2001:db9:0:1::10', - 'instance_uuid': 0, - 'allocated': False, - 'virtual_interface_id': 0, - 'floating_ips': []}] - - -flavor = {'id': 0, - 'rxtx_cap': 3} - - -floating_ip_fields = {'id': 0, - 'address': '192.168.10.100', - 'pool': 'nova', - 'interface': 'eth0', - 'fixed_ip_id': 0, - 'project_id': None, - 'auto_assigned': False} - -vifs = [{'id': 0, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:00', - 'uuid': uuids.vif1_uuid, - 'network_id': 0, - 'instance_uuid': uuids.instance, - 'tag': 'fake-tag1'}, - {'id': 1, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:01', - 'uuid': '00000000-0000-0000-0000-0000000000000001', - 'network_id': 1, - 'instance_uuid': uuids.instance, - 'tag': 'fake-tag2'}, - {'id': 2, - 'created_at': None, - 'updated_at': None, - 'deleted_at': None, - 'deleted': 0, - 'address': 'DE:AD:BE:EF:00:02', - 'uuid': '00000000-0000-0000-0000-0000000000000002', - 'network_id': 2, - 'instance_uuid': uuids.instance, - 'tag': 'fake-tag3'}] - - -class FlatNetworkTestCase(test.TestCase): - - REQUIRES_LOCKING = True - - def setUp(self): - super(FlatNetworkTestCase, self).setUp() - self.tempdir = self.useFixture(fixtures.TempDir()).path - self.flags(log_dir=self.tempdir) - self.network = network_manager.FlatManager(host=HOST) - self.network.instance_dns_domain = '' - self.network.db = db - self.context = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=False) - - def test_validate_networks(self): - self.mox.StubOutWithMock(db, 'fixed_ip_get_by_address') - - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - '192.168.1.100'), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - '192.168.0.100')] - - ip = dict(test_fixed_ip.fake_fixed_ip, **fixed_ips[1]) - ip['network'] = dict(test_network.fake_network, - **networks[1]) - ip['instance_uuid'] = None - db.fixed_ip_get_by_address(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=mox.IgnoreArg() - ).AndReturn(ip) - ip = dict(test_fixed_ip.fake_fixed_ip, **fixed_ips[0]) - ip['network'] = dict(test_network.fake_network, - **networks[0]) - ip['instance_uuid'] = None - db.fixed_ip_get_by_address(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=mox.IgnoreArg() - ).AndReturn(ip) - - self.mox.ReplayAll() - self.network.validate_networks(self.context, requested_networks) - - def test_validate_networks_valid_fixed_ipv6(self): - self.mox.StubOutWithMock(db, 'fixed_ip_get_by_address') - - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - '2001:db9:0:1::10')] - - ip = dict(test_fixed_ip.fake_fixed_ip, **fixed_ips[2]) - ip['network'] = dict(test_network.fake_network, - **networks[1]) - ip['instance_uuid'] = None - db.fixed_ip_get_by_address(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=mox.IgnoreArg() - ).AndReturn(ip) - - self.mox.ReplayAll() - self.network.validate_networks(self.context, requested_networks) - - def test_validate_reserved(self): - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - nets = self.network.create_networks(context_admin, 'fake', - '192.168.0.0/24', False, 1, - 256, None, None, None, None, None) - self.assertEqual(1, len(nets)) - network = nets[0] - self.assertEqual(4, db.network_count_reserved_ips(context_admin, - network['id'])) - - def test_validate_reserved_start_end(self): - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - nets = self.network.create_networks(context_admin, 'fake', - '192.168.0.0/24', False, 1, - 256, dhcp_server='192.168.0.11', - allowed_start='192.168.0.10', - allowed_end='192.168.0.245') - self.assertEqual(1, len(nets)) - network = nets[0] - # gateway defaults to beginning of allowed_start - self.assertEqual('192.168.0.10', network['gateway']) - # vpn_server doesn't conflict with dhcp_start - self.assertEqual('192.168.0.12', network['vpn_private_address']) - # dhcp_start doesn't conflict with dhcp_server - self.assertEqual('192.168.0.13', network['dhcp_start']) - # NOTE(vish): 10 from the beginning, 10 from the end, and - # 1 for the gateway, 1 for the dhcp server, - # 1 for the vpn server - self.assertEqual(23, db.network_count_reserved_ips(context_admin, - network['id'])) - - def test_validate_reserved_start_out_of_range(self): - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - self.assertRaises(exception.AddressOutOfRange, - self.network.create_networks, - context_admin, 'fake', '192.168.0.0/24', False, - 1, 256, allowed_start='192.168.1.10') - - def test_validate_reserved_end_invalid(self): - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - self.assertRaises(exception.InvalidAddress, - self.network.create_networks, - context_admin, 'fake', '192.168.0.0/24', False, - 1, 256, allowed_end='invalid') - - def test_validate_cidr_invalid(self): - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - self.assertRaises(exception.InvalidCidr, - self.network.create_networks, - context_admin, 'fake', 'invalid', False, - 1, 256) - - def test_validate_non_int_size(self): - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - self.assertRaises(exception.InvalidIntValue, - self.network.create_networks, - context_admin, 'fake', '192.168.0.0/24', False, - 1, 'invalid') - - def test_validate_networks_none_requested_networks(self): - self.network.validate_networks(self.context, None) - - def test_validate_networks_empty_requested_networks(self): - requested_networks = [] - self.mox.ReplayAll() - - self.network.validate_networks(self.context, requested_networks) - - def test_validate_networks_invalid_fixed_ip(self): - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - '192.168.1.100.1'), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - '192.168.0.100.1')] - self.mox.ReplayAll() - - self.assertRaises(exception.FixedIpInvalid, - self.network.validate_networks, self.context, - requested_networks) - - def test_validate_networks_empty_fixed_ip(self): - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - ''), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - '')] - self.mox.ReplayAll() - - self.assertRaises(exception.FixedIpInvalid, - self.network.validate_networks, - self.context, requested_networks) - - def test_validate_networks_none_fixed_ip(self): - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - None), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - None)] - self.mox.ReplayAll() - - self.network.validate_networks(self.context, requested_networks) - - @mock.patch('nova.objects.fixed_ip.FixedIPList.get_by_instance_uuid') - def test_get_instance_nw_info(self, get): - - def make_ip(index): - vif = objects.VirtualInterface(uuid=uuids.vif1_uuid, address=index) - network = objects.Network(uuid=uuids.network_1, - bridge=index, - label=index, - project_id=fakes.FAKE_PROJECT_ID, - injected=False, - netmask='255.255.255.0', - dns1=None, - dns2=None, - cidr_v6=None, - gateway_v6=None, - broadcast_v6=None, - netmask_v6=None, - rxtx_base=None, - gateway='192.168.%s.1' % index, - dhcp_server='192.168.%s.1' % index, - broadcast='192.168.%s.255' % index, - cidr='192.168.%s.0/24' % index) - return objects.FixedIP(virtual_interface=vif, - network=network, - floating_ips=objects.FloatingIPList(), - address='192.168.%s.2' % index) - objs = [make_ip(index) for index in ('3', '1', '2')] - get.return_value = objects.FixedIPList(objects=objs) - nw_info = self.network.get_instance_nw_info(self.context, None, - None, None) - for i, vif in enumerate(nw_info): - self.assertEqual(objs[i].network.bridge, vif['network']['bridge']) - - @mock.patch.object(objects.Network, 'get_by_id') - def test_add_fixed_ip_instance_using_id_without_vpn(self, get_by_id): - # Allocate a fixed ip from a network and assign it to an instance. - # Network is given by network id. - - network_id = networks[0]['id'] - - with mock.patch.object(self.network, - 'allocate_fixed_ip') as allocate_fixed_ip: - self.network.add_fixed_ip_to_instance(self.context, FAKEUUID, HOST, - network_id) - - # Assert that we fetched the network by id, not uuid - get_by_id.assert_called_once_with(self.context, - network_id, project_only='allow_none') - - # Assert that we called allocate_fixed_ip for the given network and - # instance. We should not have requested a specific address from the - # network. - allocate_fixed_ip.assert_called_once_with(self.context, FAKEUUID, - get_by_id.return_value, - address=None) - - @mock.patch.object(objects.Network, 'get_by_uuid') - def test_add_fixed_ip_instance_using_uuid_without_vpn(self, get_by_uuid): - # Allocate a fixed ip from a network and assign it to an instance. - # Network is given by network uuid. - - network_uuid = networks[0]['uuid'] - - with mock.patch.object(self.network, - 'allocate_fixed_ip') as allocate_fixed_ip,\ - mock.patch.object(self.context, 'elevated', - return_value=mock.sentinel.elevated): - self.network.add_fixed_ip_to_instance(self.context, FAKEUUID, HOST, - network_uuid) - - # Assert that we fetched the network by uuid, not id, and with elevated - # context - get_by_uuid.assert_called_once_with(mock.sentinel.elevated, - network_uuid) - - # Assert that we called allocate_fixed_ip for the given network and - # instance. We should not have requested a specific address from the - # network. - allocate_fixed_ip.assert_called_once_with(self.context, - FAKEUUID, - get_by_uuid.return_value, - address=None) - - def test_mini_dns_driver(self): - zone1 = "example.org" - zone2 = "example.com" - driver = self.network.instance_dns_manager - driver.create_entry("hostone", "10.0.0.1", "A", zone1) - driver.create_entry("hosttwo", "10.0.0.2", "A", zone1) - driver.create_entry("hostthree", "10.0.0.3", "A", zone1) - driver.create_entry("hostfour", "10.0.0.4", "A", zone1) - driver.create_entry("hostfive", "10.0.0.5", "A", zone2) - - driver.delete_entry("hostone", zone1) - driver.modify_address("hostfour", "10.0.0.1", zone1) - driver.modify_address("hostthree", "10.0.0.1", zone1) - names = driver.get_entries_by_address("10.0.0.1", zone1) - self.assertEqual(2, len(names)) - self.assertIn('hostthree', names) - self.assertIn('hostfour', names) - - names = driver.get_entries_by_address("10.0.0.5", zone2) - self.assertEqual(1, len(names)) - self.assertIn('hostfive', names) - - addresses = driver.get_entries_by_name("hosttwo", zone1) - self.assertEqual(1, len(addresses)) - self.assertIn('10.0.0.2', addresses) - - self.assertRaises(exception.InvalidInput, - driver.create_entry, - "hostname", - "10.10.10.10", - "invalidtype", - zone1) - - def test_mini_dns_driver_with_mixed_case(self): - zone1 = "example.org" - driver = self.network.instance_dns_manager - driver.create_entry("HostTen", "10.0.0.10", "A", zone1) - addresses = driver.get_entries_by_address("10.0.0.10", zone1) - self.assertEqual(1, len(addresses)) - for n in addresses: - driver.delete_entry(n, zone1) - addresses = driver.get_entries_by_address("10.0.0.10", zone1) - self.assertEqual(0, len(addresses)) - - def test_allocate_fixed_ip_instance_dns(self): - # Test DNS entries are created when allocating a fixed IP. - # Allocate a fixed IP to an instance. Ensure that dns entries have been - # created for the instance's name and uuid. - - network = network_obj.Network._from_db_object( - self.context, network_obj.Network(), test_network.fake_network) - network.save = mock.MagicMock() - - # Create a minimal instance object - instance_params = { - 'display_name': HOST, - 'security_groups': [] - } - instance = fake_instance.fake_instance_obj( - context.RequestContext('ignore', 'ignore'), - expected_attrs=instance_params.keys(), **instance_params) - instance.save = mock.MagicMock() - - # We don't specify a specific address, so we should get a FixedIP - # automatically allocated from the pool. Fix its value here. - fip = objects.FixedIP(address='192.168.0.101') - fip.save = mock.MagicMock() - - with mock.patch.object(objects.Instance, 'get_by_uuid', - return_value=instance),\ - mock.patch.object(objects.FixedIP, 'associate_pool', - return_value=fip): - self.network.allocate_fixed_ip(self.context, FAKEUUID, network) - - instance_manager = self.network.instance_dns_manager - expected_addresses = ['192.168.0.101'] - - # Assert that we have a correct entry by instance display name - addresses = instance_manager.get_entries_by_name(HOST, - self.network.instance_dns_domain) - self.assertEqual(expected_addresses, addresses) - - # Assert that we have a correct entry by instance uuid - addresses = instance_manager.get_entries_by_name(FAKEUUID, - self.network.instance_dns_domain) - self.assertEqual(expected_addresses, addresses) - - def test_allocate_floating_ip(self): - self.assertIsNone(self.network.allocate_floating_ip(self.context, - 1, None)) - - def test_deallocate_floating_ip(self): - self.assertIsNone(self.network.deallocate_floating_ip(self.context, - 1, None)) - - def test_associate_floating_ip(self): - self.assertIsNone(self.network.associate_floating_ip(self.context, - None, None)) - - def test_disassociate_floating_ip(self): - self.assertIsNone(self.network.disassociate_floating_ip(self.context, - None, None)) - - def test_get_networks_by_uuids_ordering(self): - self.mox.StubOutWithMock(db, 'network_get_all_by_uuids') - - requested_networks = ['bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'] - db.network_get_all_by_uuids(mox.IgnoreArg(), mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn( - [dict(test_network.fake_network, **net) - for net in networks]) - - self.mox.ReplayAll() - res = self.network._get_networks_by_uuids(self.context, - requested_networks) - - self.assertEqual(1, res[0]['id']) - self.assertEqual(0, res[1]['id']) - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.quotas.Quotas.check_deltas') - @mock.patch('nova.objects.quotas.ids_from_instance') - def test_allocate_calculates_quota_auth(self, util_method, check, - get_by_uuid): - inst = objects.Instance() - inst['uuid'] = uuids.instance - get_by_uuid.return_value = inst - check.side_effect = exception.OverQuota(overs='testing', - quotas={'fixed_ips': 10}, - usages={'fixed_ips': 10}) - util_method.return_value = ('foo', 'bar') - self.assertRaises(exception.FixedIpLimitExceeded, - self.network.allocate_fixed_ip, - self.context, 123, {'uuid': uuids.instance}) - util_method.assert_called_once_with(self.context, inst) - - @mock.patch('nova.objects.fixed_ip.FixedIP.disassociate') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate_pool') - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.quotas.Quotas.check_deltas') - @mock.patch('nova.objects.quotas.ids_from_instance') - def test_allocate_over_quota_during_recheck(self, util_method, check, - get_by_uuid, associate, - disassociate): - inst = objects.Instance() - inst['uuid'] = uuids.instance - get_by_uuid.return_value = inst - - # Simulate a race where the first check passes and the recheck fails. - check.side_effect = [None, exception.OverQuota( - overs='fixed_ips', quotas={'fixed_ips': 10}, - usages={'fixed_ips': 10})] - - util_method.return_value = ('foo', 'bar') - address = netaddr.IPAddress('1.2.3.4') - fip = objects.FixedIP(instance_uuid=inst.uuid, - address=address, - virtual_interface_id=1) - associate.return_value = fip - - network = network_obj.Network._from_db_object( - self.context, network_obj.Network(), test_network.fake_network) - network.save = mock.MagicMock() - self.assertRaises(exception.FixedIpLimitExceeded, - self.network.allocate_fixed_ip, - self.context, inst.uuid, network) - - self.assertEqual(2, check.call_count) - call1 = mock.call(self.context, {'fixed_ips': 1}, 'foo') - call2 = mock.call(self.context, {'fixed_ips': 0}, 'foo') - check.assert_has_calls([call1, call2]) - - # Verify we removed the fixed IP that was added after the first quota - # check passed. - disassociate.assert_called_once_with() - - @mock.patch('nova.objects.fixed_ip.FixedIP.associate_pool') - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.quotas.Quotas.check_deltas') - @mock.patch('nova.objects.quotas.ids_from_instance') - def test_allocate_no_quota_recheck(self, util_method, check, get_by_uuid, - associate): - # Disable recheck_quota. - self.flags(recheck_quota=False, group='quota') - - inst = objects.Instance() - inst['uuid'] = uuids.instance - inst['display_name'] = 'test' - get_by_uuid.return_value = inst - - util_method.return_value = ('foo', 'bar') - network = network_obj.Network._from_db_object( - self.context, network_obj.Network(), test_network.fake_network) - network.save = mock.MagicMock() - - @mock.patch.object(self.network, '_setup_network_on_host') - @mock.patch.object(self.network, 'instance_dns_manager') - @mock.patch.object(self.network, - '_do_trigger_security_group_members_refresh_for_instance') - def _test(trigger, dns, setup): - self.network.allocate_fixed_ip(self.context, inst.uuid, network) - - _test() - - # check_deltas should have been called only once. - check.assert_called_once_with(self.context, {'fixed_ips': 1}, 'foo') - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate') - def test_allocate_fixed_ip_passes_string_address(self, mock_associate, - mock_get): - mock_associate.side_effect = test.TestingException - instance = objects.Instance(context=self.context) - instance.create() - mock_get.return_value = instance - self.assertRaises(test.TestingException, - self.network.allocate_fixed_ip, - self.context, instance.uuid, - {'cidr': '24', 'id': 1, 'uuid': uuids.instance}, - address=netaddr.IPAddress('1.2.3.4')) - mock_associate.assert_called_once_with(self.context, - '1.2.3.4', - instance.uuid, - 1, - vif_id=1) - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.virtual_interface.VirtualInterface' - '.get_by_instance_and_network') - @mock.patch('nova.objects.fixed_ip.FixedIP.disassociate') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate') - @mock.patch('nova.objects.fixed_ip.FixedIP.save') - def test_allocate_fixed_ip_cleanup(self, - mock_fixedip_save, - mock_fixedip_associate, - mock_fixedip_disassociate, - mock_vif_get, - mock_instance_get): - address = netaddr.IPAddress('1.2.3.4') - - fip = objects.FixedIP(instance_uuid=uuids.instance, - address=address, - virtual_interface_id=1) - mock_fixedip_associate.return_value = fip - - instance = objects.Instance(context=self.context) - instance.create() - mock_instance_get.return_value = instance - - mock_vif_get.return_value = vif_obj.VirtualInterface( - instance_uuid=uuids.instance, id=1) - - with test.nested( - mock.patch.object(self.network, '_setup_network_on_host'), - mock.patch.object(self.network, 'instance_dns_manager'), - mock.patch.object(self.network, - '_do_trigger_security_group_members_refresh_for_instance') - ) as (mock_setup_network, mock_dns_manager, mock_ignored): - mock_setup_network.side_effect = test.TestingException - self.assertRaises(test.TestingException, - self.network.allocate_fixed_ip, - self.context, instance.uuid, - {'cidr': '24', 'id': 1, - 'uuid': uuids.instance}, - address=address) - - mock_dns_manager.delete_entry.assert_has_calls([ - mock.call(instance.display_name, ''), - mock.call(instance.uuid, '') - ]) - - mock_fixedip_disassociate.assert_called_once_with() - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.virtual_interface.VirtualInterface' - '.get_by_instance_and_network') - @mock.patch('nova.objects.fixed_ip.FixedIP.disassociate') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate_pool') - @mock.patch('nova.network.manager.NetworkManager._add_virtual_interface') - def test_allocate_fixed_ip_create_new_vifs(self, - mock_add, - mock_fixedip_associate, - mock_fixedip_disassociate, - mock_vif_get, - mock_instance_get): - address = netaddr.IPAddress('1.2.3.4') - - fip = objects.FixedIP(instance_uuid=uuids.instance, - address=address, - virtual_interface_id=1000) - net = {'cidr': '24', 'id': 1, 'uuid': uuids.instance} - instance = objects.Instance(context=self.context) - instance.create() - - vif = objects.VirtualInterface(context, - id=1000, - address='00:00:00:00:00:00', - instance_uuid=instance.uuid, - network_id=net['id'], - uuid=uuids.instance) - mock_fixedip_associate.return_value = fip - mock_add.return_value = vif - mock_instance_get.return_value = instance - mock_vif_get.return_value = None - - with test.nested( - mock.patch.object(self.network, '_setup_network_on_host'), - mock.patch.object(self.network, 'instance_dns_manager'), - mock.patch.object(self.network, - '_do_trigger_security_group_members_refresh_for_instance') - ) as (mock_setup_network, mock_dns_manager, mock_ignored): - self.network.allocate_fixed_ip(self.context, instance['uuid'], - net) - mock_add.assert_called_once_with(self.context, instance['uuid'], - net['id']) - self.assertEqual(fip.virtual_interface_id, vif.id) - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch.object(db, 'virtual_interface_get_by_instance_and_network', - return_value=None) - @mock.patch('nova.objects.fixed_ip.FixedIP') - def test_allocate_fixed_ip_add_vif_fails(self, mock_fixedip, - mock_get_vif, mock_instance_get): - # Tests that we don't try to do anything with fixed IPs if - # _add_virtual_interface fails. - instance = fake_instance.fake_instance_obj(self.context) - mock_instance_get.return_value = instance - network = {'cidr': '24', 'id': 1, - 'uuid': '398399b3-f696-4859-8695-a6560e14cb02'} - vif_error = exception.VirtualInterfaceMacAddressException() - # mock out quotas because we don't care in this test - with mock.patch.object(self.network, 'quotas_cls', objects.QuotasNoOp): - with mock.patch.object(self.network, '_add_virtual_interface', - side_effect=vif_error): - self.assertRaises( - exception.VirtualInterfaceMacAddressException, - self.network.allocate_fixed_ip, self.context, - '9d2ee1e3-ffad-4e5f-81ff-c96dd97b0ee0', network) - self.assertFalse(mock_fixedip.called, str(mock_fixedip.mock_calls)) - - -class FlatDHCPNetworkTestCase(test.TestCase): - - REQUIRES_LOCKING = True - - def setUp(self): - super(FlatDHCPNetworkTestCase, self).setUp() - self.useFixture(test.SampleNetworks()) - self.network = network_manager.FlatDHCPManager(host=HOST) - self.network.db = db - self.context = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=False) - self.context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - - @mock.patch('nova.objects.fixed_ip.FixedIP.get_by_id') - @mock.patch('nova.objects.floating_ip.FloatingIPList.get_by_host') - @mock.patch('nova.network.linux_net.iptables_manager._apply') - @mock.patch('nova.privsep.linux_net.bind_ip') - @mock.patch('nova.privsep.linux_net.modify_ebtables') - def test_init_host_iptables_defer_apply(self, modify_ebtables, - bind_ip, iptable_apply, - floating_get_by_host, - fixed_get_by_id): - def get_by_id(context, fixed_ip_id, **kwargs): - net = objects.Network(bridge='testbridge', - cidr='192.168.1.0/24') - if fixed_ip_id == 1: - return objects.FixedIP(address='192.168.1.4', - network=net) - elif fixed_ip_id == 2: - return objects.FixedIP(address='192.168.1.5', - network=net) - - def fake_apply(): - fake_apply.count += 1 - - fake_apply.count = 0 - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=True) - float1 = objects.FloatingIP(address='1.2.3.4', fixed_ip_id=1) - float2 = objects.FloatingIP(address='1.2.3.5', fixed_ip_id=2) - float1._context = ctxt - float2._context = ctxt - - iptable_apply.side_effect = fake_apply - floating_get_by_host.return_value = [float1, float2] - fixed_get_by_id.side_effect = get_by_id - - self.network.init_host() - self.assertEqual(1, fake_apply.count) - - -class VlanNetworkTestCase(test.TestCase): - - REQUIRES_LOCKING = True - - def setUp(self): - super(VlanNetworkTestCase, self).setUp() - self.useFixture(test.SampleNetworks()) - self.network = network_manager.VlanManager(host=HOST) - self.network.db = db - self.context = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=False) - self.context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - - def test_quota_driver_type(self): - self.assertEqual(objects.QuotasNoOp, - self.network.quotas_cls) - - @mock.patch('nova.privsep.linux_net.add_bridge', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.routes_show', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.lookup_ip', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.change_ip') - @mock.patch('nova.privsep.linux_net.address_command_deprecated') - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=False) - @mock.patch('nova.privsep.linux_net._enable_ipv4_forwarding_inner') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - @mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')) - def test_vpn_allocate_fixed_ip( - self, mock_bridge_add_interface, mock_bridge_disable_stp, - mock_bridge_setfd, mock_iptables_set_rules, - mock_iptables_get_rules, mock_forwarding_enable, - mock_forwarding_check, mock_address_command, mock_change_ip, - mock_lookup_ip, mock_routes_show, mock_enabled, mock_add_bridge): - self.mox.StubOutWithMock(db, 'fixed_ip_associate') - self.mox.StubOutWithMock(db, 'fixed_ip_update') - self.mox.StubOutWithMock(db, - 'virtual_interface_get_by_instance_and_network') - self.mox.StubOutWithMock(db, 'instance_get_by_uuid') - - fixed = dict(test_fixed_ip.fake_fixed_ip, - address='192.168.0.1') - db.fixed_ip_associate(mox.IgnoreArg(), - mox.IgnoreArg(), - mox.IgnoreArg(), - network_id=mox.IgnoreArg(), - reserved=True, - virtual_interface_id=vifs[0]['id'] - ).AndReturn(fixed) - db.virtual_interface_get_by_instance_and_network(mox.IgnoreArg(), - mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(vifs[0]) - db.instance_get_by_uuid(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=['info_cache', - 'security_groups'] - ).AndReturn(fake_inst(display_name=HOST, - uuid=FAKEUUID)) - self.mox.ReplayAll() - - network = objects.Network._from_db_object( - self.context, objects.Network(), - dict(test_network.fake_network, **networks[0])) - network.vpn_private_address = '192.168.0.2' - self.network.allocate_fixed_ip(self.context, FAKEUUID, network, - vpn=True) - - @mock.patch('nova.privsep.linux_net.add_bridge', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.routes_show', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.lookup_ip', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.change_ip') - @mock.patch('nova.privsep.linux_net.address_command_deprecated') - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=False) - @mock.patch('nova.privsep.linux_net._enable_ipv4_forwarding_inner') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - @mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')) - def test_allocate_fixed_ip( - self, mock_bridge_add_interface, mock_bridge_disable_stp, - mock_bridge_setfd, mock_iptables_set_rules, - mock_iptables_get_rules, mock_forwarding_enable, - mock_forwarding_check, mock_address_command, mock_change_ip, - mock_lookup_ip, mock_routes_show, mock_enabled, mock_add_bridge): - self.stubs.Set(self.network, - '_do_trigger_security_group_members_refresh_for_instance', - lambda *a, **kw: None) - self.mox.StubOutWithMock(db, 'fixed_ip_associate_pool') - self.mox.StubOutWithMock(db, - 'virtual_interface_get_by_instance_and_network') - self.mox.StubOutWithMock(db, 'instance_get_by_uuid') - - fixed = dict(test_fixed_ip.fake_fixed_ip, - address='192.168.0.1') - db.fixed_ip_associate_pool(mox.IgnoreArg(), - mox.IgnoreArg(), - instance_uuid=mox.IgnoreArg(), - host=None, - virtual_interface_id=vifs[0]['id'] - ).AndReturn(fixed) - db.virtual_interface_get_by_instance_and_network(mox.IgnoreArg(), - mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(vifs[0]) - db.instance_get_by_uuid(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=['info_cache', - 'security_groups'] - ).AndReturn(fake_inst(display_name=HOST, - uuid=FAKEUUID)) - self.mox.ReplayAll() - - network = objects.Network._from_db_object( - self.context, objects.Network(), - dict(test_network.fake_network, **networks[0])) - network.vpn_private_address = '192.168.0.2' - self.network.allocate_fixed_ip(self.context, FAKEUUID, network) - - @mock.patch('nova.objects.fixed_ip.FixedIP.associate_pool') - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.QuotasNoOp.check_deltas') - @mock.patch('nova.objects.quotas.ids_from_instance') - def test_allocate_fixed_ip_super_call(self, mock_ids, mock_check, mock_get, - mock_associate): - # No code in the VlanManager actually calls - # NetworkManager.allocate_fixed_ip() at this time. This is just to - # test that if it did, it would call through the QuotasNoOp class. - inst = objects.Instance() - inst['uuid'] = uuids.instance - inst['display_name'] = 'test' - mock_get.return_value = inst - - mock_ids.return_value = ('foo', 'bar') - - network = network_obj.Network._from_db_object( - self.context, network_obj.Network(), test_network.fake_network) - network.save = mock.MagicMock() - - @mock.patch.object(self.network, '_setup_network_on_host') - @mock.patch.object(self.network, 'instance_dns_manager') - @mock.patch.object(self.network, - '_do_trigger_security_group_members_refresh_for_instance') - def _test(trigger, dns, setup): - super(network_manager.VlanManager, self.network).allocate_fixed_ip( - self.context, FAKEUUID, network) - - _test() - - # Make sure we called the QuotasNoOp.check_deltas() for VlanManager. - self.assertEqual(2, mock_check.call_count) - - @mock.patch('nova.network.manager.VlanManager._setup_network_on_host') - @mock.patch('nova.network.manager.VlanManager.' - '_validate_instance_zone_for_dns_domain') - @mock.patch('nova.network.manager.VlanManager.' - '_do_trigger_security_group_members_refresh_for_instance') - @mock.patch('nova.network.manager.VlanManager._add_virtual_interface') - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate') - @mock.patch('nova.objects.VirtualInterface.get_by_instance_and_network') - def test_allocate_fixed_ip_return_none(self, mock_get, - mock_associate, mock_get_uuid, mock_add, mock_trigger, - mock_validate, mock_setup): - net = {'cidr': '24', 'id': 1, 'uuid': uuids.instance} - fip = objects.FixedIP(instance_uuid=uuids.instance, - address=netaddr.IPAddress('1.2.3.4'), - virtual_interface_id=1) - - instance = objects.Instance(context=self.context) - instance.create() - - vif = objects.VirtualInterface(self.context, - id=1000, - address='00:00:00:00:00:00', - instance_uuid=instance.uuid, - network_id=net['id'], - uuid=uuids.instance) - mock_associate.return_value = fip - mock_add.return_value = vif - mock_get.return_value = None - mock_get_uuid.return_value = instance - mock_validate.return_value = False - - self.network.allocate_fixed_ip(self.context_admin, instance.uuid, net) - - mock_add.assert_called_once_with(self.context_admin, instance.uuid, - net['id']) - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate') - def test_allocate_fixed_ip_passes_string_address(self, mock_associate, - mock_get): - mock_associate.side_effect = test.TestingException - instance = objects.Instance(context=self.context) - instance.create() - mock_get.return_value = instance - self.assertRaises(test.TestingException, - self.network.allocate_fixed_ip, - self.context, instance.uuid, - {'cidr': '24', 'id': 1, 'uuid': uuids.instance}, - address=netaddr.IPAddress('1.2.3.4')) - mock_associate.assert_called_once_with(self.context, - '1.2.3.4', - instance.uuid, - 1, - vif_id=1) - - @mock.patch('nova.objects.instance.Instance.get_by_uuid') - @mock.patch('nova.objects.fixed_ip.FixedIP.associate') - def test_allocate_fixed_ip_passes_string_address_vpn(self, mock_associate, - mock_get): - mock_associate.side_effect = test.TestingException - instance = objects.Instance(context=self.context) - instance.create() - mock_get.return_value = instance - self.assertRaises(test.TestingException, - self.network.allocate_fixed_ip, - self.context, instance.uuid, - {'cidr': '24', 'id': 1, 'uuid': uuids.instance, - 'vpn_private_address': netaddr.IPAddress('1.2.3.4') - }, vpn=1) - mock_associate.assert_called_once_with(self.context, - '1.2.3.4', - instance.uuid, - 1, reserved=True, - vif_id=1) - - @mock.patch.object(db, 'virtual_interface_get_by_instance_and_network', - return_value=None) - @mock.patch('nova.objects.fixed_ip.FixedIP') - def test_allocate_fixed_ip_add_vif_fails(self, mock_fixedip, - mock_get_vif): - # Tests that we don't try to do anything with fixed IPs if - # _add_virtual_interface fails. - vif_error = exception.VirtualInterfaceMacAddressException() - with mock.patch.object(self.network, '_add_virtual_interface', - side_effect=vif_error): - self.assertRaises(exception.VirtualInterfaceMacAddressException, - self.network.allocate_fixed_ip, self.context, - '9d2ee1e3-ffad-4e5f-81ff-c96dd97b0ee0', - networks[0]) - self.assertFalse(mock_fixedip.called, str(mock_fixedip.mock_calls)) - - def test_create_networks_too_big(self): - self.assertRaises(ValueError, self.network.create_networks, None, - num_networks=4094, vlan_start=1) - - def test_create_networks_too_many(self): - self.assertRaises(ValueError, self.network.create_networks, None, - num_networks=100, vlan_start=1, - cidr='192.168.0.1/24', network_size=100) - - def test_duplicate_vlan_raises(self): - # VLAN 100 is already used and we force the network to be created - # in that vlan (vlan=100). - self.assertRaises(exception.DuplicateVlan, - self.network.create_networks, - self.context_admin, label="fake", num_networks=1, - vlan=100, cidr='192.168.0.1/24', network_size=100) - - def test_vlan_start(self): - # VLAN 100 and 101 are used, so this network should be created in 102 - networks = self.network.create_networks( - self.context_admin, label="fake", num_networks=1, - vlan_start=100, cidr='192.168.3.1/24', - network_size=100) - - self.assertEqual(102, networks[0]["vlan"]) - - def test_vlan_start_multiple(self): - # VLAN 100 and 101 are used, so these networks should be created in 102 - # and 103 - networks = self.network.create_networks( - self.context_admin, label="fake", num_networks=2, - vlan_start=100, cidr='192.168.3.1/24', - network_size=100) - - self.assertEqual(102, networks[0]["vlan"]) - self.assertEqual(103, networks[1]["vlan"]) - - def test_vlan_start_used(self): - # VLAN 100 and 101 are used, but vlan_start=99. - networks = self.network.create_networks( - self.context_admin, label="fake", num_networks=1, - vlan_start=99, cidr='192.168.3.1/24', - network_size=100) - - self.assertEqual(102, networks[0]["vlan"]) - - def test_vlan_parameter(self): - # vlan parameter could not be greater than 4094 - exc = self.assertRaises(ValueError, - self.network.create_networks, - self.context_admin, label="fake", - num_networks=1, - vlan=4095, cidr='192.168.0.1/24') - error_msg = 'The vlan number cannot be greater than 4094' - self.assertIn(error_msg, six.text_type(exc)) - - # vlan parameter could not be less than 1 - exc = self.assertRaises(ValueError, - self.network.create_networks, - self.context_admin, label="fake", - num_networks=1, - vlan=0, cidr='192.168.0.1/24') - error_msg = 'The vlan number cannot be less than 1' - self.assertIn(error_msg, six.text_type(exc)) - - def test_vlan_be_integer(self): - # vlan must be an integer - exc = self.assertRaises(ValueError, - self.network.create_networks, - self.context_admin, label="fake", - num_networks=1, - vlan='fake', cidr='192.168.0.1/24') - error_msg = 'vlan must be an integer' - self.assertIn(error_msg, six.text_type(exc)) - - def test_vlan_multiple_without_dhcp_server(self): - networks = self.network.create_networks( - self.context_admin, label="fake", num_networks=2, - vlan_start=100, cidr='192.168.3.1/24', - network_size=100) - - self.assertEqual("192.168.3.1", networks[0]["dhcp_server"]) - self.assertEqual("192.168.3.129", networks[1]["dhcp_server"]) - - def test_vlan_multiple_with_dhcp_server(self): - networks = self.network.create_networks( - self.context_admin, label="fake", num_networks=2, - vlan_start=100, cidr='192.168.3.1/24', - network_size=100, dhcp_server='192.168.3.1') - - self.assertEqual("192.168.3.1", networks[0]["dhcp_server"]) - self.assertEqual("192.168.3.1", networks[1]["dhcp_server"]) - - def test_validate_networks(self): - self.mox.StubOutWithMock(db, "fixed_ip_get_by_address") - - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - '192.168.1.100'), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - '192.168.0.100')] - - db_fixed1 = dict(test_fixed_ip.fake_fixed_ip, - network_id=networks[1]['id'], - network=dict(test_network.fake_network, - **networks[1]), - instance_uuid=None) - db.fixed_ip_get_by_address(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=mox.IgnoreArg() - ).AndReturn(db_fixed1) - db_fixed2 = dict(test_fixed_ip.fake_fixed_ip, - network_id=networks[0]['id'], - network=dict(test_network.fake_network, - **networks[0]), - instance_uuid=None) - db.fixed_ip_get_by_address(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=mox.IgnoreArg() - ).AndReturn(db_fixed2) - - self.mox.ReplayAll() - self.network.validate_networks(self.context, requested_networks) - - def test_validate_networks_none_requested_networks(self): - self.network.validate_networks(self.context, None) - - def test_validate_networks_empty_requested_networks(self): - requested_networks = [] - self.mox.ReplayAll() - - self.network.validate_networks(self.context, requested_networks) - - def test_validate_networks_invalid_fixed_ip(self): - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - '192.168.1.100.1'), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - '192.168.0.100.1')] - self.mox.ReplayAll() - - self.assertRaises(exception.FixedIpInvalid, - self.network.validate_networks, self.context, - requested_networks) - - def test_validate_networks_empty_fixed_ip(self): - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', ''), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '')] - self.mox.ReplayAll() - - self.assertRaises(exception.FixedIpInvalid, - self.network.validate_networks, - self.context, requested_networks) - - def test_validate_networks_none_fixed_ip(self): - requested_networks = [('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', None), - ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', None)] - self.mox.ReplayAll() - self.network.validate_networks(self.context, requested_networks) - - def test_floating_ip_owned_by_project(self): - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - # raises because floating_ip project_id is None - floating_ip = objects.FloatingIP(address='10.0.0.1', - project_id=None) - self.assertRaises(exception.Forbidden, - self.network._floating_ip_owned_by_project, - ctxt, - floating_ip) - - # raises because floating_ip project_id is not equal to ctxt project_id - floating_ip = objects.FloatingIP(address='10.0.0.1', - project_id=uuids.non_existent_uuid) - self.assertRaises(exception.Forbidden, - self.network._floating_ip_owned_by_project, - ctxt, - floating_ip) - - # does not raise (floating ip is owned by ctxt project) - floating_ip = objects.FloatingIP(address='10.0.0.1', - project_id=ctxt.project_id) - self.network._floating_ip_owned_by_project(ctxt, floating_ip) - - ctxt = context.RequestContext(None, None, - is_admin=True) - - # does not raise (ctxt is admin) - floating_ip = objects.FloatingIP(address='10.0.0.1', - project_id=None) - self.network._floating_ip_owned_by_project(ctxt, floating_ip) - - # does not raise (ctxt is admin) - floating_ip = objects.FloatingIP(address='10.0.0.1', - project_id=fakes.FAKE_PROJECT_ID) - self.network._floating_ip_owned_by_project(ctxt, floating_ip) - - def test_allocate_floating_ip(self): - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - self.stubs.Set(self.network, '_floating_ip_pool_exists', - lambda _x, _y: True) - - def fake_allocate_address(*args, **kwargs): - return {'address': '10.0.0.1', 'project_id': ctxt.project_id} - - self.stubs.Set(self.network.db, 'floating_ip_allocate_address', - fake_allocate_address) - - self.network.allocate_floating_ip(ctxt, ctxt.project_id) - - @mock.patch('nova.objects.FloatingIP.deallocate') - @mock.patch('nova.network.floating_ips.FloatingIP.' - '_floating_ip_owned_by_project') - @mock.patch('nova.objects.FloatingIP.get_by_address') - def test_deallocate_floating_ip(self, mock_get, mock_owned, mock_dealloc): - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - def fake1(*args, **kwargs): - params = dict(test_floating_ip.fake_floating_ip) - return objects.FloatingIP(**params) - - def fake2(*args, **kwargs): - params = dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', fixed_ip_id=1) - return objects.FloatingIP(**params) - - def fake3(*args, **kwargs): - params = dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', fixed_ip_id=None, - project_id=ctxt.project_id) - return objects.FloatingIP(**params) - - mock_dealloc.side_effect = fake1 - mock_owned.side_effect = fake1 - mock_get.side_effect = fake2 - - # this time should raise because floating ip is associated to - # fixed_ip - self.assertRaises(exception.FloatingIpAssociated, - self.network.deallocate_floating_ip, - ctxt, - 'fake-address') - mock_dealloc.assert_not_called() - - # this time should not raise - mock_dealloc.reset_mock() - mock_get.side_effect = fake3 - - self.network.deallocate_floating_ip(ctxt, 'fake-address') - mock_dealloc.assert_called_once_with(ctxt, 'fake-address') - - @mock.patch('nova.db.api.fixed_ip_get') - def test_associate_floating_ip(self, fixed_get): - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - def fake1(*args, **kwargs): - return dict(test_fixed_ip.fake_fixed_ip, - address='10.0.0.1', - network=test_network.fake_network) - - # floating ip that's already associated - def fake2(*args, **kwargs): - return dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', - pool='nova', - interface='eth0', - fixed_ip_id=1) - - # floating ip that isn't associated - def fake3(*args, **kwargs): - return dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', - pool='nova', - interface='eth0', - fixed_ip_id=None) - - # fixed ip with remote host - def fake4(*args, **kwargs): - return dict(test_fixed_ip.fake_fixed_ip, - address='10.0.0.1', - pool='nova', - instance_uuid=FAKEUUID, - interface='eth0', - network_id=123) - - def fake4_network(*args, **kwargs): - return dict(test_network.fake_network, - multi_host=False, host='jibberjabber') - - # fixed ip with local host - def fake5(*args, **kwargs): - return dict(test_fixed_ip.fake_fixed_ip, - address='10.0.0.1', - pool='nova', - instance_uuid=FAKEUUID, - interface='eth0', - network_id=1234) - - def fake5_network(*args, **kwargs): - return dict(test_network.fake_network, - multi_host=False, host='testhost') - - def fake6(ctxt, method, **kwargs): - self.local = False - - def fake7(*args, **kwargs): - self.local = True - - def fake8(*args, **kwargs): - raise processutils.ProcessExecutionError('', - 'Cannot find device "em0"\n') - - def fake9(*args, **kwargs): - raise test.TestingException() - - # raises because interface doesn't exist - self.stubs.Set(self.network.db, - 'floating_ip_fixed_ip_associate', - fake1) - self.stubs.Set(self.network.db, 'floating_ip_disassociate', fake1) - self.stubs.Set(self.network.driver, 'ensure_floating_forward', fake8) - self.assertRaises(exception.NoFloatingIpInterface, - self.network._associate_floating_ip, - ctxt, - '1.2.3.4', - '1.2.3.5', - mox.IgnoreArg(), - mox.IgnoreArg()) - - self.stubs.Set(self.network, '_floating_ip_owned_by_project', fake1) - - # raises because floating_ip is already associated to a fixed_ip - self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake2) - self.stubs.Set(self.network, 'disassociate_floating_ip', fake9) - - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address='1.2.3.4', - instance_uuid=uuids.instance, - network=test_network.fake_network) - - # doesn't raise because we exit early if the address is the same - self.network.associate_floating_ip(ctxt, mox.IgnoreArg(), '1.2.3.4') - - # raises because we call disassociate which is mocked - self.assertRaises(test.TestingException, - self.network.associate_floating_ip, - ctxt, - mox.IgnoreArg(), - 'new') - - self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake3) - - # does not raise and makes call remotely - self.local = True - self.stubs.Set(self.network.db, 'fixed_ip_get_by_address', fake4) - self.stubs.Set(self.network.db, 'network_get', fake4_network) - self.stubs.Set(self.network.network_rpcapi.client, 'prepare', - lambda **kw: self.network.network_rpcapi.client) - self.stubs.Set(self.network.network_rpcapi.client, 'call', fake6) - self.network.associate_floating_ip(ctxt, mox.IgnoreArg(), - mox.IgnoreArg()) - self.assertFalse(self.local) - - # does not raise and makes call locally - self.local = False - self.stubs.Set(self.network.db, 'fixed_ip_get_by_address', fake5) - self.stubs.Set(self.network.db, 'network_get', fake5_network) - self.stubs.Set(self.network, '_associate_floating_ip', fake7) - self.network.associate_floating_ip(ctxt, mox.IgnoreArg(), - mox.IgnoreArg()) - self.assertTrue(self.local) - - def test_add_floating_ip_nat_before_bind(self): - # Tried to verify order with documented mox record/verify - # functionality, but it doesn't seem to work since I can't make it - # fail. I'm using stubs and a flag for now, but if this mox feature - # can be made to work, it would be a better way to test this. - # - # self.mox.StubOutWithMock(self.network.driver, - # 'ensure_floating_forward') - # self.mox.StubOutWithMock(self.network.driver, 'bind_floating_ip') - # - # self.network.driver.ensure_floating_forward(mox.IgnoreArg(), - # mox.IgnoreArg(), - # mox.IgnoreArg(), - # mox.IgnoreArg()) - # self.network.driver.bind_floating_ip(mox.IgnoreArg(), - # mox.IgnoreArg()) - # self.mox.ReplayAll() - - nat_called = [False] - - def fake_nat(*args, **kwargs): - nat_called[0] = True - - def fake_bind(*args, **kwargs): - self.assertTrue(nat_called[0]) - - self.stubs.Set(self.network.driver, - 'ensure_floating_forward', - fake_nat) - self.stubs.Set(self.network.driver, 'bind_floating_ip', fake_bind) - - self.network.l3driver.add_floating_ip('fakefloat', - 'fakefixed', - 'fakeiface', - 'fakenet') - - @mock.patch('nova.db.api.floating_ip_get_all_by_host') - @mock.patch('nova.db.api.fixed_ip_get') - def _test_floating_ip_init_host(self, fixed_get, floating_get, - public_interface, expected_arg): - - floating_get.return_value = [ - dict(test_floating_ip.fake_floating_ip, - interface='foo', - address='1.2.3.4'), - dict(test_floating_ip.fake_floating_ip, - interface='fakeiface', - address='1.2.3.5', - fixed_ip_id=1), - dict(test_floating_ip.fake_floating_ip, - interface='bar', - address='1.2.3.6', - fixed_ip_id=2), - ] - - def fixed_ip_get(_context, fixed_ip_id, get_network): - if fixed_ip_id == 1: - return dict(test_fixed_ip.fake_fixed_ip, - address='1.2.3.4', - network=test_network.fake_network) - raise exception.FixedIpNotFound(id=fixed_ip_id) - fixed_get.side_effect = fixed_ip_get - - self.mox.StubOutWithMock(self.network.l3driver, 'add_floating_ip') - self.flags(public_interface=public_interface) - self.network.l3driver.add_floating_ip(netaddr.IPAddress('1.2.3.5'), - netaddr.IPAddress('1.2.3.4'), - expected_arg, - mox.IsA(objects.Network)) - self.mox.ReplayAll() - self.network.init_host_floating_ips() - self.mox.UnsetStubs() - self.mox.VerifyAll() - - def test_floating_ip_init_host_without_public_interface(self): - self._test_floating_ip_init_host(public_interface='', - expected_arg='fakeiface') - - def test_floating_ip_init_host_with_public_interface(self): - self._test_floating_ip_init_host(public_interface='fooiface', - expected_arg='fooiface') - - def test_disassociate_floating_ip(self): - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - def fake1(*args, **kwargs): - pass - - # floating ip that isn't associated - def fake2(*args, **kwargs): - return dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', - pool='nova', - interface='eth0', - fixed_ip_id=None) - - # floating ip that is associated - def fake3(*args, **kwargs): - return dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', - pool='nova', - interface='eth0', - fixed_ip_id=1, - project_id=ctxt.project_id) - - # fixed ip with remote host - def fake4(*args, **kwargs): - return dict(test_fixed_ip.fake_fixed_ip, - address='10.0.0.1', - pool='nova', - instance_uuid=FAKEUUID, - interface='eth0', - network_id=123) - - def fake4_network(*args, **kwargs): - return dict(test_network.fake_network, - multi_host=False, - host='jibberjabber') - - # fixed ip with local host - def fake5(*args, **kwargs): - return dict(test_fixed_ip.fake_fixed_ip, - address='10.0.0.1', - pool='nova', - instance_uuid=FAKEUUID, - interface='eth0', - network_id=1234) - - def fake5_network(*args, **kwargs): - return dict(test_network.fake_network, - multi_host=False, host='testhost') - - def fake6(ctxt, method, **kwargs): - self.local = False - - def fake7(*args, **kwargs): - self.local = True - - def fake8(*args, **kwargs): - return dict(test_floating_ip.fake_floating_ip, - address='10.0.0.1', - pool='nova', - interface='eth0', - fixed_ip_id=1, - auto_assigned=True, - project_id=ctxt.project_id) - - self.stubs.Set(self.network, '_floating_ip_owned_by_project', fake1) - - # raises because floating_ip is not associated to a fixed_ip - self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake2) - self.assertRaises(exception.FloatingIpNotAssociated, - self.network.disassociate_floating_ip, - ctxt, - mox.IgnoreArg()) - - self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake3) - - # does not raise and makes call remotely - self.local = True - self.stubs.Set(self.network.db, 'fixed_ip_get', fake4) - self.stubs.Set(self.network.db, 'network_get', fake4_network) - self.stubs.Set(self.network.network_rpcapi.client, 'prepare', - lambda **kw: self.network.network_rpcapi.client) - self.stubs.Set(self.network.network_rpcapi.client, 'call', fake6) - self.network.disassociate_floating_ip(ctxt, mox.IgnoreArg()) - self.assertFalse(self.local) - - # does not raise and makes call locally - self.local = False - self.stubs.Set(self.network.db, 'fixed_ip_get', fake5) - self.stubs.Set(self.network.db, 'network_get', fake5_network) - self.stubs.Set(self.network, '_disassociate_floating_ip', fake7) - self.network.disassociate_floating_ip(ctxt, mox.IgnoreArg()) - self.assertTrue(self.local) - - # raises because auto_assigned floating IP cannot be disassociated - self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake8) - self.assertRaises(exception.CannotDisassociateAutoAssignedFloatingIP, - self.network.disassociate_floating_ip, - ctxt, - mox.IgnoreArg()) - - @mock.patch('nova.privsep.linux_net.add_bridge', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.routes_show', - return_value=('fake', 0)) - @mock.patch('nova.privsep.linux_net.lookup_ip', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.change_ip') - @mock.patch('nova.privsep.linux_net.address_command_deprecated') - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=False) - @mock.patch('nova.privsep.linux_net._enable_ipv4_forwarding_inner') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - @mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')) - def test_add_fixed_ip_instance_without_vpn_requested_networks( - self, mock_bridge_add_interface, mock_bridge_disable_stp, - mock_bridge_setfd, mock_iptables_set_rules, - mock_iptables_get_rules, mock_forwarding_enable, - mock_forwarding_check, mock_address_command, mock_change_ip, - mock_lookup_ip, mock_routes_show, mock_enabled, mock_add_bridge): - self.stubs.Set(self.network, - '_do_trigger_security_group_members_refresh_for_instance', - lambda *a, **kw: None) - self.mox.StubOutWithMock(db, 'network_get') - self.mox.StubOutWithMock(db, 'fixed_ip_associate_pool') - self.mox.StubOutWithMock(db, - 'virtual_interface_get_by_instance_and_network') - self.mox.StubOutWithMock(db, 'instance_get_by_uuid') - self.mox.StubOutWithMock(self.network, 'get_instance_nw_info') - - db.virtual_interface_get_by_instance_and_network(mox.IgnoreArg(), - mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(vifs[0]) - - fixed = dict(test_fixed_ip.fake_fixed_ip, - address='192.168.0.101') - db.fixed_ip_associate_pool(mox.IgnoreArg(), - mox.IgnoreArg(), - instance_uuid=mox.IgnoreArg(), - host=None, - virtual_interface_id=vifs[0]['id'] - ).AndReturn(fixed) - db.network_get(mox.IgnoreArg(), - mox.IgnoreArg(), - project_only=mox.IgnoreArg() - ).AndReturn(dict(test_network.fake_network, - **networks[0])) - db.instance_get_by_uuid(mox.IgnoreArg(), - mox.IgnoreArg(), - columns_to_join=['info_cache', - 'security_groups'] - ).AndReturn(fake_inst(display_name=HOST, - uuid=FAKEUUID)) - self.network.get_instance_nw_info(mox.IgnoreArg(), mox.IgnoreArg(), - mox.IgnoreArg(), mox.IgnoreArg()) - self.mox.ReplayAll() - self.network.add_fixed_ip_to_instance(self.context, FAKEUUID, HOST, - networks[0]['id']) - - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.privsep.linux_net.bind_ip') - @mock.patch('nova.privsep.linux_net.unbind_ip') - @mock.patch('nova.privsep.linux_net.clean_conntrack') - @mock.patch('nova.privsep.linux_net.modify_ebtables') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_ip_association_and_allocation_of_other_project( - self, mock_iptables_set_rules, mock_iptables_get_rules, - modify_ebtables, clean_conntrack, unbind_ip, bind_ip, - net_get, fixed_get): - """Makes sure that we cannot deallocaate or disassociate - a public IP of other project. - """ - net_get.return_value = dict(test_network.fake_network, - **networks[1]) - - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - context2 = context.RequestContext('user', 'project2') - - float_ip = db.floating_ip_create(context1.elevated(), - {'address': '1.2.3.4', - 'project_id': context1.project_id}) - - float_addr = float_ip['address'] - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - - fix_addr = db.fixed_ip_associate_pool(context1.elevated(), - 1, instance['uuid']).address - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address=fix_addr, - instance_uuid=instance.uuid, - network=dict(test_network.fake_network, - **networks[1])) - - # Associate the IP with non-admin user context - self.assertRaises(exception.Forbidden, - self.network.associate_floating_ip, - context2, - float_addr, - fix_addr) - - # Deallocate address from other project - self.assertRaises(exception.Forbidden, - self.network.deallocate_floating_ip, - context2, - float_addr) - - # Now Associates the address to the actual project - self.network.associate_floating_ip(context1, float_addr, fix_addr) - - # Now try dis-associating from other project - self.assertRaises(exception.Forbidden, - self.network.disassociate_floating_ip, - context2, - float_addr) - - # Clean up the ip addresses - self.network.disassociate_floating_ip(context1, float_addr) - self.network.deallocate_floating_ip(context1, float_addr) - self.network.deallocate_fixed_ip(context1, fix_addr, 'fake') - db.floating_ip_destroy(context1.elevated(), float_addr) - db.fixed_ip_disassociate(context1.elevated(), fix_addr) - - @mock.patch('nova.network.rpcapi.NetworkAPI.release_dhcp') - @mock.patch('nova.db.api.virtual_interface_get') - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ip_update') - def test_deallocate_fixed(self, fixed_update, net_get, fixed_get, - vif_get, release_dhcp): - """Verify that release is called properly. - - Ensures https://bugs.launchpad.net/nova/+bug/973442 doesn't return - """ - net_get.return_value = dict(test_network.fake_network, - **networks[1]) - vif_get.return_value = vifs[0] - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - - elevated = context1.elevated() - fix_addr = db.fixed_ip_associate_pool(elevated, 1, instance['uuid']) - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address=fix_addr.address, - instance_uuid=instance.uuid, - allocated=True, - virtual_interface_id=3, - network=dict(test_network.fake_network, - **networks[1])) - - self.flags(force_dhcp_release=True) - self.network.deallocate_fixed_ip(context1, fix_addr.address, 'fake') - fixed_update.assert_called_once_with(context1, fix_addr.address, - {'allocated': False}) - release_dhcp.assert_called_once_with(context1, None, - networks[1]['bridge'], - fix_addr.address, - 'DE:AD:BE:EF:00:00') - - @mock.patch.object(linux_net, 'release_dhcp') - @mock.patch('nova.network.rpcapi.NetworkAPI.release_dhcp') - @mock.patch('nova.db.api.virtual_interface_get') - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ip_update') - def test_deallocate_fixed_rpc_pinned(self, fixed_update, net_get, - fixed_get, vif_get, - release_dhcp, - net_release_dhcp): - """Ensure that if the RPC call to release_dhcp raises a - RPCPinnedToOldVersion, we fall back to the previous behaviour of - calling release_dhcp in the local linux_net driver. In the previous - test, release_dhcp was mocked to call the driver, since this is what - happens on a successful RPC call. In this test, we mock it to raise, - but the expected behaviour is exactly the same - namely that - release_dhcp is called in the linux_net driver, which is why the two - tests are otherwise identical. - """ - net_get.return_value = dict(test_network.fake_network, - **networks[1]) - vif_get.return_value = vifs[0] - release_dhcp.side_effect = exception.RPCPinnedToOldVersion() - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - - elevated = context1.elevated() - fix_addr = db.fixed_ip_associate_pool(elevated, 1, instance['uuid']) - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address=fix_addr.address, - instance_uuid=instance.uuid, - allocated=True, - virtual_interface_id=3, - network=dict(test_network.fake_network, - **networks[1])) - - self.flags(force_dhcp_release=True) - self.network.deallocate_fixed_ip(context1, fix_addr.address, 'fake') - net_release_dhcp.assert_called_once_with(networks[1]['bridge'], - fix_addr.address, - 'DE:AD:BE:EF:00:00') - fixed_update.assert_called_once_with(context1, fix_addr.address, - {'allocated': False}) - - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ip_update') - def _deallocate_fixed_with_dhcp(self, mock_dev_exists, fixed_update, - net_get, fixed_get): - net_get.return_value = dict(test_network.fake_network, - **networks[1]) - - def vif_get(_context, _vif_id): - return vifs[0] - - def release_dhcp(self, context, instance, dev, address, vif_address): - linux_net.release_dhcp(dev, address, vif_address) - - with test.nested( - mock.patch.object(network_rpcapi.NetworkAPI, 'release_dhcp', - release_dhcp), - mock.patch.object(db, 'virtual_interface_get', vif_get), - mock.patch('nova.privsep.linux_net.dhcp_release', - side_effect=processutils.ProcessExecutionError()), - ) as (release_dhcp, _vif_get, privsep_dhcp_release): - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - - elevated = context1.elevated() - fix_addr = db.fixed_ip_associate_pool(elevated, 1, - instance['uuid']) - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address=fix_addr.address, - instance_uuid=instance.uuid, - allocated=True, - virtual_interface_id=3, - network=dict( - test_network.fake_network, - **networks[1])) - self.flags(force_dhcp_release=True) - self.network.deallocate_fixed_ip(context1, fix_addr.address, - 'fake') - fixed_update.assert_called_once_with(context1, fix_addr.address, - {'allocated': False}) - mock_dev_exists.assert_called_once_with(networks[1]['bridge']) - if mock_dev_exists.return_value: - privsep_dhcp_release.assert_called_once_with( - networks[1]['bridge'], fix_addr.address, - 'DE:AD:BE:EF:00:00') - - @mock.patch('nova.privsep.linux_net.device_exists', return_value=True) - def test_deallocate_fixed_with_dhcp(self, mock_dev_exists): - self._deallocate_fixed_with_dhcp(mock_dev_exists) - - @mock.patch('nova.privsep.linux_net.device_exists', return_value=False) - def test_deallocate_fixed_without_dhcp(self, mock_dev_exists): - self._deallocate_fixed_with_dhcp(mock_dev_exists) - - def test_deallocate_fixed_deleted(self): - # Verify doesn't deallocate deleted fixed_ip from deleted network. - - def teardown_network_on_host(_context, network): - if network['id'] == 0: - raise test.TestingException() - - self.stubs.Set(self.network, '_teardown_network_on_host', - teardown_network_on_host) - - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - elevated = context1.elevated() - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - network = db.network_create_safe(elevated, networks[0]) - - _fix_addr = db.fixed_ip_associate_pool(elevated, 1, instance['uuid']) - fix_addr = _fix_addr.address - db.fixed_ip_update(elevated, fix_addr, {'deleted': 1}) - elevated.read_deleted = 'yes' - delfixed = db.fixed_ip_get_by_address(elevated, fix_addr) - values = {'address': fix_addr, - 'network_id': network.id, - 'instance_uuid': delfixed['instance_uuid']} - db.fixed_ip_create(elevated, values) - elevated.read_deleted = 'no' - elevated.read_deleted = 'yes' - - deallocate = self.network.deallocate_fixed_ip - self.assertRaises(test.TestingException, deallocate, context1, - fix_addr, 'fake') - - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ip_update') - def test_deallocate_fixed_no_vif(self, fixed_update, net_get, fixed_get): - """Verify that deallocate doesn't raise when no vif is returned. - - Ensures https://bugs.launchpad.net/nova/+bug/968457 doesn't return - """ - net_get.return_value = dict(test_network.fake_network, - **networks[1]) - - def vif_get(_context, _vif_id): - return None - - self.stub_out('nova.db.api.virtual_interface_get', vif_get) - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - - elevated = context1.elevated() - fix_addr = db.fixed_ip_associate_pool(elevated, 1, instance['uuid']) - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address=fix_addr.address, - allocated=True, - virtual_interface_id=3, - instance_uuid=instance.uuid, - network=dict(test_network.fake_network, - **networks[1])) - self.flags(force_dhcp_release=True) - fixed_update.return_value = fixed_get.return_value - self.network.deallocate_fixed_ip(context1, fix_addr.address, 'fake') - fixed_update.assert_called_once_with(context1, fix_addr.address, - {'allocated': False}) - - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ip_update') - def test_fixed_ip_cleanup_fail(self, fixed_update, net_get, fixed_get): - # Verify IP is not deallocated if the security group refresh fails. - net_get.return_value = dict(test_network.fake_network, - **networks[1]) - context1 = context.RequestContext('user', fakes.FAKE_PROJECT_ID) - - instance = db.instance_create(context1, - {'project_id': fakes.FAKE_PROJECT_ID}) - - elevated = context1.elevated() - fix_addr = objects.FixedIP.associate_pool(elevated, 1, - instance['uuid']) - - def fake_refresh(instance_uuid): - raise test.TestingException() - self.stubs.Set(self.network, - '_do_trigger_security_group_members_refresh_for_instance', - fake_refresh) - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - address=fix_addr.address, - allocated=True, - virtual_interface_id=3, - instance_uuid=instance.uuid, - network=dict(test_network.fake_network, - **networks[1])) - self.assertRaises(test.TestingException, - self.network.deallocate_fixed_ip, - context1, str(fix_addr.address), 'fake') - self.assertFalse(fixed_update.called) - - def test_get_networks_by_uuids_ordering(self): - self.mox.StubOutWithMock(db, 'network_get_all_by_uuids') - - requested_networks = ['bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'] - db.network_get_all_by_uuids(mox.IgnoreArg(), mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn( - [dict(test_network.fake_network, **net) - for net in networks]) - - self.mox.ReplayAll() - res = self.network._get_networks_by_uuids(self.context, - requested_networks) - - self.assertEqual(1, res[0]['id']) - self.assertEqual(0, res[1]['id']) - - @mock.patch('nova.objects.fixed_ip.FixedIP.get_by_id') - @mock.patch('nova.objects.floating_ip.FloatingIPList.get_by_host') - @mock.patch('nova.network.linux_net.iptables_manager._apply') - @mock.patch('nova.privsep.linux_net.bind_ip') - @mock.patch('nova.privsep.linux_net.modify_ebtables') - def test_init_host_iptables_defer_apply(self, modify_ebtables, bind_ip, - iptable_apply, - floating_get_by_host, - fixed_get_by_id): - def get_by_id(context, fixed_ip_id, **kwargs): - net = objects.Network(bridge='testbridge', - cidr='192.168.1.0/24') - if fixed_ip_id == 1: - return objects.FixedIP(address='192.168.1.4', - network=net) - elif fixed_ip_id == 2: - return objects.FixedIP(address='192.168.1.5', - network=net) - - def fake_apply(): - fake_apply.count += 1 - - fake_apply.count = 0 - ctxt = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - float1 = objects.FloatingIP(address='1.2.3.4', fixed_ip_id=1) - float2 = objects.FloatingIP(address='1.2.3.5', fixed_ip_id=2) - float1._context = ctxt - float2._context = ctxt - - iptable_apply.side_effect = fake_apply - floating_get_by_host.return_value = [float1, float2] - fixed_get_by_id.side_effect = get_by_id - - self.network.init_host() - self.assertEqual(1, fake_apply.count) - - -class _TestDomainObject(object): - def __init__(self, **kwargs): - for k, v in kwargs.items(): - self.__setattr__(k, v) - - -class CommonNetworkTestCase(test.TestCase): - - REQUIRES_LOCKING = True - - def setUp(self): - super(CommonNetworkTestCase, self).setUp() - self.context = context.RequestContext('fake', 'fake') - self.flags(ipv6_backend='rfc2462', use_neutron=False) - ipv6.reset_backend() - - def test_validate_instance_zone_for_dns_domain(self): - domain = 'example.com' - az = 'test_az' - domains = { - domain: _TestDomainObject( - domain=domain, - availability_zone=az)} - - def dnsdomain_get(context, instance_domain): - return domains.get(instance_domain) - - self.stub_out('nova.db.api.dnsdomain_get', dnsdomain_get) - fake_instance = {'uuid': FAKEUUID, - 'availability_zone': az} - - manager = network_manager.NetworkManager() - res = manager._validate_instance_zone_for_dns_domain(self.context, - fake_instance) - self.assertTrue(res) - - def fake_create_fixed_ips(self, context, network_id, fixed_cidr=None, - extra_reserved=None, bottom_reserved=0, - top_reserved=0): - return None - - def test_get_instance_nw_info_client_exceptions(self): - manager = network_manager.NetworkManager() - self.mox.StubOutWithMock(manager.db, - 'fixed_ip_get_by_instance') - manager.db.fixed_ip_get_by_instance( - self.context, FAKEUUID).AndRaise(exception.InstanceNotFound( - instance_id=FAKEUUID)) - self.mox.ReplayAll() - self.assertRaises(messaging.ExpectedException, - manager.get_instance_nw_info, - self.context, FAKEUUID, 'fake_rxtx_factor', HOST) - - @mock.patch('nova.db.api.instance_get') - @mock.patch('nova.db.api.fixed_ip_get_by_instance') - def test_deallocate_for_instance_passes_host_info(self, fixed_get, - instance_get): - manager = fake_network.FakeNetworkManager() - db = manager.db - instance_get.return_value = fake_inst(uuid=uuids.non_existent_uuid) - db.virtual_interface_delete_by_instance = lambda _x, _y: None - ctx = context.RequestContext('igonre', 'igonre') - - fixed_get.return_value = [dict(test_fixed_ip.fake_fixed_ip, - address='1.2.3.4', - network_id=123)] - - manager.deallocate_for_instance( - ctx, instance=objects.Instance._from_db_object(self.context, - objects.Instance(), instance_get.return_value)) - - self.assertEqual([ - (ctx, '1.2.3.4', 'fake-host') - ], manager.deallocate_fixed_ip_calls) - - @mock.patch('nova.db.api.fixed_ip_get_by_instance') - def test_deallocate_for_instance_passes_host_info_with_update_dns_entries( - self, fixed_get): - self.flags(update_dns_entries=True) - manager = fake_network.FakeNetworkManager() - db = manager.db - db.virtual_interface_delete_by_instance = lambda _x, _y: None - ctx = context.RequestContext('igonre', 'igonre') - - fixed_get.return_value = [dict(test_fixed_ip.fake_fixed_ip, - address='1.2.3.4', - network_id=123)] - - with mock.patch.object(manager.network_rpcapi, - 'update_dns') as mock_update_dns: - manager.deallocate_for_instance( - ctx, instance=fake_instance.fake_instance_obj(ctx)) - mock_update_dns.assert_called_once_with(ctx, ['123']) - - self.assertEqual([ - (ctx, '1.2.3.4', 'fake-host') - ], manager.deallocate_fixed_ip_calls) - - def test_deallocate_for_instance_with_requested_networks(self): - manager = fake_network.FakeNetworkManager() - db = manager.db - db.virtual_interface_delete_by_instance = mock.Mock() - ctx = context.RequestContext('igonre', 'igonre') - requested_networks = objects.NetworkRequestList.from_tuples( - [('123', '1.2.3.4'), ('123', '4.3.2.1'), ('123', None)]) - manager.deallocate_for_instance( - ctx, - instance=fake_instance.fake_instance_obj(ctx), - requested_networks=requested_networks) - - self.assertEqual([ - (ctx, '1.2.3.4', 'fake-host'), (ctx, '4.3.2.1', 'fake-host') - ], manager.deallocate_fixed_ip_calls) - - def test_deallocate_for_instance_with_update_dns_entries(self): - self.flags(update_dns_entries=True) - manager = fake_network.FakeNetworkManager() - db = manager.db - db.virtual_interface_delete_by_instance = mock.Mock() - ctx = context.RequestContext('igonre', 'igonre') - requested_networks = objects.NetworkRequestList.from_tuples( - [('123', '1.2.3.4'), ('123', '4.3.2.1')]) - with mock.patch.object(manager.network_rpcapi, - 'update_dns') as mock_update_dns: - manager.deallocate_for_instance( - ctx, - instance=fake_instance.fake_instance_obj(ctx), - requested_networks=requested_networks) - mock_update_dns.assert_called_once_with(ctx, ['123']) - - self.assertEqual([ - (ctx, '1.2.3.4', 'fake-host'), (ctx, '4.3.2.1', 'fake-host') - ], manager.deallocate_fixed_ip_calls) - - @mock.patch('nova.db.api.fixed_ip_get_by_instance') - @mock.patch('nova.db.api.fixed_ip_disassociate') - def test_remove_fixed_ip_from_instance(self, disassociate, get): - manager = fake_network.FakeNetworkManager() - get.return_value = [ - dict(test_fixed_ip.fake_fixed_ip, **x) - for x in manager.db.fixed_ip_get_by_instance(None, - FAKEUUID)] - manager.remove_fixed_ip_from_instance(self.context, FAKEUUID, - HOST, - '10.0.0.1') - - self.assertEqual('10.0.0.1', manager.deallocate_called) - disassociate.assert_called_once_with(self.context, '10.0.0.1') - - @mock.patch('nova.db.api.fixed_ip_get_by_instance') - def test_remove_fixed_ip_from_instance_bad_input(self, get): - manager = fake_network.FakeNetworkManager() - get.return_value = [] - self.assertRaises(exception.FixedIpNotFoundForSpecificInstance, - manager.remove_fixed_ip_from_instance, - self.context, 99, HOST, 'bad input') - - def test_validate_cidrs(self): - manager = fake_network.FakeNetworkManager() - nets = manager.create_networks(self.context.elevated(), 'fake', - '192.168.0.0/24', - False, 1, 256, None, None, None, - None, None) - self.assertEqual(1, len(nets)) - cidrs = [str(net['cidr']) for net in nets] - self.assertIn('192.168.0.0/24', cidrs) - - def test_validate_cidrs_split_exact_in_half(self): - manager = fake_network.FakeNetworkManager() - nets = manager.create_networks(self.context.elevated(), 'fake', - '192.168.0.0/24', - False, 2, 128, None, None, None, - None, None) - self.assertEqual(2, len(nets)) - cidrs = [str(net['cidr']) for net in nets] - self.assertIn('192.168.0.0/25', cidrs) - self.assertIn('192.168.0.128/25', cidrs) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_split_cidr_in_use_middle_of_range(self, get_all): - manager = fake_network.FakeNetworkManager() - get_all.return_value = [dict(test_network.fake_network, - id=1, cidr='192.168.2.0/24')] - nets = manager.create_networks(self.context.elevated(), 'fake', - '192.168.0.0/16', - False, 4, 256, None, None, None, - None, None) - self.assertEqual(4, len(nets)) - cidrs = [str(net['cidr']) for net in nets] - exp_cidrs = ['192.168.0.0/24', '192.168.1.0/24', '192.168.3.0/24', - '192.168.4.0/24'] - for exp_cidr in exp_cidrs: - self.assertIn(exp_cidr, cidrs) - self.assertNotIn('192.168.2.0/24', cidrs) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_smaller_subnet_in_use(self, get_all): - manager = fake_network.FakeNetworkManager() - get_all.return_value = [dict(test_network.fake_network, - id=1, cidr='192.168.2.9/25')] - # CidrConflict: requested cidr (192.168.2.0/24) conflicts with - # existing smaller cidr - args = (self.context.elevated(), 'fake', '192.168.2.0/24', False, - 1, 256, None, None, None, None, None) - self.assertRaises(exception.CidrConflict, - manager.create_networks, *args) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_split_smaller_cidr_in_use(self, get_all): - manager = fake_network.FakeNetworkManager() - get_all.return_value = [dict(test_network.fake_network, - id=1, cidr='192.168.2.0/25')] - nets = manager.create_networks(self.context.elevated(), 'fake', - '192.168.0.0/16', - False, 4, 256, None, None, None, None, - None) - self.assertEqual(4, len(nets)) - cidrs = [str(net['cidr']) for net in nets] - exp_cidrs = ['192.168.0.0/24', '192.168.1.0/24', '192.168.3.0/24', - '192.168.4.0/24'] - for exp_cidr in exp_cidrs: - self.assertIn(exp_cidr, cidrs) - self.assertNotIn('192.168.2.0/24', cidrs) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_split_smaller_cidr_in_use2(self, get_all): - manager = fake_network.FakeNetworkManager() - self.mox.StubOutWithMock(manager.db, 'network_get_all') - get_all.return_value = [dict(test_network.fake_network, id=1, - cidr='192.168.2.9/29')] - nets = manager.create_networks(self.context.elevated(), 'fake', - '192.168.2.0/24', - False, 3, 32, None, None, None, None, - None) - self.assertEqual(3, len(nets)) - cidrs = [str(net['cidr']) for net in nets] - exp_cidrs = ['192.168.2.32/27', '192.168.2.64/27', '192.168.2.96/27'] - for exp_cidr in exp_cidrs: - self.assertIn(exp_cidr, cidrs) - self.assertNotIn('192.168.2.0/27', cidrs) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_split_all_in_use(self, get_all): - manager = fake_network.FakeNetworkManager() - in_use = [dict(test_network.fake_network, **values) for values in - [{'id': 1, 'cidr': '192.168.2.9/29'}, - {'id': 2, 'cidr': '192.168.2.64/26'}, - {'id': 3, 'cidr': '192.168.2.128/26'}]] - get_all.return_value = in_use - args = (self.context.elevated(), 'fake', '192.168.2.0/24', False, - 3, 64, None, None, None, None, None) - # CidrConflict: Not enough subnets avail to satisfy requested num_ - # networks - some subnets in requested range already - # in use - self.assertRaises(exception.CidrConflict, - manager.create_networks, *args) - - def test_validate_cidrs_one_in_use(self): - manager = fake_network.FakeNetworkManager() - args = (None, 'fake', '192.168.0.0/24', False, 2, 256, None, None, - None, None, None) - # ValueError: network_size * num_networks exceeds cidr size - self.assertRaises(ValueError, manager.create_networks, *args) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_already_used(self, get_all): - manager = fake_network.FakeNetworkManager() - get_all.return_value = [dict(test_network.fake_network, - cidr='192.168.0.0/24')] - # CidrConflict: cidr already in use - args = (self.context.elevated(), 'fake', '192.168.0.0/24', False, - 1, 256, None, None, None, None, None) - self.assertRaises(exception.CidrConflict, - manager.create_networks, *args) - - def test_validate_cidrs_too_many(self): - manager = fake_network.FakeNetworkManager() - args = (None, 'fake', '192.168.0.0/24', False, 200, 256, None, None, - None, None, None) - # ValueError: Not enough subnets avail to satisfy requested - # num_networks - self.assertRaises(ValueError, manager.create_networks, *args) - - def test_validate_cidrs_split_partial(self): - manager = fake_network.FakeNetworkManager() - nets = manager.create_networks(self.context.elevated(), 'fake', - '192.168.0.0/16', - False, 2, 256, None, None, None, None, - None) - returned_cidrs = [str(net['cidr']) for net in nets] - self.assertIn('192.168.0.0/24', returned_cidrs) - self.assertIn('192.168.1.0/24', returned_cidrs) - - @mock.patch('nova.db.api.network_get_all') - def test_validate_cidrs_conflict_existing_supernet(self, get_all): - manager = fake_network.FakeNetworkManager() - get_all.return_value = [dict(test_network.fake_network, - id=1, cidr='192.168.0.0/8')] - args = (self.context.elevated(), 'fake', '192.168.0.0/24', False, - 1, 256, None, None, None, None, None) - # CidrConflict: requested cidr (192.168.0.0/24) conflicts - # with existing supernet - self.assertRaises(exception.CidrConflict, - manager.create_networks, *args) - - def test_create_networks(self): - cidr = '192.168.0.0/24' - manager = fake_network.FakeNetworkManager() - self.stubs.Set(manager, '_create_fixed_ips', - self.fake_create_fixed_ips) - args = [self.context.elevated(), 'foo', cidr, None, 1, 256, - 'fd00::/48', None, None, None, None, None] - self.assertTrue(manager.create_networks(*args)) - - def test_create_networks_with_uuid(self): - cidr = '192.168.0.0/24' - uuid = FAKEUUID - manager = fake_network.FakeNetworkManager() - self.stubs.Set(manager, '_create_fixed_ips', - self.fake_create_fixed_ips) - args = [self.context.elevated(), 'foo', cidr, None, 1, 256, - 'fd00::/48', None, None, None, None, None] - kwargs = {'uuid': uuid} - nets = manager.create_networks(*args, **kwargs) - self.assertEqual(1, len(nets)) - net = nets[0] - self.assertEqual(uuid, net['uuid']) - - @mock.patch('nova.db.api.network_get_all') - def test_create_networks_cidr_already_used(self, get_all): - manager = fake_network.FakeNetworkManager() - get_all.return_value = [dict(test_network.fake_network, - id=1, cidr='192.168.0.0/24')] - args = [self.context.elevated(), 'foo', '192.168.0.0/24', None, 1, 256, - 'fd00::/48', None, None, None, None, None] - self.assertRaises(exception.CidrConflict, - manager.create_networks, *args) - - def test_create_networks_many(self): - cidr = '192.168.0.0/16' - manager = fake_network.FakeNetworkManager() - self.stubs.Set(manager, '_create_fixed_ips', - self.fake_create_fixed_ips) - args = [self.context.elevated(), 'foo', cidr, None, 10, 256, - 'fd00::/48', None, None, None, None, None] - self.assertTrue(manager.create_networks(*args)) - - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ips_by_virtual_interface') - def test_get_instance_uuids_by_ip_regex(self, fixed_get, network_get): - manager = fake_network.FakeNetworkManager(self.stubs) - fixed_get.side_effect = manager.db.fixed_ips_by_virtual_interface - _vifs = manager.db.virtual_interface_get_all(None) - fake_context = context.RequestContext('user', 'project') - network_get.return_value = dict(test_network.fake_network, - **manager.db.network_get(None, 1)) - - # Greedy get eveything - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip': '.*'}) - self.assertEqual(len(_vifs), len(res)) - - # Doesn't exist - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip': '10.0.0.1'}) - self.assertFalse(res) - - # Get instance 1 - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip': '172.16.0.2'}) - self.assertTrue(res) - self.assertEqual(1, len(res)) - self.assertEqual(_vifs[1]['instance_uuid'], res[0]['instance_uuid']) - - # Get instance 2 - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip': '173.16.0.2'}) - self.assertTrue(res) - self.assertEqual(1, len(res)) - self.assertEqual(_vifs[2]['instance_uuid'], res[0]['instance_uuid']) - - # Get instance 0 and 1 - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip': '172.16.0.*'}) - self.assertTrue(res) - self.assertEqual(2, len(res)) - self.assertEqual(_vifs[0]['instance_uuid'], res[0]['instance_uuid']) - self.assertEqual(_vifs[1]['instance_uuid'], res[1]['instance_uuid']) - - # Get instance 1 and 2 - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip': '17..16.0.2'}) - self.assertTrue(res) - self.assertEqual(2, len(res)) - self.assertEqual(_vifs[1]['instance_uuid'], res[0]['instance_uuid']) - self.assertEqual(_vifs[2]['instance_uuid'], res[1]['instance_uuid']) - - @mock.patch('nova.db.api.network_get') - def test_get_instance_uuids_by_ipv6_regex(self, network_get): - manager = fake_network.FakeNetworkManager(self.stubs) - _vifs = manager.db.virtual_interface_get_all(None) - fake_context = context.RequestContext('user', 'project') - - def _network_get(context, network_id, **args): - return dict(test_network.fake_network, - **manager.db.network_get(context, network_id)) - network_get.side_effect = _network_get - - # Greedy get eveything - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip6': '.*'}) - self.assertEqual(len(_vifs), len(res)) - - # Doesn't exist - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip6': '.*1034.*'}) - self.assertFalse(res) - - # Get instance 1 - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip6': '2001:.*2'}) - self.assertTrue(res) - self.assertEqual(1, len(res)) - self.assertEqual(_vifs[1]['instance_uuid'], res[0]['instance_uuid']) - - # Get instance 2 - ip6 = '2001:db8:69:1f:dead:beff:feff:ef03' - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip6': ip6}) - self.assertTrue(res) - self.assertEqual(1, len(res)) - self.assertEqual(_vifs[2]['instance_uuid'], res[0]['instance_uuid']) - - # Get instance 0 and 1 - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip6': '.*ef0[1,2]'}) - self.assertTrue(res) - self.assertEqual(2, len(res)) - self.assertEqual(_vifs[0]['instance_uuid'], res[0]['instance_uuid']) - self.assertEqual(_vifs[1]['instance_uuid'], res[1]['instance_uuid']) - - # Get instance 1 and 2 - ip6 = '2001:db8:69:1.:dead:beff:feff:ef0.' - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'ip6': ip6}) - self.assertTrue(res) - self.assertEqual(2, len(res)) - self.assertEqual(_vifs[1]['instance_uuid'], res[0]['instance_uuid']) - self.assertEqual(_vifs[2]['instance_uuid'], res[1]['instance_uuid']) - - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.fixed_ips_by_virtual_interface') - def test_get_instance_uuids_by_ip(self, fixed_get, network_get): - manager = fake_network.FakeNetworkManager(self.stubs) - fixed_get.side_effect = manager.db.fixed_ips_by_virtual_interface - _vifs = manager.db.virtual_interface_get_all(None) - fake_context = context.RequestContext('user', 'project') - network_get.return_value = dict(test_network.fake_network, - **manager.db.network_get(None, 1)) - - # No regex for you! - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'fixed_ip': '.*'}) - self.assertFalse(res) - - # Doesn't exist - ip = '10.0.0.1' - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'fixed_ip': ip}) - self.assertFalse(res) - - # Get instance 1 - ip = '172.16.0.2' - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'fixed_ip': ip}) - self.assertTrue(res) - self.assertEqual(1, len(res)) - self.assertEqual(_vifs[1]['instance_uuid'], res[0]['instance_uuid']) - - # Get instance 2 - ip = '173.16.0.2' - res = manager.get_instance_uuids_by_ip_filter(fake_context, - {'fixed_ip': ip}) - self.assertTrue(res) - self.assertEqual(1, len(res)) - self.assertEqual(_vifs[2]['instance_uuid'], res[0]['instance_uuid']) - - @mock.patch('nova.db.api.network_get_by_uuid') - def test_get_network(self, get): - manager = fake_network.FakeNetworkManager() - fake_context = context.RequestContext('user', 'project') - get.return_value = dict(test_network.fake_network, **networks[0]) - uuid = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' - network = manager.get_network(fake_context, uuid) - self.assertEqual(uuid, network['uuid']) - - @mock.patch('nova.db.api.network_get_by_uuid') - def test_get_network_not_found(self, get): - manager = fake_network.FakeNetworkManager() - fake_context = context.RequestContext('user', 'project') - get.side_effect = exception.NetworkNotFoundForUUID(uuid='foo') - uuid = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee' - self.assertRaises(exception.NetworkNotFound, - manager.get_network, fake_context, uuid) - - @mock.patch('nova.db.api.network_get_all') - def test_get_all_networks(self, get_all): - manager = fake_network.FakeNetworkManager() - fake_context = context.RequestContext('user', 'project') - get_all.return_value = [dict(test_network.fake_network, **net) - for net in networks] - output = manager.get_all_networks(fake_context) - self.assertEqual(2, len(networks)) - self.assertEqual('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - output[0]['uuid']) - self.assertEqual('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - output[1]['uuid']) - - @mock.patch('nova.db.api.network_get_by_uuid') - @mock.patch('nova.db.api.network_disassociate') - def test_disassociate_network(self, disassociate, get): - manager = fake_network.FakeNetworkManager() - disassociate.return_value = True - fake_context = context.RequestContext('user', 'project') - get.return_value = dict(test_network.fake_network, - **networks[0]) - uuid = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' - manager.disassociate_network(fake_context, uuid) - - @mock.patch('nova.db.api.network_get_by_uuid') - def test_disassociate_network_not_found(self, get): - manager = fake_network.FakeNetworkManager() - fake_context = context.RequestContext('user', 'project') - get.side_effect = exception.NetworkNotFoundForUUID(uuid='fake') - uuid = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee' - self.assertRaises(exception.NetworkNotFound, - manager.disassociate_network, fake_context, uuid) - - def _test_init_host_dynamic_fixed_range(self, net_manager): - self.flags(fake_network=True, - routing_source_ip='172.16.0.1', - metadata_host='172.16.0.1', - public_interface='eth1', - dmz_cidr=['10.0.3.0/24']) - binary_name = linux_net.get_binary_name() - - # Stub out calls we don't want to really run, mock the db - self.stubs.Set(linux_net.iptables_manager, '_apply', lambda: None) - self.stubs.Set(floating_ips.FloatingIP, 'init_host_floating_ips', - lambda *args: None) - self.stubs.Set(net_manager.l3driver, 'initialize_gateway', - lambda *args: None) - self.mox.StubOutWithMock(db, 'network_get_all_by_host') - fake_networks = [dict(test_network.fake_network, **n) - for n in networks] - db.network_get_all_by_host(mox.IgnoreArg(), - mox.IgnoreArg() - ).MultipleTimes().AndReturn(fake_networks) - self.mox.ReplayAll() - - net_manager.init_host() - - # Get the iptables rules that got created - current_lines = [] - new_lines = linux_net.iptables_manager._modify_rules(current_lines, - linux_net.iptables_manager.ipv4['nat'], - table_name='nat') - - expected_lines = ['[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' - '-j SNAT --to-source %s -o %s' - % (binary_name, networks[0]['cidr'], - CONF.routing_source_ip, - CONF.public_interface), - '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT' - % (binary_name, networks[0]['cidr'], - CONF.metadata_host), - '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT' - % (binary_name, networks[0]['cidr'], - CONF.dmz_cidr[0]), - '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack ! ' - '--ctstate DNAT -j ACCEPT' % (binary_name, - networks[0]['cidr'], - networks[0]['cidr']), - '[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' - '-j SNAT --to-source %s -o %s' - % (binary_name, networks[1]['cidr'], - CONF.routing_source_ip, - CONF.public_interface), - '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT' - % (binary_name, networks[1]['cidr'], - CONF.metadata_host), - '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT' - % (binary_name, networks[1]['cidr'], - CONF.dmz_cidr[0]), - '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack ! ' - '--ctstate DNAT -j ACCEPT' % (binary_name, - networks[1]['cidr'], - networks[1]['cidr'])] - - # Compare the expected rules against the actual ones - for line in expected_lines: - self.assertIn(line, new_lines) - - # Add an additional network and ensure the rules get configured - new_network = {'id': 2, - 'uuid': uuids.network_1, - 'label': 'test2', - 'injected': False, - 'multi_host': False, - 'cidr': '192.168.2.0/24', - 'cidr_v6': '2001:dba::/64', - 'gateway_v6': '2001:dba::1', - 'netmask_v6': '64', - 'netmask': '255.255.255.0', - 'bridge': 'fa1', - 'bridge_interface': 'fake_fa1', - 'gateway': '192.168.2.1', - 'dhcp_server': '192.168.2.1', - 'broadcast': '192.168.2.255', - 'dns1': '192.168.2.1', - 'dns2': '192.168.2.2', - 'vlan': None, - 'host': HOST, - 'project_id': fakes.FAKE_PROJECT_ID, - 'vpn_public_address': '192.168.2.2', - 'vpn_public_port': '22', - 'vpn_private_address': '10.0.0.2'} - new_network_obj = objects.Network._from_db_object( - self.context, objects.Network(), - dict(test_network.fake_network, **new_network)) - - ctxt = context.get_admin_context() - net_manager._setup_network_on_host(ctxt, new_network_obj) - - # Get the new iptables rules that got created from adding a new network - current_lines = [] - new_lines = linux_net.iptables_manager._modify_rules(current_lines, - linux_net.iptables_manager.ipv4['nat'], - table_name='nat') - - # Add the new expected rules to the old ones - expected_lines += ['[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' - '-j SNAT --to-source %s -o %s' - % (binary_name, new_network['cidr'], - CONF.routing_source_ip, - CONF.public_interface), - '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT' - % (binary_name, new_network['cidr'], - CONF.metadata_host), - '[0:0] -A %s-POSTROUTING -s %s -d %s -j ACCEPT' - % (binary_name, new_network['cidr'], - CONF.dmz_cidr[0]), - '[0:0] -A %s-POSTROUTING -s %s -d %s -m conntrack ' - '! --ctstate DNAT -j ACCEPT' % (binary_name, - new_network['cidr'], - new_network['cidr'])] - - # Compare the expected rules (with new network) against the actual ones - for line in expected_lines: - self.assertIn(line, new_lines) - - @mock.patch('nova.privsep.linux_net.bind_ip') - def test_flatdhcpmanager_dynamic_fixed_range(self, mock_bind_ip): - """Test FlatDHCPManager NAT rules for fixed_range.""" - # Set the network manager - self.network = network_manager.FlatDHCPManager(host=HOST) - self.network.db = db - - # Test new behavior: - # CONF.fixed_range is not set, defaults to None - # Determine networks to NAT based on lookup - self._test_init_host_dynamic_fixed_range(self.network) - - @mock.patch('nova.privsep.linux_net.bind_ip') - def test_vlanmanager_dynamic_fixed_range(self, mock_bind_ip): - """Test VlanManager NAT rules for fixed_range.""" - # Set the network manager - self.network = network_manager.VlanManager(host=HOST) - self.network.db = db - - # Test new behavior: - # CONF.fixed_range is not set, defaults to None - # Determine networks to NAT based on lookup - self._test_init_host_dynamic_fixed_range(self.network) - - def test_fixed_cidr_out_of_range(self): - manager = network_manager.NetworkManager() - ctxt = context.get_admin_context() - self.assertRaises(exception.AddressOutOfRange, - manager.create_networks, ctxt, label="fake", - cidr='10.1.0.0/24', fixed_cidr='10.1.1.0/25') - - -class FakeRPCFixedManager(network_manager.RPCAllocateFixedIP, - network_manager.NetworkManager): - """Dummy manager that implements RPCAllocateFixedIP.""" - - -class RPCAllocateTestCase(test.NoDBTestCase): - """Tests nova.network.manager.RPCAllocateFixedIP.""" - def setUp(self): - super(RPCAllocateTestCase, self).setUp() - self.rpc_fixed = FakeRPCFixedManager() - self.context = context.RequestContext('fake', 'fake') - - def test_rpc_allocate(self): - """Test to verify bug 855030 doesn't resurface. - - Mekes sure _rpc_allocate_fixed_ip returns a value so the call - returns properly and the greenpool completes. - """ - address = '10.10.10.10' - - def fake_allocate(*args, **kwargs): - return address - - def fake_network_get(*args, **kwargs): - return test_network.fake_network - - self.stubs.Set(self.rpc_fixed, 'allocate_fixed_ip', fake_allocate) - self.stubs.Set(self.rpc_fixed.db, 'network_get', fake_network_get) - rval = self.rpc_fixed._rpc_allocate_fixed_ip(self.context, - 'fake_instance', - 'fake_network') - self.assertEqual(address, rval) - - -class FakeFloatingIPManager(floating_ips.FloatingIP, - network_manager.NetworkManager): - """Dummy manager that implements FloatingIP.""" - - -class AllocateTestCase(test.TestCase): - - REQUIRES_LOCKING = True - - def setUp(self): - super(AllocateTestCase, self).setUp() - dns = 'nova.network.noop_dns_driver.NoopDNSDriver' - self.flags(instance_dns_manager=dns) - self.useFixture(test.SampleNetworks()) - self.network = network_manager.VlanManager(host=HOST) - - self.user_id = fakes.FAKE_USER_ID - self.project_id = fakes.FAKE_PROJECT_ID - self.context = context.RequestContext(self.user_id, - self.project_id, - is_admin=True) - self.user_context = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID) - - @mock.patch('nova.privsep.linux_net.add_bridge', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.set_device_mtu') - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.set_device_macaddr') - @mock.patch('nova.privsep.linux_net.bind_ip') - @mock.patch('nova.privsep.linux_net.unbind_ip') - @mock.patch('nova.privsep.linux_net.routes_show', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.lookup_ip', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.change_ip') - @mock.patch('nova.privsep.linux_net.clean_conntrack') - @mock.patch('nova.privsep.linux_net.address_command_deprecated') - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=False) - @mock.patch('nova.privsep.linux_net._enable_ipv4_forwarding_inner') - @mock.patch('nova.privsep.linux_net.modify_ebtables') - @mock.patch('nova.privsep.linux_net.add_vlan') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - @mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')) - def test_allocate_for_instance( - self, mock_bridge_add_interface, mock_bridge_disable_stp, - mock_bridge_setfd, mock_iptables_set_rules, - mock_iptables_get_rules, mock_add_vlan, mock_modify_ebtables, - mock_forwarding_enable, mock_forwarding_check, - mock_clean_conntrack, mock_address_command, - mock_change_ip, mock_lookup_ip, mock_routes_show, mock_unbind, - mock_bind, mock_set_macaddr, mock_set_enabled, mock_set_mtu, - mock_add_bridge): - address = "10.10.10.10" - self.flags(auto_assign_floating_ip=True) - - db.floating_ip_create(self.context, - {'address': address, - 'pool': 'nova'}) - inst = objects.Instance(context=self.context) - inst.host = HOST - inst.display_name = HOST - inst.instance_type_id = 1 - inst.uuid = FAKEUUID - inst.create() - networks = db.network_get_all(self.context) - reqnets = objects.NetworkRequestList(objects=[]) - index = 0 - project_id = self.user_context.project_id - for network in networks: - db.network_update(self.context, network['id'], - {'host': HOST, - 'project_id': project_id}) - if index == 0: - reqnets.objects.append(objects.NetworkRequest( - network_id=network['uuid'], - tag='mynic')) - index += 1 - nw_info = self.network.allocate_for_instance(self.user_context, - instance_id=inst['id'], instance_uuid=inst['uuid'], - host=inst['host'], vpn=None, rxtx_factor=3, - project_id=project_id, macs=None, requested_networks=reqnets) - self.assertEqual(1, len(nw_info)) - vifs = objects.VirtualInterfaceList.get_all(self.context) - self.assertEqual(['mynic'], [vif.tag for vif in vifs]) - fixed_ip = nw_info.fixed_ips()[0]['address'] - self.assertTrue(netutils.is_valid_ipv4(fixed_ip)) - self.network.deallocate_for_instance(self.context, - instance=inst) - - def test_allocate_for_instance_illegal_network(self): - networks = db.network_get_all(self.context) - requested_networks = [] - for network in networks: - # set all networks to other projects - db.network_update(self.context, network['id'], - {'host': HOST, - 'project_id': 'otherid'}) - requested_networks.append((network['uuid'], None)) - # set the first network to our project - db.network_update(self.context, networks[0]['id'], - {'project_id': self.user_context.project_id}) - - inst = objects.Instance(context=self.context) - inst.host = HOST - inst.display_name = HOST - inst.instance_type_id = 1 - inst.uuid = FAKEUUID - inst.create() - self.assertRaises(exception.NetworkNotFoundForProject, - self.network.allocate_for_instance, self.user_context, - instance_id=inst['id'], instance_uuid=inst['uuid'], - host=inst['host'], vpn=None, rxtx_factor=3, - project_id=self.context.project_id, macs=None, - requested_networks=requested_networks) - - @mock.patch('nova.privsep.linux_net.add_bridge', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.set_device_mtu') - @mock.patch('nova.privsep.linux_net.set_device_enabled') - @mock.patch('nova.privsep.linux_net.set_device_macaddr') - @mock.patch('nova.privsep.linux_net.routes_show', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.lookup_ip', return_value=('', '')) - @mock.patch('nova.privsep.linux_net.change_ip') - @mock.patch('nova.privsep.linux_net.address_command_deprecated') - @mock.patch('nova.privsep.linux_net.ipv4_forwarding_check', - return_value=False) - @mock.patch('nova.privsep.linux_net._enable_ipv4_forwarding_inner') - @mock.patch('nova.privsep.linux_net.add_vlan') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.bridge_setfd') - @mock.patch('nova.privsep.linux_net.bridge_disable_stp') - @mock.patch('nova.privsep.linux_net.bridge_add_interface', - return_value=('', '')) - def test_allocate_for_instance_with_mac( - self, mock_bridge_add_interface, mock_bridge_disable_stp, - mock_bridge_setfd, mock_iptables_set_rules, - mock_iptables_get_rules, mock_add_vlan, mock_forwarding_enable, - mock_forwarding_check, mock_address_command, - mock_change_ip, mock_lookup_ip, mock_routes_show, - mock_set_addr, mock_enabled, mock_set_mtu, mock_add_bridge): - available_macs = set(['ca:fe:de:ad:be:ef']) - inst = db.instance_create(self.context, {'host': HOST, - 'display_name': HOST, - 'instance_type_id': 1}) - networks = db.network_get_all(self.context) - for network in networks: - db.network_update(self.context, network['id'], - {'host': HOST}) - project_id = self.context.project_id - nw_info = self.network.allocate_for_instance(self.user_context, - instance_id=inst['id'], instance_uuid=inst['uuid'], - host=inst['host'], vpn=None, rxtx_factor=3, - project_id=project_id, macs=available_macs) - assigned_macs = [vif['address'] for vif in nw_info] - self.assertEqual(1, len(assigned_macs)) - self.assertEqual(available_macs.pop(), assigned_macs[0]) - self.network.deallocate_for_instance(self.context, - instance_id=inst['id'], - host=self.network.host, - project_id=project_id) - - def test_allocate_for_instance_not_enough_macs(self): - available_macs = set() - inst = db.instance_create(self.context, {'host': HOST, - 'display_name': HOST, - 'instance_type_id': 1}) - networks = db.network_get_all(self.context) - for network in networks: - db.network_update(self.context, network['id'], - {'host': self.network.host}) - project_id = self.context.project_id - self.assertRaises(exception.VirtualInterfaceCreateException, - self.network.allocate_for_instance, - self.user_context, - instance_id=inst['id'], instance_uuid=inst['uuid'], - host=inst['host'], vpn=None, rxtx_factor=3, - project_id=project_id, macs=available_macs) - - -class FloatingIPTestCase(test.TestCase): - """Tests nova.network.manager.FloatingIP.""" - - REQUIRES_LOCKING = True - - def setUp(self): - super(FloatingIPTestCase, self).setUp() - self.tempdir = self.useFixture(fixtures.TempDir()).path - self.flags(log_dir=self.tempdir) - self.network = FakeFloatingIPManager() - self.network.db = db - self.project_id = fakes.FAKE_PROJECT_ID - self.context = context.RequestContext('testuser', self.project_id, - is_admin=False) - - @mock.patch('nova.db.api.fixed_ip_get') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.instance_get_by_uuid') - @mock.patch('nova.db.api.service_get_by_host_and_binary') - @mock.patch('nova.db.api.floating_ip_get_by_address') - def test_disassociate_floating_ip_multi_host_calls(self, floating_get, - service_get, - inst_get, net_get, - fixed_get): - floating_ip = dict(test_floating_ip.fake_floating_ip, - fixed_ip_id=12) - - fixed_ip = dict(test_fixed_ip.fake_fixed_ip, - network_id=None, - instance_uuid=uuids.instance) - - network = dict(test_network.fake_network, - multi_host=True) - - instance = dict(fake_instance.fake_db_instance(host='some-other-host')) - - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - self.stubs.Set(self.network, - '_floating_ip_owned_by_project', - lambda _x, _y: True) - - floating_get.return_value = floating_ip - fixed_get.return_value = fixed_ip - net_get.return_value = network - inst_get.return_value = instance - service_get.return_value = test_service.fake_service - - self.stubs.Set(self.network.servicegroup_api, - 'service_is_up', - lambda _x: True) - - self.mox.StubOutWithMock( - self.network.network_rpcapi, '_disassociate_floating_ip') - - self.network.network_rpcapi._disassociate_floating_ip( - ctxt, 'fl_ip', mox.IgnoreArg(), 'some-other-host', - uuids.instance) - self.mox.ReplayAll() - - self.network.disassociate_floating_ip(ctxt, 'fl_ip', True) - - @mock.patch('nova.db.api.fixed_ip_get_by_address') - @mock.patch('nova.db.api.network_get') - @mock.patch('nova.db.api.instance_get_by_uuid') - @mock.patch('nova.db.api.floating_ip_get_by_address') - def test_associate_floating_ip_multi_host_calls(self, floating_get, - inst_get, net_get, - fixed_get): - floating_ip = dict(test_floating_ip.fake_floating_ip, - fixed_ip_id=None) - - fixed_ip = dict(test_fixed_ip.fake_fixed_ip, - network_id=None, - instance_uuid=uuids.instance) - - network = dict(test_network.fake_network, - multi_host=True) - - instance = dict(fake_instance.fake_db_instance(host='some-other-host')) - - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=False) - - self.stubs.Set(self.network, - '_floating_ip_owned_by_project', - lambda _x, _y: True) - - floating_get.return_value = floating_ip - fixed_get.return_value = fixed_ip - net_get.return_value = network - inst_get.return_value = instance - - self.mox.StubOutWithMock( - self.network.network_rpcapi, '_associate_floating_ip') - - self.network.network_rpcapi._associate_floating_ip( - ctxt, 'fl_ip', 'fix_ip', mox.IgnoreArg(), 'some-other-host', - uuids.instance) - self.mox.ReplayAll() - - self.network.associate_floating_ip(ctxt, 'fl_ip', 'fix_ip', True) - - def test_double_deallocation(self): - instance_ref = db.instance_create(self.context, - {"project_id": self.project_id}) - # Run it twice to make it fault if it does not handle - # instances without fixed networks - # If this fails in either, it does not handle having no addresses - self.network.deallocate_for_instance(self.context, - instance_id=instance_ref['id']) - self.network.deallocate_for_instance(self.context, - instance_id=instance_ref['id']) - - @mock.patch('nova.privsep.linux_net.unbind_ip') - @mock.patch('nova.privsep.linux_net.clean_conntrack') - @mock.patch('nova.privsep.linux_net.modify_ebtables') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_deallocation_deleted_instance( - self, mock_iptables_set_rules, mock_iptables_get_rules, - mock_modify_ebtables, mock_clean_conntrack, mock_unbind_ip): - self.stubs.Set(self.network, '_teardown_network_on_host', - lambda *args, **kwargs: None) - instance = objects.Instance(context=self.context) - instance.project_id = self.project_id - instance.create() - instance.destroy() - network = db.network_create_safe(self.context.elevated(), { - 'project_id': self.project_id, - 'host': CONF.host, - 'label': 'foo'}) - fixed = db.fixed_ip_create(self.context, {'allocated': True, - 'instance_uuid': instance.uuid, 'address': '10.1.1.1', - 'network_id': network['id']}) - db.floating_ip_create(self.context, { - 'address': '10.10.10.10', 'instance_uuid': instance.uuid, - 'fixed_ip_id': fixed['id'], - 'project_id': self.project_id}) - self.network.deallocate_for_instance(self.context, instance=instance) - - @mock.patch('nova.privsep.linux_net.unbind_ip') - @mock.patch('nova.privsep.linux_net.clean_conntrack') - @mock.patch('nova.privsep.linux_net.modify_ebtables') - @mock.patch('nova.privsep.linux_net.iptables_get_rules', - return_value=('', '')) - @mock.patch('nova.privsep.linux_net.iptables_set_rules', - return_value=('', '')) - def test_deallocation_duplicate_floating_ip( - self, mock_iptables_set_rules, mock_iptables_get_rules, - mock_modify_ebtables, mock_clean_conntrack, mock_unbind_ip): - self.stubs.Set(self.network, '_teardown_network_on_host', - lambda *args, **kwargs: None) - instance = objects.Instance(context=self.context) - instance.project_id = self.project_id - instance.create() - network = db.network_create_safe(self.context.elevated(), { - 'project_id': self.project_id, - 'host': CONF.host, - 'label': 'foo'}) - fixed = db.fixed_ip_create(self.context, {'allocated': True, - 'instance_uuid': instance.uuid, 'address': '10.1.1.1', - 'network_id': network['id']}) - db.floating_ip_create(self.context, { - 'address': '10.10.10.10', - 'deleted': True}) - db.floating_ip_create(self.context, { - 'address': '10.10.10.10', 'instance_uuid': instance.uuid, - 'fixed_ip_id': fixed['id'], - 'project_id': self.project_id}) - self.network.deallocate_for_instance(self.context, instance=instance) - - @mock.patch('nova.db.api.fixed_ip_get') - @mock.patch('nova.db.api.floating_ip_get_by_address') - @mock.patch('nova.db.api.floating_ip_update') - @mock.patch('nova.privsep.linux_net.clean_conntrack') - def test_migrate_instance_start(self, clean_conntrack, floating_update, - floating_get, fixed_get): - called = {'count': 0} - - def fake_floating_ip_get_by_address(context, address): - return dict(test_floating_ip.fake_floating_ip, - address=address, - fixed_ip_id=0) - - def fake_is_stale_floating_ip_address(context, floating_ip): - return str(floating_ip.address) == '172.24.4.23' - - floating_get.side_effect = fake_floating_ip_get_by_address - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - instance_uuid=uuids.instance, - address='10.0.0.2', - network=test_network.fake_network) - floating_update.return_value = fake_floating_ip_get_by_address( - None, '1.2.3.4') - - def fake_remove_floating_ip(floating_addr, fixed_addr, interface, - network): - called['count'] += 1 - - def fake_clean_conntrack(fixed_ip): - if not str(fixed_ip) == "10.0.0.2": - raise exception.FixedIpInvalid(address=fixed_ip) - - self.stubs.Set(self.network, '_is_stale_floating_ip_address', - fake_is_stale_floating_ip_address) - self.stubs.Set(self.network.l3driver, 'remove_floating_ip', - fake_remove_floating_ip) - clean_conntrack.side_effect = fake_clean_conntrack - - self.mox.ReplayAll() - addresses = ['172.24.4.23', '172.24.4.24', '172.24.4.25'] - self.network.migrate_instance_start(self.context, - instance_uuid=FAKEUUID, - floating_addresses=addresses, - rxtx_factor=3, - project_id=self.project_id, - source='fake_source', - dest='fake_dest') - - self.assertEqual(2, called['count']) - - @mock.patch('nova.db.api.fixed_ip_get') - @mock.patch('nova.db.api.floating_ip_update') - def test_migrate_instance_finish(self, floating_update, fixed_get): - called = {'count': 0} - - def fake_floating_ip_get_by_address(context, address): - return dict(test_floating_ip.fake_floating_ip, - address=address, - fixed_ip_id=0) - - def fake_is_stale_floating_ip_address(context, floating_ip): - return str(floating_ip.address) == '172.24.4.23' - - fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip, - instance_uuid=uuids.instance, - address='10.0.0.2', - network=test_network.fake_network) - floating_update.return_value = fake_floating_ip_get_by_address( - None, '1.2.3.4') - - def fake_add_floating_ip(floating_addr, fixed_addr, interface, - network): - called['count'] += 1 - - self.stubs.Set(self.network.db, 'floating_ip_get_by_address', - fake_floating_ip_get_by_address) - self.stubs.Set(self.network, '_is_stale_floating_ip_address', - fake_is_stale_floating_ip_address) - self.stubs.Set(self.network.l3driver, 'add_floating_ip', - fake_add_floating_ip) - self.mox.ReplayAll() - addresses = ['172.24.4.23', '172.24.4.24', '172.24.4.25'] - self.network.migrate_instance_finish(self.context, - instance_uuid=FAKEUUID, - floating_addresses=addresses, - host='fake_dest', - rxtx_factor=3, - project_id=self.project_id, - source='fake_source') - - self.assertEqual(2, called['count']) - - def test_floating_dns_create_conflict(self): - zone = "example.org" - address1 = "10.10.10.11" - name1 = "foo" - - self.network.add_dns_entry(self.context, address1, name1, "A", zone) - - self.assertRaises(exception.FloatingIpDNSExists, - self.network.add_dns_entry, self.context, - address1, name1, "A", zone) - - def test_floating_create_and_get(self): - zone = "example.org" - address1 = "10.10.10.11" - name1 = "foo" - name2 = "bar" - entries = self.network.get_dns_entries_by_address(self.context, - address1, zone) - self.assertFalse(entries) - - self.network.add_dns_entry(self.context, address1, name1, "A", zone) - self.network.add_dns_entry(self.context, address1, name2, "A", zone) - entries = self.network.get_dns_entries_by_address(self.context, - address1, zone) - self.assertEqual(2, len(entries)) - self.assertEqual(name1, entries[0]) - self.assertEqual(name2, entries[1]) - - entries = self.network.get_dns_entries_by_name(self.context, - name1, zone) - self.assertEqual(1, len(entries)) - self.assertEqual(address1, entries[0]) - - def test_floating_dns_delete(self): - zone = "example.org" - address1 = "10.10.10.11" - name1 = "foo" - name2 = "bar" - - self.network.add_dns_entry(self.context, address1, name1, "A", zone) - self.network.add_dns_entry(self.context, address1, name2, "A", zone) - self.network.delete_dns_entry(self.context, name1, zone) - - entries = self.network.get_dns_entries_by_address(self.context, - address1, zone) - self.assertEqual(1, len(entries)) - self.assertEqual(name2, entries[0]) - - self.assertRaises(exception.NotFound, - self.network.delete_dns_entry, self.context, - name1, zone) - - def test_floating_dns_domains_public(self): - domain1 = "example.org" - domain2 = "example.com" - address1 = '10.10.10.10' - entryname = 'testentry' - - self.network.create_public_dns_domain(self.context, domain1, - fakes.FAKE_PROJECT_ID) - self.network.create_public_dns_domain(self.context, domain2, - 'fakeproject') - - domains = self.network.get_dns_domains(self.context) - self.assertEqual(2, len(domains)) - self.assertEqual(domain1, domains[0]['domain']) - self.assertEqual(domain2, domains[1]['domain']) - self.assertEqual(fakes.FAKE_PROJECT_ID, domains[0]['project']) - self.assertEqual('fakeproject', domains[1]['project']) - - self.network.add_dns_entry(self.context, address1, entryname, - 'A', domain1) - entries = self.network.get_dns_entries_by_name(self.context, - entryname, domain1) - self.assertEqual(1, len(entries)) - self.assertEqual(address1, entries[0]) - - self.network.delete_dns_domain(self.context, domain1) - self.network.delete_dns_domain(self.context, domain2) - - # Verify that deleting the domain deleted the associated entry - entries = self.network.get_dns_entries_by_name(self.context, - entryname, domain1) - self.assertFalse(entries) - - def test_delete_all_by_ip(self): - domain1 = "example.org" - domain2 = "example.com" - address = "10.10.10.10" - name1 = "foo" - name2 = "bar" - - def fake_domains(context): - return [{'domain': 'example.org', 'scope': 'public'}, - {'domain': 'example.com', 'scope': 'public'}, - {'domain': 'test.example.org', 'scope': 'public'}] - - self.stubs.Set(self.network, 'get_dns_domains', fake_domains) - - context_admin = context.RequestContext('testuser', - fakes.FAKE_PROJECT_ID, - is_admin=True) - - self.network.create_public_dns_domain(context_admin, domain1, - fakes.FAKE_PROJECT_ID) - self.network.create_public_dns_domain(context_admin, domain2, - 'fakeproject') - - domains = self.network.get_dns_domains(self.context) - for domain in domains: - self.network.add_dns_entry(self.context, address, - name1, "A", domain['domain']) - self.network.add_dns_entry(self.context, address, - name2, "A", domain['domain']) - entries = self.network.get_dns_entries_by_address(self.context, - address, - domain['domain']) - self.assertEqual(2, len(entries)) - - self.network._delete_all_entries_for_ip(self.context, address) - - for domain in domains: - entries = self.network.get_dns_entries_by_address(self.context, - address, - domain['domain']) - self.assertFalse(entries) - - self.network.delete_dns_domain(context_admin, domain1) - self.network.delete_dns_domain(context_admin, domain2) - - def test_mac_conflicts(self): - # Make sure MAC collisions are retried. - self.flags(create_unique_mac_address_attempts=3) - ctxt = context.RequestContext('testuser', fakes.FAKE_PROJECT_ID, - is_admin=True) - macs = ['bb:bb:bb:bb:bb:bb', 'aa:aa:aa:aa:aa:aa'] - - # Create a VIF with aa:aa:aa:aa:aa:aa - crash_test_dummy_vif = { - 'address': macs[1], - 'instance_uuid': uuids.instance, - 'network_id': 123, - 'uuid': 'fake_uuid', - } - self.network.db.virtual_interface_create(ctxt, crash_test_dummy_vif) - - # Hand out a collision first, then a legit MAC - def fake_gen_mac(): - return macs.pop() - self.stubs.Set(utils, 'generate_mac_address', fake_gen_mac) - - # SQLite doesn't seem to honor the uniqueness constraint on the - # address column, so fake the collision-avoidance here - def fake_vif_save(vif, session=None): - if vif.address == crash_test_dummy_vif['address']: - raise db_exc.DBError("If you're smart, you'll retry!") - # NOTE(russellb) The VirtualInterface object requires an ID to be - # set, and we expect it to get set automatically when we do the - # save. - vif.id = 1 - self.stubs.Set(models.VirtualInterface, 'save', fake_vif_save) - - # Attempt to add another and make sure that both MACs are consumed - # by the retry loop - self.network._add_virtual_interface(ctxt, uuids.instance, 123) - self.assertEqual([], macs) - - def test_deallocate_client_exceptions(self): - # Ensure that FloatingIpNotFoundForAddress is wrapped. - self.mox.StubOutWithMock(self.network.db, 'floating_ip_get_by_address') - self.network.db.floating_ip_get_by_address( - self.context, '1.2.3.4').AndRaise( - exception.FloatingIpNotFoundForAddress(address='fake')) - self.mox.ReplayAll() - self.assertRaises(messaging.ExpectedException, - self.network.deallocate_floating_ip, - self.context, '1.2.3.4') - - def test_associate_client_exceptions(self): - # Ensure that FloatingIpNotFoundForAddress is wrapped. - self.mox.StubOutWithMock(self.network.db, 'floating_ip_get_by_address') - self.network.db.floating_ip_get_by_address( - self.context, '1.2.3.4').AndRaise( - exception.FloatingIpNotFoundForAddress(address='fake')) - self.mox.ReplayAll() - self.assertRaises(messaging.ExpectedException, - self.network.associate_floating_ip, - self.context, '1.2.3.4', '10.0.0.1') - - def test_disassociate_client_exceptions(self): - # Ensure that FloatingIpNotFoundForAddress is wrapped. - self.mox.StubOutWithMock(self.network.db, 'floating_ip_get_by_address') - self.network.db.floating_ip_get_by_address( - self.context, '1.2.3.4').AndRaise( - exception.FloatingIpNotFoundForAddress(address='fake')) - self.mox.ReplayAll() - self.assertRaises(messaging.ExpectedException, - self.network.disassociate_floating_ip, - self.context, '1.2.3.4') - - def test_get_floating_ip_client_exceptions(self): - # Ensure that FloatingIpNotFoundForAddress is wrapped. - self.mox.StubOutWithMock(self.network.db, 'floating_ip_get') - self.network.db.floating_ip_get(self.context, 'fake-id').AndRaise( - exception.FloatingIpNotFound(id='fake')) - self.mox.ReplayAll() - self.assertRaises(messaging.ExpectedException, - self.network.get_floating_ip, - self.context, 'fake-id') - - def _test_associate_floating_ip_failure(self, stdout, expected_exception): - def _fake_catchall(*args, **kwargs): - return dict(test_fixed_ip.fake_fixed_ip, - network=test_network.fake_network) - - def _fake_add_floating_ip(*args, **kwargs): - raise processutils.ProcessExecutionError(stdout) - - self.stubs.Set(self.network.db, 'floating_ip_fixed_ip_associate', - _fake_catchall) - self.stubs.Set(self.network.db, 'floating_ip_disassociate', - _fake_catchall) - self.stubs.Set(self.network.l3driver, 'add_floating_ip', - _fake_add_floating_ip) - - self.assertRaises(expected_exception, - self.network._associate_floating_ip, self.context, - '1.2.3.4', '1.2.3.5', '', '') - - def test_associate_floating_ip_failure(self): - self._test_associate_floating_ip_failure(None, - processutils.ProcessExecutionError) - - def test_associate_floating_ip_failure_interface_not_found(self): - self._test_associate_floating_ip_failure('Cannot find device', - exception.NoFloatingIpInterface) - - @mock.patch('nova.objects.FloatingIP.get_by_address') - def test_get_floating_ip_by_address(self, mock_get): - mock_get.return_value = mock.sentinel.floating - self.assertEqual(mock.sentinel.floating, - self.network.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): - mock_get.return_value = mock.sentinel.floatings - self.assertEqual(mock.sentinel.floatings, - self.network.get_floating_ips_by_project( - self.context)) - mock_get.assert_called_once_with(self.context, self.context.project_id) - - @mock.patch('nova.objects.FloatingIPList.get_by_fixed_address') - def test_get_floating_ips_by_fixed_address(self, mock_get): - mock_get.return_value = [objects.FloatingIP(address='1.2.3.4'), - objects.FloatingIP(address='5.6.7.8')] - self.assertEqual(['1.2.3.4', '5.6.7.8'], - self.network.get_floating_ips_by_fixed_address( - self.context, mock.sentinel.address)) - mock_get.assert_called_once_with(self.context, mock.sentinel.address) - - @mock.patch('nova.db.api.floating_ip_get_pools') - def test_floating_ip_pool_exists(self, floating_ip_get_pools): - floating_ip_get_pools.return_value = [{'name': 'public'}] - self.assertTrue(self.network._floating_ip_pool_exists(self.context, - 'public')) - - @mock.patch('nova.db.api.floating_ip_get_pools') - def test_floating_ip_pool_does_not_exist(self, floating_ip_get_pools): - floating_ip_get_pools.return_value = [] - self.assertFalse(self.network._floating_ip_pool_exists(self.context, - 'public')) - - -class InstanceDNSTestCase(test.TestCase): - """Tests nova.network.manager instance DNS.""" - def setUp(self): - super(InstanceDNSTestCase, self).setUp() - self.tempdir = self.useFixture(fixtures.TempDir()).path - self.flags(log_dir=self.tempdir) - self.network = FakeFloatingIPManager() - self.network.db = db - self.project_id = fakes.FAKE_PROJECT_ID - self.context = context.RequestContext('testuser', self.project_id, - is_admin=False) - - def test_dns_domains_private(self): - zone1 = 'testzone' - domain1 = 'example.org' - - self.network.create_private_dns_domain(self.context, domain1, zone1) - domains = self.network.get_dns_domains(self.context) - self.assertEqual(1, len(domains)) - self.assertEqual(domain1, domains[0]['domain']) - self.assertEqual(zone1, domains[0]['availability_zone']) - - self.network.delete_dns_domain(self.context, domain1) - - -domain1 = "example.org" -domain2 = "example.com" - - -@testtools.skipIf(six.PY3, 'python-ldap is not compatible for Python 3.') -class LdapDNSTestCase(test.NoDBTestCase): - """Tests nova.network.ldapdns.LdapDNS.""" - def setUp(self): - super(LdapDNSTestCase, self).setUp() - - self.useFixture(fixtures.MonkeyPatch( - 'nova.network.ldapdns.ldap', - fake_ldap)) - dns_class = 'nova.network.ldapdns.LdapDNS' - self.driver = importutils.import_object(dns_class) - - attrs = {'objectClass': ['domainrelatedobject', 'dnsdomain', - 'domain', 'dcobject', 'top'], - 'associateddomain': ['root'], - 'dc': ['root']} - self.driver.lobj.add_s("ou=hosts,dc=example,dc=org", attrs.items()) - self.driver.create_domain(domain1) - self.driver.create_domain(domain2) - - def tearDown(self): - self.driver.delete_domain(domain1) - self.driver.delete_domain(domain2) - super(LdapDNSTestCase, self).tearDown() - - def test_ldap_dns_domains(self): - domains = self.driver.get_domains() - self.assertEqual(2, len(domains)) - self.assertIn(domain1, domains) - self.assertIn(domain2, domains) - - def test_ldap_dns_create_conflict(self): - address1 = "10.10.10.11" - name1 = "foo" - - self.driver.create_entry(name1, address1, "A", domain1) - - self.assertRaises(exception.FloatingIpDNSExists, - self.driver.create_entry, - name1, address1, "A", domain1) - - def test_ldap_dns_create_and_get(self): - address1 = "10.10.10.11" - name1 = "foo" - name2 = "bar" - entries = self.driver.get_entries_by_address(address1, domain1) - self.assertFalse(entries) - - self.driver.create_entry(name1, address1, "A", domain1) - self.driver.create_entry(name2, address1, "A", domain1) - entries = self.driver.get_entries_by_address(address1, domain1) - self.assertEqual(2, len(entries)) - self.assertEqual(name1, entries[0]) - self.assertEqual(name2, entries[1]) - - entries = self.driver.get_entries_by_name(name1, domain1) - self.assertEqual(1, len(entries)) - self.assertEqual(address1, entries[0]) - - def test_ldap_dns_delete(self): - address1 = "10.10.10.11" - name1 = "foo" - name2 = "bar" - - self.driver.create_entry(name1, address1, "A", domain1) - self.driver.create_entry(name2, address1, "A", domain1) - entries = self.driver.get_entries_by_address(address1, domain1) - self.assertEqual(2, len(entries)) - - self.driver.delete_entry(name1, domain1) - entries = self.driver.get_entries_by_address(address1, domain1) - LOG.debug("entries: %s", entries) - self.assertEqual(1, len(entries)) - self.assertEqual(name2, entries[0]) - - self.assertRaises(exception.NotFound, - self.driver.delete_entry, - name1, domain1) - - -class NetworkManagerNoDBTestCase(test.NoDBTestCase): - """Tests nova.network.manager.NetworkManager without a database.""" - - def setUp(self): - super(NetworkManagerNoDBTestCase, self).setUp() - self.context = context.RequestContext('fake-user', 'fake-project') - self.manager = network_manager.NetworkManager() - - @mock.patch.object(objects.FixedIP, 'get_by_address') - def test_release_fixed_ip_not_associated(self, mock_fip_get_by_addr): - # Tests that the method is a no-op when the fixed IP is not associated - # to an instance. - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fake_network.next_fixed_ip(1)) - fip.instance_uuid = None - with mock.patch.object(fip, 'disassociate') as mock_disassociate: - self.manager.release_fixed_ip(self.context, fip.address) - - self.assertFalse(mock_disassociate.called, - str(mock_disassociate.mock_calls)) - - @mock.patch.object(objects.FixedIP, 'get_by_address') - def test_release_fixed_ip_allocated(self, mock_fip_get_by_addr): - # Tests that the fixed IP is not disassociated if it's allocated. - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fake_network.next_fixed_ip(1)) - fip.leased = False - fip.allocated = True - with mock.patch.object(fip, 'disassociate') as mock_disassociate: - self.manager.release_fixed_ip(self.context, fip.address) - - self.assertFalse(mock_disassociate.called, - str(mock_disassociate.mock_calls)) - - @mock.patch.object(objects.FixedIP, 'get_by_address') - @mock.patch.object(objects.VirtualInterface, 'get_by_address') - def test_release_fixed_ip_mac_matches_associated_instance(self, - mock_vif_get_by_addr, - mock_fip_get_by_addr): - # Tests that the fixed IP is disassociated when the mac passed to - # release_fixed_ip matches the VIF which has the same instance_uuid - # as the instance associated to the FixedIP object. Also tests - # that the fixed IP is marked as not leased in the database if it was - # currently leased. - instance = fake_instance.fake_instance_obj(self.context) - fip = fake_network.next_fixed_ip(1) - fip['instance_uuid'] = instance.uuid - fip['leased'] = True - vif = fip['virtual_interface'] - vif['instance_uuid'] = instance.uuid - vif = objects.VirtualInterface._from_db_object( - self.context, objects.VirtualInterface(), vif) - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fip) - mock_fip_get_by_addr.return_value = fip - mock_vif_get_by_addr.return_value = vif - - with mock.patch.object(fip, 'save') as mock_fip_save: - with mock.patch.object(fip, 'disassociate') as mock_disassociate: - self.manager.release_fixed_ip( - self.context, fip.address, vif.address) - - mock_fip_save.assert_called_once_with() - self.assertFalse(fip.leased) - mock_vif_get_by_addr.assert_called_once_with(self.context, vif.address) - mock_disassociate.assert_called_once_with() - - @mock.patch.object(objects.FixedIP, 'get_by_address') - @mock.patch.object(objects.VirtualInterface, 'get_by_address', - return_value=None) - def test_release_fixed_ip_vif_not_found_for_mac(self, mock_vif_get_by_addr, - mock_fip_get_by_addr): - # Tests that the fixed IP is disassociated when the fixed IP is marked - # as deallocated and there is no VIF found in the database for the mac - # passed in. - fip = fake_network.next_fixed_ip(1) - fip['leased'] = False - mac = fip['virtual_interface']['address'] - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fip) - mock_fip_get_by_addr.return_value = fip - - with mock.patch.object(fip, 'disassociate') as mock_disassociate: - self.manager.release_fixed_ip(self.context, fip.address, mac) - - mock_vif_get_by_addr.assert_called_once_with(self.context, mac) - mock_disassociate.assert_called_once_with() - - @mock.patch.object(objects.FixedIP, 'get_by_address') - def test_release_fixed_ip_no_mac(self, mock_fip_get_by_addr): - # Tests that the fixed IP is disassociated when the fixed IP is - # deallocated and there is no mac address passed in (like before - # the network rpc api version bump to pass it in). - fip = fake_network.next_fixed_ip(1) - fip['leased'] = False - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fip) - mock_fip_get_by_addr.return_value = fip - - with mock.patch.object(fip, 'disassociate') as mock_disassociate: - self.manager.release_fixed_ip(self.context, fip.address) - - mock_disassociate.assert_called_once_with() - - @mock.patch.object(objects.FixedIP, 'get_by_address') - @mock.patch.object(objects.VirtualInterface, 'get_by_address') - def test_release_fixed_ip_mac_mismatch_associated_instance(self, - mock_vif_get_by_addr, - mock_fip_get_by_addr): - # Tests that the fixed IP is not disassociated when the VIF for the mac - # passed to release_fixed_ip does not have an instance_uuid that - # matches fixed_ip.instance_uuid. - old_instance = fake_instance.fake_instance_obj(self.context) - new_instance = fake_instance.fake_instance_obj(self.context) - fip = fake_network.next_fixed_ip(1) - fip['instance_uuid'] = new_instance.uuid - fip['leased'] = False - vif = fip['virtual_interface'] - vif['instance_uuid'] = old_instance.uuid - vif = objects.VirtualInterface._from_db_object( - self.context, objects.VirtualInterface(), vif) - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fip) - mock_fip_get_by_addr.return_value = fip - mock_vif_get_by_addr.return_value = vif - - with mock.patch.object(fip, 'disassociate') as mock_disassociate: - self.manager.release_fixed_ip( - self.context, fip.address, vif.address) - - mock_vif_get_by_addr.assert_called_once_with(self.context, vif.address) - self.assertFalse(mock_disassociate.called, - str(mock_disassociate.mock_calls)) - - @mock.patch.object(network_rpcapi.NetworkAPI, 'release_dhcp') - @mock.patch.object(objects.FixedIP, 'get_by_address') - @mock.patch.object(objects.VirtualInterface, 'get_by_id') - @mock.patch.object(objects.Quotas, 'reserve') - def test_deallocate_fixed_ip_explicit_disassociate(self, - mock_quota_reserve, - mock_vif_get_by_id, - mock_fip_get_by_addr, - mock_release_dhcp): - # Tests that we explicitly call FixedIP.disassociate when the fixed IP - # is not leased and has an associated instance (race with dnsmasq). - self.flags(force_dhcp_release=True) - fake_inst = fake_instance.fake_instance_obj(self.context) - fip = fake_network.next_fixed_ip(1) - fip['instance_uuid'] = fake_inst.uuid - fip['leased'] = False - vif = fip['virtual_interface'] - vif['instance_uuid'] = fake_inst.uuid - vif = objects.VirtualInterface._from_db_object( - self.context, objects.VirtualInterface(), vif) - fip = objects.FixedIP._from_db_object( - self.context, objects.FixedIP(), fip) - fip.network = fake_network.fake_network_obj(self.context, - fip.network_id) - mock_fip_get_by_addr.return_value = fip - mock_vif_get_by_id.return_value = vif - - @mock.patch.object(self.manager, - '_do_trigger_security_group_members_refresh_for_instance') - @mock.patch.object(self.manager, - '_validate_instance_zone_for_dns_domain', - return_value=False) - @mock.patch.object(self.manager, '_teardown_network_on_host') - @mock.patch.object(fip, 'save') - @mock.patch.object(fip, 'disassociate') - def do_test(mock_disassociate, mock_fip_save, - mock_teardown_network_on_host, mock_validate_zone, - mock_trigger_secgroup_refresh): - self.assertEqual(fake_inst.uuid, fip.instance_uuid) - self.assertFalse(fip.leased) - self.manager.deallocate_fixed_ip( - self.context, fip['address'], instance=fake_inst) - - mock_trigger_secgroup_refresh.assert_called_once_with( - fake_inst.uuid) - mock_teardown_network_on_host.assert_called_once_with(self.context, - fip.network) - mock_disassociate.assert_called_once_with() - - do_test() diff --git a/nova/tests/unit/network/test_rpcapi.py b/nova/tests/unit/network/test_rpcapi.py deleted file mode 100644 index 26a620d9d800..000000000000 --- a/nova/tests/unit/network/test_rpcapi.py +++ /dev/null @@ -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') diff --git a/nova/tests/unit/objects/test_dns_domain.py b/nova/tests/unit/objects/test_dns_domain.py deleted file mode 100644 index fc2810fbedca..000000000000 --- a/nova/tests/unit/objects/test_dns_domain.py +++ /dev/null @@ -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 diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index cfcfc71f39b6..2cdf1d52298c 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -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', diff --git a/nova/tests/unit/privsep/test_linux_net.py b/nova/tests/unit/privsep/test_linux_net.py index 86776544d4f4..5bdac6ca0233 100644 --- a/nova/tests/unit/privsep/test_linux_net.py +++ b/nova/tests/unit/privsep/test_linux_net.py @@ -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) diff --git a/nova/tests/unit/privsep/test_utils.py b/nova/tests/unit/privsep/test_utils.py index f136572750e8..84d0767c2963 100644 --- a/nova/tests/unit/privsep/test_utils.py +++ b/nova/tests/unit/privsep/test_utils.py @@ -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) diff --git a/nova/tests/unit/test_fixtures.py b/nova/tests/unit/test_fixtures.py index 271173090759..3ca706629087 100644 --- a/nova/tests/unit/test_fixtures.py +++ b/nova/tests/unit/test_fixtures.py @@ -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()) diff --git a/nova/tests/unit/test_iptables_network.py b/nova/tests/unit/test_iptables_network.py deleted file mode 100644 index 45b0052a5923..000000000000 --- a/nova/tests/unit/test_iptables_network.py +++ /dev/null @@ -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) diff --git a/nova/tests/unit/test_ipv6.py b/nova/tests/unit/test_ipv6.py deleted file mode 100644 index 7314d128e795..000000000000 --- a/nova/tests/unit/test_ipv6.py +++ /dev/null @@ -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)) diff --git a/nova/tests/unit/test_profiler.py b/nova/tests/unit/test_profiler.py index 7b5e64dad6f4..4cffd53345d2 100644 --- a/nova/tests/unit/test_profiler.py +++ b/nova/tests/unit/test_profiler.py @@ -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', diff --git a/nova/tests/unit/utils.py b/nova/tests/unit/utils.py index d3752ffe8d2b..eb306c2ea42d 100644 --- a/nova/tests/unit/utils.py +++ b/nova/tests/unit/utils.py @@ -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 ((""" diff --git a/nova/utils.py b/nova/utils.py index 72665fe8910b..914d5516ffdb 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -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: diff --git a/releasenotes/notes/remove-nova-network-c02953ba72a1795d.yaml b/releasenotes/notes/remove-nova-network-c02953ba72a1795d.yaml index 843cebd2f1b8..bdf9bf0d3e0f 100644 --- a/releasenotes/notes/remove-nova-network-c02953ba72a1795d.yaml +++ b/releasenotes/notes/remove-nova-network-c02953ba72a1795d.yaml @@ -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`` diff --git a/setup.cfg b/setup.cfg index afc8b5d1d8b5..b9b8f8eeea9a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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 diff --git a/test-requirements.txt b/test-requirements.txt index aae938f1c214..44df4e47a99b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -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