sigs.k8s.io/external-dns@v0.14.1/scripts/update_route53_k8s_txt_owner.py (about) 1 #!/usr/bin/env python 2 3 # Copyright 2018 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # This is a script that we wrote to try to help the migration over to using external-dns. 18 # This script looks at kubernetes ingresses and services (which are the two things we have 19 # external-dns looking at) and compares them to existing TXT and A records in route53 to 20 # find out where there are gaps. It then assigns the heritage and owner TXT records where 21 # needed so external-dns can take over managing those resources. You can modify the script 22 # to only look at one or the other if needed. 23 # 24 # pip install kubernetes boto3 25 26 import boto3 27 from kubernetes import client, config 28 29 # replace with your hosted zone id 30 hosted_zone_id = '' 31 # replace with your txt-owner-id you are using 32 # inside of your external-dns controller 33 txt_owner_id = '' 34 35 # change to false if you have external-dns not looking at services 36 external_dns_manages_services = True 37 38 # change to false if you have external-dns not looking at ingresses 39 external_dns_manages_ingresses = True 40 41 config.load_kube_config() 42 43 # grab all the domains that k8s thinks it is going to 44 # manage (services with domainName specified and 45 # ingress hosts) 46 k8s_domains = [] 47 48 if external_dns_manages_services: 49 v1 = client.CoreV1Api() 50 svcs = v1.list_service_for_all_namespaces() 51 for i in svcs.items: 52 annotations = i.metadata.annotations 53 if annotations is not None and 'domainName' in annotations: 54 k8s_domains.extend(annotations['domainName'].split(',')) 55 56 if external_dns_manages_ingresses: 57 ev1 = client.NetworkingV1Api() 58 ings = ev1.list_ingress_for_all_namespaces() 59 for i in ings.items: 60 for r in i.spec.rules: 61 if r.host not in k8s_domains: 62 k8s_domains.append(r.host) 63 64 65 r53client = boto3.client('route53') 66 67 # grab the existing route53 domains and identify gaps where a domain may be 68 # missing a txt record pair 69 existing_r53_txt_domains=[] 70 existing_r53_domains=[] 71 has_next = True 72 next_record_name, next_record_type='','' 73 74 while has_next: 75 if next_record_name is not '' and next_record_type is not '': 76 resource_records = r53client.list_resource_record_sets(HostedZoneId=hosted_zone_id, 77 StartRecordName=next_record_name, 78 StartRecordType=next_record_type) 79 else: 80 resource_records = r53client.list_resource_record_sets(HostedZoneId=hosted_zone_id) 81 82 for r in resource_records['ResourceRecordSets']: 83 if r['Type'] == 'TXT': 84 existing_r53_txt_domains.append(r['Name'][:-1]) 85 elif r['Type'] == 'A': 86 existing_r53_domains.append(r['Name'][:-1]) 87 has_next = resource_records['IsTruncated'] 88 if has_next: 89 next_record_name, next_record_type = resource_records['NextRecordName'], resource_records['NextRecordType'] 90 91 # grab only the domains in route53 that kubernetes is managing 92 r53_k8s_domains = [r for r in k8s_domains if r in existing_r53_domains] 93 # from those find the ones that do not have matching txt entries 94 missing_k8s_txt = [r for r in r53_k8s_domains if r not in existing_r53_txt_domains] 95 96 # make the change batch for the route53 call, modify this as needed 97 change_batch=[] 98 for r in missing_k8s_txt: 99 change_batch.append( 100 { 101 'Action': 'CREATE', 102 'ResourceRecordSet': { 103 'Name': r, 104 'Type': 'TXT', 105 'TTL': 300, 106 'ResourceRecords': [ 107 { 108 'Value': '\heritage=external-dns,owner="' + txt_owner_id + '\"' 109 }, 110 ] 111 } 112 }) 113 114 print('This will create the following resources') 115 print(change_batch) 116 response = input("Good to go? ") 117 118 if response.lower() in ['y', 'yes', 'yup', 'ok', 'sure', 'why not', 'why not?']: 119 print('Updating route53') 120 change_response = r53client.change_resource_record_sets( 121 HostedZoneId=hosted_zone_id, 122 ChangeBatch={ 123 'Changes': change_batch 124 }) 125 print('Submitted change request to route53. Details below.') 126 print(change_response) 127 else: 128 print('No changes were made')