
This change replaces remaining occurences of the notify method with calls to the publish method. As NSX admin utilities heavily rely on callbacks, this change also ensures that all callbacks are now accepting event payloads rather thank kwargs. Change-Id: I0450fff486898d6ab74086b7952dc27134cb77e2
352 lines
14 KiB
Python
352 lines
14 KiB
Python
# Copyright 2016 VMware, Inc. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from neutron.db import db_base_plugin_v2
|
|
from neutron.db import l3_db
|
|
from neutron_lib.callbacks import registry
|
|
from neutron_lib import context as neutron_context
|
|
from oslo_log import log as logging
|
|
|
|
from vmware_nsx.common import utils as nsx_utils
|
|
from vmware_nsx.db import db as nsx_db
|
|
from vmware_nsx.db import nsx_models
|
|
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
|
|
from vmware_nsx.shell.admin.plugins.common import constants
|
|
from vmware_nsx.shell.admin.plugins.common import formatters
|
|
from vmware_nsx.shell.admin.plugins.common import utils as admin_utils
|
|
from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils
|
|
from vmware_nsx.shell import resources as shell
|
|
from vmware_nsxlib.v3 import exceptions as nsx_exc
|
|
from vmware_nsxlib.v3 import nsx_constants
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
neutron_client = utils.NeutronDbClient()
|
|
|
|
|
|
class RoutersPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|
l3_db.L3_NAT_db_mixin):
|
|
pass
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def list_missing_routers(resource, event, trigger, **kwargs):
|
|
"""List neutron routers that are missing the NSX backend router
|
|
"""
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
plugin = RoutersPlugin()
|
|
admin_cxt = neutron_context.get_admin_context()
|
|
filters = utils.get_plugin_filters(admin_cxt)
|
|
neutron_routers = plugin.get_routers(admin_cxt, filters=filters)
|
|
routers = []
|
|
for router in neutron_routers:
|
|
neutron_id = router['id']
|
|
# get the router nsx id from the mapping table
|
|
nsx_id = nsx_db.get_nsx_router_id(admin_cxt.session,
|
|
neutron_id)
|
|
if not nsx_id:
|
|
routers.append({'name': router['name'],
|
|
'neutron_id': neutron_id,
|
|
'nsx_id': None})
|
|
else:
|
|
try:
|
|
nsxlib.logical_router.get(nsx_id)
|
|
except nsx_exc.ResourceNotFound:
|
|
routers.append({'name': router['name'],
|
|
'neutron_id': neutron_id,
|
|
'nsx_id': nsx_id})
|
|
if len(routers) > 0:
|
|
title = ("Found %d routers missing from the NSX "
|
|
"manager:") % len(routers)
|
|
LOG.info(formatters.output_formatter(
|
|
title, routers,
|
|
['name', 'neutron_id', 'nsx_id']))
|
|
else:
|
|
LOG.info("All routers exist on the NSX manager")
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def update_nat_rules(resource, event, trigger, **kwargs):
|
|
"""Update all routers NAT rules to not bypass the firewall"""
|
|
# This feature is supported only since nsx version 2
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
version = nsxlib.get_version()
|
|
if not nsx_utils.is_nsx_version_2_0_0(version):
|
|
LOG.info("NAT rules update only supported from 2.0 onwards")
|
|
LOG.info("Version is %s", version)
|
|
return
|
|
|
|
# Go over all neutron routers
|
|
plugin = RoutersPlugin()
|
|
admin_cxt = neutron_context.get_admin_context()
|
|
filters = utils.get_plugin_filters(admin_cxt)
|
|
neutron_routers = plugin.get_routers(admin_cxt, filters=filters)
|
|
num_of_updates = 0
|
|
for router in neutron_routers:
|
|
neutron_id = router['id']
|
|
# get the router nsx id from the mapping table
|
|
nsx_id = nsx_db.get_nsx_router_id(admin_cxt.session,
|
|
neutron_id)
|
|
if nsx_id:
|
|
# get all NAT rules:
|
|
rules = nsxlib.logical_router.list_nat_rules(nsx_id)['results']
|
|
for rule in rules:
|
|
if rule['action'] not in ["NO_SNAT", "NO_DNAT", "NO_NAT"]:
|
|
if 'nat_pass' not in rule or rule['nat_pass']:
|
|
nsxlib.logical_router.update_nat_rule(
|
|
nsx_id, rule['id'], nat_pass=False)
|
|
num_of_updates = num_of_updates + 1
|
|
if num_of_updates:
|
|
LOG.info("Done updating %s NAT rules", num_of_updates)
|
|
else:
|
|
LOG.info("Did not find any NAT rule to update")
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def update_enable_standby_relocation(resource, event, trigger, **kwargs):
|
|
"""Enable standby relocation on all routers """
|
|
# This feature is supported only since nsx version 2.4
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
version = nsxlib.get_version()
|
|
if not nsx_utils.is_nsx_version_2_4_0(version):
|
|
LOG.info("Standby relocation update is only supported from 2.4 "
|
|
"onwards")
|
|
LOG.info("Version is %s", version)
|
|
return
|
|
|
|
# Go over all neutron routers
|
|
plugin = RoutersPlugin()
|
|
admin_cxt = neutron_context.get_admin_context()
|
|
filters = utils.get_plugin_filters(admin_cxt)
|
|
neutron_routers = plugin.get_routers(admin_cxt, filters=filters)
|
|
for router in neutron_routers:
|
|
neutron_id = router['id']
|
|
# get the router nsx id from the mapping table
|
|
nsx_id = nsx_db.get_nsx_router_id(admin_cxt.session,
|
|
neutron_id)
|
|
try:
|
|
nsxlib.logical_router.update(lrouter_id=nsx_id,
|
|
enable_standby_relocation=True)
|
|
except Exception as e:
|
|
# This may fail if the service router is not created
|
|
LOG.warning("Router %s cannot enable standby relocation: %s",
|
|
neutron_id, e)
|
|
else:
|
|
LOG.info("Router %s was enabled with standby relocation",
|
|
neutron_id)
|
|
LOG.info("Done")
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def list_orphaned_routers(resource, event, trigger, **kwargs):
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
admin_cxt = neutron_context.get_admin_context()
|
|
missing_routers = v3_utils.get_orphaned_routers(admin_cxt, nsxlib)
|
|
LOG.info(formatters.output_formatter(constants.ORPHANED_ROUTERS,
|
|
missing_routers,
|
|
['id', 'display_name']))
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def delete_backend_router(resource, event, trigger, **kwargs):
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
errmsg = ("Need to specify nsx-id property. Add --property nsx-id=<id>")
|
|
if not kwargs.get('property'):
|
|
LOG.error("%s", errmsg)
|
|
return
|
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
|
nsx_id = properties.get('nsx-id')
|
|
if not nsx_id:
|
|
LOG.error("%s", errmsg)
|
|
return
|
|
|
|
# check if the router exists
|
|
try:
|
|
nsxlib.logical_router.get(nsx_id, silent=True)
|
|
except nsx_exc.ResourceNotFound:
|
|
LOG.warning("Backend router %s was not found.", nsx_id)
|
|
return
|
|
|
|
# try to delete it
|
|
success, error = v3_utils.delete_orphaned_router(nsxlib, nsx_id)
|
|
if not success:
|
|
LOG.error("Failed to delete backend router %(id)s : %(e)s.", {
|
|
'id': nsx_id, 'e': error})
|
|
return
|
|
|
|
# Verify that the router was deleted since the backend does not always
|
|
# throws errors
|
|
try:
|
|
nsxlib.logical_router.get(nsx_id, silent=True)
|
|
except nsx_exc.ResourceNotFound:
|
|
LOG.info("Backend router %s was deleted.", nsx_id)
|
|
else:
|
|
LOG.error("Failed to delete backend router %s.", nsx_id)
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def update_dhcp_relay(resource, event, trigger, **kwargs):
|
|
"""Update all routers dhcp relay service by the current configuration"""
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
if not nsxlib.feature_supported(nsx_constants.FEATURE_DHCP_RELAY):
|
|
version = nsxlib.get_version()
|
|
LOG.error("DHCP relay is not supported by NSX version %s", version)
|
|
return
|
|
|
|
admin_cxt = neutron_context.get_admin_context()
|
|
filters = utils.get_plugin_filters(admin_cxt)
|
|
with utils.NsxV3PluginWrapper() as plugin:
|
|
# Make sure FWaaS was initialized
|
|
plugin.init_fwaas_for_admin_utils()
|
|
|
|
# get all neutron routers and interfaces ports
|
|
routers = plugin.get_routers(admin_cxt, filters=filters)
|
|
for router in routers:
|
|
LOG.info("Updating router %s", router['id'])
|
|
port_filters = {'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
|
|
'device_id': [router['id']]}
|
|
ports = plugin.get_ports(admin_cxt, filters=port_filters)
|
|
for port in ports:
|
|
# get the backend router port by the tag
|
|
nsx_port_id = nsxlib.get_id_by_resource_and_tag(
|
|
'LogicalRouterDownLinkPort',
|
|
'os-neutron-rport-id', port['id'])
|
|
if not nsx_port_id:
|
|
LOG.warning("Couldn't find nsx router port for interface "
|
|
"%s", port['id'])
|
|
continue
|
|
# get the network of this port
|
|
network_id = port['network_id']
|
|
# check the relay service on the az of the network
|
|
az = plugin.get_network_az_by_net_id(admin_cxt, network_id)
|
|
nsxlib.logical_router_port.update(
|
|
nsx_port_id, relay_service_uuid=az.dhcp_relay_service)
|
|
|
|
# if FWaaS is enables, also update the firewall rules
|
|
try:
|
|
plugin.update_router_firewall(admin_cxt, router['id'])
|
|
except Exception as e:
|
|
LOG.warning("Updating router firewall was skipped because of "
|
|
"an error %s", e)
|
|
|
|
LOG.info("Done.")
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def update_tier0(resource, event, trigger, **kwargs):
|
|
"""Replace old tier0 with a new one on the neutron DB and NSX backend"""
|
|
errmsg = ("Need to specify old and new tier0 ID. Add --property "
|
|
"old-tier0=<id> --property new-tier0=<id>")
|
|
if not kwargs.get('property'):
|
|
LOG.error("%s", errmsg)
|
|
return
|
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
|
old_tier0 = properties.get('old-tier0')
|
|
new_tier0 = properties.get('new-tier0')
|
|
if not old_tier0 or not new_tier0:
|
|
LOG.error("%s", errmsg)
|
|
return
|
|
# Verify the id of the new tier0 (old one might not exist any more)
|
|
nsxlib = utils.get_connected_nsxlib()
|
|
try:
|
|
tier0_obj = nsxlib.logical_router.get(new_tier0)
|
|
except Exception:
|
|
LOG.error("Tier0 logical router %s was not found", new_tier0)
|
|
return
|
|
if tier0_obj.get('router_type') != 'TIER0':
|
|
LOG.error("Logical router %s is not a tier0 router", new_tier0)
|
|
return
|
|
|
|
# update all neutron DB entries
|
|
old_tier0_networks = []
|
|
admin_cxt = neutron_context.get_admin_context()
|
|
with admin_cxt.session.begin(subtransactions=True):
|
|
bindings = admin_cxt.session.query(
|
|
nsx_models.TzNetworkBinding).filter_by(phy_uuid=old_tier0).all()
|
|
for bind in bindings:
|
|
old_tier0_networks.append(bind.network_id)
|
|
bind.phy_uuid = new_tier0
|
|
|
|
if not old_tier0_networks:
|
|
LOG.info("Did not find any provider networks using tier0 %s",
|
|
old_tier0)
|
|
return
|
|
|
|
LOG.info("Updated provider networks in DB: %s", old_tier0_networks)
|
|
|
|
# Update tier1 routers GW to point to the new tier0 in the backend
|
|
plugin = RoutersPlugin()
|
|
filters = utils.get_plugin_filters(admin_cxt)
|
|
neutron_routers = plugin.get_routers(admin_cxt, filters=filters)
|
|
for router in neutron_routers:
|
|
router_gw_net = (router.get('external_gateway_info') and
|
|
router['external_gateway_info'].get('network_id'))
|
|
if router_gw_net and router_gw_net in old_tier0_networks:
|
|
nsx_router_id = nsx_db.get_nsx_router_id(
|
|
admin_cxt.session, router['id'])
|
|
try:
|
|
nsxlib.router.remove_router_link_port(nsx_router_id)
|
|
except Exception as e:
|
|
LOG.info("Could not delete router %s linked port: %s",
|
|
router['id'], e)
|
|
tags = nsxlib.build_v3_tags_payload(
|
|
router, resource_type='os-neutron-rport',
|
|
project_name=admin_cxt.tenant_name)
|
|
try:
|
|
nsxlib.router.add_router_link_port(nsx_router_id,
|
|
new_tier0,
|
|
tags=tags)
|
|
except Exception as e:
|
|
LOG.error("Failed to create router %s linked port: %s",
|
|
router['id'], e)
|
|
else:
|
|
LOG.info("Updated router %s uplink port", router['id'])
|
|
|
|
LOG.info("Done.")
|
|
|
|
|
|
registry.subscribe(list_missing_routers,
|
|
constants.ROUTERS,
|
|
shell.Operations.LIST_MISMATCHES.value)
|
|
|
|
registry.subscribe(update_nat_rules,
|
|
constants.ROUTERS,
|
|
shell.Operations.NSX_UPDATE_RULES.value)
|
|
|
|
registry.subscribe(list_orphaned_routers,
|
|
constants.ORPHANED_ROUTERS,
|
|
shell.Operations.LIST.value)
|
|
|
|
registry.subscribe(delete_backend_router,
|
|
constants.ORPHANED_ROUTERS,
|
|
shell.Operations.NSX_CLEAN.value)
|
|
|
|
registry.subscribe(update_dhcp_relay,
|
|
constants.ROUTERS,
|
|
shell.Operations.NSX_UPDATE_DHCP_RELAY.value)
|
|
|
|
registry.subscribe(update_enable_standby_relocation,
|
|
constants.ROUTERS,
|
|
shell.Operations.NSX_ENABLE_STANDBY_RELOCATION.value)
|
|
|
|
registry.subscribe(update_tier0,
|
|
constants.ROUTERS,
|
|
shell.Operations.UPDATE_TIER0.value)
|