3ac633ec68
Support randomly selecting which will be the primary datastore and which will be the secondary one when deplying an edge, in order to balance the load. This new option is available globally as well as per availability_zone via a new configuration parameter edge_placement_random which will be False by default. Change-Id: I5bf8f8999100c4c6da4645bda6e74165575c3818
151 lines
6.0 KiB
Python
151 lines
6.0 KiB
Python
# 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 oslo_config import cfg
|
|
|
|
from vmware_nsx._i18n import _
|
|
from vmware_nsx.common import config
|
|
from vmware_nsx.common import exceptions as nsx_exc
|
|
|
|
DEFAULT_NAME = 'default'
|
|
|
|
|
|
class ConfiguredAvailabilityZone(object):
|
|
|
|
def __init__(self, config_line):
|
|
if config_line and ':' in config_line:
|
|
# Older configuration - each line contains all the relevant
|
|
# values for one availability zones, separated by ':'
|
|
values = config_line.split(':')
|
|
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 size in the DB is 36
|
|
if len(self.name) > 36:
|
|
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]
|
|
|
|
# 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
|
|
# Use the global configuration for ha_placement_random
|
|
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
|
|
elif config_line:
|
|
# Newer configuration - the name of the availability zone can be
|
|
# used to get the rest of the configuration for this AZ
|
|
self.name = config_line
|
|
az_info = config.get_nsxv_az_opts(self.name)
|
|
self.resource_pool = az_info.get('resource_pool_id')
|
|
if not self.resource_pool:
|
|
raise nsx_exc.NsxInvalidConfiguration(
|
|
opt_name="resource_pool_id",
|
|
opt_value='None',
|
|
reason=(_("resource_pool_id for availability zone %s "
|
|
"must be defined") % self.name))
|
|
self.datastore_id = az_info.get('datastore_id')
|
|
if not self.datastore_id:
|
|
raise nsx_exc.NsxInvalidConfiguration(
|
|
opt_name="datastore_id",
|
|
opt_value='None',
|
|
reason=(_("datastore_id for availability zone %s "
|
|
"must be defined") % self.name))
|
|
self.edge_ha = az_info.get('edge_ha', False)
|
|
# The HA datastore can be empty
|
|
self.ha_datastore_id = (az_info.get('ha_datastore_id')
|
|
if self.edge_ha else None)
|
|
|
|
# Use the global config for ha_placement_random if not set
|
|
self.ha_placement_random = az_info.get('ha_placement_random')
|
|
if self.ha_placement_random is None:
|
|
self.ha_placement_random = (
|
|
cfg.CONF.nsxv.ha_placement_random)
|
|
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
|
|
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
|
|
|
|
|
|
class ConfiguredAvailabilityZones(object):
|
|
|
|
def __init__(self):
|
|
self.availability_zones = {}
|
|
|
|
# Add the configured availability zones
|
|
for az in cfg.CONF.nsxv.availability_zones:
|
|
obj = ConfiguredAvailabilityZone(az)
|
|
self.availability_zones[obj.name] = obj
|
|
|
|
# add a default entry
|
|
obj = ConfiguredAvailabilityZone(None)
|
|
self.availability_zones[obj.name] = obj
|
|
|
|
def get_resources(self):
|
|
"""Return a list of all the resources in all the availability zones
|
|
"""
|
|
resources = []
|
|
for az in self.availability_zones.values():
|
|
resources.append(az.resource_pool)
|
|
resources.append(az.datastore_id)
|
|
if az.ha_datastore_id:
|
|
resources.append(az.ha_datastore_id)
|
|
return resources
|
|
|
|
def get_availability_zone(self, name):
|
|
"""Return an availability zone object by its name
|
|
"""
|
|
if name in self.availability_zones.keys():
|
|
return self.availability_zones[name]
|
|
return self.get_default_availability_zone()
|
|
|
|
def get_default_availability_zone(self):
|
|
"""Return the default availability zone object
|
|
"""
|
|
return self.availability_zones[DEFAULT_NAME]
|
|
|
|
def list_availability_zones(self):
|
|
"""Return a list of availability zones names
|
|
"""
|
|
return self.availability_zones.keys()
|