diff --git a/tools/python-nsxadmin/admin/plugins/common/constants.py b/tools/python-nsxadmin/admin/plugins/common/constants.py index f87276edee..d85b443226 100644 --- a/tools/python-nsxadmin/admin/plugins/common/constants.py +++ b/tools/python-nsxadmin/admin/plugins/common/constants.py @@ -24,3 +24,4 @@ SECURITY_GROUPS = 'security-groups' # NSXV Resource Constants EDGES = 'edges' SPOOFGUARD_POLICY = 'spoofguard-policy' +DHCP_BINDING = 'dhcp-binding' diff --git a/tools/python-nsxadmin/admin/plugins/nsxv/resources/dhcp_binding.py b/tools/python-nsxadmin/admin/plugins/nsxv/resources/dhcp_binding.py new file mode 100644 index 0000000000..bf448f1c69 --- /dev/null +++ b/tools/python-nsxadmin/admin/plugins/nsxv/resources/dhcp_binding.py @@ -0,0 +1,86 @@ +# Copyright 2015 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 admin.plugins.common import constants +from admin.plugins.common.utils import output_header +import admin.plugins.nsxv.resources.utils as utils +from admin.shell import Operations + +from neutron.callbacks import registry +from neutron.i18n import _LI + +from vmware_nsx.db import nsxv_db + +LOG = logging.getLogger(__name__) +nsxv = utils.get_nsxv_client() +neutron_db = utils.NeutronDbClient() + + +def nsx_get_static_bindings_by_edge(edge_id): + nsx_dhcp_static_bindings = set() + + nsx_dhcp_bindings = nsxv.query_dhcp_configuration(edge_id) + # nsx_dhcp_bindings[0] contains response headers; + # nsx_dhcp_bindings[1] contains response payload + sbindings = nsx_dhcp_bindings[1].get('staticBindings').get( + 'staticBindings') + + for binding in sbindings: + nsx_dhcp_static_bindings.add( + (edge_id, binding.get('macAddress').lower(), + binding.get('bindingId').lower())) + + return nsx_dhcp_static_bindings + + +def neutron_get_static_bindings_by_edge(edge_id): + neutron_db_dhcp_bindings = set() + for binding in nsxv_db.get_dhcp_static_bindings_by_edge( + neutron_db.context.session, edge_id): + neutron_db_dhcp_bindings.add( + (binding.edge_id, binding.mac_address.lower(), + binding.binding_id.lower())) + return neutron_db_dhcp_bindings + + +@output_header +def list_missing_dhcp_bindings(resource, event, trigger, **kwargs): + """List missing DHCP bindings from NSXv backend. + + Missing DHCP bindings are those that exist in Neutron DB; + but are not present on corresponding NSXv Edge. + """ + + for (edge_id, _) in nsxv_db.get_nsxv_dhcp_bindings_count_per_edge( + neutron_db.context.session): + LOG.info(_LI("%s"), "=" * 60) + LOG.info(_LI("For edge: %s"), edge_id) + nsx_dhcp_static_bindings = nsx_get_static_bindings_by_edge( + edge_id) + neutron_dhcp_static_bindings = neutron_get_static_bindings_by_edge( + edge_id) + LOG.info(_LI("# of DHCP bindings in Neutron DB: %s"), + len(neutron_dhcp_static_bindings)) + LOG.info(_LI("# of DHCP bindings on NSXv backend: %s"), + len(nsx_dhcp_static_bindings)) + LOG.info(_LI("Missing DHCP bindings:")) + LOG.info(neutron_dhcp_static_bindings - nsx_dhcp_static_bindings) + + +registry.subscribe(list_missing_dhcp_bindings, + constants.DHCP_BINDING, + Operations.LIST.value) diff --git a/tools/python-nsxadmin/admin/shell.py b/tools/python-nsxadmin/admin/shell.py index 573fc56f7a..de6931d409 100644 --- a/tools/python-nsxadmin/admin/shell.py +++ b/tools/python-nsxadmin/admin/shell.py @@ -83,7 +83,9 @@ nsxv_resources = { constants.EDGES: Resource(constants.EDGES, [Operations.LIST.name, Operations.CLEAN.name]), constants.SPOOFGUARD_POLICY: Resource(constants.SPOOFGUARD_POLICY, - [Operations.LIST.name]) + [Operations.LIST.name]), + constants.DHCP_BINDING: Resource(constants.DHCP_BINDING, + [Operations.LIST.name]), } nsxv3_resources_names = map(lambda res: res.name, nsxv3_resources.itervalues()) diff --git a/vmware_nsx/db/nsxv_db.py b/vmware_nsx/db/nsxv_db.py index 6cda092881..3dd2c5b59b 100644 --- a/vmware_nsx/db/nsxv_db.py +++ b/vmware_nsx/db/nsxv_db.py @@ -269,12 +269,25 @@ def get_edge_dhcp_static_binding(session, edge_id, mac_address): edge_id=edge_id, mac_address=mac_address).first() +def get_dhcp_static_bindings_by_edge(session, edge_id): + return session.query(nsxv_models.NsxvEdgeDhcpStaticBinding).filter_by( + edge_id=edge_id).all() + + def delete_edge_dhcp_static_binding(session, edge_id, mac_address): with session.begin(subtransactions=True): session.query(nsxv_models.NsxvEdgeDhcpStaticBinding).filter_by( edge_id=edge_id, mac_address=mac_address).delete() +def get_nsxv_dhcp_bindings_count_per_edge(session): + return ( + session.query( + NsxvEdgeDhcpStaticBinding.edge_id, + func.count(NsxvEdgeDhcpStaticBinding.mac_address)).group_by( + NsxvEdgeDhcpStaticBinding.edge_id).all()) + + def clean_edge_dhcp_static_bindings_by_edge(session, edge_id): with session.begin(subtransactions=True): session.query(nsxv_models.NsxvEdgeDhcpStaticBinding).filter_by( @@ -697,11 +710,3 @@ def del_nsxv_lbaas_certificate_binding(session, cert_id, edge_id): return (session.query(nsxv_models.NsxvLbaasCertificateBinding). filter_by(cert_id=cert_id, edge_id=edge_id).delete()) - - -def get_nsxv_dhcp_bindings_count_per_edge(session): - return ( - session.query( - NsxvEdgeDhcpStaticBinding.edge_id, - func.count(NsxvEdgeDhcpStaticBinding.mac_address)).group_by( - NsxvEdgeDhcpStaticBinding.edge_id).all())