NSX|V add edge_ha per availability zone

Support different edge_ha flag per availability zone

Change-Id: Iff1b9d76a62d23d600b57ad83d868c4de2b04ee9
This commit is contained in:
Adit Sarfaty 2016-07-19 15:18:48 +03:00
parent 2b7210313c
commit 2f2d770b9b
9 changed files with 135 additions and 26 deletions

View File

@ -27,7 +27,7 @@ NSXV_PASSWORD # NSXv password.
NSXV_CLUSTER_MOID # clusters ids containing OpenStack hosts.
NSXV_DATACENTER_MOID # datacenter id for edge deployment.
NSXV_RESOURCE_POOL_ID # resource-pool id for edge deployment.
NSXV_AVAILABILITY_ZONES # alternative resource-pools ids for edge deployment
NSXV_AVAILABILITY_ZONES # alternative resource-pools/data stores ids/edge_ha for edge deployment
NSXV_DATASTORE_ID # datastore id for edge deployment.
NSXV_EXTERNAL_NETWORK # id of logic switch for physical network connectivity.
NSXV_VDN_SCOPE_ID # network scope id for VXLAN virtual-wires.

View File

@ -431,8 +431,8 @@ nsxv_opts = [
default=[],
help=_('Optional parameter defining the availability zones '
'for deploying NSX Edges with the format: <zone name>:'
'<resource pool id]:<datastore id>:<(optional)HA '
'datastore id>.')),
'<resource pool id]:<datastore id>:<edge_ha True/False>'
'<(optional)HA datastore id>.')),
cfg.StrOpt('datastore_id',
deprecated_group="vcns",
help=_('Optional parameter identifying the ID of datastore to '

View File

@ -188,3 +188,8 @@ class NsxTaaSDriverException(NsxPluginException):
class NsxPortMirrorSessionMappingNotFound(n_exc.NotFound):
message = _("Unable to find mapping for Tap Flow: %(tf)s")
class NsxInvalidConfiguration(n_exc.InvalidConfigurationOption):
message = _("An invalid value was provided for %(opt_name)s: "
"%(opt_value)s: %(reason)s")

View File

@ -13,10 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron_lib import exceptions as n_exc
from oslo_config import cfg
from vmware_nsx._i18n import _
from vmware_nsx.common import exceptions as nsx_exc
DEFAULT_NAME = 'default'
@ -26,23 +26,49 @@ class ConfiguredAvailabilityZone(object):
def __init__(self, config_line):
if config_line:
values = config_line.split(':')
if len(values) < 3 or len(values) > 4:
raise n_exc.Invalid(_("Invalid availability zones format"))
if len(values) < 4 or len(values) > 5:
raise nsx_exc.NsxInvalidConfiguration(
opt_name="availability_zones",
opt_value=config_line,
reason=_("Expected 4 or 5 values per zone"))
self.name = values[0]
# field name limit in the DB
# field name size in the DB is 36
if len(self.name) > 36:
raise n_exc.Invalid(_("Invalid availability zone name %s: "
"max name length is 36"), self.name)
raise nsx_exc.NsxInvalidConfiguration(
opt_name="availability_zones",
opt_value=config_line,
reason=_("Maximum name length is 36"))
self.resource_pool = values[1]
self.datastore_id = values[2]
self.ha_datastore_id = values[3] if len(values) == 4 else None
# validate the edge_ha
if values[3].lower() == "true":
self.edge_ha = True
elif values[3].lower() == "false":
self.edge_ha = False
else:
raise nsx_exc.NsxInvalidConfiguration(
opt_name="availability_zones",
opt_value=config_line,
reason=_("Expected the 4th value to be true/false"))
# HA datastore id is relevant only with edge_ha
if not self.edge_ha and len(values) == 5:
raise nsx_exc.NsxInvalidConfiguration(
opt_name="availability_zones",
opt_value=config_line,
reason=_("Expected HA datastore ID only when edge_ha is "
"enabled"))
self.ha_datastore_id = values[4] if len(values) == 5 else None
else:
# use the default configuration
self.name = DEFAULT_NAME
self.resource_pool = cfg.CONF.nsxv.resource_pool_id
self.datastore_id = cfg.CONF.nsxv.datastore_id
self.edge_ha = cfg.CONF.nsxv.edge_ha
self.ha_datastore_id = cfg.CONF.nsxv.ha_datastore_id
@ -55,7 +81,6 @@ class ConfiguredAvailabilityZones(object):
for az in cfg.CONF.nsxv.availability_zones:
obj = ConfiguredAvailabilityZone(az)
self.availability_zones[obj.name] = obj
# DEBUG ADIT - name max len 36 (DB)
# add a default entry
obj = ConfiguredAvailabilityZone(None)

View File

@ -46,7 +46,8 @@ class EdgeApplianceDriver(object):
def _assemble_edge(self, name, appliance_size="compact",
deployment_container_id=None, datacenter_moid=None,
enable_aesni=True, dist=False,
enable_fips=False, remote_access=False):
enable_fips=False, remote_access=False,
edge_ha=False):
edge = {
'name': name,
'fqdn': None,
@ -86,7 +87,7 @@ class EdgeApplianceDriver(object):
if datacenter_moid:
edge['datacenterMoid'] = datacenter_moid
if not dist and cfg.CONF.nsxv.edge_ha:
if not dist and edge_ha:
self._enable_high_availability(edge)
return edge
@ -97,7 +98,7 @@ class EdgeApplianceDriver(object):
appliances.append(self._assemble_edge_appliance(
availability_zone.resource_pool,
availability_zone.datastore_id))
if availability_zone.ha_datastore_id and cfg.CONF.nsxv.edge_ha:
if availability_zone.ha_datastore_id and availability_zone.edge_ha:
appliances.append(self._assemble_edge_appliance(
availability_zone.resource_pool,
availability_zone.ha_datastore_id))
@ -522,7 +523,8 @@ class EdgeApplianceDriver(object):
edge = self._assemble_edge(
edge_name, datacenter_moid=self.datacenter_moid,
deployment_container_id=self.deployment_container_id,
appliance_size=appliance_size, remote_access=False, dist=dist)
appliance_size=appliance_size, remote_access=False, dist=dist,
edge_ha=availability_zone.edge_ha)
appliances = self._assemble_edge_appliances(availability_zone)
if appliances:
edge['appliances']['appliances'] = appliances
@ -610,7 +612,8 @@ class EdgeApplianceDriver(object):
edge = self._assemble_edge(
edge_name, datacenter_moid=self.datacenter_moid,
deployment_container_id=self.deployment_container_id,
appliance_size=appliance_size, remote_access=False, dist=dist)
appliance_size=appliance_size, remote_access=False, dist=dist,
edge_ha=availability_zone.edge_ha)
edge['id'] = edge_id
appliances = self._assemble_edge_appliances(availability_zone)
if appliances:

View File

@ -19,7 +19,6 @@ from networking_l2gw.services.l2gateway.common import constants as l2gw_const
from networking_l2gw.services.l2gateway import exceptions as l2gw_exc
from neutron import manager
from neutron_lib import exceptions as n_exc
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import uuidutils
@ -119,7 +118,7 @@ class NsxvL2GatewayDriver(l2gateway_db.L2GatewayMixin):
if not edge_binding:
raise nsx_exc.NsxL2GWDeviceNotFound()
# Enable edge HA on the DLR
if cfg.CONF.nsxv.edge_ha:
if availability_zone.edge_ha:
edge_id = edge_binding['edge_id']
self._edge_manager.nsxv_manager.update_edge_ha(edge_id)
return edge_binding['edge_id']

View File

@ -25,7 +25,6 @@ import vmware_nsx.shell.resources as shell
from neutron.callbacks import registry
from neutron_lib import exceptions
from oslo_config import cfg
from vmware_nsx._i18n import _LE, _LI
from vmware_nsx.common import nsxv_constants
@ -208,14 +207,13 @@ def change_edge_appliance(edge_id):
configuration is updated, or when the configuration of a specific
availability zone was updated.
"""
edge_ha = cfg.CONF.nsxv.edge_ha
# find out what is the current resource pool & size, so we can keep them
az_name, size = _get_edge_az_and_size(edge_id)
az = nsx_az.ConfiguredAvailabilityZones().get_availability_zone(az_name)
appliances = [{'resourcePoolId': az.resource_pool,
'datastoreId': az.datastore_id}]
if az.ha_datastore_id and edge_ha:
if az.ha_datastore_id and az.edge_ha:
appliances.append({'resourcePoolId': az.resource_pool,
'datastoreId': az.ha_datastore_id})
request = {'appliances': appliances, 'applianceSize': size}
@ -227,7 +225,7 @@ def change_edge_appliance(edge_id):
LOG.error(_LE("%s"), str(e))
else:
# also update the edge_ha of the edge
change_edge_ha(edge_ha, edge_id)
change_edge_ha(az.edge_ha, edge_id)
@admin_utils.output_header

View File

@ -0,0 +1,79 @@
# 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.
from neutron.tests import base
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.plugins.nsx_v import availability_zones as nsx_az
class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
def test_simple_availability_zone(self):
az = nsx_az.ConfiguredAvailabilityZone(
"name:respool:datastore:true:hastore")
self.assertEqual("name", az.name)
self.assertEqual("respool", az.resource_pool)
self.assertEqual("datastore", az.datastore_id)
self.assertEqual(True, az.edge_ha)
self.assertEqual("hastore", az.ha_datastore_id)
def test_availability_zone_without_ha_datastore(self):
az = nsx_az.ConfiguredAvailabilityZone(
"name:respool:datastore:true")
self.assertEqual("name", az.name)
self.assertEqual("respool", az.resource_pool)
self.assertEqual("datastore", az.datastore_id)
self.assertEqual(True, az.edge_ha)
self.assertEqual(None, az.ha_datastore_id)
def test_availability_zone_without_edge_ha(self):
az = nsx_az.ConfiguredAvailabilityZone(
"name:respool:datastore:FALSE")
self.assertEqual("name", az.name)
self.assertEqual("respool", az.resource_pool)
self.assertEqual("datastore", az.datastore_id)
self.assertEqual(False, az.edge_ha)
self.assertEqual(None, az.ha_datastore_id)
def test_availability_fail_long_name(self):
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.ConfiguredAvailabilityZone,
"very-very-very-very-very-longest-name:respool:da:true:ha")
def test_availability_fail_few_args(self):
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.ConfiguredAvailabilityZone,
"name:respool")
def test_availability_fail_many_args(self):
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.ConfiguredAvailabilityZone,
"name:1:2:3:4:5:6")
def test_availability_fail_bad_edge_ha(self):
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.ConfiguredAvailabilityZone,
"name:respool:datastore:truex:hastore")
def test_availability_fail_no_ha_datastore(self):
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.ConfiguredAvailabilityZone,
"name:respool:datastore:false:hastore")

View File

@ -632,7 +632,7 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxVPluginV2TestCase):
def test_create_network_with_az_hint(self):
az_name = 'az7'
az_config = az_name + ':respool-7:datastore-7'
az_config = az_name + ':respool-7:datastore-7:False'
cfg.CONF.set_override('availability_zones', [az_config], group="nsxv")
p = manager.NeutronManager.get_plugin()
p._availability_zones_data = nsx_az.ConfiguredAvailabilityZones()
@ -3085,7 +3085,7 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
def test_create_router_with_az_hint(self):
az_name = 'az7'
az_config = az_name + ':respool-7:datastore-7'
az_config = az_name + ':respool-7:datastore-7:True'
cfg.CONF.set_override('availability_zones', [az_config], group="nsxv")
p = manager.NeutronManager.get_plugin()
p._availability_zones_data = nsx_az.ConfiguredAvailabilityZones()
@ -3379,7 +3379,7 @@ class TestVdrTestCase(L3NatTest, L3NatTestCaseBase,
def _test_create_rotuer_with_az_hint(self, with_hint):
# init the availability zones in the plugin
az_name = 'az7'
az_config = az_name + ':respool-7:datastore-7'
az_config = az_name + ':respool-7:datastore-7:False'
cfg.CONF.set_override('availability_zones', [az_config], group="nsxv")
p = manager.NeutronManager.get_plugin()
p._availability_zones_data = nsx_az.ConfiguredAvailabilityZones()
@ -4584,7 +4584,7 @@ class TestSharedRouterTestCase(L3NatTest, L3NatTestCaseBase,
def _test_create_rotuer_with_az_hint(self, with_hint):
# init the availability zones in the plugin
az_name = 'az7'
az_config = az_name + ':respool-7:datastore-7'
az_config = az_name + ':respool-7:datastore-7:True'
cfg.CONF.set_override('availability_zones', [az_config], group="nsxv")
p = manager.NeutronManager.get_plugin()
p._availability_zones_data = nsx_az.ConfiguredAvailabilityZones()