vmware-nsx/quantum/plugins/nicira/nicira_nvp_plugin/common/metadata_access.py
Salvatore Orlando 2acc26f922 Fix NVP plugin not notifying metadata access network to DHCP agent
Bug 1133395

Due to recent changes in notification logic between Quantum and the DHCP
agent, the notifier the NVP plugin previously used for metadata access
network was not working anymore and needed to be replaced

Change-Id: Ifa0ea55116cf5ef6d546d28ca52e643987b3e5a0
2013-02-26 18:01:00 +01:00

149 lines
7.1 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Nicira, 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 equired 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.
#
# @author: Salvatore Orlando, VMware
import netaddr
from oslo.config import cfg
from quantum.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from quantum.api.v2 import attributes
from quantum.common import constants
from quantum.common import exceptions as q_exc
from quantum.db import l3_db
from quantum.openstack.common import log as logging
from quantum.openstack.common.notifier import api as notifier_api
from quantum.plugins.nicira.nicira_nvp_plugin.common import (exceptions
as nvp_exc)
from quantum.plugins.nicira.nicira_nvp_plugin import NvpApiClient
LOG = logging.getLogger(__name__)
METADATA_DEFAULT_PREFIX = 30
METADATA_SUBNET_CIDR = '169.254.169.252/%d' % METADATA_DEFAULT_PREFIX
METADATA_GATEWAY_IP = '169.254.169.253'
class NvpMetadataAccess(object):
def _find_metadata_port(self, context, ports):
for port in ports:
for fixed_ip in port['fixed_ips']:
cidr = netaddr.IPNetwork(
self.get_subnet(context, fixed_ip['subnet_id'])['cidr'])
if cidr in netaddr.IPNetwork(METADATA_SUBNET_CIDR):
return port
def _create_metadata_access_network(self, context, router_id):
# This will still ensure atomicity on Quantum DB
# context.elevated() creates a deep-copy context
ctx_elevated = context.elevated()
with ctx_elevated.session.begin(subtransactions=True):
# Add network
# Network name is likely to be truncated on NVP
net_data = {'name': ('meta-%s' % router_id)[:40],
'tenant_id': '', # intentionally not set
'admin_state_up': True,
'port_security_enabled': False,
'shared': False,
'status': constants.NET_STATUS_ACTIVE}
meta_net = self.create_network(ctx_elevated,
{'network': net_data})
# Add subnet
subnet_data = {'network_id': meta_net['id'],
'tenant_id': '', # intentionally not set
'name': 'meta-%s' % router_id,
'ip_version': 4,
'shared': False,
'cidr': METADATA_SUBNET_CIDR,
'enable_dhcp': True,
# Ensure default allocation pool is generated
'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
'gateway_ip': METADATA_GATEWAY_IP,
'dns_nameservers': [],
'host_routes': []}
meta_sub = self.create_subnet(ctx_elevated,
{'subnet': subnet_data})
self.add_router_interface(ctx_elevated, router_id,
{'subnet_id': meta_sub['id']})
if cfg.CONF.dhcp_agent_notification:
# We need to send a notification to the dhcp agent in
# order to start the metadata agent proxy
dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
dhcp_notifier.notify(ctx_elevated,
{'network': meta_net},
'network.create.end')
def _destroy_metadata_access_network(self, context, router_id, ports):
# context.elevated() creates a deep-copy context
ctx_elevated = context.elevated()
# This will still ensure atomicity on Quantum DB
with ctx_elevated.session.begin(subtransactions=True):
if ports:
meta_port = self._find_metadata_port(ctx_elevated, ports)
if not meta_port:
return
meta_net_id = meta_port['network_id']
self.remove_router_interface(
ctx_elevated, router_id, {'port_id': meta_port['id']})
# Remove network (this will remove the subnet too)
self.delete_network(ctx_elevated, meta_net_id)
if cfg.CONF.dhcp_agent_notification:
# We need to send a notification to the dhcp agent in
# order to stop the metadata agent proxy
dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
dhcp_notifier.notify(ctx_elevated,
{'network': {'id': meta_net_id}},
'network.delete.end')
def _handle_metadata_access_network(self, context, router_id):
if not cfg.CONF.NVP.enable_metadata_access_network:
LOG.debug(_("Metadata access network is disabled"))
return
# As we'll use a different device_owner for metadata interface
# this query will return only 'real' router interfaces
ctx_elevated = context.elevated()
device_filter = {'device_id': [router_id],
'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF]}
with ctx_elevated.session.begin(subtransactions=True):
ports = self.get_ports(ctx_elevated, filters=device_filter)
try:
if ports:
if not self._find_metadata_port(ctx_elevated, ports):
self._create_metadata_access_network(context,
router_id)
elif len(ports) == 1:
# The only port left if the metadata port
self._destroy_metadata_access_network(context,
router_id,
ports)
else:
LOG.debug(_("No router interface found for router '%s'. "
"No metadata access network should be "
"created or destroyed"), router_id)
# TODO(salvatore-orlando): A better exception handling in the
# NVP plugin would allow us to improve error handling here
except (q_exc.QuantumException, nvp_exc.NvpPluginException,
NvpApiClient.NvpApiException):
# Any exception here should be regarded as non-fatal
LOG.exception(_("An error occurred while operating on the "
"metadata access network for router:'%s'"),
router_id)