nova-net: Kill it
Finish the job by removing all the now-unused modules. This also allows us to - wait for it - kill mox at long last. It's a great day in the parish. Partial-Implements: blueprint remove-nova-network-ussuri Partial-Implements: blueprint mox-removal-ussuri Change-Id: Ia33ec2604b2fc2d3b6830b596cac669cc3ad6c96
This commit is contained in:
parent
828f3f2691
commit
f5f73b4c4e
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
"""),
|
||||
]
|
||||
|
||||
|
1336
nova/conf/network.py
1336
nova/conf/network.py
File diff suppressed because it is too large
Load Diff
@ -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'.
|
||||
|
@ -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)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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'
|
||||
|
@ -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
|
@ -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]])
|
@ -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()
|
@ -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]])
|
@ -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()
|
||||
|
@ -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})
|
@ -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
|
||||
|
@ -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()
|
@ -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)
|
@ -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.< |