7dde4283b7
Commit 87a79256c494c36f2d9597313f430b24c0110161 added neutron_lib for shared constants. This patch moves us to make use of the aforementioned library. Change-Id: I9f541602a2c321c56f4d99c3ddf5a3f4b7e07ffe
183 lines
7.4 KiB
Python
183 lines
7.4 KiB
Python
# Copyright 2014 VMware, 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 neutron.extensions import external_net
|
|
from neutron_lib import constants as const
|
|
from neutron_lib import exceptions as n_exc
|
|
from oslo_log import log as logging
|
|
|
|
from vmware_nsx._i18n import _, _LE
|
|
from vmware_nsx.common import exceptions as p_exc
|
|
from vmware_nsx.dhcp_meta import nsx
|
|
from vmware_nsx.dhcp_meta import rpc
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class DhcpMetadataBuilder(object):
|
|
|
|
def __init__(self, plugin, agent_notifier):
|
|
self.plugin = plugin
|
|
self.notifier = agent_notifier
|
|
|
|
def dhcp_agent_get_all(self, context, network_id):
|
|
"""Return the agents managing the network."""
|
|
return self.plugin.list_dhcp_agents_hosting_network(
|
|
context, network_id)['agents']
|
|
|
|
def dhcp_port_get_all(self, context, network_id):
|
|
"""Return the dhcp ports allocated for the network."""
|
|
filters = {
|
|
'network_id': [network_id],
|
|
'device_owner': [const.DEVICE_OWNER_DHCP]
|
|
}
|
|
return self.plugin.get_ports(context, filters=filters)
|
|
|
|
def router_id_get(self, context, subnet=None):
|
|
"""Return the router and interface used for the subnet."""
|
|
if not subnet:
|
|
return
|
|
network_id = subnet['network_id']
|
|
filters = {
|
|
'network_id': [network_id],
|
|
'device_owner': [const.DEVICE_OWNER_ROUTER_INTF]
|
|
}
|
|
ports = self.plugin.get_ports(context, filters=filters)
|
|
for port in ports:
|
|
if port['fixed_ips'][0]['subnet_id'] == subnet['id']:
|
|
return port['device_id']
|
|
|
|
def metadata_deallocate(self, context, router_id, subnet_id):
|
|
"""Deallocate metadata services for the subnet."""
|
|
interface = {'subnet_id': subnet_id}
|
|
self.plugin.remove_router_interface(context, router_id, interface)
|
|
|
|
def metadata_allocate(self, context, router_id, subnet_id):
|
|
"""Allocate metadata resources for the subnet via the router."""
|
|
interface = {'subnet_id': subnet_id}
|
|
self.plugin.add_router_interface(context, router_id, interface)
|
|
|
|
def dhcp_deallocate(self, context, network_id, agents, ports):
|
|
"""Deallocate dhcp resources for the network."""
|
|
for agent in agents:
|
|
self.plugin.remove_network_from_dhcp_agent(
|
|
context, agent['id'], network_id)
|
|
for port in ports:
|
|
try:
|
|
self.plugin.delete_port(context, port['id'])
|
|
except n_exc.PortNotFound:
|
|
LOG.error(_LE('Port %s is already gone'), port['id'])
|
|
|
|
def dhcp_allocate(self, context, network_id, subnet):
|
|
"""Allocate dhcp resources for the subnet."""
|
|
# Create LSN resources
|
|
network_data = {'id': network_id}
|
|
nsx.handle_network_dhcp_access(self.plugin, context,
|
|
network_data, 'create_network')
|
|
if subnet:
|
|
subnet_data = {'subnet': subnet}
|
|
self.notifier.notify(context, subnet_data, 'subnet.create.end')
|
|
# Get DHCP host and metadata entries created for the LSN
|
|
port = {
|
|
'network_id': network_id,
|
|
'fixed_ips': [{'subnet_id': subnet['id']}]
|
|
}
|
|
self.notifier.notify(context, {'port': port}, 'port.update.end')
|
|
|
|
|
|
class MigrationManager(object):
|
|
|
|
def __init__(self, plugin, lsn_manager, agent_notifier):
|
|
self.plugin = plugin
|
|
self.manager = lsn_manager
|
|
self.builder = DhcpMetadataBuilder(plugin, agent_notifier)
|
|
|
|
def validate(self, context, network_id):
|
|
"""Validate and return subnet's dhcp info for migration."""
|
|
network = self.plugin.get_network(context, network_id)
|
|
|
|
if self.manager.lsn_exists(context, network_id):
|
|
reason = _("LSN already exist")
|
|
raise p_exc.LsnMigrationConflict(net_id=network_id, reason=reason)
|
|
|
|
if network[external_net.EXTERNAL]:
|
|
reason = _("Cannot migrate an external network")
|
|
raise n_exc.BadRequest(resource='network', msg=reason)
|
|
|
|
filters = {'network_id': [network_id]}
|
|
subnets = self.plugin.get_subnets(context, filters=filters)
|
|
count = len(subnets)
|
|
if count == 0:
|
|
return None
|
|
elif count == 1 and subnets[0]['cidr'] == rpc.METADATA_SUBNET_CIDR:
|
|
reason = _("Cannot migrate a 'metadata' network")
|
|
raise n_exc.BadRequest(resource='network', msg=reason)
|
|
elif count > 1:
|
|
reason = _("Unable to support multiple subnets per network")
|
|
raise p_exc.LsnMigrationConflict(net_id=network_id, reason=reason)
|
|
else:
|
|
return subnets[0]
|
|
|
|
def migrate(self, context, network_id, subnet=None):
|
|
"""Migrate subnet resources to LSN."""
|
|
router_id = self.builder.router_id_get(context, subnet)
|
|
if router_id and subnet:
|
|
# Deallocate resources taken for the router, if any
|
|
self.builder.metadata_deallocate(context, router_id, subnet['id'])
|
|
if subnet:
|
|
# Deallocate reources taken for the agent, if any
|
|
agents = self.builder.dhcp_agent_get_all(context, network_id)
|
|
ports = self.builder.dhcp_port_get_all(context, network_id)
|
|
self.builder.dhcp_deallocate(context, network_id, agents, ports)
|
|
# (re)create the configuration for LSN
|
|
self.builder.dhcp_allocate(context, network_id, subnet)
|
|
if router_id and subnet:
|
|
# Allocate resources taken for the router, if any
|
|
self.builder.metadata_allocate(context, router_id, subnet['id'])
|
|
|
|
def report(self, context, network_id, subnet_id=None):
|
|
"""Return a report of the dhcp and metadata resources in use."""
|
|
if subnet_id:
|
|
lsn_id, lsn_port_id = self.manager.lsn_port_get(
|
|
context, network_id, subnet_id, raise_on_err=False)
|
|
else:
|
|
filters = {'network_id': [network_id]}
|
|
subnets = self.plugin.get_subnets(context, filters=filters)
|
|
if subnets:
|
|
lsn_id, lsn_port_id = self.manager.lsn_port_get(
|
|
context, network_id, subnets[0]['id'], raise_on_err=False)
|
|
else:
|
|
lsn_id = self.manager.lsn_get(context, network_id,
|
|
raise_on_err=False)
|
|
lsn_port_id = None
|
|
if lsn_id:
|
|
ports = [lsn_port_id] if lsn_port_id else []
|
|
report = {
|
|
'type': 'lsn',
|
|
'services': [lsn_id],
|
|
'ports': ports
|
|
}
|
|
else:
|
|
agents = self.builder.dhcp_agent_get_all(context, network_id)
|
|
ports = self.builder.dhcp_port_get_all(context, network_id)
|
|
report = {
|
|
'type': 'agent',
|
|
'services': [a['id'] for a in agents],
|
|
'ports': [p['id'] for p in ports]
|
|
}
|
|
return report
|