Merge "Nsxv3: Add admin utility to clean orphaned DHCP servers"
This commit is contained in:
commit
3009cc87ec
@ -155,7 +155,7 @@ Metadata
|
|||||||
NSXv3
|
NSXv3
|
||||||
-----
|
-----
|
||||||
|
|
||||||
The following resources are supported: 'security-groups', 'routers', 'networks', 'nsx-security-groups', 'dhcp-binding' and 'ports'.
|
The following resources are supported: 'security-groups', 'routers', 'networks', 'nsx-security-groups', 'dhcp-binding', 'metadata-proxy', 'orphaned-dhcp-servers', and 'ports'.
|
||||||
|
|
||||||
Networks
|
Networks
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
@ -235,6 +235,17 @@ DHCP Bindings
|
|||||||
|
|
||||||
nsxadmin -r dhcp-binding -o nsx-update --property dhcp_profile_uuid=<dhcp_profile_uuid>
|
nsxadmin -r dhcp-binding -o nsx-update --property dhcp_profile_uuid=<dhcp_profile_uuid>
|
||||||
|
|
||||||
|
Orphaned DHCP Servers
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- List orphaned DHCP servers (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB)::
|
||||||
|
|
||||||
|
nsxadmin -r orphaned-dhcp-servers -o nsx-list
|
||||||
|
|
||||||
|
- Clean orphaned DHCP servers (delete logical DHCP servers from NSXv3 backend)::
|
||||||
|
|
||||||
|
nsxadmin -r orphaned-dhcp-servers -o nsx-clean
|
||||||
|
|
||||||
Upgrade Steps (Version 1.0.0 to Version 1.1.0)
|
Upgrade Steps (Version 1.0.0 to Version 1.1.0)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -23,22 +23,23 @@ NSXV_PLUGIN = 'vmware_nsx.plugin.NsxVPlugin'
|
|||||||
# Common Resource Constants
|
# Common Resource Constants
|
||||||
NETWORKS = 'networks'
|
NETWORKS = 'networks'
|
||||||
ROUTERS = 'routers'
|
ROUTERS = 'routers'
|
||||||
|
DHCP_BINDING = 'dhcp-binding'
|
||||||
|
|
||||||
# NSXV3 Resource Constants
|
# NSXV3 Resource Constants
|
||||||
FIREWALL_SECTIONS = 'firewall-sections'
|
FIREWALL_SECTIONS = 'firewall-sections'
|
||||||
FIREWALL_NSX_GROUPS = 'nsx-security-groups'
|
FIREWALL_NSX_GROUPS = 'nsx-security-groups'
|
||||||
SECURITY_GROUPS = 'security-groups'
|
SECURITY_GROUPS = 'security-groups'
|
||||||
PORTS = 'ports'
|
PORTS = 'ports'
|
||||||
|
METADATA_PROXY = 'metadata-proxy'
|
||||||
|
ORPHANED_DHCP_SERVERS = 'orphaned-dhcp-servers'
|
||||||
|
|
||||||
# NSXV Resource Constants
|
# NSXV Resource Constants
|
||||||
EDGES = 'edges'
|
EDGES = 'edges'
|
||||||
SPOOFGUARD_POLICY = 'spoofguard-policy'
|
SPOOFGUARD_POLICY = 'spoofguard-policy'
|
||||||
DHCP_BINDING = 'dhcp-binding'
|
|
||||||
BACKUP_EDGES = 'backup-edges'
|
BACKUP_EDGES = 'backup-edges'
|
||||||
ORPHANED_EDGES = 'orphaned-edges'
|
ORPHANED_EDGES = 'orphaned-edges'
|
||||||
MISSING_EDGES = 'missing-edges'
|
MISSING_EDGES = 'missing-edges'
|
||||||
METADATA = 'metadata'
|
METADATA = 'metadata'
|
||||||
METADATA_PROXY = 'metadata-proxy'
|
|
||||||
MISSING_NETWORKS = 'missing-networks'
|
MISSING_NETWORKS = 'missing-networks'
|
||||||
ORPHANED_NETWORKS = 'orphaned-networks'
|
ORPHANED_NETWORKS = 'orphaned-networks'
|
||||||
LBAAS = 'lbaas'
|
LBAAS = 'lbaas'
|
||||||
|
@ -31,6 +31,7 @@ from vmware_nsxlib.v3 import resources
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
neutron_client = utils.NeutronDbClient()
|
neutron_client = utils.NeutronDbClient()
|
||||||
|
nsxlib = utils.get_connected_nsxlib()
|
||||||
|
|
||||||
|
|
||||||
@admin_utils.output_header
|
@admin_utils.output_header
|
||||||
@ -47,10 +48,9 @@ def list_dhcp_bindings(resource, event, trigger, **kwargs):
|
|||||||
def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
|
def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
|
||||||
"""Resync DHCP bindings for NSXv3 CrossHairs."""
|
"""Resync DHCP bindings for NSXv3 CrossHairs."""
|
||||||
|
|
||||||
nsxlib = utils.get_connected_nsxlib()
|
|
||||||
nsx_version = nsxlib.get_version()
|
nsx_version = nsxlib.get_version()
|
||||||
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
||||||
LOG.info(_LI("This utility is not available for NSX version %s"),
|
LOG.error(_LE("This utility is not available for NSX version %s"),
|
||||||
nsx_version)
|
nsx_version)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
168
vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_servers.py
Normal file
168
vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_servers.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from neutron.callbacks import registry
|
||||||
|
from neutron import context
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _LE, _LI
|
||||||
|
from vmware_nsx.common import utils as nsx_utils
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
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
|
||||||
|
import vmware_nsx.shell.resources as shell
|
||||||
|
from vmware_nsxlib.v3 import nsx_constants
|
||||||
|
from vmware_nsxlib.v3 import resources
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
neutron_client = utils.NeutronDbClient()
|
||||||
|
nsx_client = utils.get_nsxv3_client()
|
||||||
|
nsxlib = utils.get_connected_nsxlib()
|
||||||
|
port_resource = resources.LogicalPort(nsx_client)
|
||||||
|
dhcp_server_resource = resources.LogicalDhcpServer(nsx_client)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_dhcp_profile_uuid(**kwargs):
|
||||||
|
if kwargs.get('property'):
|
||||||
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
||||||
|
dhcp_profile_uuid = properties.get('dhcp_profile_uuid')
|
||||||
|
if dhcp_profile_uuid:
|
||||||
|
return dhcp_profile_uuid
|
||||||
|
if cfg.CONF.nsx_v3.dhcp_profile:
|
||||||
|
return nsxlib.native_dhcp_profile.get_id_by_name_or_id(
|
||||||
|
cfg.CONF.nsx_v3.dhcp_profile)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_orphaned_dhcp_servers(dhcp_profile_uuid):
|
||||||
|
# An orphaned DHCP server means the associated neutron network
|
||||||
|
# does not exist or has no DHCP-enabled subnet.
|
||||||
|
|
||||||
|
orphaned_servers = []
|
||||||
|
server_net_pairs = []
|
||||||
|
|
||||||
|
# Find matching DHCP servers for a given dhcp_profile_uuid.
|
||||||
|
response = dhcp_server_resource.list()
|
||||||
|
for dhcp_server in response['results']:
|
||||||
|
if dhcp_server['dhcp_profile_id'] != dhcp_profile_uuid:
|
||||||
|
continue
|
||||||
|
found = False
|
||||||
|
for tag in dhcp_server['tags']:
|
||||||
|
if tag['scope'] == 'os-neutron-net-id':
|
||||||
|
server_net_pairs.append((dhcp_server, tag['tag']))
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
# The associated neutron network is not defined.
|
||||||
|
dhcp_server['neutron_net_id'] = None
|
||||||
|
orphaned_servers.append(dhcp_server)
|
||||||
|
|
||||||
|
# Check if there is DHCP-enabled subnet in each network.
|
||||||
|
for dhcp_server, net_id in server_net_pairs:
|
||||||
|
try:
|
||||||
|
network = neutron_client.get_network(net_id)
|
||||||
|
except Exception:
|
||||||
|
# The associated neutron network is not found in DB.
|
||||||
|
dhcp_server['neutron_net_id'] = None
|
||||||
|
orphaned_servers.append(dhcp_server)
|
||||||
|
continue
|
||||||
|
dhcp_enabled = False
|
||||||
|
for subnet_id in network['subnets']:
|
||||||
|
subnet = neutron_client.get_subnet(subnet_id)
|
||||||
|
if subnet['enable_dhcp']:
|
||||||
|
dhcp_enabled = True
|
||||||
|
break
|
||||||
|
if not dhcp_enabled:
|
||||||
|
dhcp_server['neutron_net_id'] = net_id
|
||||||
|
orphaned_servers.append(dhcp_server)
|
||||||
|
|
||||||
|
return orphaned_servers
|
||||||
|
|
||||||
|
|
||||||
|
@admin_utils.output_header
|
||||||
|
def nsx_list_orphaned_dhcp_servers(resource, event, trigger, **kwargs):
|
||||||
|
"""List logical DHCP servers without associated DHCP-enabled subnet."""
|
||||||
|
|
||||||
|
nsx_version = nsxlib.get_version()
|
||||||
|
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
||||||
|
LOG.error(_LE("This utility is not available for NSX version %s"),
|
||||||
|
nsx_version)
|
||||||
|
return
|
||||||
|
|
||||||
|
dhcp_profile_uuid = _get_dhcp_profile_uuid(**kwargs)
|
||||||
|
if not dhcp_profile_uuid:
|
||||||
|
LOG.error(_LE("dhcp_profile_uuid is not defined"))
|
||||||
|
return
|
||||||
|
|
||||||
|
orphaned_servers = _get_orphaned_dhcp_servers(dhcp_profile_uuid)
|
||||||
|
LOG.info(formatters.output_formatter(constants.ORPHANED_DHCP_SERVERS,
|
||||||
|
orphaned_servers,
|
||||||
|
['id', 'neutron_net_id']))
|
||||||
|
|
||||||
|
|
||||||
|
@admin_utils.output_header
|
||||||
|
def nsx_clean_orphaned_dhcp_servers(resource, event, trigger, **kwargs):
|
||||||
|
"""Remove logical DHCP servers without associated DHCP-enabled subnet."""
|
||||||
|
|
||||||
|
# For each orphaned DHCP server,
|
||||||
|
# (1) delete the attached logical DHCP port,
|
||||||
|
# (2) delete the logical DHCP server,
|
||||||
|
# (3) clean corresponding neutron DB entry.
|
||||||
|
|
||||||
|
nsx_version = nsxlib.get_version()
|
||||||
|
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
||||||
|
LOG.error(_LE("This utility is not available for NSX version %s"),
|
||||||
|
nsx_version)
|
||||||
|
return
|
||||||
|
|
||||||
|
dhcp_profile_uuid = _get_dhcp_profile_uuid(**kwargs)
|
||||||
|
if not dhcp_profile_uuid:
|
||||||
|
LOG.error(_LE("dhcp_profile_uuid is not defined"))
|
||||||
|
return
|
||||||
|
|
||||||
|
cfg.CONF.set_override('dhcp_agent_notification', False)
|
||||||
|
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
|
||||||
|
cfg.CONF.set_override('dhcp_profile', dhcp_profile_uuid, 'nsx_v3')
|
||||||
|
|
||||||
|
orphaned_servers = _get_orphaned_dhcp_servers(dhcp_profile_uuid)
|
||||||
|
|
||||||
|
for server in orphaned_servers:
|
||||||
|
try:
|
||||||
|
resource = ('?attachment_type=DHCP_SERVICE&attachment_id=%s' %
|
||||||
|
server['id'])
|
||||||
|
response = port_resource._client.url_get(resource)
|
||||||
|
if response and response['result_count'] > 0:
|
||||||
|
port_resource.delete(response['results'][0]['id'])
|
||||||
|
dhcp_server_resource.delete(server['id'])
|
||||||
|
net_id = server.get('neutron_net_id')
|
||||||
|
if net_id:
|
||||||
|
# Delete neutron_net_id -> dhcp_service_id mapping from the DB.
|
||||||
|
nsx_db.delete_neutron_nsx_service_binding(
|
||||||
|
context.get_admin_context().session, net_id,
|
||||||
|
nsx_constants.SERVICE_DHCP)
|
||||||
|
LOG.info(_LI("Removed orphaned DHCP server %s"), server['id'])
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE("Failed to clean orphaned DHCP server %(id)s. "
|
||||||
|
"Exception: %(e)s"), {'id': server['id'], 'e': e})
|
||||||
|
|
||||||
|
|
||||||
|
registry.subscribe(nsx_list_orphaned_dhcp_servers,
|
||||||
|
constants.ORPHANED_DHCP_SERVERS,
|
||||||
|
shell.Operations.NSX_LIST.value)
|
||||||
|
registry.subscribe(nsx_clean_orphaned_dhcp_servers,
|
||||||
|
constants.ORPHANED_DHCP_SERVERS,
|
||||||
|
shell.Operations.NSX_CLEAN.value)
|
@ -31,6 +31,7 @@ from vmware_nsxlib.v3 import resources
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
neutron_client = utils.NeutronDbClient()
|
neutron_client = utils.NeutronDbClient()
|
||||||
|
nsxlib = utils.get_connected_nsxlib()
|
||||||
|
|
||||||
|
|
||||||
def _is_metadata_network(network):
|
def _is_metadata_network(network):
|
||||||
@ -58,9 +59,9 @@ def list_metadata_networks(resource, event, trigger, **kwargs):
|
|||||||
def nsx_update_metadata_proxy(resource, event, trigger, **kwargs):
|
def nsx_update_metadata_proxy(resource, event, trigger, **kwargs):
|
||||||
"""Update Metadata proxy for NSXv3 CrossHairs."""
|
"""Update Metadata proxy for NSXv3 CrossHairs."""
|
||||||
|
|
||||||
nsx_version = utils.get_connected_nsxlib().get_version()
|
nsx_version = nsxlib.get_version()
|
||||||
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
||||||
LOG.info(_LI("This utility is not available for NSX version %s"),
|
LOG.error(_LE("This utility is not available for NSX version %s"),
|
||||||
nsx_version)
|
nsx_version)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ def nsx_update_metadata_proxy(resource, event, trigger, **kwargs):
|
|||||||
lswitch_id = neutron_client.net_id_to_lswitch_id(network['id'])
|
lswitch_id = neutron_client.net_id_to_lswitch_id(network['id'])
|
||||||
if not lswitch_id:
|
if not lswitch_id:
|
||||||
continue
|
continue
|
||||||
tags = utils.get_connected_nsxlib().build_v3_tags_payload(
|
tags = nsxlib.build_v3_tags_payload(
|
||||||
network, resource_type='os-neutron-net-id',
|
network, resource_type='os-neutron-net-id',
|
||||||
project_name='admin')
|
project_name='admin')
|
||||||
name = nsx_utils.get_name_and_uuid('%s-%s' % (
|
name = nsx_utils.get_name_and_uuid('%s-%s' % (
|
||||||
|
@ -85,6 +85,9 @@ nsxv3_resources = {
|
|||||||
constants.METADATA_PROXY: Resource(constants.METADATA_PROXY,
|
constants.METADATA_PROXY: Resource(constants.METADATA_PROXY,
|
||||||
[Operations.LIST.value,
|
[Operations.LIST.value,
|
||||||
Operations.NSX_UPDATE.value]),
|
Operations.NSX_UPDATE.value]),
|
||||||
|
constants.ORPHANED_DHCP_SERVERS: Resource(constants.ORPHANED_DHCP_SERVERS,
|
||||||
|
[Operations.NSX_LIST.value,
|
||||||
|
Operations.NSX_CLEAN.value]),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add supported NSX-V resources in this dictionary
|
# Add supported NSX-V resources in this dictionary
|
||||||
|
@ -139,6 +139,8 @@ class TestNsxv3AdminUtils(AbstractTestAdminUtils,
|
|||||||
'__init__', return_value=None)
|
'__init__', return_value=None)
|
||||||
self._patch_object(nsx_v3_resources.LogicalDhcpServer,
|
self._patch_object(nsx_v3_resources.LogicalDhcpServer,
|
||||||
'__init__', return_value=None)
|
'__init__', return_value=None)
|
||||||
|
self._patch_object(nsx_v3_resources.LogicalDhcpServer,
|
||||||
|
'list', return_value={'results': []})
|
||||||
self._patch_object(nsx_v3_resources.LogicalRouter,
|
self._patch_object(nsx_v3_resources.LogicalRouter,
|
||||||
'__init__', return_value=None)
|
'__init__', return_value=None)
|
||||||
self._patch_object(nsx_v3_resources.SwitchingProfile,
|
self._patch_object(nsx_v3_resources.SwitchingProfile,
|
||||||
|
Loading…
Reference in New Issue
Block a user