2021-10-22 21:47:29 +00:00
""" Route53Backend class with methods for supported APIs. """
2022-11-30 23:35:20 +00:00
import copy
2021-04-20 11:50:05 +00:00
import itertools
2021-10-22 21:47:29 +00:00
import re
2017-09-22 22:50:01 +00:00
import string
2022-09-28 09:35:12 +00:00
from collections import defaultdict
2015-01-17 19:50:19 +00:00
from jinja2 import Template
2023-04-19 10:25:48 +00:00
from typing import Any , Dict , List , Optional , Tuple
2015-01-17 19:50:19 +00:00
2021-10-22 21:47:29 +00:00
from moto . route53 . exceptions import (
2022-06-10 19:33:17 +00:00
HostedZoneNotEmpty ,
2022-06-14 14:22:07 +00:00
InvalidActionValue ,
InvalidCloudWatchArn ,
2022-06-14 10:14:15 +00:00
LastVPCAssociation ,
2021-10-22 21:47:29 +00:00
NoSuchCloudWatchLogsLogGroup ,
2022-01-31 00:53:05 +00:00
NoSuchDelegationSet ,
2022-06-10 19:33:17 +00:00
NoSuchHealthCheck ,
2021-10-22 21:47:29 +00:00
NoSuchHostedZone ,
NoSuchQueryLoggingConfig ,
2022-06-14 10:14:15 +00:00
PublicZoneVPCAssociation ,
2021-10-22 21:47:29 +00:00
QueryLoggingConfigAlreadyExists ,
2022-11-30 23:35:20 +00:00
DnsNameInvalidForZone ,
2022-12-21 23:38:27 +00:00
ResourceRecordAlreadyExists ,
2022-12-10 11:07:30 +00:00
InvalidInput ,
2021-10-22 21:47:29 +00:00
)
2022-11-10 09:43:20 +00:00
from moto . core import BaseBackend , BackendDict , BaseModel , CloudFormationModel
2022-09-28 09:35:12 +00:00
from moto . moto_api . _internal import mock_random as random
2021-10-22 21:47:29 +00:00
from moto . utilities . paginator import paginate
from . utils import PAGINATION_MODEL
2017-09-22 22:50:01 +00:00
ROUTE53_ID_CHOICE = string . ascii_uppercase + string . digits
2023-04-19 10:25:48 +00:00
def create_route53_zone_id ( ) - > str :
2017-09-22 22:50:01 +00:00
# New ID's look like this Z1RWWTK7Y8UDDQ
return " " . join ( [ random . choice ( ROUTE53_ID_CHOICE ) for _ in range ( 0 , 15 ) ] )
2013-11-14 19:14:14 +00:00
2022-01-31 00:53:05 +00:00
class DelegationSet ( BaseModel ) :
2023-04-19 10:25:48 +00:00
def __init__ (
self ,
caller_reference : str ,
name_servers : Optional [ List [ str ] ] ,
delegation_set_id : Optional [ str ] ,
) :
2022-01-31 00:53:05 +00:00
self . caller_reference = caller_reference
self . name_servers = name_servers or [
" ns-2048.awsdns-64.com " ,
" ns-2049.awsdns-65.net " ,
" ns-2050.awsdns-66.org " ,
" ns-2051.awsdns-67.co.uk " ,
]
self . id = delegation_set_id or " " . join (
[ random . choice ( ROUTE53_ID_CHOICE ) for _ in range ( 5 ) ]
)
self . location = f " https://route53.amazonaws.com/delegationset/ { self . id } "
2020-08-01 14:23:36 +00:00
class HealthCheck ( CloudFormationModel ) :
2023-04-19 10:25:48 +00:00
def __init__ (
self ,
health_check_id : str ,
caller_reference : str ,
health_check_args : Dict [ str , Any ] ,
) :
2015-01-18 00:06:43 +00:00
self . id = health_check_id
self . ip_address = health_check_args . get ( " ip_address " )
2021-08-22 09:51:21 +00:00
self . port = health_check_args . get ( " port " ) or 80
2019-02-27 10:54:55 +00:00
self . type_ = health_check_args . get ( " type " )
2015-01-18 00:06:43 +00:00
self . resource_path = health_check_args . get ( " resource_path " )
self . fqdn = health_check_args . get ( " fqdn " )
self . search_string = health_check_args . get ( " search_string " )
2021-08-22 09:51:21 +00:00
self . request_interval = health_check_args . get ( " request_interval " ) or 30
self . failure_threshold = health_check_args . get ( " failure_threshold " ) or 3
self . health_threshold = health_check_args . get ( " health_threshold " )
self . measure_latency = health_check_args . get ( " measure_latency " ) or False
self . inverted = health_check_args . get ( " inverted " ) or False
self . disabled = health_check_args . get ( " disabled " ) or False
2022-06-19 11:21:28 +00:00
self . enable_sni = health_check_args . get ( " enable_sni " ) or True
2021-08-22 09:51:21 +00:00
self . caller_reference = caller_reference
2022-06-19 11:21:28 +00:00
self . children = None
self . regions = None
2023-04-19 10:25:48 +00:00
def set_children ( self , children : Any ) - > None :
2022-06-19 11:21:28 +00:00
if children and isinstance ( children , list ) :
2023-04-19 10:25:48 +00:00
self . children = children # type: ignore
2022-06-19 11:21:28 +00:00
elif children and isinstance ( children , str ) :
2023-04-19 10:25:48 +00:00
self . children = [ children ] # type: ignore
2022-06-19 11:21:28 +00:00
2023-04-19 10:25:48 +00:00
def set_regions ( self , regions : Any ) - > None :
2022-06-19 11:21:28 +00:00
if regions and isinstance ( regions , list ) :
2023-04-19 10:25:48 +00:00
self . regions = regions # type: ignore
2022-06-19 11:21:28 +00:00
elif regions and isinstance ( regions , str ) :
2023-04-19 10:25:48 +00:00
self . regions = [ regions ] # type: ignore
2015-01-18 00:06:43 +00:00
@property
2023-04-19 10:25:48 +00:00
def physical_resource_id ( self ) - > str :
2015-01-18 00:06:43 +00:00
return self . id
2020-08-01 14:23:36 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_name_type ( ) - > str :
return " "
2020-08-01 14:23:36 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_type ( ) - > str :
2020-08-01 14:23:36 +00:00
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-healthcheck.html
return " AWS::Route53::HealthCheck "
2015-01-18 00:06:43 +00:00
@classmethod
2023-04-19 10:25:48 +00:00
def create_from_cloudformation_json ( # type: ignore[misc]
cls ,
resource_name : str ,
cloudformation_json : Any ,
account_id : str ,
region_name : str ,
* * kwargs : Any ,
) - > " HealthCheck " :
2015-01-18 00:06:43 +00:00
properties = cloudformation_json [ " Properties " ] [ " HealthCheckConfig " ]
health_check_args = {
" ip_address " : properties . get ( " IPAddress " ) ,
" port " : properties . get ( " Port " ) ,
" type " : properties [ " Type " ] ,
" resource_path " : properties . get ( " ResourcePath " ) ,
" fqdn " : properties . get ( " FullyQualifiedDomainName " ) ,
" search_string " : properties . get ( " SearchString " ) ,
" request_interval " : properties . get ( " RequestInterval " ) ,
" failure_threshold " : properties . get ( " FailureThreshold " ) ,
}
2022-08-13 09:49:43 +00:00
backend = route53_backends [ account_id ] [ " global " ]
health_check = backend . create_health_check (
2021-08-22 09:51:21 +00:00
caller_reference = resource_name , health_check_args = health_check_args
)
2015-01-18 00:06:43 +00:00
return health_check
2023-04-19 10:25:48 +00:00
def to_xml ( self ) - > str :
2015-01-18 00:06:43 +00:00
template = Template (
""" <HealthCheck>
< Id > { { health_check . id } } < / Id >
2021-08-22 09:51:21 +00:00
< CallerReference > { { health_check . caller_reference } } < / CallerReference >
2015-01-18 00:06:43 +00:00
< HealthCheckConfig >
2021-08-22 09:51:21 +00:00
{ % if health_check . type_ != " CALCULATED " % }
< IPAddress > { { health_check . ip_address } } < / IPAddress >
< Port > { { health_check . port } } < / Port >
{ % endif % }
2019-02-27 10:54:55 +00:00
< Type > { { health_check . type_ } } < / Type >
2021-08-22 09:51:21 +00:00
{ % if health_check . resource_path % }
< ResourcePath > { { health_check . resource_path } } < / ResourcePath >
{ % endif % }
{ % if health_check . fqdn % }
< FullyQualifiedDomainName > { { health_check . fqdn } } < / FullyQualifiedDomainName >
{ % endif % }
{ % if health_check . type_ != " CALCULATED " % }
< RequestInterval > { { health_check . request_interval } } < / RequestInterval >
< FailureThreshold > { { health_check . failure_threshold } } < / FailureThreshold >
< MeasureLatency > { { health_check . measure_latency } } < / MeasureLatency >
{ % endif % }
{ % if health_check . type_ == " CALCULATED " % }
< HealthThreshold > { { health_check . health_threshold } } < / HealthThreshold >
{ % endif % }
< Inverted > { { health_check . inverted } } < / Inverted >
< Disabled > { { health_check . disabled } } < / Disabled >
< EnableSNI > { { health_check . enable_sni } } < / EnableSNI >
2015-01-18 00:06:43 +00:00
{ % if health_check . search_string % }
< SearchString > { { health_check . search_string } } < / SearchString >
{ % endif % }
2021-08-22 09:51:21 +00:00
{ % if health_check . children % }
< ChildHealthChecks >
{ % for child in health_check . children % }
2022-06-19 11:21:28 +00:00
< ChildHealthCheck > { { child } } < / ChildHealthCheck >
2021-08-22 09:51:21 +00:00
{ % endfor % }
< / ChildHealthChecks >
{ % endif % }
2022-06-19 11:21:28 +00:00
{ % if health_check . regions % }
< Regions >
{ % for region in health_check . regions % }
< Region > { { region } } < / Region >
{ % endfor % }
< / Regions >
{ % endif % }
2015-01-18 00:06:43 +00:00
< / HealthCheckConfig >
< HealthCheckVersion > 1 < / HealthCheckVersion >
< / HealthCheck > """
)
return template . render ( health_check = self )
2020-08-01 14:23:36 +00:00
class RecordSet ( CloudFormationModel ) :
2023-04-19 10:25:48 +00:00
def __init__ ( self , kwargs : Dict [ str , Any ] ) :
self . name = kwargs . get ( " Name " , " " )
2019-02-27 10:54:55 +00:00
self . type_ = kwargs . get ( " Type " )
2021-12-09 22:33:09 +00:00
self . ttl = kwargs . get ( " TTL " , 0 )
2015-01-17 19:50:19 +00:00
self . records = kwargs . get ( " ResourceRecords " , [ ] )
self . set_identifier = kwargs . get ( " SetIdentifier " )
2021-12-09 22:33:09 +00:00
self . weight = kwargs . get ( " Weight " , 0 )
2015-09-08 21:36:32 +00:00
self . region = kwargs . get ( " Region " )
2015-01-18 00:06:43 +00:00
self . health_check = kwargs . get ( " HealthCheckId " )
2016-03-02 22:33:02 +00:00
self . hosted_zone_name = kwargs . get ( " HostedZoneName " )
self . hosted_zone_id = kwargs . get ( " HostedZoneId " )
2022-06-10 19:33:17 +00:00
self . alias_target = kwargs . get ( " AliasTarget " , [ ] )
self . failover = kwargs . get ( " Failover " , [ ] )
self . geo_location = kwargs . get ( " GeoLocation " , [ ] )
2015-01-17 19:50:19 +00:00
2020-08-01 14:23:36 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_name_type ( ) - > str :
2020-08-01 14:23:36 +00:00
return " Name "
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_type ( ) - > str :
2020-08-01 14:23:36 +00:00
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-recordset.html
return " AWS::Route53::RecordSet "
2015-01-17 20:37:46 +00:00
@classmethod
2023-04-19 10:25:48 +00:00
def create_from_cloudformation_json ( # type: ignore[misc]
cls ,
resource_name : str ,
cloudformation_json : Any ,
account_id : str ,
region_name : str ,
* * kwargs : Any ,
) - > " RecordSet " :
2015-01-17 20:37:46 +00:00
properties = cloudformation_json [ " Properties " ]
2016-03-07 19:25:25 +00:00
zone_name = properties . get ( " HostedZoneName " )
2022-08-13 09:49:43 +00:00
backend = route53_backends [ account_id ] [ " global " ]
2016-03-07 19:25:25 +00:00
if zone_name :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone_by_name ( zone_name )
2016-03-07 19:25:25 +00:00
else :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone ( properties [ " HostedZoneId " ] )
2015-01-17 20:37:46 +00:00
record_set = hosted_zone . add_rrset ( properties )
return record_set
2016-04-28 13:21:54 +00:00
@classmethod
2023-04-19 10:25:48 +00:00
def update_from_cloudformation_json ( # type: ignore[misc]
2022-08-13 09:49:43 +00:00
cls ,
2023-04-19 10:25:48 +00:00
original_resource : Any ,
new_resource_name : str ,
cloudformation_json : Any ,
account_id : str ,
region_name : str ,
) - > " RecordSet " :
2017-02-24 02:37:43 +00:00
cls . delete_from_cloudformation_json (
2022-08-13 09:49:43 +00:00
original_resource . name , cloudformation_json , account_id , region_name
2017-02-24 02:37:43 +00:00
)
2016-04-28 13:21:54 +00:00
return cls . create_from_cloudformation_json (
2022-08-13 09:49:43 +00:00
new_resource_name , cloudformation_json , account_id , region_name
2016-04-28 13:21:54 +00:00
)
@classmethod
2023-04-19 10:25:48 +00:00
def delete_from_cloudformation_json ( # type: ignore[misc]
cls ,
resource_name : str ,
cloudformation_json : Any ,
account_id : str ,
region_name : str ,
) - > None :
2017-02-24 02:37:43 +00:00
# this will break if you changed the zone the record is in,
# unfortunately
2016-04-28 13:21:54 +00:00
properties = cloudformation_json [ " Properties " ]
zone_name = properties . get ( " HostedZoneName " )
2022-08-13 09:49:43 +00:00
backend = route53_backends [ account_id ] [ " global " ]
2016-04-28 13:21:54 +00:00
if zone_name :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone_by_name ( zone_name )
2016-04-28 13:21:54 +00:00
else :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone ( properties [ " HostedZoneId " ] )
2016-04-28 13:21:54 +00:00
try :
2019-06-18 09:03:28 +00:00
hosted_zone . delete_rrset ( { " Name " : resource_name } )
2016-04-28 13:21:54 +00:00
except KeyError :
pass
2016-04-28 13:42:10 +00:00
@property
2023-04-19 10:25:48 +00:00
def physical_resource_id ( self ) - > str :
2016-04-28 13:42:10 +00:00
return self . name
2023-04-19 10:25:48 +00:00
def delete (
self , account_id : str , region : str # pylint: disable=unused-argument
) - > None :
2022-08-13 09:49:43 +00:00
""" Not exposed as part of the Route 53 API - used for CloudFormation """
2022-08-23 13:45:01 +00:00
backend = route53_backends [ account_id ] [ " global " ]
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone_by_name ( self . hosted_zone_name )
2016-03-07 19:25:25 +00:00
if not hosted_zone :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone ( self . hosted_zone_id )
2019-06-18 09:03:28 +00:00
hosted_zone . delete_rrset ( { " Name " : self . name , " Type " : self . type_ } )
2016-03-02 22:33:02 +00:00
2015-01-17 19:50:19 +00:00
2023-04-19 10:25:48 +00:00
def reverse_domain_name ( domain_name : str ) - > str :
2019-06-14 14:17:50 +00:00
if domain_name . endswith ( " . " ) : # normalize without trailing dot
domain_name = domain_name [ : - 1 ]
return " . " . join ( reversed ( domain_name . split ( " . " ) ) )
2016-03-02 22:33:02 +00:00
2015-01-17 19:50:19 +00:00
2023-04-19 10:25:48 +00:00
class ChangeList ( List [ Dict [ str , Any ] ] ) :
2022-12-10 11:07:30 +00:00
"""
Contains a ' clean ' list of ResourceRecordChangeSets
"""
2023-04-19 10:25:48 +00:00
def append ( self , item : Any ) - > None :
2022-12-10 11:07:30 +00:00
item [ " ResourceRecordSet " ] [ " Name " ] = item [ " ResourceRecordSet " ] [ " Name " ] . strip ( " . " )
super ( ) . append ( item )
2023-04-19 10:25:48 +00:00
def __contains__ ( self , item : Any ) - > bool :
2022-12-10 11:07:30 +00:00
item [ " ResourceRecordSet " ] [ " Name " ] = item [ " ResourceRecordSet " ] [ " Name " ] . strip ( " . " )
return super ( ) . __contains__ ( item )
2020-08-01 14:23:36 +00:00
class FakeZone ( CloudFormationModel ) :
2022-01-27 11:28:31 +00:00
def __init__ (
2022-01-31 00:53:05 +00:00
self ,
2023-04-19 10:25:48 +00:00
name : str ,
id_ : str ,
private_zone : bool ,
comment : Optional [ str ] = None ,
delegation_set : Optional [ DelegationSet ] = None ,
2022-01-27 11:28:31 +00:00
) :
2013-11-14 19:14:14 +00:00
self . name = name
2014-08-30 01:14:24 +00:00
self . id = id_
2023-04-19 10:25:48 +00:00
self . vpcs : List [ Dict [ str , Any ] ] = [ ]
2016-02-17 14:32:38 +00:00
if comment is not None :
self . comment = comment
2016-06-03 13:57:33 +00:00
self . private_zone = private_zone
2023-04-19 10:25:48 +00:00
self . rrsets : List [ RecordSet ] = [ ]
2022-01-31 00:53:05 +00:00
self . delegation_set = delegation_set
2022-12-10 11:07:30 +00:00
self . rr_changes = ChangeList ( )
2013-11-14 19:14:14 +00:00
2023-04-19 10:25:48 +00:00
def add_rrset ( self , record_set : Dict [ str , Any ] ) - > RecordSet :
record_set_obj = RecordSet ( record_set )
self . rrsets . append ( record_set_obj )
return record_set_obj
2013-11-14 19:14:14 +00:00
2023-04-19 10:25:48 +00:00
def upsert_rrset ( self , record_set : Dict [ str , Any ] ) - > RecordSet :
2016-04-12 17:37:01 +00:00
new_rrset = RecordSet ( record_set )
for i , rrset in enumerate ( self . rrsets ) :
2019-07-17 23:37:47 +00:00
if (
rrset . name == new_rrset . name
and rrset . type_ == new_rrset . type_
and rrset . set_identifier == new_rrset . set_identifier
) :
2016-04-12 17:37:01 +00:00
self . rrsets [ i ] = new_rrset
break
else :
self . rrsets . append ( new_rrset )
return new_rrset
2023-04-19 10:25:48 +00:00
def delete_rrset ( self , rrset : Dict [ str , Any ] ) - > None :
2017-02-24 02:37:43 +00:00
self . rrsets = [
2019-06-17 13:53:32 +00:00
record_set
for record_set in self . rrsets
if record_set . name != rrset [ " Name " ]
2019-06-17 14:59:07 +00:00
or ( rrset . get ( " Type " ) is not None and record_set . type_ != rrset [ " Type " ] )
2019-06-17 13:53:32 +00:00
]
2015-01-17 19:50:19 +00:00
2023-04-19 10:25:48 +00:00
def delete_rrset_by_id ( self , set_identifier : str ) - > None :
2017-02-24 02:37:43 +00:00
self . rrsets = [
record_set
for record_set in self . rrsets
if record_set . set_identifier != set_identifier
]
2015-04-30 22:51:01 +00:00
2023-04-19 10:25:48 +00:00
def add_vpc (
self , vpc_id : Optional [ str ] , vpc_region : Optional [ str ]
) - > Dict [ str , Any ] :
2022-06-14 10:14:15 +00:00
vpc = { }
if vpc_id is not None :
vpc [ " vpc_id " ] = vpc_id
if vpc_region is not None :
vpc [ " vpc_region " ] = vpc_region
if vpc_id or vpc_region :
self . vpcs . append ( vpc )
return vpc
2023-04-19 10:25:48 +00:00
def delete_vpc ( self , vpc_id : str ) - > None :
2022-06-14 10:14:15 +00:00
self . vpcs = [ vpc for vpc in self . vpcs if vpc [ " vpc_id " ] != vpc_id ]
2023-04-19 10:25:48 +00:00
def get_record_sets ( self , start_type : str , start_name : str ) - > List [ RecordSet ] :
def predicate ( rrset : RecordSet ) - > bool :
2021-04-20 11:50:05 +00:00
rrset_name_reversed = reverse_domain_name ( rrset . name )
start_name_reversed = reverse_domain_name ( start_name )
return rrset_name_reversed < start_name_reversed or (
2023-04-19 10:25:48 +00:00
rrset_name_reversed == start_name_reversed and rrset . type_ < start_type # type: ignore
2021-04-20 11:50:05 +00:00
)
record_sets = sorted (
self . rrsets ,
key = lambda rrset : ( reverse_domain_name ( rrset . name ) , rrset . type_ ) ,
)
2017-10-23 15:25:40 +00:00
if start_name :
2021-04-20 11:50:05 +00:00
start_type = start_type or " "
2023-04-19 10:25:48 +00:00
record_sets = itertools . dropwhile ( predicate , record_sets ) # type: ignore
2015-01-17 19:50:19 +00:00
return record_sets
2015-01-17 15:17:25 +00:00
@property
2023-04-19 10:25:48 +00:00
def physical_resource_id ( self ) - > str :
2017-10-21 21:10:45 +00:00
return self . id
2015-01-17 15:17:25 +00:00
2020-08-01 14:23:36 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_name_type ( ) - > str :
2020-08-01 14:23:36 +00:00
return " Name "
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_type ( ) - > str :
2020-08-01 14:23:36 +00:00
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone.html
return " AWS::Route53::HostedZone "
2015-01-17 15:17:25 +00:00
@classmethod
2023-04-19 10:25:48 +00:00
def create_from_cloudformation_json ( # type: ignore[misc]
cls ,
resource_name : str ,
cloudformation_json : Any ,
account_id : str ,
region_name : str ,
* * kwargs : Any ,
) - > " FakeZone " :
2022-08-13 09:49:43 +00:00
hosted_zone = route53_backends [ account_id ] [ " global " ] . create_hosted_zone (
2020-08-27 09:11:47 +00:00
resource_name , private_zone = False
)
2015-01-17 15:17:25 +00:00
return hosted_zone
2020-08-01 14:23:36 +00:00
class RecordSetGroup ( CloudFormationModel ) :
2023-04-19 10:25:48 +00:00
def __init__ ( self , hosted_zone_id : str , record_sets : List [ str ] ) :
2015-01-17 19:50:19 +00:00
self . hosted_zone_id = hosted_zone_id
2015-01-17 15:17:25 +00:00
self . record_sets = record_sets
2015-01-17 19:50:19 +00:00
@property
2023-04-19 10:25:48 +00:00
def physical_resource_id ( self ) - > str :
2021-10-22 21:47:29 +00:00
return f " arn:aws:route53:::hostedzone/ { self . hosted_zone_id } "
2015-01-17 19:50:19 +00:00
2020-08-01 14:23:36 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_name_type ( ) - > str :
return " "
2020-08-01 14:23:36 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def cloudformation_type ( ) - > str :
2020-08-01 14:23:36 +00:00
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-recordsetgroup.html
return " AWS::Route53::RecordSetGroup "
2015-01-17 15:17:25 +00:00
@classmethod
2023-04-19 10:25:48 +00:00
def create_from_cloudformation_json ( # type: ignore[misc]
cls ,
resource_name : str ,
cloudformation_json : Any ,
account_id : str ,
region_name : str ,
* * kwargs : Any ,
) - > " RecordSetGroup " :
2015-01-17 15:17:25 +00:00
properties = cloudformation_json [ " Properties " ]
2017-03-05 03:31:45 +00:00
zone_name = properties . get ( " HostedZoneName " )
2022-08-13 09:49:43 +00:00
backend = route53_backends [ account_id ] [ " global " ]
2017-03-05 03:31:45 +00:00
if zone_name :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone_by_name ( zone_name )
2017-03-05 03:31:45 +00:00
else :
2022-08-13 09:49:43 +00:00
hosted_zone = backend . get_hosted_zone ( properties [ " HostedZoneId " ] )
2015-01-17 15:17:25 +00:00
record_sets = properties [ " RecordSets " ]
for record_set in record_sets :
2015-01-17 19:50:19 +00:00
hosted_zone . add_rrset ( record_set )
2015-01-17 15:17:25 +00:00
2015-01-17 19:50:19 +00:00
record_set_group = RecordSetGroup ( hosted_zone . id , record_sets )
2015-01-17 15:17:25 +00:00
return record_set_group
2013-11-14 19:14:14 +00:00
2021-10-22 21:47:29 +00:00
class QueryLoggingConfig ( BaseModel ) :
""" QueryLoggingConfig class; this object isn ' t part of Cloudformation. """
def __init__ (
2023-04-19 10:25:48 +00:00
self ,
query_logging_config_id : str ,
hosted_zone_id : str ,
cloudwatch_logs_log_group_arn : str ,
2021-10-22 21:47:29 +00:00
) :
self . hosted_zone_id = hosted_zone_id
self . cloudwatch_logs_log_group_arn = cloudwatch_logs_log_group_arn
self . query_logging_config_id = query_logging_config_id
self . location = f " https://route53.amazonaws.com/2013-04-01/queryloggingconfig/ { self . query_logging_config_id } "
2023-04-19 10:25:48 +00:00
def to_xml ( self ) - > str :
2021-10-22 21:47:29 +00:00
template = Template (
""" <QueryLoggingConfig>
< CloudWatchLogsLogGroupArn > { { query_logging_config . cloudwatch_logs_log_group_arn } } < / CloudWatchLogsLogGroupArn >
< HostedZoneId > { { query_logging_config . hosted_zone_id } } < / HostedZoneId >
< Id > { { query_logging_config . query_logging_config_id } } < / Id >
< / QueryLoggingConfig > """
)
# The "Location" value must be put into the header; that's done in
# responses.py.
return template . render ( query_logging_config = self )
2013-11-14 19:14:14 +00:00
class Route53Backend ( BaseBackend ) :
2023-04-19 10:25:48 +00:00
def __init__ ( self , region_name : str , account_id : str ) :
2022-06-04 11:30:16 +00:00
super ( ) . __init__ ( region_name , account_id )
2023-04-19 10:25:48 +00:00
self . zones : Dict [ str , FakeZone ] = { }
self . health_checks : Dict [ str , HealthCheck ] = { }
self . resource_tags : Dict [ str , Any ] = defaultdict ( dict )
self . query_logging_configs : Dict [ str , QueryLoggingConfig ] = { }
self . delegation_sets : Dict [ str , DelegationSet ] = dict ( )
2013-11-14 19:14:14 +00:00
2022-01-27 11:28:31 +00:00
def create_hosted_zone (
2022-01-31 00:53:05 +00:00
self ,
2023-04-19 10:25:48 +00:00
name : str ,
private_zone : bool ,
vpcid : Optional [ str ] = None ,
vpcregion : Optional [ str ] = None ,
comment : Optional [ str ] = None ,
delegation_set_id : Optional [ str ] = None ,
) - > FakeZone :
2017-09-22 22:50:01 +00:00
new_id = create_route53_zone_id ( )
2022-01-31 00:53:05 +00:00
delegation_set = self . create_reusable_delegation_set (
caller_reference = f " DelSet_ { name } " , delegation_set_id = delegation_set_id
)
2022-06-10 19:33:17 +00:00
# default delegation set does not contains id
if not delegation_set_id :
delegation_set . id = " "
2022-01-27 11:28:31 +00:00
new_zone = FakeZone (
name ,
new_id ,
private_zone = private_zone ,
comment = comment ,
2022-01-31 00:53:05 +00:00
delegation_set = delegation_set ,
2022-01-27 11:28:31 +00:00
)
2022-12-14 23:58:55 +00:00
# For each public hosted zone that you create, Amazon Route 53 automatically creates a name server (NS) record
# and a start of authority (SOA) record.
# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/SOA-NSrecords.html
soa_record_set = {
" Name " : f " { name } " + ( " " if name . endswith ( " . " ) else " . " ) ,
" Type " : " SOA " ,
" TTL " : 900 ,
" ResourceRecords " : [
{
" Value " : f " { delegation_set . name_servers [ 0 ] } . hostmaster.example.com. 1 7200 900 1209600 86400 "
}
] ,
}
2022-06-10 19:33:17 +00:00
# default nameservers are also part of rrset
2022-12-14 23:58:55 +00:00
ns_record_set = {
2022-06-10 19:33:17 +00:00
" Name " : name ,
" ResourceRecords " : delegation_set . name_servers ,
" TTL " : " 172800 " ,
" Type " : " NS " ,
}
2022-12-14 23:58:55 +00:00
new_zone . add_rrset ( ns_record_set )
new_zone . add_rrset ( soa_record_set )
2022-06-14 10:14:15 +00:00
new_zone . add_vpc ( vpcid , vpcregion )
2013-11-14 19:14:14 +00:00
self . zones [ new_id ] = new_zone
return new_zone
2023-04-19 10:25:48 +00:00
def get_dnssec ( self , zone_id : str ) - > None :
2022-06-10 19:33:17 +00:00
# check if hosted zone exists
self . get_hosted_zone ( zone_id )
2023-04-19 10:25:48 +00:00
def associate_vpc_with_hosted_zone (
self , zone_id : str , vpcid : str , vpcregion : str
) - > FakeZone :
2022-06-14 10:14:15 +00:00
zone = self . get_hosted_zone ( zone_id )
if not zone . private_zone :
raise PublicZoneVPCAssociation ( )
zone . add_vpc ( vpcid , vpcregion )
return zone
2023-04-19 10:25:48 +00:00
def disassociate_vpc_from_hosted_zone ( self , zone_id : str , vpcid : str ) - > FakeZone :
2022-06-14 10:14:15 +00:00
zone = self . get_hosted_zone ( zone_id )
if len ( zone . vpcs ) < = 1 :
raise LastVPCAssociation ( )
zone . delete_vpc ( vpcid )
return zone
2023-04-19 10:25:48 +00:00
def change_tags_for_resource ( self , resource_id : str , tags : Any ) - > None :
2016-09-21 00:41:23 +00:00
if " Tag " in tags :
2016-09-23 01:38:47 +00:00
if isinstance ( tags [ " Tag " ] , list ) :
for tag in tags [ " Tag " ] :
self . resource_tags [ resource_id ] [ tag [ " Key " ] ] = tag [ " Value " ]
else :
key , value = ( tags [ " Tag " ] [ " Key " ] , tags [ " Tag " ] [ " Value " ] )
self . resource_tags [ resource_id ] [ key ] = value
2016-09-21 00:41:23 +00:00
else :
2016-09-23 01:38:47 +00:00
if " Key " in tags :
if isinstance ( tags [ " Key " ] , list ) :
for key in tags [ " Key " ] :
2016-09-21 00:41:23 +00:00
del self . resource_tags [ resource_id ] [ key ]
else :
2016-09-23 01:38:47 +00:00
del self . resource_tags [ resource_id ] [ tags [ " Key " ] ]
2016-09-21 00:41:23 +00:00
2023-04-19 10:25:48 +00:00
def list_tags_for_resource ( self , resource_id : str ) - > Dict [ str , str ] :
2016-09-21 00:41:23 +00:00
if resource_id in self . resource_tags :
return self . resource_tags [ resource_id ]
2019-08-28 18:55:19 +00:00
return { }
2016-09-21 00:41:23 +00:00
2023-04-19 10:25:48 +00:00
def list_resource_record_sets (
self , zone_id : str , start_type : str , start_name : str , max_items : int
) - > Tuple [ List [ RecordSet ] , Optional [ str ] , Optional [ str ] , bool ] :
2022-01-31 00:53:05 +00:00
"""
The StartRecordIdentifier - parameter is not yet implemented
"""
2021-12-08 15:42:08 +00:00
the_zone = self . get_hosted_zone ( zone_id )
2022-01-31 00:53:05 +00:00
all_records = list ( the_zone . get_record_sets ( start_type , start_name ) )
records = all_records [ 0 : max_items ]
next_record = all_records [ max_items ] if len ( all_records ) > max_items else None
next_start_name = next_record . name if next_record else None
next_start_type = next_record . type_ if next_record else None
is_truncated = next_record is not None
return records , next_start_name , next_start_type , is_truncated
2021-12-08 15:42:08 +00:00
2023-04-19 10:25:48 +00:00
def change_resource_record_sets (
self , zoneid : str , change_list : List [ Dict [ str , Any ] ]
) - > None :
2021-12-08 15:42:08 +00:00
the_zone = self . get_hosted_zone ( zoneid )
2022-11-30 23:35:20 +00:00
2022-12-21 23:38:27 +00:00
for value in change_list :
if value [ " Action " ] == " CREATE " and value in the_zone . rr_changes :
name = value [ " ResourceRecordSet " ] [ " Name " ] + " . "
_type = value [ " ResourceRecordSet " ] [ " Type " ]
raise ResourceRecordAlreadyExists ( name = name , _type = _type )
2022-11-30 23:35:20 +00:00
2022-12-10 11:07:30 +00:00
for value in change_list :
if value [ " Action " ] == " DELETE " :
# To delete a resource record set, you must specify all the same values that you specified when you created it.
corresponding_create = copy . deepcopy ( value )
corresponding_create [ " Action " ] = " CREATE "
corresponding_upsert = copy . deepcopy ( value )
corresponding_upsert [ " Action " ] = " UPSERT "
if (
corresponding_create not in the_zone . rr_changes
and corresponding_upsert not in the_zone . rr_changes
) :
msg = f " Invalid request: Expected exactly one of [AliasTarget, all of [TTL, and ResourceRecords], or TrafficPolicyInstanceId], but found none in Change with [Action=DELETE, Name= { value [ ' ResourceRecordSet ' ] [ ' Name ' ] } , Type= { value [ ' ResourceRecordSet ' ] [ ' Type ' ] } , SetIdentifier= { value [ ' ResourceRecordSet ' ] . get ( ' SetIdentifier ' , ' null ' ) } ] "
raise InvalidInput ( msg )
2021-10-12 22:04:43 +00:00
for value in change_list :
2022-11-30 23:35:20 +00:00
original_change = copy . deepcopy ( value )
2021-10-12 22:04:43 +00:00
action = value [ " Action " ]
2022-06-14 14:22:07 +00:00
if action not in ( " CREATE " , " UPSERT " , " DELETE " ) :
raise InvalidActionValue ( action )
2021-10-12 22:04:43 +00:00
record_set = value [ " ResourceRecordSet " ]
cleaned_record_name = record_set [ " Name " ] . strip ( " . " )
cleaned_hosted_zone_name = the_zone . name . strip ( " . " )
if not cleaned_record_name . endswith ( cleaned_hosted_zone_name ) :
2022-11-30 23:35:20 +00:00
raise DnsNameInvalidForZone (
name = record_set [ " Name " ] , zone_name = the_zone . name
)
2021-10-12 22:04:43 +00:00
if not record_set [ " Name " ] . endswith ( " . " ) :
record_set [ " Name " ] + = " . "
if action in ( " CREATE " , " UPSERT " ) :
if " ResourceRecords " in record_set :
resource_records = list ( record_set [ " ResourceRecords " ] . values ( ) ) [ 0 ]
if not isinstance ( resource_records , list ) :
# Depending on how many records there are, this may
# or may not be a list
resource_records = [ resource_records ]
record_set [ " ResourceRecords " ] = [
x [ " Value " ] for x in resource_records
]
if action == " CREATE " :
the_zone . add_rrset ( record_set )
else :
the_zone . upsert_rrset ( record_set )
elif action == " DELETE " :
if " SetIdentifier " in record_set :
the_zone . delete_rrset_by_id ( record_set [ " SetIdentifier " ] )
else :
the_zone . delete_rrset ( record_set )
2022-11-30 23:35:20 +00:00
the_zone . rr_changes . append ( original_change )
2021-10-12 22:04:43 +00:00
2023-04-19 10:25:48 +00:00
def list_hosted_zones ( self ) - > List [ FakeZone ] :
return list ( self . zones . values ( ) )
2013-11-14 19:14:14 +00:00
2023-04-19 10:25:48 +00:00
def list_hosted_zones_by_name (
self , dnsnames : Optional [ List [ str ] ]
) - > Tuple [ Optional [ str ] , List [ FakeZone ] ] :
if dnsnames :
dnsname = dnsnames [ 0 ] # type: ignore
2021-10-12 22:04:43 +00:00
if dnsname [ - 1 ] != " . " :
dnsname + = " . "
2023-04-19 10:25:48 +00:00
zones = [ zone for zone in self . list_hosted_zones ( ) if zone . name == dnsname ] # type: ignore
2021-10-12 22:04:43 +00:00
else :
2023-04-19 10:25:48 +00:00
dnsname = None
2021-10-12 22:04:43 +00:00
# sort by names, but with domain components reversed
# see http://boto3.readthedocs.io/en/latest/reference/services/route53.html#Route53.Client.list_hosted_zones_by_name
2023-04-19 10:25:48 +00:00
def sort_key ( zone : FakeZone ) - > str :
2021-10-12 22:04:43 +00:00
domains = zone . name . split ( " . " )
if domains [ - 1 ] == " " :
domains = domains [ - 1 : ] + domains [ : - 1 ]
return " . " . join ( reversed ( domains ) )
zones = self . list_hosted_zones ( )
zones = sorted ( zones , key = sort_key )
2023-04-19 10:25:48 +00:00
return dnsname , zones # type: ignore
2021-10-12 22:04:43 +00:00
2023-04-19 10:25:48 +00:00
def list_hosted_zones_by_vpc ( self , vpc_id : str ) - > List [ Dict [ str , Any ] ] :
2022-03-11 21:28:45 +00:00
"""
Pagination is not yet implemented
"""
2022-01-29 11:11:24 +00:00
zone_list = [ ]
for zone in self . list_hosted_zones ( ) :
2022-03-15 13:27:17 +00:00
if zone . private_zone is True :
2022-01-29 11:11:24 +00:00
this_zone = self . get_hosted_zone ( zone . id )
2022-06-14 10:14:15 +00:00
for vpc in this_zone . vpcs :
if vpc [ " vpc_id " ] == vpc_id :
zone_list . append (
{
2022-06-15 20:01:11 +00:00
" HostedZoneId " : zone . id ,
2022-06-14 10:14:15 +00:00
" Name " : zone . name ,
2022-08-13 09:49:43 +00:00
" Owner " : { " OwningAccount " : self . account_id } ,
2022-06-14 10:14:15 +00:00
}
)
2022-01-29 11:11:24 +00:00
return zone_list
2023-04-19 10:25:48 +00:00
def get_hosted_zone ( self , id_ : str ) - > FakeZone :
2021-12-08 15:42:08 +00:00
the_zone = self . zones . get ( id_ . replace ( " /hostedzone/ " , " " ) )
if not the_zone :
raise NoSuchHostedZone ( id_ )
return the_zone
2013-11-14 19:14:14 +00:00
2023-04-19 10:25:48 +00:00
def get_hosted_zone_count ( self ) - > int :
2022-01-30 13:25:36 +00:00
return len ( self . list_hosted_zones ( ) )
2023-04-19 10:25:48 +00:00
def get_hosted_zone_by_name ( self , name : str ) - > Optional [ FakeZone ] :
2021-10-12 22:04:43 +00:00
for zone in self . list_hosted_zones ( ) :
2015-01-17 15:17:25 +00:00
if zone . name == name :
return zone
2021-10-22 21:47:29 +00:00
return None
2015-01-17 15:17:25 +00:00
2023-04-19 10:25:48 +00:00
def delete_hosted_zone ( self , id_ : str ) - > Optional [ FakeZone ] :
2021-12-08 15:42:08 +00:00
# Verify it exists
2022-06-10 19:33:17 +00:00
zone = self . get_hosted_zone ( id_ )
if len ( zone . rrsets ) > 0 :
for rrset in zone . rrsets :
if rrset . type_ != " NS " and rrset . type_ != " SOA " :
raise HostedZoneNotEmpty ( )
2017-03-17 02:45:58 +00:00
return self . zones . pop ( id_ . replace ( " /hostedzone/ " , " " ) , None )
2013-11-14 19:14:14 +00:00
2023-04-19 10:25:48 +00:00
def update_hosted_zone_comment ( self , id_ : str , comment : str ) - > FakeZone :
2022-06-14 10:14:15 +00:00
zone = self . get_hosted_zone ( id_ )
zone . comment = comment
return zone
2023-04-19 10:25:48 +00:00
def create_health_check (
self , caller_reference : str , health_check_args : Dict [ str , Any ]
) - > HealthCheck :
2022-09-28 09:35:12 +00:00
health_check_id = str ( random . uuid4 ( ) )
2021-08-22 09:51:21 +00:00
health_check = HealthCheck ( health_check_id , caller_reference , health_check_args )
2022-06-19 11:21:28 +00:00
health_check . set_children ( health_check_args . get ( " children " ) )
health_check . set_regions ( health_check_args . get ( " regions " ) )
2015-01-18 00:06:43 +00:00
self . health_checks [ health_check_id ] = health_check
return health_check
2023-04-19 10:25:48 +00:00
def update_health_check (
self , health_check_id : str , health_check_args : Dict [ str , Any ]
) - > HealthCheck :
2022-06-19 11:21:28 +00:00
health_check = self . health_checks . get ( health_check_id )
if not health_check :
2023-04-19 10:25:48 +00:00
raise NoSuchHealthCheck ( health_check_id )
2022-06-19 11:21:28 +00:00
if health_check_args . get ( " ip_address " ) :
health_check . ip_address = health_check_args . get ( " ip_address " )
if health_check_args . get ( " port " ) :
health_check . port = health_check_args . get ( " port " )
if health_check_args . get ( " resource_path " ) :
health_check . resource_path = health_check_args . get ( " resource_path " )
if health_check_args . get ( " fqdn " ) :
health_check . fqdn = health_check_args . get ( " fqdn " )
if health_check_args . get ( " search_string " ) :
health_check . search_string = health_check_args . get ( " search_string " )
if health_check_args . get ( " request_interval " ) :
health_check . request_interval = health_check_args . get ( " request_interval " )
if health_check_args . get ( " failure_threshold " ) :
health_check . failure_threshold = health_check_args . get ( " failure_threshold " )
if health_check_args . get ( " health_threshold " ) :
health_check . health_threshold = health_check_args . get ( " health_threshold " )
if health_check_args . get ( " inverted " ) :
health_check . inverted = health_check_args . get ( " inverted " )
if health_check_args . get ( " disabled " ) :
health_check . disabled = health_check_args . get ( " disabled " )
if health_check_args . get ( " enable_sni " ) :
health_check . enable_sni = health_check_args . get ( " enable_sni " )
if health_check_args . get ( " children " ) :
health_check . set_children ( health_check_args . get ( " children " ) )
if health_check_args . get ( " regions " ) :
health_check . set_regions ( health_check_args . get ( " regions " ) )
return health_check
2023-04-19 10:25:48 +00:00
def list_health_checks ( self ) - > List [ HealthCheck ] :
return list ( self . health_checks . values ( ) )
2015-01-18 00:06:43 +00:00
2023-04-19 10:25:48 +00:00
def delete_health_check ( self , health_check_id : str ) - > None :
self . health_checks . pop ( health_check_id , None )
2013-11-14 19:14:14 +00:00
2023-04-19 10:25:48 +00:00
def get_health_check ( self , health_check_id : str ) - > HealthCheck :
2022-06-10 19:33:17 +00:00
health_check = self . health_checks . get ( health_check_id )
if not health_check :
raise NoSuchHealthCheck ( health_check_id )
return health_check
2023-07-15 21:34:51 +00:00
def get_health_check_status ( self ) - > None :
pass # Logic implemented in responses.py
2021-10-22 21:47:29 +00:00
@staticmethod
2023-04-19 10:25:48 +00:00
def _validate_arn ( region : str , arn : str ) - > None :
2021-10-22 21:47:29 +00:00
match = re . match ( rf " arn:aws:logs: { region } : \ d {{ 12 }} :log-group:.+ " , arn )
if not arn or not match :
2022-06-14 14:22:07 +00:00
raise InvalidCloudWatchArn ( )
2021-10-22 21:47:29 +00:00
# The CloudWatch Logs log group must be in the "us-east-1" region.
match = re . match ( r " ^(?:[^:]+:) {3} (?P<region>[^:]+).* " , arn )
2023-04-19 10:25:48 +00:00
if not match or match . group ( " region " ) != " us-east-1 " :
2022-06-14 14:22:07 +00:00
raise InvalidCloudWatchArn ( )
2021-10-22 21:47:29 +00:00
2023-04-19 10:25:48 +00:00
def create_query_logging_config (
self , region : str , hosted_zone_id : str , log_group_arn : str
) - > QueryLoggingConfig :
2021-10-22 21:47:29 +00:00
""" Process the create_query_logging_config request. """
# Does the hosted_zone_id exist?
response = self . list_hosted_zones ( )
zones = list ( response ) if response else [ ]
for zone in zones :
if zone . id == hosted_zone_id :
break
else :
raise NoSuchHostedZone ( hosted_zone_id )
# Ensure CloudWatch Logs log ARN is valid, otherwise raise an error.
self . _validate_arn ( region , log_group_arn )
# Note: boto3 checks the resource policy permissions before checking
# whether the log group exists. moto doesn't have a way of checking
# the resource policy, so in some instances moto will complain
# about a log group that doesn't exist whereas boto3 will complain
# that "The resource policy that you're using for Route 53 query
# logging doesn't grant Route 53 sufficient permission to create
# a log stream in the specified log group."
from moto . logs import logs_backends # pylint: disable=import-outside-toplevel
2022-08-13 09:49:43 +00:00
response = logs_backends [ self . account_id ] [ region ] . describe_log_groups ( )
2021-10-22 21:47:29 +00:00
log_groups = response [ 0 ] if response else [ ]
2023-04-19 10:25:48 +00:00
for entry in log_groups : # type: ignore
2021-10-22 21:47:29 +00:00
if log_group_arn == entry [ " arn " ] :
break
else :
# There is no CloudWatch Logs log group with the specified ARN.
raise NoSuchCloudWatchLogsLogGroup ( )
# Verify there is no existing query log config using the same hosted
# zone.
for query_log in self . query_logging_configs . values ( ) :
if query_log . hosted_zone_id == hosted_zone_id :
raise QueryLoggingConfigAlreadyExists ( )
# Create an instance of the query logging config.
2022-09-28 09:35:12 +00:00
query_logging_config_id = str ( random . uuid4 ( ) )
2021-10-22 21:47:29 +00:00
query_logging_config = QueryLoggingConfig (
query_logging_config_id , hosted_zone_id , log_group_arn
)
self . query_logging_configs [ query_logging_config_id ] = query_logging_config
return query_logging_config
2023-04-19 10:25:48 +00:00
def delete_query_logging_config ( self , query_logging_config_id : str ) - > None :
2021-10-22 21:47:29 +00:00
""" Delete query logging config, if it exists. """
if query_logging_config_id not in self . query_logging_configs :
raise NoSuchQueryLoggingConfig ( )
self . query_logging_configs . pop ( query_logging_config_id )
2023-04-19 10:25:48 +00:00
def get_query_logging_config (
self , query_logging_config_id : str
) - > QueryLoggingConfig :
2021-10-22 21:47:29 +00:00
""" Return query logging config, if it exists. """
if query_logging_config_id not in self . query_logging_configs :
raise NoSuchQueryLoggingConfig ( )
return self . query_logging_configs [ query_logging_config_id ]
2023-04-29 10:40:11 +00:00
@paginate ( pagination_model = PAGINATION_MODEL ) # type: ignore[misc]
2023-04-19 10:25:48 +00:00
def list_query_logging_configs ( self , hosted_zone_id : Optional [ str ] = None ) - > List [ QueryLoggingConfig ] : # type: ignore
2021-10-22 21:47:29 +00:00
""" Return a list of query logging configs. """
if hosted_zone_id :
# Does the hosted_zone_id exist?
response = self . list_hosted_zones ( )
zones = list ( response ) if response else [ ]
for zone in zones :
if zone . id == hosted_zone_id :
break
else :
raise NoSuchHostedZone ( hosted_zone_id )
return list ( self . query_logging_configs . values ( ) )
2022-01-31 00:53:05 +00:00
def create_reusable_delegation_set (
2023-04-19 10:25:48 +00:00
self ,
caller_reference : str ,
delegation_set_id : Optional [ str ] = None ,
hosted_zone_id : Optional [ str ] = None ,
) - > DelegationSet :
name_servers : Optional [ List [ str ] ] = None
2022-01-31 00:53:05 +00:00
if hosted_zone_id :
hosted_zone = self . get_hosted_zone ( hosted_zone_id )
2023-04-19 10:25:48 +00:00
name_servers = hosted_zone . delegation_set . name_servers # type: ignore
2022-01-31 00:53:05 +00:00
delegation_set = DelegationSet (
caller_reference , name_servers , delegation_set_id
)
self . delegation_sets [ delegation_set . id ] = delegation_set
return delegation_set
2023-04-19 10:25:48 +00:00
def list_reusable_delegation_sets ( self ) - > List [ DelegationSet ] :
2022-01-31 00:53:05 +00:00
"""
Pagination is not yet implemented
"""
2023-04-19 10:25:48 +00:00
return list ( self . delegation_sets . values ( ) )
2022-01-31 00:53:05 +00:00
2023-04-19 10:25:48 +00:00
def delete_reusable_delegation_set ( self , delegation_set_id : str ) - > None :
2022-01-31 00:53:05 +00:00
self . delegation_sets . pop ( delegation_set_id , None )
2023-04-19 10:25:48 +00:00
def get_reusable_delegation_set ( self , delegation_set_id : str ) - > DelegationSet :
2022-01-31 00:53:05 +00:00
if delegation_set_id not in self . delegation_sets :
raise NoSuchDelegationSet ( delegation_set_id )
return self . delegation_sets [ delegation_set_id ]
2017-02-24 02:37:43 +00:00
2022-06-04 11:30:16 +00:00
route53_backends = BackendDict (
Route53Backend , " route53 " , use_boto3_regions = False , additional_regions = [ " global " ]
)