# 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 time import xml.etree.ElementTree as et import mock from oslo_config import cfg from oslo_log import log as logging from neutron_lib import context as neutron_context from neutron_lib.plugins import directory from vmware_nsx.common import config from vmware_nsx.db import db as nsx_db from vmware_nsx.db import nsxv_db from vmware_nsx.extensions import projectpluginmap from vmware_nsx import plugin from vmware_nsx.plugins.nsx_v.vshield import vcns from vmware_nsx.shell.admin.plugins.common import utils as admin_utils LOG = logging.getLogger(__name__) network_types = ['Network', 'VirtualWire', 'DistributedVirtualPortgroup'] PORTGROUP_PREFIX = 'dvportgroup' def get_nsxv_client(): return vcns.Vcns( address=cfg.CONF.nsxv.manager_uri, user=cfg.CONF.nsxv.user, password=cfg.CONF.nsxv.password, ca_file=cfg.CONF.nsxv.ca_file, insecure=cfg.CONF.nsxv.insecure) def get_plugin_filters(context): return admin_utils.get_plugin_filters( context, projectpluginmap.NsxPlugins.NSX_V) class NeutronDbClient(object): def __init__(self): super(NeutronDbClient, self) self.context = neutron_context.get_admin_context() class NsxVPluginWrapper(plugin.NsxVPlugin): def __init__(self): config.register_nsxv_azs(cfg.CONF, cfg.CONF.nsxv.availability_zones) self.context = neutron_context.get_admin_context() self.filters = get_plugin_filters(self.context) super(NsxVPluginWrapper, self).__init__() # Make this the core plugin directory.add_plugin('CORE', self) # finish the plugin initialization # (with md-proxy config, but without housekeeping) with mock.patch("vmware_nsx.plugins.common.housekeeper." "housekeeper.NsxHousekeeper"): self.init_complete(0, 0, 0) admin_utils._init_plugin_mock_quota() def start_rpc_listeners(self): pass def _extend_get_network_dict_provider(self, context, net): self._extend_network_dict_provider(context, net) # skip getting the Qos policy ID because get_object calls # plugin init again on admin-util environment def count_spawn_jobs(self): # check if there are any spawn jobs running return self.edge_manager._get_worker_pool().running() # Define enter & exit to be used in with statements def __enter__(self): return self def __exit__(self, type, value, traceback): """Wait until no more jobs are pending We want to wait until all spawn edge creation are done, or else the edges might be in PERNDING_CREATE state in the nsx DB """ if not self.count_spawn_jobs(): return LOG.warning("Waiting for plugin jobs to finish properly...") sleep_time = 1 print_time = 20 max_loop = 600 for print_index in range(1, max_loop): n_jobs = self.count_spawn_jobs() if n_jobs > 0: if (print_index % print_time) == 0: LOG.warning("Still Waiting on %(jobs)s " "job%(plural)s", {'jobs': n_jobs, 'plural': 's' if n_jobs > 1 else ''}) time.sleep(sleep_time) else: LOG.warning("Done.") return LOG.warning("Sorry. Waited for too long. Some jobs are still " "running.") def _update_filters(self, requested_filters): filters = self.filters.copy() if requested_filters: filters.update(requested_filters) return filters def get_networks(self, context, filters=None, fields=None, filter_project=True): if filter_project: filters = self._update_filters(filters) return super(NsxVPluginWrapper, self).get_networks( context, filters=filters, fields=fields) def get_subnets(self, context, filters=None, fields=None, filter_project=True): if filter_project: filters = self._update_filters(filters) return super(NsxVPluginWrapper, self).get_subnets( context, filters=filters, fields=fields) def get_ports(self, context, filters=None, fields=None, filter_project=True): if filter_project: filters = self._update_filters(filters) return super(NsxVPluginWrapper, self).get_ports( context, filters=filters, fields=fields) def get_routers(self, context, filters=None, fields=None, filter_project=True): if filter_project: filters = self._update_filters(filters) return super(NsxVPluginWrapper, self).get_routers( context, filters=filters, fields=fields) def get_nsxv_backend_edges(): """Get a list of all the backend edges and some of their attributes """ nsxv = get_nsxv_client() edges = nsxv.get_edges() backend_edges = [] for edge in edges: summary = edge.get('appliancesSummary') size = ha = None if summary: size = summary.get('applianceSize') deployed_vms = summary.get('numberOfDeployedVms', 1) ha = 'Enabled' if deployed_vms > 1 else 'Disabled' # get all the relevant backend information for this edge edge_data = { 'id': edge.get('id'), 'name': edge.get('name'), 'size': size, 'type': edge.get('edgeType'), 'ha': ha, } backend_edges.append(edge_data) return backend_edges def get_edge_syslog_info(edge_id): """Get syslog information for specific edge id""" nsxv = get_nsxv_client() syslog_info = nsxv.get_edge_syslog(edge_id)[1] if not syslog_info['enabled']: return 'Disabled' output = "" if 'protocol' in syslog_info: output += syslog_info['protocol'] if 'serverAddresses' in syslog_info: for server_address in syslog_info['serverAddresses']['ipAddress']: output += "\n" + server_address return output def get_networks_from_backend(): nsxv = get_nsxv_client() so_list = nsxv.get_scoping_objects() return et.fromstring(so_list) def get_networks(): """Create an array of all the backend networks and their data """ root = get_networks_from_backend() networks = [] for obj in root.iter('object'): if obj.find('objectTypeName').text in network_types: networks.append({'type': obj.find('objectTypeName').text, 'moref': obj.find('objectId').text, 'name': obj.find('name').text}) return networks def get_orphaned_networks(backend_networks): """List the NSX networks which are missing the neutron DB """ admin_context = neutron_context.get_admin_context() missing_networks = [] # get all neutron distributed routers in advanced with NsxVPluginWrapper() as plugin: neutron_routers = plugin.get_routers( admin_context, fields=['id', 'name', 'distributed']) neutron_dist_routers = [rtr for rtr in neutron_routers if rtr['distributed']] # get the list of backend networks: for net in backend_networks: moref = net['moref'] backend_name = net['name'] # Decide if this is a neutron network by its name (which should always # contain the net-id), and type if (backend_name.startswith('edge-') or len(backend_name) < 36 or net['type'] == 'Network'): # This is not a neutron network continue if backend_name.startswith('int-') and net['type'] == 'VirtualWire': # This is a PLR network. Check that the router exists found = False # compare the expected lswitch name by the dist router name & id for rtr in neutron_dist_routers: lswitch_name = ('int-' + rtr['name'] + rtr['id'])[:36] if lswitch_name == backend_name: found = True break # if the neutron router got renamed, this will not work. # compare ids prefixes instead (might cause false positives) for rtr in neutron_dist_routers: if rtr['id'][:5] in backend_name: LOG.info("Logical switch %s probably matches distributed " "router %s", backend_name, rtr['id']) found = True break if not found: missing_networks.append(net) continue # get the list of neutron networks with this moref neutron_networks = nsx_db.get_nsx_network_mapping_for_nsx_id( admin_context.session, moref) if not neutron_networks: # no network found for this moref missing_networks.append(net) elif moref.startswith(PORTGROUP_PREFIX): # This is a VLAN network. Also verify that the DVS Id matches for entry in neutron_networks: if (not entry['dvs_id'] or backend_name.startswith(entry['dvs_id'])): found = True # this moref & dvs-id does not appear in the DB if not found: missing_networks.append(net) return missing_networks def get_router_edge_bindings(): edgeapi = NeutronDbClient() return nsxv_db.get_nsxv_router_bindings(edgeapi.context) def get_orphaned_edges_data(): nsxv_edges = get_nsxv_backend_edges() neutron_edge_bindings = set() for binding in get_router_edge_bindings(): neutron_edge_bindings.add(binding.edge_id) return [edge for edge in nsxv_edges if edge['id'] not in neutron_edge_bindings] def get_orphaned_edges(): return [edge['id'] for edge in get_orphaned_edges_data()]