diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py index f895caed57..5b844d3cc7 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py @@ -831,6 +831,19 @@ class EdgeManager(object): edges = [binding['dhcp_edge_id'] for binding in bindings] return edges + def _get_random_available_edge(self, available_edge_ids): + while available_edge_ids: + # Randomly select an edge ID from the pool. + new_id = random.choice(available_edge_ids) + # Validate whether the edge exists on the backend. + if not self.check_edge_active_at_backend(new_id): + # Remove edge_id from available edges pool. + available_edge_ids.remove(new_id) + LOG.warning(_LW("Skipping edge: %s due to inactive status on " + "the backend."), new_id) + else: + return new_id + def _get_available_edges(self, context, network_id, conflicting_nets): if conflicting_nets is None: conflicting_nets = [] @@ -961,11 +974,15 @@ class EdgeManager(object): # one #4. Update the address groups to the vnic if available_edge_ids: - new_id = random.choice(available_edge_ids) - LOG.debug("Select edge %s to support dhcp for " - "network %s", new_id, network_id) - self.reuse_existing_dhcp_edge( - context, new_id, resource_id, network_id) + new_id = self._get_random_available_edge( + available_edge_ids) + if new_id: + LOG.debug("Select edge %s to support dhcp for " + "network %s", new_id, network_id) + self.reuse_existing_dhcp_edge( + context, new_id, resource_id, network_id) + else: + allocate_new_edge = True else: allocate_new_edge = True # case 2: attach the subnet to a new edge and update vnic @@ -977,11 +994,15 @@ class EdgeManager(object): available_edge_ids, conflict_edge_ids) # There is available one if available_edge_ids: - new_id = random.choice(available_edge_ids) - LOG.debug("Select edge %s to support dhcp for network %s", - new_id, network_id) - self.reuse_existing_dhcp_edge( - context, new_id, resource_id, network_id) + new_id = self._get_random_available_edge( + available_edge_ids) + if new_id: + LOG.debug("Select edge %s to support dhcp for network " + "%s", new_id, network_id) + self.reuse_existing_dhcp_edge( + context, new_id, resource_id, network_id) + else: + allocate_new_edge = True else: allocate_new_edge = True diff --git a/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py b/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py index e549d2302b..756b195a16 100644 --- a/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py +++ b/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py @@ -117,6 +117,25 @@ class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin): appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'], dist=False) + def test_get_random_available_edge(self): + available_edge_ids = ['edge-1', 'edge-2'] + selected_edge_id = self.edge_manager._get_random_available_edge( + available_edge_ids) + self.assertIn(selected_edge_id, available_edge_ids) + + def test_get_random_available_edge_missing_edges_returns_none(self): + available_edge_ids = ['edge-1', 'edge-2'] + # Always return inactive(False) while checking whether the edge + # exists on the backend. + with mock.patch.object(self.edge_manager, + 'check_edge_active_at_backend', + return_value=False): + selected_edge_id = self.edge_manager._get_random_available_edge( + available_edge_ids) + # If no active edges are found on the backend, return None so that + # a new DHCP edge is created. + self.assertIsNone(selected_edge_id) + class EdgeUtilsTestCase(EdgeUtilsTestCaseMixin):