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')