# 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. import abc from neutron.extensions import availability_zone as az_ext from neutron_lib import exceptions as n_exc from vmware_nsx._i18n import _ from vmware_nsx.common import exceptions as nsx_exc DEFAULT_NAME = 'default' class ConfiguredAvailabilityZone(object): def __init__(self, config_line): self.name = "" 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(':') self.name = values[0] self._validate_zone_name(self.name) self.init_from_config_line(config_line) 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 self._validate_zone_name(config_line) self.init_from_config_section(self.name) else: # Default zone configuration self.name = DEFAULT_NAME self.init_default_az() def is_default(self): return self.name == DEFAULT_NAME def _validate_zone_name(self, config_line): if len(self.name) > 36: raise nsx_exc.NsxInvalidConfiguration( opt_name="availability_zones", opt_value=config_line, reason=_("Maximum name length is 36")) @abc.abstractmethod def init_from_config_line(self, config_values): pass @abc.abstractmethod def init_from_config_section(self, az_name): pass @abc.abstractmethod def init_default_az(self): pass class ConfiguredAvailabilityZones(object): def __init__(self, az_conf, az_class): self.availability_zones = {} # Add the configured availability zones for az in az_conf: obj = az_class(az) self.availability_zones[obj.name] = obj # add a default entry obj = az_class(None) self.availability_zones[obj.name] = obj 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() def list_availability_zones_objects(self): """Return a list of availability zones objects """ return self.availability_zones.values() class NSXAvailabilityZonesPluginCommon(object): @abc.abstractmethod def init_availability_zones(self): # To be initialized by the real plugin self._availability_zones_data = None def get_azs_list(self): return self._availability_zones_data.list_availability_zones_objects() def get_azs_names(self): return self._availability_zones_data.list_availability_zones() def validate_obj_azs(self, availability_zones): """Verify that the availability zones exist, and only 1 hint was set. """ # For now we support only 1 hint per network/router # TODO(asarfaty): support multiple hints if len(availability_zones) > 1: err_msg = _("Can't use multiple availability zone hints") raise n_exc.InvalidInput(error_message=err_msg) # check that all hints appear in the predefined list of availability # zones diff = (set(availability_zones) - set(self.get_azs_names())) if diff: raise az_ext.AvailabilityZoneNotFound( availability_zone=diff.pop()) def get_az_by_hint(self, hint): az = self._availability_zones_data.get_availability_zone(hint) if not az: raise az_ext.AvailabilityZoneNotFound(availability_zone=hint) return az def get_default_az(self): return self._availability_zones_data.get_default_availability_zone() def get_obj_az_by_hints(self, obj): if az_ext.AZ_HINTS in obj: for hint in obj[az_ext.AZ_HINTS]: # For now we use only the first hint return self.get_az_by_hint(hint) # return the default return self.get_default_az() def get_network_az(self, network): return self.get_obj_az_by_hints(network) def get_router_az(self, router): return self.get_obj_az_by_hints(router)