Merge "Refactoring for nicira plugin to support NVP DHCP/Metadata services"
This commit is contained in:
commit
3eaeae5d1f
@ -90,3 +90,14 @@
|
|||||||
|
|
||||||
# The default network transport type to use (stt, gre, bridge, ipsec_gre, or ipsec_stt)
|
# The default network transport type to use (stt, gre, bridge, ipsec_gre, or ipsec_stt)
|
||||||
# default_transport_type = stt
|
# default_transport_type = stt
|
||||||
|
|
||||||
|
# Specifies in which mode the plugin needs to operate in order to provide DHCP and
|
||||||
|
# metadata proxy services to tenant instances. If 'agent' is chosen (default)
|
||||||
|
# the NVP plugin relies on external RPC agents (i.e. dhcp and metadata agents) to
|
||||||
|
# provide such services. In this mode, the plugin supports API extensions 'agent'
|
||||||
|
# and 'dhcp_agent_scheduler'. If 'agentless' is chosen (experimental in Havana),
|
||||||
|
# the plugin will use NVP logical services for DHCP and metadata proxy. This
|
||||||
|
# simplifies the deployment model for Neutron, in that the plugin no longer requires
|
||||||
|
# the RPC agents to operate. When 'agentless' is chosen, the config option metadata_mode
|
||||||
|
# becomes ineffective. The mode 'agentless' is not supported for NVP 3.2 or below.
|
||||||
|
# agent_mode = agent
|
||||||
|
@ -28,20 +28,15 @@ from oslo.config import cfg
|
|||||||
from sqlalchemy.orm import exc as sa_exc
|
from sqlalchemy.orm import exc as sa_exc
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
|
||||||
from neutron.api.v2 import attributes as attr
|
from neutron.api.v2 import attributes as attr
|
||||||
from neutron.api.v2 import base
|
from neutron.api.v2 import base
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions as q_exc
|
from neutron.common import exceptions as q_exc
|
||||||
from neutron.common import rpc as q_rpc
|
|
||||||
from neutron.common import topics
|
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
from neutron import context as q_context
|
from neutron import context as q_context
|
||||||
from neutron.db import agents_db
|
|
||||||
from neutron.db import agentschedulers_db
|
from neutron.db import agentschedulers_db
|
||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
|
||||||
from neutron.db import extraroute_db
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import l3_gwmode_db
|
from neutron.db import l3_gwmode_db
|
||||||
@ -58,17 +53,15 @@ from neutron.extensions import portsecurity as psec
|
|||||||
from neutron.extensions import providernet as pnet
|
from neutron.extensions import providernet as pnet
|
||||||
from neutron.extensions import securitygroup as ext_sg
|
from neutron.extensions import securitygroup as ext_sg
|
||||||
from neutron.openstack.common import excutils
|
from neutron.openstack.common import excutils
|
||||||
from neutron.openstack.common import importutils
|
from neutron.plugins.nicira.common import config
|
||||||
from neutron.openstack.common import rpc
|
|
||||||
from neutron.plugins.nicira.common import config # noqa
|
|
||||||
from neutron.plugins.nicira.common import exceptions as nvp_exc
|
from neutron.plugins.nicira.common import exceptions as nvp_exc
|
||||||
from neutron.plugins.nicira.common import metadata_access as nvp_meta
|
|
||||||
from neutron.plugins.nicira.common import securitygroups as nvp_sec
|
from neutron.plugins.nicira.common import securitygroups as nvp_sec
|
||||||
from neutron.plugins.nicira.dbexts import distributedrouter as dist_rtr
|
from neutron.plugins.nicira.dbexts import distributedrouter as dist_rtr
|
||||||
from neutron.plugins.nicira.dbexts import maclearning as mac_db
|
from neutron.plugins.nicira.dbexts import maclearning as mac_db
|
||||||
from neutron.plugins.nicira.dbexts import nicira_db
|
from neutron.plugins.nicira.dbexts import nicira_db
|
||||||
from neutron.plugins.nicira.dbexts import nicira_networkgw_db as networkgw_db
|
from neutron.plugins.nicira.dbexts import nicira_networkgw_db as networkgw_db
|
||||||
from neutron.plugins.nicira.dbexts import nicira_qos_db as qos_db
|
from neutron.plugins.nicira.dbexts import nicira_qos_db as qos_db
|
||||||
|
from neutron.plugins.nicira import dhcpmeta_modes
|
||||||
from neutron.plugins.nicira.extensions import maclearning as mac_ext
|
from neutron.plugins.nicira.extensions import maclearning as mac_ext
|
||||||
from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
|
from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
|
||||||
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
|
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
|
||||||
@ -117,34 +110,19 @@ def create_nvp_cluster(cluster_opts, concurrent_connections,
|
|||||||
return cluster
|
return cluster
|
||||||
|
|
||||||
|
|
||||||
class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
class NvpPluginV2(agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
|
db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
# Set RPC API version to 1.0 by default.
|
dhcpmeta_modes.DhcpMetadataAccess,
|
||||||
RPC_API_VERSION = '1.1'
|
dist_rtr.DistributedRouter_mixin,
|
||||||
|
|
||||||
def create_rpc_dispatcher(self):
|
|
||||||
'''Get the rpc dispatcher for this manager.
|
|
||||||
|
|
||||||
If a manager would like to set an rpc API version, or support more than
|
|
||||||
one class as the target of rpc messages, override this method.
|
|
||||||
'''
|
|
||||||
return q_rpc.PluginRpcDispatcher([self,
|
|
||||||
agents_db.AgentExtRpcCallback()])
|
|
||||||
|
|
||||||
|
|
||||||
class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
dist_rtr.DistributedRouter_mixin,
|
|
||||||
portbindings_db.PortBindingMixin,
|
|
||||||
portsecurity_db.PortSecurityDbMixin,
|
|
||||||
securitygroups_db.SecurityGroupDbMixin,
|
|
||||||
mac_db.MacLearningDbMixin,
|
mac_db.MacLearningDbMixin,
|
||||||
networkgw_db.NetworkGatewayMixin,
|
networkgw_db.NetworkGatewayMixin,
|
||||||
qos_db.NVPQoSDbMixin,
|
|
||||||
nvp_sec.NVPSecurityGroups,
|
nvp_sec.NVPSecurityGroups,
|
||||||
nvp_meta.NvpMetadataAccess,
|
portbindings_db.PortBindingMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin):
|
portsecurity_db.PortSecurityDbMixin,
|
||||||
|
qos_db.NVPQoSDbMixin,
|
||||||
|
securitygroups_db.SecurityGroupDbMixin):
|
||||||
"""L2 Virtual network plugin.
|
"""L2 Virtual network plugin.
|
||||||
|
|
||||||
NvpPluginV2 is a Neutron plugin that provides L2 Virtual Network
|
NvpPluginV2 is a Neutron plugin that provides L2 Virtual Network
|
||||||
@ -213,13 +191,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
'security-group' in self.supported_extension_aliases}}
|
'security-group' in self.supported_extension_aliases}}
|
||||||
|
|
||||||
db.configure_db()
|
db.configure_db()
|
||||||
# Extend the fault map
|
|
||||||
self._extend_fault_map()
|
self._extend_fault_map()
|
||||||
# Set up RPC interface for DHCP agent
|
self.setup_dhcpmeta_access()
|
||||||
self.setup_rpc()
|
|
||||||
self.network_scheduler = importutils.import_object(
|
|
||||||
cfg.CONF.network_scheduler_driver
|
|
||||||
)
|
|
||||||
# Set this flag to false as the default gateway has not
|
# Set this flag to false as the default gateway has not
|
||||||
# been yet updated from the config file
|
# been yet updated from the config file
|
||||||
self._is_default_net_gw_in_sync = False
|
self._is_default_net_gw_in_sync = False
|
||||||
@ -888,18 +861,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"logical network %s"), network.id)
|
"logical network %s"), network.id)
|
||||||
raise nvp_exc.NvpNoMorePortsException(network=network.id)
|
raise nvp_exc.NvpNoMorePortsException(network=network.id)
|
||||||
|
|
||||||
def setup_rpc(self):
|
|
||||||
# RPC support for dhcp
|
|
||||||
self.topic = topics.PLUGIN
|
|
||||||
self.conn = rpc.create_connection(new=True)
|
|
||||||
self.dispatcher = NVPRpcCallbacks().create_rpc_dispatcher()
|
|
||||||
self.conn.create_consumer(self.topic, self.dispatcher,
|
|
||||||
fanout=False)
|
|
||||||
self.agent_notifiers[constants.AGENT_TYPE_DHCP] = (
|
|
||||||
dhcp_rpc_agent_api.DhcpAgentNotifyAPI())
|
|
||||||
# Consume from all consumers in a thread
|
|
||||||
self.conn.consume_in_thread()
|
|
||||||
|
|
||||||
def _convert_to_nvp_transport_zones(self, cluster, network=None,
|
def _convert_to_nvp_transport_zones(self, cluster, network=None,
|
||||||
bindings=None):
|
bindings=None):
|
||||||
nvp_transport_zones_config = []
|
nvp_transport_zones_config = []
|
||||||
@ -1033,7 +994,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self._extend_network_dict_provider(context, new_net,
|
self._extend_network_dict_provider(context, new_net,
|
||||||
provider_type,
|
provider_type,
|
||||||
net_bindings)
|
net_bindings)
|
||||||
self.schedule_network(context, new_net)
|
self.handle_network_dhcp_access(context, new_net,
|
||||||
|
action='create_network')
|
||||||
return new_net
|
return new_net
|
||||||
|
|
||||||
def delete_network(self, context, id):
|
def delete_network(self, context, id):
|
||||||
@ -1081,6 +1043,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
context.tenant_id)
|
context.tenant_id)
|
||||||
except q_exc.NotFound:
|
except q_exc.NotFound:
|
||||||
LOG.warning(_("Did not found lswitch %s in NVP"), id)
|
LOG.warning(_("Did not found lswitch %s in NVP"), id)
|
||||||
|
self.handle_network_dhcp_access(context, id, action='delete_network')
|
||||||
|
|
||||||
def get_network(self, context, id, fields=None):
|
def get_network(self, context, id, fields=None):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
@ -1338,20 +1301,13 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# ATTR_NOT_SPECIFIED is for the case where a port is created on a
|
# ATTR_NOT_SPECIFIED is for the case where a port is created on a
|
||||||
# shared network that is not owned by the tenant.
|
# shared network that is not owned by the tenant.
|
||||||
port_data = port['port']
|
port_data = port['port']
|
||||||
notify_dhcp_agent = False
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
# First we allocate port in neutron database
|
# First we allocate port in neutron database
|
||||||
neutron_db = super(NvpPluginV2, self).create_port(context, port)
|
neutron_db = super(NvpPluginV2, self).create_port(context, port)
|
||||||
neutron_port_id = neutron_db['id']
|
neutron_port_id = neutron_db['id']
|
||||||
# Update fields obtained from neutron db (eg: MAC address)
|
# Update fields obtained from neutron db (eg: MAC address)
|
||||||
port["port"].update(neutron_db)
|
port["port"].update(neutron_db)
|
||||||
# metadata_dhcp_host_route
|
self.handle_port_metadata_access(context, neutron_db)
|
||||||
if (cfg.CONF.NVP.metadata_mode == "dhcp_host_route" and
|
|
||||||
neutron_db.get('device_owner') == constants.DEVICE_OWNER_DHCP):
|
|
||||||
if (neutron_db.get('fixed_ips') and
|
|
||||||
len(neutron_db['fixed_ips'])):
|
|
||||||
notify_dhcp_agent = self._ensure_metadata_host_route(
|
|
||||||
context, neutron_db['fixed_ips'][0])
|
|
||||||
# port security extension checks
|
# port security extension checks
|
||||||
(port_security, has_ip) = self._determine_port_security_and_has_ip(
|
(port_security, has_ip) = self._determine_port_security_and_has_ip(
|
||||||
context, port_data)
|
context, port_data)
|
||||||
@ -1408,13 +1364,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
self._delete_port(context, neutron_port_id)
|
self._delete_port(context, neutron_port_id)
|
||||||
|
|
||||||
# Port has been created both on DB and NVP - proceed with
|
self.handle_port_dhcp_access(context, port_data, action='create_port')
|
||||||
# scheduling network and notifying DHCP agent
|
|
||||||
net = self.get_network(context, port_data['network_id'])
|
|
||||||
self.schedule_network(context, net)
|
|
||||||
if notify_dhcp_agent:
|
|
||||||
self._send_subnet_update_end(
|
|
||||||
context, neutron_db['fixed_ips'][0]['subnet_id'])
|
|
||||||
return port_data
|
return port_data
|
||||||
|
|
||||||
def update_port(self, context, id, port):
|
def update_port(self, context, id, port):
|
||||||
@ -1540,23 +1490,17 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
port_delete_func(context, neutron_db_port)
|
port_delete_func(context, neutron_db_port)
|
||||||
self.disassociate_floatingips(context, id)
|
self.disassociate_floatingips(context, id)
|
||||||
notify_dhcp_agent = False
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
queue = self._get_port_queue_bindings(context, {'port_id': [id]})
|
queue = self._get_port_queue_bindings(context, {'port_id': [id]})
|
||||||
# metadata_dhcp_host_route
|
# metadata_dhcp_host_route
|
||||||
port_device_owner = neutron_db_port['device_owner']
|
self.handle_port_metadata_access(
|
||||||
if (cfg.CONF.NVP.metadata_mode == "dhcp_host_route" and
|
context, neutron_db_port, is_delete=True)
|
||||||
port_device_owner == constants.DEVICE_OWNER_DHCP):
|
|
||||||
notify_dhcp_agent = self._ensure_metadata_host_route(
|
|
||||||
context, neutron_db_port['fixed_ips'][0],
|
|
||||||
is_delete=True)
|
|
||||||
super(NvpPluginV2, self).delete_port(context, id)
|
super(NvpPluginV2, self).delete_port(context, id)
|
||||||
# Delete qos queue if possible
|
# Delete qos queue if possible
|
||||||
if queue:
|
if queue:
|
||||||
self.delete_qos_queue(context, queue[0]['queue_id'], False)
|
self.delete_qos_queue(context, queue[0]['queue_id'], False)
|
||||||
if notify_dhcp_agent:
|
self.handle_port_dhcp_access(
|
||||||
self._send_subnet_update_end(
|
context, neutron_db_port, action='delete_port')
|
||||||
context, neutron_db_port['fixed_ips'][0]['subnet_id'])
|
|
||||||
|
|
||||||
def get_port(self, context, id, fields=None):
|
def get_port(self, context, id, fields=None):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
@ -1744,14 +1688,15 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
nvplib.update_explicit_routes_lrouter(
|
nvplib.update_explicit_routes_lrouter(
|
||||||
self.cluster, router_id, previous_routes)
|
self.cluster, router_id, previous_routes)
|
||||||
|
|
||||||
def delete_router(self, context, id):
|
def delete_router(self, context, router_id):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
# Ensure metadata access network is detached and destroyed
|
# Ensure metadata access network is detached and destroyed
|
||||||
# This will also destroy relevant objects on NVP platform.
|
# This will also destroy relevant objects on NVP platform.
|
||||||
# NOTE(salvatore-orlando): A failure in this operation will
|
# NOTE(salvatore-orlando): A failure in this operation will
|
||||||
# cause the router delete operation to fail too.
|
# cause the router delete operation to fail too.
|
||||||
self._handle_metadata_access_network(context, id, do_create=False)
|
self.handle_router_metadata_access(
|
||||||
super(NvpPluginV2, self).delete_router(context, id)
|
context, router_id, do_create=False)
|
||||||
|
super(NvpPluginV2, self).delete_router(context, router_id)
|
||||||
# If removal is successful in Neutron it should be so on
|
# If removal is successful in Neutron it should be so on
|
||||||
# the NVP platform too - otherwise the transaction should
|
# the NVP platform too - otherwise the transaction should
|
||||||
# be automatically aborted
|
# be automatically aborted
|
||||||
@ -1759,14 +1704,14 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# allow an extra field for storing the cluster information
|
# allow an extra field for storing the cluster information
|
||||||
# together with the resource
|
# together with the resource
|
||||||
try:
|
try:
|
||||||
nvplib.delete_lrouter(self.cluster, id)
|
nvplib.delete_lrouter(self.cluster, router_id)
|
||||||
except q_exc.NotFound:
|
except q_exc.NotFound:
|
||||||
LOG.warning(_("Logical router '%s' not found "
|
LOG.warning(_("Logical router '%s' not found "
|
||||||
"on NVP Platform") % id)
|
"on NVP Platform") % router_id)
|
||||||
except NvpApiClient.NvpApiException:
|
except NvpApiClient.NvpApiException:
|
||||||
raise nvp_exc.NvpPluginException(
|
raise nvp_exc.NvpPluginException(
|
||||||
err_msg=(_("Unable to delete logical router"
|
err_msg=(_("Unable to delete logical router '%s'"
|
||||||
"on NVP Platform")))
|
"on NVP Platform") % router_id))
|
||||||
|
|
||||||
def get_router(self, context, id, fields=None):
|
def get_router(self, context, id, fields=None):
|
||||||
router = self._get_router(context, id)
|
router = self._get_router(context, id)
|
||||||
@ -1892,7 +1837,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# Ensure the NVP logical router has a connection to a 'metadata access'
|
# Ensure the NVP logical router has a connection to a 'metadata access'
|
||||||
# network (with a proxy listening on its DHCP port), by creating it
|
# network (with a proxy listening on its DHCP port), by creating it
|
||||||
# if needed.
|
# if needed.
|
||||||
self._handle_metadata_access_network(context, router_id)
|
self.handle_router_metadata_access(context, router_id)
|
||||||
LOG.debug(_("Add_router_interface completed for subnet:%(subnet_id)s "
|
LOG.debug(_("Add_router_interface completed for subnet:%(subnet_id)s "
|
||||||
"and router:%(router_id)s"),
|
"and router:%(router_id)s"),
|
||||||
{'subnet_id': subnet_id, 'router_id': router_id})
|
{'subnet_id': subnet_id, 'router_id': router_id})
|
||||||
@ -1936,7 +1881,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# Ensure the connection to the 'metadata access network'
|
# Ensure the connection to the 'metadata access network'
|
||||||
# is removed (with the network) if this the last subnet
|
# is removed (with the network) if this the last subnet
|
||||||
# on the router
|
# on the router
|
||||||
self._handle_metadata_access_network(context, router_id)
|
self.handle_router_metadata_access(context, router_id)
|
||||||
try:
|
try:
|
||||||
if not subnet:
|
if not subnet:
|
||||||
subnet = self._get_subnet(context, subnet_id)
|
subnet = self._get_subnet(context, subnet_id)
|
||||||
|
@ -16,6 +16,19 @@
|
|||||||
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
class AgentModes:
|
||||||
|
AGENT = 'agent'
|
||||||
|
# TODO(armando-migliaccio): support to be added, maybe we could add a
|
||||||
|
# mixed mode to support no-downtime migrations?
|
||||||
|
AGENTLESS = 'agentless'
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataModes:
|
||||||
|
DIRECT = 'access_network'
|
||||||
|
INDIRECT = 'dhcp_host_route'
|
||||||
|
|
||||||
|
|
||||||
nvp_opts = [
|
nvp_opts = [
|
||||||
cfg.IntOpt('max_lp_per_bridged_ls', default=64,
|
cfg.IntOpt('max_lp_per_bridged_ls', default=64,
|
||||||
help=_("Maximum number of ports of a logical switch on a "
|
help=_("Maximum number of ports of a logical switch on a "
|
||||||
@ -28,7 +41,7 @@ nvp_opts = [
|
|||||||
cfg.IntOpt('nvp_gen_timeout', default=-1,
|
cfg.IntOpt('nvp_gen_timeout', default=-1,
|
||||||
help=_("Number of seconds a generation id should be valid for "
|
help=_("Number of seconds a generation id should be valid for "
|
||||||
"(default -1 meaning do not time out)")),
|
"(default -1 meaning do not time out)")),
|
||||||
cfg.StrOpt('metadata_mode', default='access_network',
|
cfg.StrOpt('metadata_mode', default=MetadataModes.DIRECT,
|
||||||
help=_("If set to access_network this enables a dedicated "
|
help=_("If set to access_network this enables a dedicated "
|
||||||
"connection to the metadata proxy for metadata server "
|
"connection to the metadata proxy for metadata server "
|
||||||
"access via Neutron router. If set to dhcp_host_route "
|
"access via Neutron router. If set to dhcp_host_route "
|
||||||
@ -39,6 +52,8 @@ nvp_opts = [
|
|||||||
cfg.StrOpt('default_transport_type', default='stt',
|
cfg.StrOpt('default_transport_type', default='stt',
|
||||||
help=_("The default network tranport type to use (stt, gre, "
|
help=_("The default network tranport type to use (stt, gre, "
|
||||||
"bridge, ipsec_gre, or ipsec_stt)")),
|
"bridge, ipsec_gre, or ipsec_stt)")),
|
||||||
|
cfg.StrOpt('agent_mode', default=AgentModes.AGENT,
|
||||||
|
help=_("The mode used to implement DHCP/metadata services.")),
|
||||||
]
|
]
|
||||||
|
|
||||||
connection_opts = [
|
connection_opts = [
|
||||||
|
@ -1,204 +0,0 @@
|
|||||||
# 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 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.
|
|
||||||
#
|
|
||||||
# @author: Salvatore Orlando, VMware
|
|
||||||
|
|
||||||
from eventlet import greenthread
|
|
||||||
import netaddr
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.common import constants
|
|
||||||
from neutron.common import exceptions as ntn_exc
|
|
||||||
from neutron.db import db_base_plugin_v2
|
|
||||||
from neutron.db import l3_db
|
|
||||||
from neutron.db import models_v2
|
|
||||||
from neutron.openstack.common import log as logging
|
|
||||||
from neutron.plugins.nicira.common import exceptions as nvp_exc
|
|
||||||
from neutron.plugins.nicira 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'
|
|
||||||
METADATA_DHCP_ROUTE = '169.254.169.254/32'
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
|
||||||
# Add network
|
|
||||||
# Network name is likely to be truncated on NVP
|
|
||||||
net_data = {'name': 'meta-%s' % router_id,
|
|
||||||
'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(context,
|
|
||||||
{'network': net_data})
|
|
||||||
greenthread.sleep(0) # yield
|
|
||||||
# From this point on there will be resources to garbage-collect
|
|
||||||
# in case of failures
|
|
||||||
meta_sub = None
|
|
||||||
try:
|
|
||||||
# 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(context,
|
|
||||||
{'subnet': subnet_data})
|
|
||||||
greenthread.sleep(0) # yield
|
|
||||||
self.add_router_interface(context, router_id,
|
|
||||||
{'subnet_id': meta_sub['id']})
|
|
||||||
greenthread.sleep(0) # yield
|
|
||||||
except (ntn_exc.NeutronException,
|
|
||||||
nvp_exc.NvpPluginException,
|
|
||||||
NvpApiClient.NvpApiException):
|
|
||||||
# It is not necessary to explicitly delete the subnet
|
|
||||||
# as it will be removed with the network
|
|
||||||
self.delete_network(context, meta_net['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(context, {'network': meta_net},
|
|
||||||
'network.create.end')
|
|
||||||
|
|
||||||
def _destroy_metadata_access_network(self, context, router_id, ports):
|
|
||||||
if not ports:
|
|
||||||
return
|
|
||||||
meta_port = self._find_metadata_port(context, ports)
|
|
||||||
if not meta_port:
|
|
||||||
return
|
|
||||||
meta_net_id = meta_port['network_id']
|
|
||||||
meta_sub_id = meta_port['fixed_ips'][0]['subnet_id']
|
|
||||||
self.remove_router_interface(
|
|
||||||
context, router_id, {'port_id': meta_port['id']})
|
|
||||||
greenthread.sleep(0) # yield
|
|
||||||
try:
|
|
||||||
# Remove network (this will remove the subnet too)
|
|
||||||
self.delete_network(context, meta_net_id)
|
|
||||||
greenthread.sleep(0) # yield
|
|
||||||
except (ntn_exc.NeutronException, nvp_exc.NvpPluginException,
|
|
||||||
NvpApiClient.NvpApiException):
|
|
||||||
# must re-add the router interface
|
|
||||||
self.add_router_interface(context, 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 stop the metadata agent proxy
|
|
||||||
dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
|
||||||
dhcp_notifier.notify(context,
|
|
||||||
{'network': {'id': meta_net_id}},
|
|
||||||
'network.delete.end')
|
|
||||||
|
|
||||||
def _handle_metadata_access_network(self, context, router_id,
|
|
||||||
do_create=True):
|
|
||||||
if cfg.CONF.NVP.metadata_mode != "access_network":
|
|
||||||
LOG.debug(_("Metadata access network is disabled"))
|
|
||||||
return
|
|
||||||
if not cfg.CONF.allow_overlapping_ips:
|
|
||||||
LOG.warn(_("Overlapping IPs must be enabled in order to setup "
|
|
||||||
"the metadata access network"))
|
|
||||||
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]}
|
|
||||||
# Retrieve ports calling database plugin
|
|
||||||
ports = db_base_plugin_v2.NeutronDbPluginV2.get_ports(
|
|
||||||
self, context, filters=device_filter)
|
|
||||||
try:
|
|
||||||
if ports:
|
|
||||||
if (do_create and
|
|
||||||
not self._find_metadata_port(ctx_elevated, ports)):
|
|
||||||
self._create_metadata_access_network(ctx_elevated,
|
|
||||||
router_id)
|
|
||||||
elif len(ports) == 1:
|
|
||||||
# The only port left might be the metadata port
|
|
||||||
self._destroy_metadata_access_network(ctx_elevated,
|
|
||||||
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 (ntn_exc.NeutronException, 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)
|
|
||||||
|
|
||||||
def _ensure_metadata_host_route(self, context, fixed_ip_data,
|
|
||||||
is_delete=False):
|
|
||||||
subnet = self._get_subnet(context, fixed_ip_data['subnet_id'])
|
|
||||||
# If subnet does not have a gateway do not create metadata route. This
|
|
||||||
# is done via the enable_isolated_metadata option if desired.
|
|
||||||
if not subnet.get('gateway_ip'):
|
|
||||||
return
|
|
||||||
metadata_routes = [r for r in subnet.routes
|
|
||||||
if r['destination'] == METADATA_DHCP_ROUTE]
|
|
||||||
|
|
||||||
if metadata_routes:
|
|
||||||
# We should have only a single metadata route at any time
|
|
||||||
# because the route logic forbids two routes with the same
|
|
||||||
# destination. Update next hop with the provided IP address
|
|
||||||
if not is_delete:
|
|
||||||
metadata_routes[0].nexthop = fixed_ip_data['ip_address']
|
|
||||||
else:
|
|
||||||
context.session.delete(metadata_routes[0])
|
|
||||||
else:
|
|
||||||
# add the metadata route
|
|
||||||
route = models_v2.SubnetRoute(subnet_id=subnet.id,
|
|
||||||
destination=METADATA_DHCP_ROUTE,
|
|
||||||
nexthop=fixed_ip_data['ip_address'])
|
|
||||||
context.session.add(route)
|
|
||||||
return cfg.CONF.dhcp_agent_notification
|
|
||||||
|
|
||||||
def _send_subnet_update_end(self, context, subnet_id):
|
|
||||||
updated_subnet = self.get_subnet(context, subnet_id)
|
|
||||||
dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
|
||||||
dhcp_notifier.notify(context,
|
|
||||||
{'subnet': updated_subnet},
|
|
||||||
'subnet.update.end')
|
|
16
neutron/plugins/nicira/dhcp_meta/__init__.py
Normal file
16
neutron/plugins/nicira/dhcp_meta/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 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.
|
245
neutron/plugins/nicira/dhcp_meta/rpc.py
Normal file
245
neutron/plugins/nicira/dhcp_meta/rpc.py
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 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 eventlet import greenthread
|
||||||
|
import netaddr
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron.common import constants as const
|
||||||
|
from neutron.common import exceptions as ntn_exc
|
||||||
|
from neutron.common import rpc as n_rpc
|
||||||
|
from neutron.db import agents_db
|
||||||
|
from neutron.db import db_base_plugin_v2
|
||||||
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import l3_db
|
||||||
|
from neutron.db import models_v2
|
||||||
|
from neutron.openstack.common import log as logging
|
||||||
|
from neutron.plugins.nicira.common import config
|
||||||
|
from neutron.plugins.nicira.common import exceptions as nvp_exc
|
||||||
|
from neutron.plugins.nicira 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'
|
||||||
|
METADATA_DHCP_ROUTE = '169.254.169.254/32'
|
||||||
|
|
||||||
|
|
||||||
|
class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
||||||
|
|
||||||
|
RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
|
def create_rpc_dispatcher(self):
|
||||||
|
'''Get the rpc dispatcher for this manager.
|
||||||
|
|
||||||
|
If a manager would like to set an rpc API version, or support more than
|
||||||
|
one class as the target of rpc messages, override this method.
|
||||||
|
'''
|
||||||
|
return n_rpc.PluginRpcDispatcher([self,
|
||||||
|
agents_db.AgentExtRpcCallback()])
|
||||||
|
|
||||||
|
|
||||||
|
def handle_network_dhcp_access(plugin, context, network, action):
|
||||||
|
# TODO(armando-migliaccio): revise the implementation of this
|
||||||
|
# method in the context bug #1212555; a potential fix might be
|
||||||
|
# as simple as a 'pass', but keeping the hook might be useful
|
||||||
|
# in other agent modes.
|
||||||
|
if action == 'create_network':
|
||||||
|
plugin.schedule_network(context, network)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_port_dhcp_access(plugin, context, port_data, action):
|
||||||
|
if action == 'create_port':
|
||||||
|
net = plugin.get_network(context, port_data['network_id'])
|
||||||
|
plugin.schedule_network(context, net)
|
||||||
|
|
||||||
|
active_port = (cfg.CONF.NVP.metadata_mode == config.MetadataModes.INDIRECT
|
||||||
|
and port_data.get('device_owner') == const.DEVICE_OWNER_DHCP
|
||||||
|
and port_data.get('fixed_ips', []))
|
||||||
|
if active_port:
|
||||||
|
subnet_id = port_data['fixed_ips'][0]['subnet_id']
|
||||||
|
subnet = plugin.get_subnet(context, subnet_id)
|
||||||
|
if (cfg.CONF.dhcp_agent_notification and subnet.get('gateway_ip')
|
||||||
|
or action == 'delete_port'):
|
||||||
|
dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||||
|
dhcp_notifier.notify(
|
||||||
|
context, {'subnet': subnet}, 'subnet.update.end')
|
||||||
|
|
||||||
|
|
||||||
|
def handle_port_metadata_access(context, port, is_delete=False):
|
||||||
|
if (cfg.CONF.NVP.metadata_mode == config.MetadataModes.INDIRECT and
|
||||||
|
port.get('device_owner') == const.DEVICE_OWNER_DHCP):
|
||||||
|
if port.get('fixed_ips', []) or is_delete:
|
||||||
|
fixed_ip = port['fixed_ips'][0]
|
||||||
|
query = context.session.query(models_v2.Subnet)
|
||||||
|
subnet = query.filter(
|
||||||
|
models_v2.Subnet.id == fixed_ip['subnet_id']).one()
|
||||||
|
# If subnet does not have a gateway do not create metadata
|
||||||
|
# route. This is done via the enable_isolated_metadata
|
||||||
|
# option if desired.
|
||||||
|
if not subnet.get('gateway_ip'):
|
||||||
|
return
|
||||||
|
metadata_routes = [r for r in subnet.routes
|
||||||
|
if r['destination'] == METADATA_DHCP_ROUTE]
|
||||||
|
if metadata_routes:
|
||||||
|
# We should have only a single metadata route at any time
|
||||||
|
# because the route logic forbids two routes with the same
|
||||||
|
# destination. Update next hop with the provided IP address
|
||||||
|
if not is_delete:
|
||||||
|
metadata_routes[0].nexthop = fixed_ip['ip_address']
|
||||||
|
else:
|
||||||
|
context.session.delete(metadata_routes[0])
|
||||||
|
else:
|
||||||
|
# add the metadata route
|
||||||
|
route = models_v2.SubnetRoute(
|
||||||
|
subnet_id=subnet.id,
|
||||||
|
destination=METADATA_DHCP_ROUTE,
|
||||||
|
nexthop=fixed_ip['ip_address'])
|
||||||
|
context.session.add(route)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_router_metadata_access(plugin, context, router_id, do_create=True):
|
||||||
|
if cfg.CONF.NVP.metadata_mode != config.MetadataModes.DIRECT:
|
||||||
|
LOG.debug(_("Metadata access network is disabled"))
|
||||||
|
return
|
||||||
|
if not cfg.CONF.allow_overlapping_ips:
|
||||||
|
LOG.warn(_("Overlapping IPs must be enabled in order to setup "
|
||||||
|
"the metadata access network"))
|
||||||
|
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]}
|
||||||
|
# Retrieve ports calling database plugin
|
||||||
|
ports = db_base_plugin_v2.NeutronDbPluginV2.get_ports(
|
||||||
|
plugin, context, filters=device_filter)
|
||||||
|
try:
|
||||||
|
if ports:
|
||||||
|
if (do_create and
|
||||||
|
not _find_metadata_port(plugin, ctx_elevated, ports)):
|
||||||
|
_create_metadata_access_network(
|
||||||
|
plugin, ctx_elevated, router_id)
|
||||||
|
elif len(ports) == 1:
|
||||||
|
# The only port left might be the metadata port
|
||||||
|
_destroy_metadata_access_network(
|
||||||
|
plugin, ctx_elevated, 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 (ntn_exc.NeutronException, 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)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_metadata_port(plugin, context, ports):
|
||||||
|
for port in ports:
|
||||||
|
for fixed_ip in port['fixed_ips']:
|
||||||
|
cidr = netaddr.IPNetwork(
|
||||||
|
plugin.get_subnet(context, fixed_ip['subnet_id'])['cidr'])
|
||||||
|
if cidr in netaddr.IPNetwork(METADATA_SUBNET_CIDR):
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
def _create_metadata_access_network(plugin, context, router_id):
|
||||||
|
# Add network
|
||||||
|
# Network name is likely to be truncated on NVP
|
||||||
|
net_data = {'name': 'meta-%s' % router_id,
|
||||||
|
'tenant_id': '', # intentionally not set
|
||||||
|
'admin_state_up': True,
|
||||||
|
'port_security_enabled': False,
|
||||||
|
'shared': False,
|
||||||
|
'status': const.NET_STATUS_ACTIVE}
|
||||||
|
meta_net = plugin.create_network(context,
|
||||||
|
{'network': net_data})
|
||||||
|
greenthread.sleep(0) # yield
|
||||||
|
# From this point on there will be resources to garbage-collect
|
||||||
|
# in case of failures
|
||||||
|
meta_sub = None
|
||||||
|
try:
|
||||||
|
# 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 = plugin.create_subnet(context,
|
||||||
|
{'subnet': subnet_data})
|
||||||
|
greenthread.sleep(0) # yield
|
||||||
|
plugin.add_router_interface(context, router_id,
|
||||||
|
{'subnet_id': meta_sub['id']})
|
||||||
|
greenthread.sleep(0) # yield
|
||||||
|
except (ntn_exc.NeutronException,
|
||||||
|
nvp_exc.NvpPluginException,
|
||||||
|
NvpApiClient.NvpApiException):
|
||||||
|
# It is not necessary to explicitly delete the subnet
|
||||||
|
# as it will be removed with the network
|
||||||
|
plugin.delete_network(context, meta_net['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(context, {'network': meta_net},
|
||||||
|
'network.create.end')
|
||||||
|
|
||||||
|
|
||||||
|
def _destroy_metadata_access_network(plugin, context, router_id, ports):
|
||||||
|
if not ports:
|
||||||
|
return
|
||||||
|
meta_port = _find_metadata_port(plugin, context, ports)
|
||||||
|
if not meta_port:
|
||||||
|
return
|
||||||
|
meta_net_id = meta_port['network_id']
|
||||||
|
meta_sub_id = meta_port['fixed_ips'][0]['subnet_id']
|
||||||
|
plugin.remove_router_interface(
|
||||||
|
context, router_id, {'port_id': meta_port['id']})
|
||||||
|
greenthread.sleep(0) # yield
|
||||||
|
try:
|
||||||
|
# Remove network (this will remove the subnet too)
|
||||||
|
plugin.delete_network(context, meta_net_id)
|
||||||
|
greenthread.sleep(0) # yield
|
||||||
|
except (ntn_exc.NeutronException, nvp_exc.NvpPluginException,
|
||||||
|
NvpApiClient.NvpApiException):
|
||||||
|
# must re-add the router interface
|
||||||
|
plugin.add_router_interface(context, 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 stop the metadata agent proxy
|
||||||
|
dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||||
|
dhcp_notifier.notify(context,
|
||||||
|
{'network': {'id': meta_net_id}},
|
||||||
|
'network.delete.end')
|
87
neutron/plugins/nicira/dhcpmeta_modes.py
Normal file
87
neutron/plugins/nicira/dhcpmeta_modes.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 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 oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||||
|
from neutron.common import constants as const
|
||||||
|
from neutron.common import topics
|
||||||
|
from neutron.openstack.common import importutils
|
||||||
|
from neutron.openstack.common import rpc
|
||||||
|
from neutron.plugins.nicira.common import config
|
||||||
|
from neutron.plugins.nicira.dhcp_meta import rpc as nvp_rpc
|
||||||
|
|
||||||
|
|
||||||
|
class DhcpMetadataAccess(object):
|
||||||
|
|
||||||
|
def setup_dhcpmeta_access(self):
|
||||||
|
"""Initialize support for DHCP and Metadata services."""
|
||||||
|
if cfg.CONF.NVP.agent_mode == config.AgentModes.AGENT:
|
||||||
|
self._setup_rpc_dhcp_metadata()
|
||||||
|
self.handle_network_dhcp_access_delegate = (
|
||||||
|
nvp_rpc.handle_network_dhcp_access
|
||||||
|
)
|
||||||
|
self.handle_port_dhcp_access_delegate = (
|
||||||
|
nvp_rpc.handle_port_dhcp_access
|
||||||
|
)
|
||||||
|
self.handle_port_metadata_access_delegate = (
|
||||||
|
nvp_rpc.handle_port_metadata_access
|
||||||
|
)
|
||||||
|
self.handle_metadata_access_delegate = (
|
||||||
|
nvp_rpc.handle_router_metadata_access
|
||||||
|
)
|
||||||
|
elif cfg.CONF.NVP.agent_mode == config.AgentModes.AGENTLESS:
|
||||||
|
# In agentless mode the following extensions, and related
|
||||||
|
# operations, are not supported; so do not publish them
|
||||||
|
if "agent" in self.supported_extension_aliases:
|
||||||
|
self.supported_extension_aliases.remove("agent")
|
||||||
|
if "dhcp_agent_scheduler" in self.supported_extension_aliases:
|
||||||
|
self.supported_extension_aliases.remove(
|
||||||
|
"dhcp_agent_scheduler")
|
||||||
|
# TODO(armando-migliaccio): agentless support is not yet complete
|
||||||
|
# so it's better to raise an exception for now, in case some admin
|
||||||
|
# decides to jump the gun
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def _setup_rpc_dhcp_metadata(self):
|
||||||
|
self.topic = topics.PLUGIN
|
||||||
|
self.conn = rpc.create_connection(new=True)
|
||||||
|
self.dispatcher = nvp_rpc.NVPRpcCallbacks().create_rpc_dispatcher()
|
||||||
|
self.conn.create_consumer(self.topic, self.dispatcher,
|
||||||
|
fanout=False)
|
||||||
|
self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
|
||||||
|
dhcp_rpc_agent_api.DhcpAgentNotifyAPI())
|
||||||
|
self.conn.consume_in_thread()
|
||||||
|
self.network_scheduler = importutils.import_object(
|
||||||
|
cfg.CONF.network_scheduler_driver
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle_network_dhcp_access(self, context, network, action):
|
||||||
|
self.handle_network_dhcp_access_delegate(self, context,
|
||||||
|
network, action)
|
||||||
|
|
||||||
|
def handle_port_dhcp_access(self, context, port_data, action):
|
||||||
|
self.handle_port_dhcp_access_delegate(self, context, port_data, action)
|
||||||
|
|
||||||
|
def handle_port_metadata_access(self, context, port, is_delete=False):
|
||||||
|
self.handle_port_metadata_access_delegate(context, port, is_delete)
|
||||||
|
|
||||||
|
def handle_router_metadata_access(self, context,
|
||||||
|
router_id, do_create=True):
|
||||||
|
self.handle_metadata_access_delegate(self, context,
|
||||||
|
router_id, do_create)
|
17
neutron/tests/unit/nicira/etc/nvp.ini.agentless.test
Normal file
17
neutron/tests/unit/nicira/etc/nvp.ini.agentless.test
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
default_tz_uuid = fake_tz_uuid
|
||||||
|
nova_zone_id = whatever
|
||||||
|
nvp_cluster_uuid = fake_cluster_uuid
|
||||||
|
nvp_controllers = fake_1, fake_2
|
||||||
|
nvp_user = foo
|
||||||
|
nvp_password = bar
|
||||||
|
default_l3_gw_service_uuid = whatever
|
||||||
|
default_l2_gw_service_uuid = whatever
|
||||||
|
default_interface_name = whatever
|
||||||
|
req_timeout = 14
|
||||||
|
http_timeout = 13
|
||||||
|
redirects = 12
|
||||||
|
retries = 11
|
||||||
|
|
||||||
|
[NVP]
|
||||||
|
agent_mode = agentless
|
@ -32,6 +32,7 @@ NVP_BASE_CONF_PATH = get_fake_conf('neutron.conf.test')
|
|||||||
NVP_INI_PATH = get_fake_conf('nvp.ini.basic.test')
|
NVP_INI_PATH = get_fake_conf('nvp.ini.basic.test')
|
||||||
NVP_INI_FULL_PATH = get_fake_conf('nvp.ini.full.test')
|
NVP_INI_FULL_PATH = get_fake_conf('nvp.ini.full.test')
|
||||||
NVP_INI_DEPR_PATH = get_fake_conf('nvp.ini.grizzly.test')
|
NVP_INI_DEPR_PATH = get_fake_conf('nvp.ini.grizzly.test')
|
||||||
|
NVP_INI_AGENTLESS_PATH = get_fake_conf('nvp.ini.agentless.test')
|
||||||
|
|
||||||
|
|
||||||
class NVPClusterTest(testtools.TestCase):
|
class NVPClusterTest(testtools.TestCase):
|
||||||
@ -140,6 +141,31 @@ class ConfigurationTest(testtools.TestCase):
|
|||||||
NeutronManager().get_plugin()
|
NeutronManager().get_plugin()
|
||||||
self.assertIn('extensions', cfg.CONF.api_extensions_path)
|
self.assertIn('extensions', cfg.CONF.api_extensions_path)
|
||||||
|
|
||||||
|
def test_agentless_extensions(self):
|
||||||
|
self.skipTest('Enable once agentless support is added')
|
||||||
|
q_config.parse(['--config-file', NVP_BASE_CONF_PATH,
|
||||||
|
'--config-file', NVP_INI_AGENTLESS_PATH])
|
||||||
|
cfg.CONF.set_override('core_plugin', PLUGIN_NAME)
|
||||||
|
self.assertEqual(config.AgentModes.AGENTLESS,
|
||||||
|
cfg.CONF.NVP.agent_mode)
|
||||||
|
plugin = NeutronManager().get_plugin()
|
||||||
|
self.assertNotIn('agent',
|
||||||
|
plugin.supported_extension_aliases)
|
||||||
|
self.assertNotIn('dhcp_agent_scheduler',
|
||||||
|
plugin.supported_extension_aliases)
|
||||||
|
|
||||||
|
def test_agent_extensions(self):
|
||||||
|
q_config.parse(['--config-file', NVP_BASE_CONF_PATH,
|
||||||
|
'--config-file', NVP_INI_FULL_PATH])
|
||||||
|
cfg.CONF.set_override('core_plugin', PLUGIN_NAME)
|
||||||
|
self.assertEqual(config.AgentModes.AGENT,
|
||||||
|
cfg.CONF.NVP.agent_mode)
|
||||||
|
plugin = NeutronManager().get_plugin()
|
||||||
|
self.assertIn('agent',
|
||||||
|
plugin.supported_extension_aliases)
|
||||||
|
self.assertIn('dhcp_agent_scheduler',
|
||||||
|
plugin.supported_extension_aliases)
|
||||||
|
|
||||||
|
|
||||||
class OldConfigurationTest(testtools.TestCase):
|
class OldConfigurationTest(testtools.TestCase):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user