NSX|V network creation with availability zones hints
Add support for availability zones hints on networks creation The network dhcp service will be created on an edge that belongs to the requested resource pool Change-Id: I425a7586ff2f5b6ca885fe4fede51c676426d381
This commit is contained in:
parent
b2858f8719
commit
d56b3765fb
@ -148,6 +148,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
"advanced-service-providers",
|
||||
"subnet_allocation",
|
||||
"availability_zone",
|
||||
"network_availability_zone",
|
||||
"router_availability_zone"]
|
||||
|
||||
supported_qos_rule_types = [qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
@ -497,6 +498,10 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
pnet.SEGMENTATION_ID: binding.vlan_id}
|
||||
for binding in bindings]
|
||||
|
||||
# update availability zones
|
||||
network[az_ext.AVAILABILITY_ZONES] = (
|
||||
self.get_network_availability_zones(context, network))
|
||||
|
||||
def _get_subnet_as_providers(self, context, subnet):
|
||||
net_id = subnet.get('network_id')
|
||||
if net_id is None:
|
||||
@ -720,10 +725,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# is here only for overriding the original api
|
||||
result = {}
|
||||
for az in self._availability_zones_data.keys():
|
||||
# Add this availability zone as a router resource
|
||||
resource = 'router'
|
||||
key = (az, resource)
|
||||
result[key] = True
|
||||
# Add this availability zone as a router & network resource
|
||||
for resource in ('router', 'network'):
|
||||
result[(az, resource)] = True
|
||||
return result
|
||||
|
||||
def _validate_availability_zones_in_obj(self, context, resource_type,
|
||||
@ -751,6 +755,16 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
raise az_ext.AvailabilityZoneNotFound(
|
||||
availability_zone=diff.pop())
|
||||
|
||||
def get_network_resource_pool(self, context, network_id):
|
||||
network = self.get_network(context, network_id)
|
||||
if az_ext.AZ_HINTS in network:
|
||||
for hint in network[az_ext.AZ_HINTS]:
|
||||
# For now we use only the first hint
|
||||
return self.get_res_pool_id_by_name(hint)
|
||||
|
||||
# return the default
|
||||
return cfg.CONF.nsxv.resource_pool_id
|
||||
|
||||
def create_network(self, context, network):
|
||||
net_data = network['network']
|
||||
tenant_id = net_data['tenant_id']
|
||||
@ -758,6 +772,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Process the provider network extension
|
||||
provider_type = self._convert_to_transport_zones_dict(net_data)
|
||||
self._validate_provider_create(context, net_data)
|
||||
self._validate_availability_zones_in_obj(context, 'network', net_data)
|
||||
net_data['id'] = str(uuid.uuid4())
|
||||
|
||||
external = net_data.get(ext_net_extn.EXTERNAL)
|
||||
@ -839,6 +854,19 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
self._process_network_port_security_create(
|
||||
context, net_data, new_net)
|
||||
|
||||
# update the network with the availability zone hints
|
||||
if az_ext.AZ_HINTS in net_data:
|
||||
self.validate_availability_zones(context, 'network',
|
||||
net_data[az_ext.AZ_HINTS])
|
||||
az_hints = az_ext.convert_az_list_to_string(
|
||||
net_data[az_ext.AZ_HINTS])
|
||||
super(NsxVPluginV2, self).update_network(context,
|
||||
new_net['id'],
|
||||
{'network': {az_ext.AZ_HINTS: az_hints}})
|
||||
new_net[az_ext.AZ_HINTS] = az_hints
|
||||
# still no availability zones until subnets creation
|
||||
new_net[az_ext.AVAILABILITY_ZONES] = []
|
||||
|
||||
# DB Operations for setting the network as external
|
||||
self._process_l3_create(context, new_net, net_data)
|
||||
if (net_data.get(mpnet.SEGMENTS) and
|
||||
@ -1960,16 +1988,37 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
super(NsxVPluginV2, self).delete_router(context, id)
|
||||
router_driver.delete_router(context, id)
|
||||
|
||||
def _get_availability_zone_by_edge(self, context, edge_id):
|
||||
resource_pool = nsxv_db.get_edge_resource_pool(
|
||||
context.session, edge_id)
|
||||
if resource_pool:
|
||||
av_zone = self.get_res_pool_name_by_id(resource_pool)
|
||||
return av_zone
|
||||
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attr.NETWORKS, ['_extend_availability_zone_hints'])
|
||||
|
||||
def _extend_availability_zone_hints(self, net_res, net_db):
|
||||
net_res[az_ext.AZ_HINTS] = az_ext.convert_az_string_to_list(
|
||||
net_db[az_ext.AZ_HINTS])
|
||||
|
||||
def get_network_availability_zones(self, context, net_db):
|
||||
"""Return availability zones which a network belongs to."""
|
||||
|
||||
resource_id = (vcns_const.DHCP_EDGE_PREFIX + net_db["id"])[:36]
|
||||
dhcp_edge_binding = nsxv_db.get_nsxv_router_binding(
|
||||
context.session, resource_id)
|
||||
if dhcp_edge_binding:
|
||||
edge_id = dhcp_edge_binding['edge_id']
|
||||
return [self._get_availability_zone_by_edge(context, edge_id)]
|
||||
return []
|
||||
|
||||
def get_router_availability_zones(self, router):
|
||||
"""Return availability zones which a router belongs to."""
|
||||
context = n_context.get_admin_context()
|
||||
edge_id = self._get_edge_id_by_rtr_id(context, router["id"])
|
||||
if edge_id:
|
||||
resource_pool = nsxv_db.get_edge_resource_pool(
|
||||
context.session, edge_id)
|
||||
if resource_pool:
|
||||
av_zone = self.get_res_pool_name_by_id(resource_pool)
|
||||
return [av_zone]
|
||||
return [self._get_availability_zone_by_edge(context, edge_id)]
|
||||
return []
|
||||
|
||||
def get_router(self, context, id, fields=None):
|
||||
|
@ -740,12 +740,13 @@ class EdgeManager(object):
|
||||
self.nsxv_manager.delete_edge(
|
||||
router_id, edge_id, jobdata=jobdata, dist=dist)
|
||||
|
||||
def _allocate_dhcp_edge_appliance(self, context, resource_id):
|
||||
def _allocate_dhcp_edge_appliance(self, context, resource_id, res_pool):
|
||||
resource_name = (vcns_const.DHCP_EDGE_PREFIX +
|
||||
_uuid())[:vcns_const.EDGE_NAME_LEN]
|
||||
self._allocate_edge_appliance(
|
||||
context, resource_id, resource_name,
|
||||
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'])
|
||||
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
|
||||
res_pool=res_pool)
|
||||
|
||||
def _free_dhcp_edge_appliance(self, context, network_id):
|
||||
router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||
@ -989,12 +990,12 @@ class EdgeManager(object):
|
||||
available_edge_ids.append(x)
|
||||
return (conflict_edge_ids, available_edge_ids)
|
||||
|
||||
def _get_used_edges(self, context, subnet):
|
||||
def _get_used_edges(self, context, subnet, resource_pool):
|
||||
"""Returns conflicting and available edges for the subnet."""
|
||||
conflicting = self.plugin._get_conflicting_networks_for_subnet(
|
||||
context, subnet)
|
||||
return self._get_available_edges(context, subnet['network_id'],
|
||||
conflicting)
|
||||
conflicting, resource_pool)
|
||||
|
||||
def remove_network_from_dhcp_edge(self, context, network_id, edge_id):
|
||||
old_binding = nsxv_db.get_edge_vnic_binding(
|
||||
@ -1045,8 +1046,11 @@ class EdgeManager(object):
|
||||
nsxv_db.allocate_edge_vnic_with_tunnel_index(
|
||||
context.session, edge_id, network_id)
|
||||
|
||||
def allocate_new_dhcp_edge(self, context, network_id, resource_id):
|
||||
self._allocate_dhcp_edge_appliance(context, resource_id)
|
||||
def allocate_new_dhcp_edge(self, context, network_id, resource_id,
|
||||
res_pool):
|
||||
if not res_pool:
|
||||
res_pool = cfg.CONF.nsxv.resource_pool_id
|
||||
self._allocate_dhcp_edge_appliance(context, resource_id, res_pool)
|
||||
with locking.LockManager.get_lock('nsx-edge-pool'):
|
||||
new_edge = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
resource_id)
|
||||
@ -1062,6 +1066,7 @@ class EdgeManager(object):
|
||||
|
||||
If new edge was allocated, return resource_id, else return None
|
||||
"""
|
||||
res_pool = self.plugin.get_network_resource_pool(context, network_id)
|
||||
# Check if the network has one related dhcp edge
|
||||
resource_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||
dhcp_edge_binding = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
@ -1072,7 +1077,8 @@ class EdgeManager(object):
|
||||
with locking.LockManager.get_lock('nsx-edge-pool'):
|
||||
edge_id = dhcp_edge_binding['edge_id']
|
||||
(conflict_edge_ids,
|
||||
available_edge_ids) = self._get_used_edges(context, subnet)
|
||||
available_edge_ids) = self._get_used_edges(context, subnet,
|
||||
res_pool)
|
||||
LOG.debug("The available edges %s, the conflict edges %s "
|
||||
"at present is using edge %s",
|
||||
available_edge_ids, conflict_edge_ids, edge_id)
|
||||
@ -1106,7 +1112,8 @@ class EdgeManager(object):
|
||||
else:
|
||||
with locking.LockManager.get_lock('nsx-edge-pool'):
|
||||
(conflict_edge_ids,
|
||||
available_edge_ids) = self._get_used_edges(context, subnet)
|
||||
available_edge_ids) = self._get_used_edges(context, subnet,
|
||||
res_pool)
|
||||
LOG.debug('The available edges %s, the conflict edges %s',
|
||||
available_edge_ids, conflict_edge_ids)
|
||||
# There is available one
|
||||
@ -1124,7 +1131,8 @@ class EdgeManager(object):
|
||||
allocate_new_edge = True
|
||||
|
||||
if allocate_new_edge:
|
||||
self.allocate_new_dhcp_edge(context, network_id, resource_id)
|
||||
self.allocate_new_dhcp_edge(context, network_id, resource_id,
|
||||
res_pool)
|
||||
|
||||
# If a new Edge was allocated, return resource_id
|
||||
return resource_id
|
||||
@ -1219,7 +1227,6 @@ class EdgeManager(object):
|
||||
|
||||
def configure_dhcp_for_vdr_network(
|
||||
self, context, network_id, vdr_router_id):
|
||||
|
||||
# If network is already attached to a DHCP Edge, detach from it
|
||||
resource_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||
dhcp_edge_binding = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
@ -1241,8 +1248,10 @@ class EdgeManager(object):
|
||||
context, dhcp_edge_id, resource_id, network_id)
|
||||
else:
|
||||
# Attach to DHCP Edge
|
||||
resource_pool = self.plugin.get_network_resource_pool(context,
|
||||
network_id)
|
||||
dhcp_edge_id = self.allocate_new_dhcp_edge(
|
||||
context, network_id, resource_id)
|
||||
context, network_id, resource_id, resource_pool)
|
||||
|
||||
self.plugin.metadata_proxy_handler.configure_router_edge(
|
||||
resource_id, context)
|
||||
|
@ -603,6 +603,46 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxVPluginV2TestCase):
|
||||
self.assertTrue(fake_init_from_policy.called)
|
||||
self.assertTrue(fake_dvs_update.called)
|
||||
|
||||
def test_create_network_with_bad_az_hint(self):
|
||||
p = manager.NeutronManager.get_plugin()
|
||||
ctx = context.get_admin_context()
|
||||
data = {'network': {
|
||||
'name': 'test-qos',
|
||||
'tenant_id': self._tenant_id,
|
||||
'port_security_enabled': False,
|
||||
'admin_state_up': True,
|
||||
'shared': False,
|
||||
'availability_zone_hints': ['bad_hint']
|
||||
}}
|
||||
self.assertRaises(n_exc.NeutronException,
|
||||
p.create_network,
|
||||
ctx, data)
|
||||
|
||||
def test_create_network_with_az_hint(self):
|
||||
p = manager.NeutronManager.get_plugin()
|
||||
ctx = context.get_admin_context()
|
||||
alter_pool_id = 'respool-7'
|
||||
alter_pool_name = 'rs-7'
|
||||
p._availability_zones_data = {'default': self.default_res_pool,
|
||||
alter_pool_name: alter_pool_id}
|
||||
|
||||
data = {'network': {
|
||||
'name': 'test-qos',
|
||||
'tenant_id': self._tenant_id,
|
||||
'port_security_enabled': False,
|
||||
'admin_state_up': True,
|
||||
'shared': False,
|
||||
'availability_zone_hints': [alter_pool_name]
|
||||
}}
|
||||
|
||||
# network creation should succeed
|
||||
net = p.create_network(ctx, data)
|
||||
self.assertEqual([alter_pool_name],
|
||||
net['availability_zone_hints'])
|
||||
# the availability zone is still empty until subnet creation
|
||||
self.assertEqual([],
|
||||
net['availability_zones'])
|
||||
|
||||
|
||||
class TestVnicIndex(NsxVPluginV2TestCase,
|
||||
test_vnic_index.VnicIndexDbTestCase):
|
||||
|
@ -84,6 +84,11 @@ class EdgeUtilsTestCaseMixin(testlib_api.SqlTestCase):
|
||||
resource_pool=binding['resource_pool'])
|
||||
|
||||
|
||||
class DummyPlugin(object):
|
||||
def get_network_resource_pool(self, context, network_id):
|
||||
return cfg.CONF.nsxv.resource_pool_id
|
||||
|
||||
|
||||
class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
|
||||
|
||||
def setUp(self):
|
||||
@ -115,6 +120,7 @@ class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
|
||||
self._populate_vcns_router_binding(fake_edge_pool)
|
||||
fake_network = self._create_network()
|
||||
fake_subnet = self._create_subnet(fake_network['id'])
|
||||
self.edge_manager.plugin = DummyPlugin()
|
||||
with mock.patch.object(self.edge_manager,
|
||||
'_get_used_edges', return_value=([], [])):
|
||||
self.edge_manager.create_dhcp_edge_service(self.ctx,
|
||||
@ -125,7 +131,8 @@ class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
|
||||
self.nsxv_manager.update_edge.assert_called_once_with(
|
||||
resource_id, 'edge-1', mock.ANY, None, jobdata=jobdata,
|
||||
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
|
||||
dist=False, set_errors=True, res_pool=None)
|
||||
dist=False, set_errors=True,
|
||||
res_pool=cfg.CONF.nsxv.resource_pool_id)
|
||||
|
||||
def test_get_random_available_edge(self):
|
||||
available_edge_ids = ['edge-1', 'edge-2']
|
||||
|
Loading…
Reference in New Issue
Block a user