def create_update_traffic_manager_endpoint(self): ''' Creates or updates a Traffic Manager endpoint. :return: deserialized Traffic Manager endpoint state dictionary ''' self.log("Creating / Updating the Traffic Manager endpoint {0}".format(self.name)) parameters = Endpoint(target_resource_id=self.target_resource_id, target=self.target, endpoint_status=self.endpoint_status, weight=self.weight, priority=self.priority, endpoint_location=self.location, min_child_endpoints=self.min_child_endpoints, geo_mapping=self.geo_mapping) try: response = self.traffic_manager_management_client.endpoints.create_or_update(self.resource_group, self.profile_name, self.type, self.name, parameters) return traffic_manager_endpoint_to_dict(response) except CloudError as exc: request_id = exc.request_id if exc.request_id else '' self.fail("Error creating the Traffic Manager endpoint {0}, request id {1} - {2}".format(self.name, request_id, str(exc)))
def _create_or_update_traffic_manager( self, tag: str, traffic_manager_name: str, appgw_public_ip_addresses: typing.List[PublicIPAddress], ) -> Profile: """ Creates new or updates existing Traffic Manager in Azure. """ logging.debug("Creating or updating traffic manager") tm_profile = self.traffic_manager.profiles.create_or_update( resource_group_name=self.options.azure_trafficmanager_resource_group, profile_name=traffic_manager_name, parameters=Profile( name=traffic_manager_name, location="global", tags=get_policy_tags(additional_tags={TAG_APPGWGROUP: tag}), profile_status="Enabled", traffic_routing_method="Priority", dns_config=DnsConfig( relative_name=traffic_manager_name, ttl=TRAFFICMANAGER_DNS_TTL ), monitor_config=MonitorConfig( protocol="https", port=80, path="/", interval_in_seconds=10, timeout_in_seconds=5, tolerated_number_of_failures=1, custom_headers=[ MonitorConfigCustomHeadersItem( name="Host", value=TRAFFICMANAGER_HEALTHCHECK_HOSTNAME ) ], expected_status_code_ranges=[ MonitorConfigExpectedStatusCodeRangesItem(min=200, max=399) ], ), endpoints=[], ), ) # Construct endpoints for traffic manager for index, ip in enumerate(appgw_public_ip_addresses): self.traffic_manager.endpoints.create_or_update( resource_group_name=self.options.azure_trafficmanager_resource_group, profile_name=tm_profile.name, endpoint_type="AzureEndpoints", endpoint_name=f"endpoint-{index}", parameters=Endpoint( name=f"endpoint-{index}", target_resource_id=ip.id, target=ip.ip_address, ), ) return tm_profile
def create_endpoint_instance(endpoint): return Endpoint(id=endpoint['id'], name=endpoint['name'], type=endpoint['type'], target_resource_id=endpoint['target_resource_id'], target=endpoint['target'], endpoint_status=endpoint['endpoint_status'], weight=endpoint['weight'], priority=endpoint['priority'], endpoint_location=endpoint['endpoint_location'], min_child_endpoints=endpoint['min_child_endpoints'], geo_mapping=endpoint['geo_mapping'])
def _generate_traffic_managers(self, record): traffic_managers = [] pools = record.dynamic.pools default = record.value[:-1] tm_suffix = _traffic_manager_suffix(record) profile = self._generate_tm_profile geo_endpoints = [] pool_profiles = {} for rule in record.dynamic.rules: # Prepare the list of Traffic manager geos rule_geos = rule.data.get('geos', []) geos = [] for geo in rule_geos: if '-' in geo: # country/state geos.append(geo.split('-', 1)[-1]) else: # continent if geo == 'AS': # Middle East is part of Asia in octoDNS, but # Azure treats it as a separate "group", so let's # add it in the list of geo mappings. We will drop # it when we later parse the list of regions. geos.append('GEO-ME') elif geo == 'OC': # Azure uses Australia/Pacific (AP) instead of # Oceania geo = 'AP' geos.append('GEO-{}'.format(geo)) if not geos: geos.append('WORLD') pool_name = rule.data['pool'] rule_endpoints = [] priority = 1 default_seen = False while pool_name: # iterate until we reach end of fallback chain default_seen = False pool = pools[pool_name].data if len(pool['values']) > 1: # create Weighted profile for multi-value pool pool_profile = pool_profiles.get(pool_name) if pool_profile is None: endpoints = [] for val in pool['values']: target = val['value'] # strip trailing dot from CNAME value target = target[:-1] ep_name = '{}--{}'.format(pool_name, target) if target == default: # mark default ep_name += '--default--' default_seen = True endpoints.append(Endpoint( name=ep_name, target=target, weight=val.get('weight', 1), )) profile_name = 'pool-{}--{}'.format( pool_name, tm_suffix) pool_profile = profile(profile_name, 'Weighted', endpoints, record) traffic_managers.append(pool_profile) pool_profiles[pool_name] = pool_profile # append pool to endpoint list of fallback rule profile rule_endpoints.append(Endpoint( name=pool_name, target_resource_id=pool_profile.id, priority=priority, )) else: # Skip Weighted profile hop for single-value pool # append its value as an external endpoint to fallback # rule profile target = pool['values'][0]['value'][:-1] ep_name = pool_name if target == default: # mark default ep_name += '--default--' default_seen = True rule_endpoints.append(Endpoint( name=pool_name, target=target, priority=priority, )) priority += 1 pool_name = pool.get('fallback') # append default endpoint unless it is already included in # last pool of rule profile if not default_seen: rule_endpoints.append(Endpoint( name='--default--', target=default, priority=priority, )) if len(rule_endpoints) > 1: # create rule profile with fallback chain rule_profile_name = 'rule-{}--{}'.format( rule.data['pool'], tm_suffix) rule_profile = profile(rule_profile_name, 'Priority', rule_endpoints, record) traffic_managers.append(rule_profile) # append rule profile to top-level geo profile geo_endpoints.append(Endpoint( name='rule-{}'.format(rule.data['pool']), target_resource_id=rule_profile.id, geo_mapping=geos, )) else: # Priority profile has only one endpoint; skip the hop and # append its only endpoint to the top-level profile rule_ep = rule_endpoints[0] if rule_ep.target_resource_id: # point directly to the Weighted pool profile geo_endpoints.append(Endpoint( name='rule-{}'.format(rule.data['pool']), target_resource_id=rule_ep.target_resource_id, geo_mapping=geos, )) else: # just add the value of single-value pool geo_endpoints.append(Endpoint( name=rule_ep.name + '--default--', target=rule_ep.target, geo_mapping=geos, )) if len(geo_endpoints) == 1 and \ geo_endpoints[0].geo_mapping == ['WORLD'] and \ geo_endpoints[0].target_resource_id: # Single WORLD rule does not require a Geographic profile, use # the target profile as the root profile target_profile_id = geo_endpoints[0].target_resource_id profile_map = dict((tm.id, tm) for tm in traffic_managers) target_profile = profile_map[target_profile_id] self._update_tm_name(target_profile, tm_suffix) else: geo_profile = profile(tm_suffix, 'Geographic', geo_endpoints, record) traffic_managers.append(geo_profile) return traffic_managers
def _data_for_dynamic(self, azrecord): default = set() pools = defaultdict(lambda: {'fallback': None, 'values': []}) rules = [] # top level profile root_profile = self._get_tm_profile_by_id(azrecord.target_resource.id) if root_profile.traffic_routing_method != 'Geographic': # This record does not use geo fencing, so we skip the Geographic # profile hop; let's pretend to be a geo-profile's only endpoint geo_ep = Endpoint(target_resource_id=root_profile.id) geo_ep.target_resource = root_profile endpoints = [geo_ep] else: endpoints = root_profile.endpoints for geo_ep in endpoints: rule = {} # resolve list of regions geo_map = list(geo_ep.geo_mapping or []) if geo_map and geo_map != ['WORLD']: if 'GEO-ME' in geo_map: # Azure treats Middle East as a separate group, but # its part of Asia in octoDNS, so we need to remove GEO-ME # if GEO-AS is also in the list # Throw exception otherwise, it should not happen if the # profile was generated by octoDNS if 'GEO-AS' not in geo_map: msg = 'Profile={} for record {}: '.format( root_profile.name, azrecord.fqdn) msg += 'Middle East (GEO-ME) is not supported by ' + \ 'octoDNS. It needs to be either paired ' + \ 'with Asia (GEO-AS) or expanded into ' + \ 'individual list of countries.' raise AzureException(msg) geo_map.remove('GEO-ME') geos = rule.setdefault('geos', []) for code in geo_map: if code.startswith('GEO-'): # continent if code == 'GEO-AP': # Azure uses Australia/Pacific (AP) instead of # Oceania https://docs.microsoft.com/en-us/azure/ # traffic-manager/ # traffic-manager-geographic-regions geos.append('OC') else: geos.append(code[len('GEO-'):]) elif '-' in code: # state country, province = code.split('-', 1) country = GeoCodes.country_to_code(country) geos.append('{}-{}'.format(country, province)) else: # country geos.append(GeoCodes.country_to_code(code)) # build fallback chain from second level priority profile if geo_ep.target_resource_id: target = geo_ep.target_resource if target.traffic_routing_method == 'Priority': rule_endpoints = target.endpoints rule_endpoints.sort(key=lambda e: e.priority) else: # Weighted geo_ep.name = target.endpoints[0].name.split('--', 1)[0] rule_endpoints = [geo_ep] else: # this geo directly points to the default, so we skip the # Priority profile hop and directly use an external endpoint; # let's pretend to be a Priority profile's only endpoint rule_endpoints = [geo_ep] pool = None for rule_ep in rule_endpoints: pool_name = rule_ep.name # last/default pool if pool_name.endswith('--default--'): default.add(rule_ep.target) if pool_name == '--default--': # this should be the last one, so let's break here break # last pool is a single value pool and its value is same # as record's default value pool_name = pool_name[:-len('--default--')] # set first priority endpoint as the rule's primary pool if 'pool' not in rule: rule['pool'] = pool_name if pool: # set current pool as fallback of the previous pool pool['fallback'] = pool_name if pool_name in pools: # we've already populated the pool continue # populate the pool from Weighted profile # these should be leaf node entries with no further nesting pool = pools[pool_name] endpoints = [] if rule_ep.target_resource_id: # third (and last) level weighted RR profile endpoints = rule_ep.target_resource.endpoints else: # single-value pool, so we skip the Weighted profile hop # and directly use an external endpoint; let's pretend to # be a Weighted profile's only endpoint endpoints = [rule_ep] for pool_ep in endpoints: val = pool_ep.target pool['values'].append({ 'value': _check_endswith_dot(val), 'weight': pool_ep.weight or 1, }) if pool_ep.name.endswith('--default--'): default.add(val) rules.append(rule) # Order and convert to a list default = sorted(default) data = { 'dynamic': { 'pools': pools, 'rules': rules, }, 'value': _check_endswith_dot(default[0]), } return data
def _generate_traffic_managers(self, record): traffic_managers = [] pools = record.dynamic.pools tm_suffix = _traffic_manager_suffix(record) profile = self._generate_tm_profile geo_endpoints = [] for rule in record.dynamic.rules: pool_name = rule.data['pool'] rule_endpoints = [] priority = 1 while pool_name: # iterate until we reach end of fallback chain pool = pools[pool_name].data profile_name = 'pool-{}--{}'.format(pool_name, tm_suffix) if len(pool['values']) > 1: # create Weighted profile for multi-value pool endpoints = [] for val in pool['values']: target = val['value'] # strip trailing dot from CNAME value target = target[:-1] endpoints.append(Endpoint( name=target, target=target, weight=val.get('weight', 1), )) pool_profile = profile(profile_name, 'Weighted', endpoints, record) traffic_managers.append(pool_profile) # append pool to endpoint list of fallback rule profile rule_endpoints.append(Endpoint( name=pool_name, target_resource_id=pool_profile.id, priority=priority, )) else: # add single-value pool as an external endpoint target = pool['values'][0]['value'][:-1] rule_endpoints.append(Endpoint( name=pool_name, target=target, priority=priority, )) priority += 1 pool_name = pool.get('fallback') # append default profile to the end rule_endpoints.append(Endpoint( name='--default--', target=record.value[:-1], priority=priority, )) # create rule profile with fallback chain rule_profile_name = 'rule-{}--{}'.format(rule.data['pool'], tm_suffix) rule_profile = profile(rule_profile_name, 'Priority', rule_endpoints, record) traffic_managers.append(rule_profile) # append rule profile to top-level geo profile rule_geos = rule.data.get('geos', []) geos = [] if len(rule_geos) > 0: for geo in rule_geos: if '-' in geo: # country or state geos.append(geo.split('-', 1)[-1]) else: # continent if geo == 'AS': # Middle East is part of Asia in octoDNS, but # Azure treats it as a separate "group", so let's # add it in the list of geo mappings. We will drop # it when we later parse the list of regions. geos.append('GEO-ME') elif geo == 'OC': # Azure uses Australia/Pacific (AP) instead of # Oceania geo = 'AP' geos.append('GEO-{}'.format(geo)) else: geos.append('WORLD') geo_endpoints.append(Endpoint( name='rule-{}'.format(rule.data['pool']), target_resource_id=rule_profile.id, geo_mapping=geos, )) geo_profile = profile(tm_suffix, 'Geographic', geo_endpoints, record) traffic_managers.append(geo_profile) return traffic_managers
def create_or_update_traffic_manager_profile(self, update): ''' Create or update a Traffic Manager profile. :param name: name of a traffic manager :return: traffic manage object ''' self.log('Creating or updating Traffic Manager {0}'.format(self.name)) try: # Create MonitorConfig monitor_config = MonitorConfig( protocol=self.monitor_config.get('protocol', 'HTTP'), port=self.monitor_config.get('port', 80), path=self.monitor_config.get('path', '/'), timeout_in_seconds=self.monitor_config.get( 'timeout_in_seconds', 10), interval_in_seconds=self.monitor_config.get( 'interval_in_seconds', 30), tolerated_number_of_failures=self.monitor_config.get( 'tolerated_number_of_failures', 3)) # Create DnsConfig dns_config = DnsConfig(relative_name=self.dns_config.get( 'relative_name', self.name), ttl=self.dns_config.get('ttl', 60)) # Create Endpoints endpoints = [] for end in self.endpoints: endpoint_instance = Endpoint( name=end.get('name'), type=end.get('type'), target=end.get('target'), endpoint_status=end.get('endpoint_status', 'Enabled'), weight=end.get('weight'), priority=end.get('priority'), target_resource_id=end.get('target_resource_id'), endpoint_location=end.get('endpoint_location'), min_child_endpoints=end.get('min_child_endpoints'), geo_mapping=end.get('geo_mapping')) endpoints.append(endpoint_instance) profile = Profile( tags=self.tags, location="global", profile_status=self.profile_status, traffic_routing_method=self.traffic_routing_method, dns_config=dns_config, monitor_config=monitor_config, endpoints=endpoints) return self.trafficmanager_client.profiles.create_or_update( self.resource_group, self.name, profile).as_dict() except CloudError as cloud_error: if update: self.fail( 'Error Updating the Traffic Manager: {0}. {1}'.format( self.name, str(cloud_error))) else: self.fail( 'Error Creating the Traffic Manager: {0}. {1}'.format( self.name, str(cloud_error))) except Exception as exc: self.fail('Error retrieving Traffic Manager {0} - {1}'.format( self.name, str(exc)))