Merge "Add support for NSX/NVP Metadata services"
This commit is contained in:
commit
458a19a780
@ -169,3 +169,15 @@
|
||||
|
||||
# Default DHCP lease time
|
||||
# default_lease_time = 43200
|
||||
|
||||
[nvp_metadata]
|
||||
# IP address used by Metadata server
|
||||
# metadata_server_address = 127.0.0.1
|
||||
|
||||
# TCP Port used by Metadata server
|
||||
# metadata_server_port = 8775
|
||||
|
||||
# When proxying metadata requests, Neutron signs the Instance-ID header with a
|
||||
# shared secret to prevent spoofing. You may select any string for a secret,
|
||||
# but it MUST match with the configuration used by the Metadata server
|
||||
# metadata_shared_secret =
|
||||
|
@ -1552,7 +1552,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# router, but if it does, it should not happen within a
|
||||
# transaction, and it should be restored on rollback
|
||||
self.handle_router_metadata_access(
|
||||
context, router_id, do_create=False)
|
||||
context, router_id, interface=None)
|
||||
# Pre-delete checks
|
||||
# NOTE(salv-orlando): These checks will be repeated anyway when
|
||||
# calling the superclass. This is wasteful, but is the simplest
|
||||
@ -1654,7 +1654,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Ensure the NVP logical router has a connection to a 'metadata access'
|
||||
# network (with a proxy listening on its DHCP port), by creating it
|
||||
# if needed.
|
||||
self.handle_router_metadata_access(context, router_id)
|
||||
self.handle_router_metadata_access(
|
||||
context, router_id, interface=router_iface_info)
|
||||
LOG.debug(_("Add_router_interface completed for subnet:%(subnet_id)s "
|
||||
"and router:%(router_id)s"),
|
||||
{'subnet_id': subnet_id, 'router_id': router_id})
|
||||
@ -1698,7 +1699,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Ensure the connection to the 'metadata access network'
|
||||
# is removed (with the network) if this the last subnet
|
||||
# on the router
|
||||
self.handle_router_metadata_access(context, router_id)
|
||||
self.handle_router_metadata_access(
|
||||
context, router_id, interface=info)
|
||||
try:
|
||||
if not subnet:
|
||||
subnet = self._get_subnet(context, subnet_id)
|
||||
|
@ -22,6 +22,8 @@ from neutron.api.v2 import attributes as attr
|
||||
from neutron.common import constants as const
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import l3_db
|
||||
from neutron.extensions import external_net
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.nicira.common import exceptions as p_exc
|
||||
from neutron.plugins.nicira.nsxlib import lsn as lsn_api
|
||||
@ -29,7 +31,17 @@ from neutron.plugins.nicira import nvplib
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# A unique MAC to quickly identify the LSN port used for metadata services
|
||||
# when dhcp on the subnet is off. Inspired by leet-speak for 'metadata'.
|
||||
METADATA_MAC = "fa:15:73:74:d4:74"
|
||||
METADATA_PORT_ID = 'metadata:id'
|
||||
METADATA_PORT_NAME = 'metadata:name'
|
||||
METADATA_DEVICE_ID = 'metadata:device'
|
||||
META_CONF = 'metadata-proxy'
|
||||
DHCP_CONF = 'dhcp'
|
||||
SPECIAL_OWNERS = (const.DEVICE_OWNER_DHCP,
|
||||
const.DEVICE_OWNER_ROUTER_GW,
|
||||
l3_db.DEVICE_OWNER_ROUTER_INTF)
|
||||
|
||||
dhcp_opts = [
|
||||
cfg.ListOpt('extra_domain_name_servers',
|
||||
@ -44,10 +56,27 @@ dhcp_opts = [
|
||||
]
|
||||
|
||||
|
||||
metadata_opts = [
|
||||
cfg.StrOpt('metadata_server_address', default='127.0.0.1',
|
||||
help=_("IP address used by Metadata server.")),
|
||||
cfg.IntOpt('metadata_server_port',
|
||||
default=8775,
|
||||
help=_("TCP Port used by Metadata server.")),
|
||||
cfg.StrOpt('metadata_shared_secret',
|
||||
default='',
|
||||
help=_('Shared secret to sign instance-id request'),
|
||||
secret=True)
|
||||
]
|
||||
|
||||
|
||||
def register_dhcp_opts(config):
|
||||
config.CONF.register_opts(dhcp_opts, "NVP_DHCP")
|
||||
|
||||
|
||||
def register_metadata_opts(config):
|
||||
config.CONF.register_opts(metadata_opts, "NVP_METADATA")
|
||||
|
||||
|
||||
class LsnManager(object):
|
||||
"""Manage LSN entities associated with networks."""
|
||||
|
||||
@ -161,6 +190,24 @@ class LsnManager(object):
|
||||
context, network_id, mac_address, raise_on_err=False)
|
||||
if lsn_port_id:
|
||||
self.lsn_port_delete(context, lsn_id, lsn_port_id)
|
||||
if mac_address == METADATA_MAC:
|
||||
try:
|
||||
lswitch_port = nvplib.get_port_by_neutron_tag(
|
||||
self.cluster, network_id, METADATA_PORT_ID)
|
||||
if lswitch_port:
|
||||
lswitch_port_id = lswitch_port['uuid']
|
||||
nvplib.delete_port(
|
||||
self.cluster, network_id, lswitch_port_id)
|
||||
else:
|
||||
LOG.warn(_("Metadata port not found while attempting "
|
||||
"to delete it from network %s"), network_id)
|
||||
except (n_exc.PortNotFoundOnNetwork,
|
||||
nvplib.NvpApiClient.NvpApiException):
|
||||
LOG.warn(_("Metadata port not found while attempting "
|
||||
"to delete it from network %s"), network_id)
|
||||
else:
|
||||
LOG.warn(_("Unable to find Logical Services Node "
|
||||
"Port with MAC %s"), mac_address)
|
||||
|
||||
def lsn_port_dhcp_setup(
|
||||
self, context, network_id, port_id, port_data, subnet_config=None):
|
||||
@ -187,6 +234,36 @@ class LsnManager(object):
|
||||
else:
|
||||
return (lsn_id, lsn_port_id)
|
||||
|
||||
def lsn_port_metadata_setup(self, context, lsn_id, subnet):
|
||||
"""Connect subnet to specified LSN."""
|
||||
data = {
|
||||
"mac_address": METADATA_MAC,
|
||||
"ip_address": subnet['cidr'],
|
||||
"subnet_id": subnet['id']
|
||||
}
|
||||
network_id = subnet['network_id']
|
||||
tenant_id = subnet['tenant_id']
|
||||
lswitch_port_id = None
|
||||
try:
|
||||
lswitch_port_id = nvplib.create_lport(
|
||||
self.cluster, network_id, tenant_id,
|
||||
METADATA_PORT_ID, METADATA_PORT_NAME,
|
||||
METADATA_DEVICE_ID, True)['uuid']
|
||||
lsn_port_id = self.lsn_port_create(self.cluster, lsn_id, data)
|
||||
except (n_exc.NotFound, p_exc.NvpPluginException,
|
||||
nvplib.NvpApiClient.NvpApiException):
|
||||
raise p_exc.PortConfigurationError(
|
||||
net_id=network_id, lsn_id=lsn_id, port_id=lswitch_port_id)
|
||||
else:
|
||||
try:
|
||||
lsn_api.lsn_port_plug_network(
|
||||
self.cluster, lsn_id, lsn_port_id, lswitch_port_id)
|
||||
except p_exc.LsnConfigurationConflict:
|
||||
self.lsn_port_delete(self.cluster, lsn_id, lsn_port_id)
|
||||
nvplib.delete_port(self.cluster, network_id, lswitch_port_id)
|
||||
raise p_exc.PortConfigurationError(
|
||||
net_id=network_id, lsn_id=lsn_id, port_id=lsn_port_id)
|
||||
|
||||
def lsn_port_dhcp_configure(self, context, lsn_id, lsn_port_id, subnet):
|
||||
"""Enable/disable dhcp services with the given config options."""
|
||||
is_enabled = subnet["enable_dhcp"]
|
||||
@ -214,6 +291,36 @@ class LsnManager(object):
|
||||
LOG.error(err_msg)
|
||||
raise p_exc.NvpPluginException(err_msg=err_msg)
|
||||
|
||||
def lsn_metadata_configure(self, context, subnet_id, is_enabled):
|
||||
"""Configure metadata service for the specified subnet."""
|
||||
subnet = self.plugin.get_subnet(context, subnet_id)
|
||||
network_id = subnet['network_id']
|
||||
meta_conf = cfg.CONF.NVP_METADATA
|
||||
metadata_options = {
|
||||
'metadata_server_ip': meta_conf.metadata_server_address,
|
||||
'metadata_server_port': meta_conf.metadata_server_port,
|
||||
'metadata_proxy_shared_secret': meta_conf.metadata_shared_secret
|
||||
}
|
||||
try:
|
||||
lsn_id = self.lsn_get(context, network_id)
|
||||
lsn_api.lsn_metadata_configure(
|
||||
self.cluster, lsn_id, is_enabled, metadata_options)
|
||||
except (p_exc.LsnNotFound, nvplib.NvpApiClient.NvpApiException):
|
||||
err_msg = (_('Unable to configure metadata access '
|
||||
'for subnet %s') % subnet_id)
|
||||
LOG.error(err_msg)
|
||||
raise p_exc.NvpPluginException(err_msg=err_msg)
|
||||
if is_enabled:
|
||||
try:
|
||||
# test that the lsn port exists
|
||||
self.lsn_port_get(context, network_id, subnet_id)
|
||||
except p_exc.LsnPortNotFound:
|
||||
# this might happen if subnet had dhcp off when created
|
||||
# so create one, and wire it
|
||||
self.lsn_port_metadata_setup(context, lsn_id, subnet)
|
||||
else:
|
||||
self.lsn_port_dispose(context, network_id, METADATA_MAC)
|
||||
|
||||
def _lsn_port_host_conf(self, context, network_id, subnet_id, data, hdlr):
|
||||
lsn_id = None
|
||||
lsn_port_id = None
|
||||
@ -228,7 +335,7 @@ class LsnManager(object):
|
||||
net_id=network_id, lsn_id=lsn_id, port_id=lsn_port_id)
|
||||
|
||||
def lsn_port_dhcp_host_add(self, context, network_id, subnet_id, host):
|
||||
"""Add dhcp host entry from LSN port configuration."""
|
||||
"""Add dhcp host entry to LSN port configuration."""
|
||||
self._lsn_port_host_conf(context, network_id, subnet_id, host,
|
||||
lsn_api.lsn_port_dhcp_host_add)
|
||||
|
||||
@ -237,6 +344,34 @@ class LsnManager(object):
|
||||
self._lsn_port_host_conf(context, network_id, subnet_id, host,
|
||||
lsn_api.lsn_port_dhcp_host_remove)
|
||||
|
||||
def lsn_port_meta_host_add(self, context, network_id, subnet_id, host):
|
||||
"""Add metadata host entry to LSN port configuration."""
|
||||
self._lsn_port_host_conf(context, network_id, subnet_id, host,
|
||||
lsn_api.lsn_port_metadata_host_add)
|
||||
|
||||
def lsn_port_meta_host_remove(self, context, network_id, subnet_id, host):
|
||||
"""Remove meta host entry from LSN port configuration."""
|
||||
self._lsn_port_host_conf(context, network_id, subnet_id, host,
|
||||
lsn_api.lsn_port_metadata_host_remove)
|
||||
|
||||
def lsn_port_update(
|
||||
self, context, network_id, subnet_id, dhcp=None, meta=None):
|
||||
"""Update the specified configuration for the LSN port."""
|
||||
if not dhcp and not meta:
|
||||
return
|
||||
try:
|
||||
lsn_id, lsn_port_id = self.lsn_port_get(
|
||||
context, network_id, subnet_id, raise_on_err=False)
|
||||
if dhcp and lsn_id and lsn_port_id:
|
||||
lsn_api.lsn_port_host_entries_update(
|
||||
self.cluster, lsn_id, lsn_port_id, DHCP_CONF, dhcp)
|
||||
if meta and lsn_id and lsn_port_id:
|
||||
lsn_api.lsn_port_host_entries_update(
|
||||
self.cluster, lsn_id, lsn_port_id, META_CONF, meta)
|
||||
except nvplib.NvpApiClient.NvpApiException:
|
||||
raise p_exc.PortConfigurationError(
|
||||
net_id=network_id, lsn_id=lsn_id, port_id=lsn_port_id)
|
||||
|
||||
|
||||
class DhcpAgentNotifyAPI(object):
|
||||
|
||||
@ -251,6 +386,33 @@ class DhcpAgentNotifyAPI(object):
|
||||
[resource, action, _e] = methodname.split('.')
|
||||
if resource == 'subnet':
|
||||
self._handle_subnet_dhcp_access[action](context, data['subnet'])
|
||||
elif resource == 'port' and action == 'update':
|
||||
self._port_update(context, data['port'])
|
||||
|
||||
def _port_update(self, context, port):
|
||||
# With no fixed IP's there's nothing that can be updated
|
||||
if not port["fixed_ips"]:
|
||||
return
|
||||
network_id = port['network_id']
|
||||
subnet_id = port["fixed_ips"][0]['subnet_id']
|
||||
filters = {'network_id': [network_id]}
|
||||
# Because NVP does not support updating a single host entry we
|
||||
# got to build the whole list from scratch and update in bulk
|
||||
ports = self.plugin.get_ports(context, filters)
|
||||
if not ports:
|
||||
return
|
||||
dhcp_conf = [
|
||||
{'mac_address': p['mac_address'],
|
||||
'ip_address': p["fixed_ips"][0]['ip_address']}
|
||||
for p in ports if is_user_port(p)
|
||||
]
|
||||
meta_conf = [
|
||||
{'instance_id': p['device_id'],
|
||||
'ip_address': p["fixed_ips"][0]['ip_address']}
|
||||
for p in ports if is_user_port(p, check_dev_id=True)
|
||||
]
|
||||
self.lsn_manager.lsn_port_update(
|
||||
context, network_id, subnet_id, dhcp=dhcp_conf, meta=meta_conf)
|
||||
|
||||
def _subnet_create(self, context, subnet, clean_on_err=True):
|
||||
if subnet['enable_dhcp']:
|
||||
@ -268,7 +430,7 @@ class DhcpAgentNotifyAPI(object):
|
||||
}
|
||||
try:
|
||||
# This will end up calling handle_port_dhcp_access
|
||||
# down below
|
||||
# down below as well as handle_port_metadata_access
|
||||
self.plugin.create_port(context, {'port': dhcp_port})
|
||||
except p_exc.PortConfigurationError as e:
|
||||
err_msg = (_("Error while creating subnet %(cidr)s for "
|
||||
@ -292,7 +454,13 @@ class DhcpAgentNotifyAPI(object):
|
||||
context, lsn_id, lsn_port_id, subnet)
|
||||
except p_exc.LsnPortNotFound:
|
||||
# It's possible that the subnet was created with dhcp off;
|
||||
# check that a dhcp port exists first and provision it
|
||||
# check if the subnet was uplinked onto a router, and if so
|
||||
# remove the patch attachment between the metadata port and
|
||||
# the lsn port, in favor on the one we'll be creating during
|
||||
# _subnet_create
|
||||
self.lsn_manager.lsn_port_dispose(
|
||||
context, network_id, METADATA_MAC)
|
||||
# also, check that a dhcp port exists first and provision it
|
||||
# accordingly
|
||||
filters = dict(network_id=[network_id],
|
||||
device_owner=[const.DEVICE_OWNER_DHCP])
|
||||
@ -313,10 +481,15 @@ class DhcpAgentNotifyAPI(object):
|
||||
ports = self.plugin.get_ports(context, filters=filters)
|
||||
if ports:
|
||||
# This will end up calling handle_port_dhcp_access
|
||||
# down below
|
||||
# down below as well as handle_port_metadata_access
|
||||
self.plugin.delete_port(context, ports[0]['id'])
|
||||
|
||||
|
||||
def is_user_port(p, check_dev_id=False):
|
||||
usable = p['fixed_ips'] and p['device_owner'] not in SPECIAL_OWNERS
|
||||
return usable if not check_dev_id else usable and p['device_id']
|
||||
|
||||
|
||||
def check_services_requirements(cluster):
|
||||
ver = cluster.api_client.get_nvp_version()
|
||||
# It sounds like 4.1 is the first one where DHCP in NSX/NVP
|
||||
@ -374,7 +547,8 @@ def handle_port_dhcp_access(plugin, context, port, action):
|
||||
# do something only if there are IP's and dhcp is enabled
|
||||
subnet_id = port["fixed_ips"][0]['subnet_id']
|
||||
if not plugin.get_subnet(context, subnet_id)['enable_dhcp']:
|
||||
LOG.info(_("DHCP is disabled: nothing to do"))
|
||||
LOG.info(_("DHCP is disabled for subnet %s: nothing "
|
||||
"to do"), subnet_id)
|
||||
return
|
||||
host_data = {
|
||||
"mac_address": port["mac_address"],
|
||||
@ -395,11 +569,50 @@ def handle_port_dhcp_access(plugin, context, port, action):
|
||||
LOG.info(_("DHCP for port %s configured successfully"), port['id'])
|
||||
|
||||
|
||||
def handle_port_metadata_access(context, port, is_delete=False):
|
||||
# TODO(armando-migliaccio)
|
||||
LOG.info('%s port with data %s' % (is_delete, port))
|
||||
def handle_port_metadata_access(plugin, context, port, is_delete=False):
|
||||
if is_user_port(port, check_dev_id=True):
|
||||
network_id = port["network_id"]
|
||||
network = plugin.get_network(context, network_id)
|
||||
if network[external_net.EXTERNAL]:
|
||||
LOG.info(_("Network %s is external: nothing to do"), network_id)
|
||||
return
|
||||
subnet_id = port["fixed_ips"][0]['subnet_id']
|
||||
host_data = {
|
||||
"instance_id": port["device_id"],
|
||||
"tenant_id": port["tenant_id"],
|
||||
"ip_address": port["fixed_ips"][0]['ip_address']
|
||||
}
|
||||
LOG.info(_("Configuring metadata entry for port %s"), port)
|
||||
if not is_delete:
|
||||
handler = plugin.lsn_manager.lsn_port_meta_host_add
|
||||
else:
|
||||
handler = plugin.lsn_manager.lsn_port_meta_host_remove
|
||||
try:
|
||||
handler(context, network_id, subnet_id, host_data)
|
||||
except p_exc.PortConfigurationError:
|
||||
if not is_delete:
|
||||
db_base_plugin_v2.NeutronDbPluginV2.delete_port(
|
||||
plugin, context, port['id'])
|
||||
raise
|
||||
LOG.info(_("Metadata for port %s configured successfully"), port['id'])
|
||||
|
||||
|
||||
def handle_router_metadata_access(plugin, context, router_id, do_create=True):
|
||||
# TODO(armando-migliaccio)
|
||||
LOG.info('%s router %s' % (do_create, router_id))
|
||||
def handle_router_metadata_access(plugin, context, router_id, interface=None):
|
||||
LOG.info(_("Handle metadata access via router: %(r)s and "
|
||||
"interface %(i)s") % {'r': router_id, 'i': interface})
|
||||
if interface:
|
||||
try:
|
||||
plugin.get_port(context, interface['port_id'])
|
||||
is_enabled = True
|
||||
except n_exc.NotFound:
|
||||
is_enabled = False
|
||||
subnet_id = interface['subnet_id']
|
||||
try:
|
||||
plugin.lsn_manager.lsn_metadata_configure(
|
||||
context, subnet_id, is_enabled)
|
||||
except p_exc.NvpPluginException:
|
||||
if is_enabled:
|
||||
l3_db.L3_NAT_db_mixin.remove_router_interface(
|
||||
plugin, context, router_id, interface)
|
||||
raise
|
||||
LOG.info(_("Metadata for router %s handled successfully"), router_id)
|
||||
|
@ -80,7 +80,7 @@ def handle_port_dhcp_access(plugin, context, port_data, action):
|
||||
_notify_rpc_agent(context, {'subnet': subnet}, 'subnet.update.end')
|
||||
|
||||
|
||||
def handle_port_metadata_access(context, port, is_delete=False):
|
||||
def handle_port_metadata_access(plugin, 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:
|
||||
@ -112,7 +112,7 @@ def handle_port_metadata_access(context, port, is_delete=False):
|
||||
context.session.add(route)
|
||||
|
||||
|
||||
def handle_router_metadata_access(plugin, context, router_id, do_create=True):
|
||||
def handle_router_metadata_access(plugin, context, router_id, interface=None):
|
||||
if cfg.CONF.NVP.metadata_mode != config.MetadataModes.DIRECT:
|
||||
LOG.debug(_("Metadata access network is disabled"))
|
||||
return
|
||||
@ -128,7 +128,7 @@ def handle_router_metadata_access(plugin, context, router_id, do_create=True):
|
||||
plugin, ctx_elevated, filters=device_filter)
|
||||
try:
|
||||
if ports:
|
||||
if (do_create and
|
||||
if (interface and
|
||||
not _find_metadata_port(plugin, ctx_elevated, ports)):
|
||||
_create_metadata_access_network(
|
||||
plugin, ctx_elevated, router_id)
|
||||
|
@ -77,6 +77,7 @@ class DhcpMetadataAccess(object):
|
||||
self.supported_extension_aliases.remove(
|
||||
"dhcp_agent_scheduler")
|
||||
nvp_svc.register_dhcp_opts(cfg)
|
||||
nvp_svc.register_metadata_opts(cfg)
|
||||
self.lsn_manager = nvp_svc.LsnManager(self)
|
||||
self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
|
||||
nvp_svc.DhcpAgentNotifyAPI(self, self.lsn_manager))
|
||||
@ -106,9 +107,10 @@ class DhcpMetadataAccess(object):
|
||||
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)
|
||||
self.handle_port_metadata_access_delegate(self, context,
|
||||
port, is_delete)
|
||||
|
||||
def handle_router_metadata_access(self, context,
|
||||
router_id, do_create=True):
|
||||
router_id, interface=None):
|
||||
self.handle_metadata_access_delegate(self, context,
|
||||
router_id, do_create)
|
||||
router_id, interface)
|
||||
|
@ -33,6 +33,7 @@ HTTP_PUT = "PUT"
|
||||
SERVICECLUSTER_RESOURCE = "service-cluster"
|
||||
LSERVICESNODE_RESOURCE = "lservices-node"
|
||||
LSERVICESNODEPORT_RESOURCE = "lport/%s" % LSERVICESNODE_RESOURCE
|
||||
SUPPORTED_METADATA_OPTIONS = ['metadata_proxy_shared_secret']
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -82,6 +83,18 @@ def lsn_delete(cluster, lsn_id):
|
||||
cluster=cluster)
|
||||
|
||||
|
||||
def lsn_port_host_entries_update(
|
||||
cluster, lsn_id, lsn_port_id, conf, hosts_data):
|
||||
hosts_obj = {'hosts': hosts_data}
|
||||
do_request(HTTP_PUT,
|
||||
_build_uri_path(LSERVICESNODEPORT_RESOURCE,
|
||||
parent_resource_id=lsn_id,
|
||||
resource_id=lsn_port_id,
|
||||
extra_action=conf),
|
||||
json.dumps(hosts_obj),
|
||||
cluster=cluster)
|
||||
|
||||
|
||||
def lsn_port_create(cluster, lsn_id, port_data):
|
||||
port_obj = {
|
||||
"ip_address": port_data["ip_address"],
|
||||
@ -151,6 +164,18 @@ def lsn_port_plug_network(cluster, lsn_id, lsn_port_id, lswitch_port_id):
|
||||
raise nvp_exc.LsnConfigurationConflict(lsn_id=lsn_id)
|
||||
|
||||
|
||||
def _lsn_configure_action(
|
||||
cluster, lsn_id, action, is_enabled, obj):
|
||||
lsn_obj = {"enabled": is_enabled}
|
||||
lsn_obj.update(obj)
|
||||
do_request(HTTP_PUT,
|
||||
_build_uri_path(LSERVICESNODE_RESOURCE,
|
||||
resource_id=lsn_id,
|
||||
extra_action=action),
|
||||
json.dumps(lsn_obj),
|
||||
cluster=cluster)
|
||||
|
||||
|
||||
def _lsn_port_configure_action(
|
||||
cluster, lsn_id, lsn_port_id, action, is_enabled, obj):
|
||||
do_request(HTTP_PUT,
|
||||
@ -179,6 +204,22 @@ def lsn_port_dhcp_configure(
|
||||
cluster, lsn_id, lsn_port_id, 'dhcp', is_enabled, dhcp_obj)
|
||||
|
||||
|
||||
def lsn_metadata_configure(
|
||||
cluster, lsn_id, is_enabled=True, metadata_info=None):
|
||||
opts = [
|
||||
"%s=%s" % (opt, metadata_info[opt])
|
||||
for opt in SUPPORTED_METADATA_OPTIONS
|
||||
if metadata_info.get(opt)
|
||||
]
|
||||
meta_obj = {
|
||||
'metadata_server_ip': metadata_info['metadata_server_ip'],
|
||||
'metadata_server_port': metadata_info['metadata_server_port'],
|
||||
'misc_options': opts
|
||||
}
|
||||
_lsn_configure_action(
|
||||
cluster, lsn_id, 'metadata-proxy', is_enabled, meta_obj)
|
||||
|
||||
|
||||
def _lsn_port_host_action(
|
||||
cluster, lsn_id, lsn_port_id, host_obj, extra_action, action):
|
||||
do_request(HTTP_POST,
|
||||
@ -199,3 +240,13 @@ def lsn_port_dhcp_host_add(cluster, lsn_id, lsn_port_id, host_data):
|
||||
def lsn_port_dhcp_host_remove(cluster, lsn_id, lsn_port_id, host_data):
|
||||
_lsn_port_host_action(
|
||||
cluster, lsn_id, lsn_port_id, host_data, 'dhcp', 'remove_host')
|
||||
|
||||
|
||||
def lsn_port_metadata_host_add(cluster, lsn_id, lsn_port_id, host_data):
|
||||
_lsn_port_host_action(
|
||||
cluster, lsn_id, lsn_port_id, host_data, 'metadata-proxy', 'add_host')
|
||||
|
||||
|
||||
def lsn_port_metadata_host_remove(cluster, lsn_id, lsn_port_id, host_data):
|
||||
_lsn_port_host_action(cluster, lsn_id, lsn_port_id,
|
||||
host_data, 'metadata-proxy', 'remove_host')
|
||||
|
@ -36,10 +36,12 @@ class LsnManagerTestCase(base.BaseTestCase):
|
||||
self.lsn_id = 'foo_lsn_id'
|
||||
self.mac = 'aa:bb:cc:dd:ee:ff'
|
||||
self.lsn_port_id = 'foo_lsn_port_id'
|
||||
self.tenant_id = 'foo_tenant_id'
|
||||
self.manager = nvp.LsnManager(mock.Mock())
|
||||
self.mock_lsn_api_p = mock.patch.object(nvp, 'lsn_api')
|
||||
self.mock_lsn_api = self.mock_lsn_api_p.start()
|
||||
nvp.register_dhcp_opts(cfg)
|
||||
nvp.register_metadata_opts(cfg)
|
||||
self.addCleanup(cfg.CONF.reset)
|
||||
self.addCleanup(self.mock_lsn_api_p.stop)
|
||||
|
||||
@ -290,6 +292,86 @@ class LsnManagerTestCase(base.BaseTestCase):
|
||||
self._test_lsn_port_dhcp_configure_with_subnet(
|
||||
expected, routes=['8.8.8.8', '9.9.9.9'])
|
||||
|
||||
def _test_lsn_metadata_configure(self, is_enabled):
|
||||
with mock.patch.object(self.manager, 'lsn_port_dispose') as f:
|
||||
self.manager.plugin.get_subnet.return_value = (
|
||||
{'network_id': self.net_id})
|
||||
self.manager.lsn_metadata_configure(mock.ANY,
|
||||
self.sub_id, is_enabled)
|
||||
expected = {
|
||||
'metadata_server_port': 8775,
|
||||
'metadata_server_ip': '127.0.0.1',
|
||||
'metadata_proxy_shared_secret': ''
|
||||
}
|
||||
self.mock_lsn_api.lsn_metadata_configure.assert_called_once_with(
|
||||
mock.ANY, mock.ANY, is_enabled, expected)
|
||||
if is_enabled:
|
||||
self.assertEqual(
|
||||
1, self.mock_lsn_api.lsn_port_by_subnet_get.call_count)
|
||||
else:
|
||||
self.assertEqual(1, f.call_count)
|
||||
|
||||
def test_lsn_metadata_configure_enabled(self):
|
||||
self._test_lsn_metadata_configure(True)
|
||||
|
||||
def test_lsn_metadata_configure_disabled(self):
|
||||
self._test_lsn_metadata_configure(False)
|
||||
|
||||
def test_lsn_metadata_configure_not_found(self):
|
||||
self.mock_lsn_api.lsn_metadata_configure.side_effect = (
|
||||
p_exc.LsnNotFound(entity='lsn', entity_id=self.lsn_id))
|
||||
self.manager.plugin.get_subnet.return_value = (
|
||||
{'network_id': self.net_id})
|
||||
self.assertRaises(p_exc.NvpPluginException,
|
||||
self.manager.lsn_metadata_configure,
|
||||
mock.ANY, self.sub_id, True)
|
||||
|
||||
def test_lsn_port_metadata_setup(self):
|
||||
subnet = {
|
||||
'cidr': '0.0.0.0/0',
|
||||
'id': self.sub_id,
|
||||
'network_id': self.net_id,
|
||||
'tenant_id': self.tenant_id
|
||||
}
|
||||
with mock.patch.object(nvp.nvplib, 'create_lport') as f:
|
||||
f.return_value = {'uuid': self.port_id}
|
||||
self.manager.lsn_port_metadata_setup(mock.ANY, self.lsn_id, subnet)
|
||||
self.assertEqual(1, self.mock_lsn_api.lsn_port_create.call_count)
|
||||
self.mock_lsn_api.lsn_port_plug_network.assert_called_once_with(
|
||||
mock.ANY, self.lsn_id, mock.ANY, self.port_id)
|
||||
|
||||
def test_lsn_port_metadata_setup_raise_not_found(self):
|
||||
subnet = {
|
||||
'cidr': '0.0.0.0/0',
|
||||
'id': self.sub_id,
|
||||
'network_id': self.net_id,
|
||||
'tenant_id': self.tenant_id
|
||||
}
|
||||
with mock.patch.object(nvp.nvplib, 'create_lport') as f:
|
||||
f.side_effect = n_exc.NotFound
|
||||
self.assertRaises(p_exc.PortConfigurationError,
|
||||
self.manager.lsn_port_metadata_setup,
|
||||
mock.ANY, self.lsn_id, subnet)
|
||||
|
||||
def test_lsn_port_metadata_setup_raise_conflict(self):
|
||||
subnet = {
|
||||
'cidr': '0.0.0.0/0',
|
||||
'id': self.sub_id,
|
||||
'network_id': self.net_id,
|
||||
'tenant_id': self.tenant_id
|
||||
}
|
||||
with mock.patch.object(nvp.nvplib, 'create_lport') as f:
|
||||
with mock.patch.object(nvp.nvplib, 'delete_port') as g:
|
||||
f.return_value = {'uuid': self.port_id}
|
||||
self.mock_lsn_api.lsn_port_plug_network.side_effect = (
|
||||
p_exc.LsnConfigurationConflict(lsn_id=self.lsn_id))
|
||||
self.assertRaises(p_exc.PortConfigurationError,
|
||||
self.manager.lsn_port_metadata_setup,
|
||||
mock.ANY, self.lsn_id, subnet)
|
||||
self.assertEqual(1,
|
||||
self.mock_lsn_api.lsn_port_delete.call_count)
|
||||
self.assertEqual(1, g.call_count)
|
||||
|
||||
def _test_lsn_port_dispose_with_values(self, lsn_id, lsn_port_id, count):
|
||||
with mock.patch.object(self.manager,
|
||||
'lsn_port_get_by_mac',
|
||||
@ -302,6 +384,17 @@ class LsnManagerTestCase(base.BaseTestCase):
|
||||
self._test_lsn_port_dispose_with_values(
|
||||
self.lsn_id, self.lsn_port_id, 1)
|
||||
|
||||
def test_lsn_port_dispose_meta_mac(self):
|
||||
self.mac = nvp.METADATA_MAC
|
||||
with mock.patch.object(nvp.nvplib, 'get_port_by_neutron_tag') as f:
|
||||
with mock.patch.object(nvp.nvplib, 'delete_port') as g:
|
||||
f.return_value = {'uuid': self.port_id}
|
||||
self._test_lsn_port_dispose_with_values(
|
||||
self.lsn_id, self.lsn_port_id, 1)
|
||||
f.assert_called_once_with(
|
||||
mock.ANY, self.net_id, nvp.METADATA_PORT_ID)
|
||||
g.assert_called_once_with(mock.ANY, self.net_id, self.port_id)
|
||||
|
||||
def test_lsn_port_dispose_lsn_not_found(self):
|
||||
self._test_lsn_port_dispose_with_values(None, None, 0)
|
||||
|
||||
@ -334,6 +427,33 @@ class LsnManagerTestCase(base.BaseTestCase):
|
||||
self.manager._lsn_port_host_conf, mock.ANY,
|
||||
self.net_id, self.sub_id, mock.ANY, mock.Mock())
|
||||
|
||||
def _test_lsn_port_update(self, dhcp=None, meta=None):
|
||||
self.manager.lsn_port_update(
|
||||
mock.ANY, self.net_id, self.sub_id, dhcp, meta)
|
||||
count = 1 if dhcp else 0
|
||||
count = count + 1 if meta else count
|
||||
self.assertEqual(count, (self.mock_lsn_api.
|
||||
lsn_port_host_entries_update.call_count))
|
||||
|
||||
def test_lsn_port_update(self):
|
||||
self._test_lsn_port_update()
|
||||
|
||||
def test_lsn_port_update_dhcp_meta(self):
|
||||
self._test_lsn_port_update(mock.ANY, mock.ANY)
|
||||
|
||||
def test_lsn_port_update_dhcp_and_nometa(self):
|
||||
self._test_lsn_port_update(mock.ANY, None)
|
||||
|
||||
def test_lsn_port_update_nodhcp_and_nmeta(self):
|
||||
self._test_lsn_port_update(None, mock.ANY)
|
||||
|
||||
def test_lsn_port_update_raise_error(self):
|
||||
self.mock_lsn_api.lsn_port_host_entries_update.side_effect = (
|
||||
NvpApiException)
|
||||
self.assertRaises(p_exc.PortConfigurationError,
|
||||
self.manager.lsn_port_update,
|
||||
mock.ANY, mock.ANY, mock.ANY, mock.ANY)
|
||||
|
||||
|
||||
class DhcpAgentNotifyAPITestCase(base.BaseTestCase):
|
||||
|
||||
@ -343,6 +463,107 @@ class DhcpAgentNotifyAPITestCase(base.BaseTestCase):
|
||||
self.plugin = self.notifier.plugin
|
||||
self.lsn_manager = self.notifier.lsn_manager
|
||||
|
||||
def _test_notify_port_update(
|
||||
self, ports, expected_count, expected_args=None):
|
||||
port = {
|
||||
'id': 'foo_port_id',
|
||||
'network_id': 'foo_network_id',
|
||||
'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]
|
||||
}
|
||||
self.notifier.plugin.get_ports.return_value = ports
|
||||
self.notifier.notify(mock.ANY, {'port': port}, 'port.update.end')
|
||||
self.lsn_manager.lsn_port_update.assert_has_calls(expected_args)
|
||||
|
||||
def test_notify_ports_update_no_ports(self):
|
||||
self._test_notify_port_update(None, 0, [])
|
||||
self._test_notify_port_update([], 0, [])
|
||||
|
||||
def test_notify_ports_update_one_port(self):
|
||||
ports = [{
|
||||
'fixed_ips': [{'subnet_id': 'foo_subnet_id',
|
||||
'ip_address': '1.2.3.4'}],
|
||||
'device_id': 'foo_device_id',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'
|
||||
}]
|
||||
call_args = mock.call(
|
||||
mock.ANY, 'foo_network_id', 'foo_subnet_id',
|
||||
dhcp=[{'ip_address': '1.2.3.4',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'}],
|
||||
meta=[{'instance_id': 'foo_device_id',
|
||||
'ip_address': '1.2.3.4'}])
|
||||
self._test_notify_port_update(ports, 1, call_args)
|
||||
|
||||
def test_notify_ports_update_ports_with_empty_device_id(self):
|
||||
ports = [{
|
||||
'fixed_ips': [{'subnet_id': 'foo_subnet_id',
|
||||
'ip_address': '1.2.3.4'}],
|
||||
'device_id': '',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'
|
||||
}]
|
||||
call_args = mock.call(
|
||||
mock.ANY, 'foo_network_id', 'foo_subnet_id',
|
||||
dhcp=[{'ip_address': '1.2.3.4',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'}],
|
||||
meta=[]
|
||||
)
|
||||
self._test_notify_port_update(ports, 1, call_args)
|
||||
|
||||
def test_notify_ports_update_ports_with_no_fixed_ips(self):
|
||||
ports = [{
|
||||
'fixed_ips': [],
|
||||
'device_id': 'foo_device_id',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'
|
||||
}]
|
||||
call_args = mock.call(
|
||||
mock.ANY, 'foo_network_id', 'foo_subnet_id', dhcp=[], meta=[])
|
||||
self._test_notify_port_update(ports, 1, call_args)
|
||||
|
||||
def test_notify_ports_update_ports_with_no_fixed_ips_and_no_device(self):
|
||||
ports = [{
|
||||
'fixed_ips': [],
|
||||
'device_id': '',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'
|
||||
}]
|
||||
call_args = mock.call(
|
||||
mock.ANY, 'foo_network_id', 'foo_subnet_id', dhcp=[], meta=[])
|
||||
self._test_notify_port_update(ports, 0, call_args)
|
||||
|
||||
def test_notify_ports_update_with_special_ports(self):
|
||||
ports = [{'fixed_ips': [],
|
||||
'device_id': '',
|
||||
'device_owner': 'network:dhcp',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'},
|
||||
{'fixed_ips': [{'subnet_id': 'foo_subnet_id',
|
||||
'ip_address': '1.2.3.4'}],
|
||||
'device_id': 'foo_device_id',
|
||||
'device_owner': 'network:router_gateway',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'}]
|
||||
call_args = mock.call(
|
||||
mock.ANY, 'foo_network_id', 'foo_subnet_id', dhcp=[], meta=[])
|
||||
self._test_notify_port_update(ports, 0, call_args)
|
||||
|
||||
def test_notify_ports_update_many_ports(self):
|
||||
ports = [{'fixed_ips': [],
|
||||
'device_id': '',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'},
|
||||
{'fixed_ips': [{'subnet_id': 'foo_subnet_id',
|
||||
'ip_address': '1.2.3.4'}],
|
||||
'device_id': 'foo_device_id',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'}]
|
||||
call_args = mock.call(
|
||||
mock.ANY, 'foo_network_id', 'foo_subnet_id',
|
||||
dhcp=[{'ip_address': '1.2.3.4',
|
||||
'mac_address': 'fa:16:3e:da:1d:46'}],
|
||||
meta=[{'instance_id': 'foo_device_id',
|
||||
'ip_address': '1.2.3.4'}])
|
||||
self._test_notify_port_update(ports, 1, call_args)
|
||||
|
||||
def _test_notify_subnet_action(self, action):
|
||||
with mock.patch.object(self.notifier, '_subnet_%s' % action) as f:
|
||||
self.notifier._handle_subnet_dhcp_access[action] = f
|
||||
@ -631,3 +852,148 @@ class DhcpTestCase(base.BaseTestCase):
|
||||
def test_handle_delete_user_port_no_fixed_ips(self):
|
||||
self._test_handle_user_port_no_fixed_ips(
|
||||
'delete_port', self.plugin.lsn_manager.lsn_port_dhcp_host_remove)
|
||||
|
||||
|
||||
class MetadataTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(MetadataTestCase, self).setUp()
|
||||
self.plugin = mock.Mock()
|
||||
self.plugin.lsn_manager = mock.Mock()
|
||||
|
||||
def _test_handle_port_metadata_access_special_owners(
|
||||
self, owner, dev_id='foo_device_id', ips=None):
|
||||
port = {
|
||||
'id': 'foo_port_id',
|
||||
'device_owner': owner,
|
||||
'device_id': dev_id,
|
||||
'fixed_ips': ips or []
|
||||
}
|
||||
nvp.handle_port_metadata_access(self.plugin, mock.ANY, port, mock.ANY)
|
||||
self.assertFalse(
|
||||
self.plugin.lsn_manager.lsn_port_meta_host_add.call_count)
|
||||
self.assertFalse(
|
||||
self.plugin.lsn_manager.lsn_port_meta_host_remove.call_count)
|
||||
|
||||
def test_handle_port_metadata_access_external_network(self):
|
||||
port = {
|
||||
'id': 'foo_port_id',
|
||||
'device_owner': 'foo_device_owner',
|
||||
'device_id': 'foo_device_id',
|
||||
'network_id': 'foo_network_id',
|
||||
'fixed_ips': [{'subnet_id': 'foo_subnet'}]
|
||||
}
|
||||
self.plugin.get_network.return_value = {'router:external': True}
|
||||
nvp.handle_port_metadata_access(self.plugin, mock.ANY, port, mock.ANY)
|
||||
self.assertFalse(
|
||||
self.plugin.lsn_manager.lsn_port_meta_host_add.call_count)
|
||||
self.assertFalse(
|
||||
self.plugin.lsn_manager.lsn_port_meta_host_remove.call_count)
|
||||
|
||||
def test_handle_port_metadata_access_dhcp_port(self):
|
||||
self._test_handle_port_metadata_access_special_owners(
|
||||
'network:dhcp', [{'subnet_id': 'foo_subnet'}])
|
||||
|
||||
def test_handle_port_metadata_access_router_port(self):
|
||||
self._test_handle_port_metadata_access_special_owners(
|
||||
'network:router_interface', [{'subnet_id': 'foo_subnet'}])
|
||||
|
||||
def test_handle_port_metadata_access_no_device_id(self):
|
||||
self._test_handle_port_metadata_access_special_owners(
|
||||
'network:dhcp', '')
|
||||
|
||||
def test_handle_port_metadata_access_no_fixed_ips(self):
|
||||
self._test_handle_port_metadata_access_special_owners(
|
||||
'foo', 'foo', None)
|
||||
|
||||
def _test_handle_port_metadata_access(self, is_delete, raise_exc=False):
|
||||
port = {
|
||||
'id': 'foo_port_id',
|
||||
'device_owner': 'foo_device_id',
|
||||
'network_id': 'foo_network_id',
|
||||
'device_id': 'foo_device_id',
|
||||
'tenant_id': 'foo_tenant_id',
|
||||
'fixed_ips': [
|
||||
{'subnet_id': 'foo_subnet_id', 'ip_address': '1.2.3.4'}
|
||||
]
|
||||
}
|
||||
meta = {
|
||||
'instance_id': port['device_id'],
|
||||
'tenant_id': port['tenant_id'],
|
||||
'ip_address': port['fixed_ips'][0]['ip_address']
|
||||
}
|
||||
self.plugin.get_network.return_value = {'router:external': False}
|
||||
if is_delete:
|
||||
mock_func = self.plugin.lsn_manager.lsn_port_meta_host_remove
|
||||
else:
|
||||
mock_func = self.plugin.lsn_manager.lsn_port_meta_host_add
|
||||
if raise_exc:
|
||||
mock_func.side_effect = p_exc.PortConfigurationError(
|
||||
lsn_id='foo_lsn_id', net_id='foo_net_id', port_id=None)
|
||||
with mock.patch.object(nvp.db_base_plugin_v2.NeutronDbPluginV2,
|
||||
'delete_port') as d:
|
||||
self.assertRaises(p_exc.PortConfigurationError,
|
||||
nvp.handle_port_metadata_access,
|
||||
self.plugin, mock.ANY, port,
|
||||
is_delete=is_delete)
|
||||
if not is_delete:
|
||||
d.assert_called_once_with(mock.ANY, mock.ANY, port['id'])
|
||||
else:
|
||||
self.assertFalse(d.call_count)
|
||||
else:
|
||||
nvp.handle_port_metadata_access(
|
||||
self.plugin, mock.ANY, port, is_delete=is_delete)
|
||||
mock_func.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY, meta)
|
||||
|
||||
def test_handle_port_metadata_access_on_delete_true(self):
|
||||
self._test_handle_port_metadata_access(True)
|
||||
|
||||
def test_handle_port_metadata_access_on_delete_false(self):
|
||||
self._test_handle_port_metadata_access(False)
|
||||
|
||||
def test_handle_port_metadata_access_on_delete_true_raise(self):
|
||||
self._test_handle_port_metadata_access(True, raise_exc=True)
|
||||
|
||||
def test_handle_port_metadata_access_on_delete_false_raise(self):
|
||||
self._test_handle_port_metadata_access(False, raise_exc=True)
|
||||
|
||||
def _test_handle_router_metadata_access(
|
||||
self, is_port_found, raise_exc=False):
|
||||
subnet = {
|
||||
'id': 'foo_subnet_id',
|
||||
'network_id': 'foo_network_id'
|
||||
}
|
||||
interface = {
|
||||
'subnet_id': subnet['id'],
|
||||
'port_id': 'foo_port_id'
|
||||
}
|
||||
mock_func = self.plugin.lsn_manager.lsn_metadata_configure
|
||||
if not is_port_found:
|
||||
self.plugin.get_port.side_effect = n_exc.NotFound
|
||||
if raise_exc:
|
||||
with mock.patch.object(nvp.l3_db.L3_NAT_db_mixin,
|
||||
'remove_router_interface') as d:
|
||||
mock_func.side_effect = p_exc.NvpPluginException(err_msg='')
|
||||
self.assertRaises(p_exc.NvpPluginException,
|
||||
nvp.handle_router_metadata_access,
|
||||
self.plugin, mock.ANY, 'foo_router_id',
|
||||
interface)
|
||||
d.assert_called_once_with(mock.ANY, mock.ANY, 'foo_router_id',
|
||||
interface)
|
||||
else:
|
||||
nvp.handle_router_metadata_access(
|
||||
self.plugin, mock.ANY, 'foo_router_id', interface)
|
||||
mock_func.assert_called_once_with(
|
||||
mock.ANY, subnet['id'], is_port_found)
|
||||
|
||||
def test_handle_router_metadata_access_add_interface(self):
|
||||
self._test_handle_router_metadata_access(True)
|
||||
|
||||
def test_handle_router_metadata_access_delete_interface(self):
|
||||
self._test_handle_router_metadata_access(False)
|
||||
|
||||
def test_handle_router_metadata_access_raise_error_on_add(self):
|
||||
self._test_handle_router_metadata_access(True, raise_exc=True)
|
||||
|
||||
def test_handle_router_metadata_access_raise_error_on_delete(self):
|
||||
self._test_handle_router_metadata_access(True, raise_exc=False)
|
||||
|
@ -112,6 +112,31 @@ class LSNTestCase(base.BaseTestCase):
|
||||
"DELETE",
|
||||
"/ws.v1/lservices-node/%s" % lsn_id, cluster=self.cluster)
|
||||
|
||||
def _test_lsn_port_host_entries_update(self, lsn_type, hosts_data):
|
||||
lsn_id = 'foo_lsn_id'
|
||||
lsn_port_id = 'foo_lsn_port_id'
|
||||
lsnlib.lsn_port_host_entries_update(
|
||||
self.cluster, lsn_id, lsn_port_id, lsn_type, hosts_data)
|
||||
self.mock_request.assert_called_once_with(
|
||||
'PUT',
|
||||
'/ws.v1/lservices-node/%s/lport/%s/%s' % (lsn_id,
|
||||
lsn_port_id,
|
||||
lsn_type),
|
||||
json.dumps({'hosts': hosts_data}),
|
||||
cluster=self.cluster)
|
||||
|
||||
def test_lsn_port_dhcp_entries_update(self):
|
||||
hosts_data = [{"ip_address": "11.22.33.44",
|
||||
"mac_address": "aa:bb:cc:dd:ee:ff"},
|
||||
{"ip_address": "44.33.22.11",
|
||||
"mac_address": "ff:ee:dd:cc:bb:aa"}]
|
||||
self._test_lsn_port_host_entries_update("dhcp", hosts_data)
|
||||
|
||||
def test_lsn_port_metadata_entries_update(self):
|
||||
hosts_data = [{"ip_address": "11.22.33.44",
|
||||
"device_id": "foo_vm_uuid"}]
|
||||
self._test_lsn_port_host_entries_update("metadata-proxy", hosts_data)
|
||||
|
||||
def test_lsn_port_create(self):
|
||||
port_data = {
|
||||
"ip_address": "1.2.3.0/24",
|
||||
@ -230,6 +255,50 @@ class LSNTestCase(base.BaseTestCase):
|
||||
self._test_lsn_port_dhcp_configure(
|
||||
lsn_id, lsn_port_id, is_enabled, opts)
|
||||
|
||||
def _test_lsn_metadata_configure(
|
||||
self, lsn_id, is_enabled, opts, expected_opts):
|
||||
lsnlib.lsn_metadata_configure(
|
||||
self.cluster, lsn_id, is_enabled, opts)
|
||||
lsn_obj = {"enabled": is_enabled}
|
||||
lsn_obj.update(expected_opts)
|
||||
self.mock_request.assert_has_calls([
|
||||
mock.call("PUT",
|
||||
"/ws.v1/lservices-node/%s/metadata-proxy" % lsn_id,
|
||||
json.dumps(lsn_obj),
|
||||
cluster=self.cluster),
|
||||
])
|
||||
|
||||
def test_lsn_port_metadata_configure_empty_secret(self):
|
||||
lsn_id = "foo_lsn_id"
|
||||
is_enabled = True
|
||||
opts = {
|
||||
"metadata_server_ip": "1.2.3.4",
|
||||
"metadata_server_port": "8775"
|
||||
}
|
||||
expected_opts = {
|
||||
"metadata_server_ip": "1.2.3.4",
|
||||
"metadata_server_port": "8775",
|
||||
"misc_options": []
|
||||
}
|
||||
self._test_lsn_metadata_configure(
|
||||
lsn_id, is_enabled, opts, expected_opts)
|
||||
|
||||
def test_lsn_metadata_configure_with_secret(self):
|
||||
lsn_id = "foo_lsn_id"
|
||||
is_enabled = True
|
||||
opts = {
|
||||
"metadata_server_ip": "1.2.3.4",
|
||||
"metadata_server_port": "8775",
|
||||
"metadata_proxy_shared_secret": "foo_secret"
|
||||
}
|
||||
expected_opts = {
|
||||
"metadata_server_ip": "1.2.3.4",
|
||||
"metadata_server_port": "8775",
|
||||
"misc_options": ["metadata_proxy_shared_secret=foo_secret"]
|
||||
}
|
||||
self._test_lsn_metadata_configure(
|
||||
lsn_id, is_enabled, opts, expected_opts)
|
||||
|
||||
def _test_lsn_port_host_action(
|
||||
self, lsn_port_action_func, extra_action, action, host):
|
||||
lsn_id = "foo_lsn_id"
|
||||
@ -256,3 +325,19 @@ class LSNTestCase(base.BaseTestCase):
|
||||
}
|
||||
self._test_lsn_port_host_action(
|
||||
lsnlib.lsn_port_dhcp_host_remove, "dhcp", "remove_host", host)
|
||||
|
||||
def test_lsn_port_metadata_host_add(self):
|
||||
host = {
|
||||
"ip_address": "1.2.3.4",
|
||||
"instance_id": "foo_instance_id"
|
||||
}
|
||||
self._test_lsn_port_host_action(lsnlib.lsn_port_metadata_host_add,
|
||||
"metadata-proxy", "add_host", host)
|
||||
|
||||
def test_lsn_port_metadata_host_remove(self):
|
||||
host = {
|
||||
"ip_address": "1.2.3.4",
|
||||
"instance_id": "foo_instance_id"
|
||||
}
|
||||
self._test_lsn_port_host_action(lsnlib.lsn_port_metadata_host_remove,
|
||||
"metadata-proxy", "remove_host", host)
|
||||
|
Loading…
x
Reference in New Issue
Block a user