【问题标题】:Update DNS record in route53 using boto使用 boto 更新 route53 中的 DNS 记录
【发布时间】:2021-11-06 17:12:01
【问题描述】:

尝试使用 boto 更新 R53 中的 dns 记录时,出现以下错误:

Traceback (most recent call last):
File "testing.py", line 106, in <module>
updateDns(load_balancer_dns)
File "testing.py", line 102, in updateDns
change.commit()
File "/usr/lib/python2.6/site-packages/boto/route53/record.py", line 149, in commit
return self.connection.change_rrsets(self.hosted_zone_id, self.to_xml())
File "/usr/lib/python2.6/site-packages/boto/route53/connection.py", line 320, in change_rrsets
body)
boto.route53.exception.DNSServerError: DNSServerError: 505 HTTP Version Not Supported

以下是我用来更新 dns 条目的函数:

def updateDns(load_balancer_dns):
    r53 = boto.route53.connection.Route53Connection(aws_access_key_id=<access_key>,aws_secret_access_key=<secret_key>)
    zone_id = r53.get_hosted_zone_by_name(<domain_name>)
    print zone_id
    change = boto.route53.record.ResourceRecordSets(connection=r53,hosted_zone_id=zone_id)
    change.add_change_record("UPSERT", boto.route53.record.Record(name=<name>, type="CNAME", resource_records=load_balancer_dns, ttl=300))
    change.commit()
    print "record changed"
    return None

updateDns(load_balancer_dns)

之前还有其他人遇到过此类问题吗?

【问题讨论】:

  • 尝试将debug=2 添加到您的boto.route53.connection.Route53Connection() 通话中。它将为您提供大量输出以帮助缩小问题范围。

标签: python amazon-web-services boto


【解决方案1】:

由于这并没有真正的权威答案,所以这是一个我刚刚拼凑起来的工作脚本:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import absolute_import, print_function

from time import sleep

import boto


def main():
    """Entrypoint."""
    r53 = boto.connect_route53()
    zones = r53.get_all_hosted_zones()['ListHostedZonesResponse']['HostedZones']
    private_zone = find_private_zone('sub.mydomain.com.', zones)
    reverse_zone = find_private_zone('100.10.in-addr.arpa.', zones)

    upsert_record(r53, private_zone, 'dangus.sub.mydomain.com.', '127.0.0.1', 'A', wait=True)
    delete_record(r53, private_zone, 'dangus.sub.mydomain.com.', '127.0.0.1', 'A', wait=True)


def find_private_zone(name, zones):
    for zone in zones:
        if zone.get('Name') == name and zone.get('Config', {}).get('PrivateZone') in [True, 'true']:
            return zone

    return None


def find_record(r53, zone_id, name, record_type):
    records = r53.get_all_rrsets(zone_id)

    for record in records:
        if record.name == name and record.type == record_type:
            return record

    return None


def upsert_record(r53, zone, name, record, record_type, ttl=60, wait=False):
    print("Inserting record {}[{}] -> {}; TTL={}".format(name, record_type, record, ttl))
    recordset = boto.route53.record.ResourceRecordSets(connection=r53, hosted_zone_id=zone.get('Id').split('/')[-1])
    recordset.add_change_record('UPSERT', boto.route53.record.Record(
        name=name,
        type=record_type,
        resource_records=[record],
        ttl=ttl
    ))
    changeset = recordset.commit()

    change_id = changeset['ChangeResourceRecordSetsResponse']['ChangeInfo']['Id'].split('/')[-1]

    while wait:
        status = r53.get_change(change_id)['GetChangeResponse']['ChangeInfo']['Status']
        if status == 'INSYNC':
            break

        sleep(10)


def delete_record(r53, zone, name, record, record_type, wait=False):
    print("Deleting record {}[{}] -> {}".format(name, record_type, record))

    zone_id = zone.get('Id').split('/')[-1]
    record = find_record(r53, zone_id, name, record_type)

    if not record:
        print("No record exists.")
        return

    recordset = boto.route53.record.ResourceRecordSets(connection=r53, hosted_zone_id=zone.get('Id').split('/')[-1])
    recordset.add_change_record('DELETE', record)
    changeset = recordset.commit()

    change_id = changeset['ChangeResourceRecordSetsResponse']['ChangeInfo']['Id'].split('/')[-1]

    while wait:
        status = r53.get_change(change_id)['GetChangeResponse']['ChangeInfo']['Status']
        if status == 'INSYNC':
            break

        sleep(10)


if __name__ == "__main__":
    main()

不幸的是,我使用过的所有 API 都没有良好的 Route 53 实现,您最终必须使用这些字典查找来查看服务实际返回的 XML。

一些陷阱:

  • 始终使用 FQDN,这意味着每条记录都应以点结尾。
  • 您不能只获取您要查找的托管区域,您需要获取所有托管区域并搜索您要查找的区域(即:与给定名称匹配的私有区域)。李>
  • 您必须从托管区域中解析出 ID。
  • 您必须从更改集中解析出 ID。
  • 删除条目时,您必须首先捕获记录的当前状态(如果存在),然后将该值作为删除更改的一部分发送到 Route 53。

这使得 API 使用起来真的很麻烦,但至少它解决了 RFC-1925 规则 1:它有效。

【讨论】:

    【解决方案2】:
        #!/usr/bin/env python
        # -*- coding: utf-8 -*-
        # src: https://stackoverflow.com/a/47166985/65706
        # courtesy of: Naftuli Kay
    
        #
    
        from __future__ import absolute_import, print_function
        from time import sleep
    
        import argparse
        import boto
        import pprint
        import sys
    
        def set_vars():
            usage_examples = '''
                clear ; poetry run python process_dns.py --action upsert --dns-zone cgfinics.com --dns-name dev.cgfinics.com --dns-value 168.10.172.10 --record-type A
                clear ; poetry run python process_dns.py --action upsert --dns-zone cgfinics.com --dns-name www.dev.cgfinics.com --dns-value  www.dev.cgfinics.com --record-type CNAME
                clear ; poetry run python process_dns.py --action delete --dns-zone cgfinics.com --dns-name dev.cgfinics.com
            '''
            parser = argparse.ArgumentParser('A quick and dirty DNS upsert to aws with boto \n\n' + usage_examples)
            parser.add_argument('--action', required=True, nargs='?',
                help="The action to perform - upsert or delete ")
            parser.add_argument('--dns-zone', required=True, nargs='?',
                help="The DNS zone to process ")
            parser.add_argument('--dns-name', required=True, nargs='?',
                help="The DNS name to process ")
            parser.add_argument('--dns-value', required=False, nargs='?',
                help="The DNS value to process ")
            parser.add_argument('--record-type', required=True, nargs='?',
                help="The DNS record type - could be A, CNAME ")
            args = parser.parse_args()
            return args
    
    
        def main():
            """Entrypoint."""
            args = set_vars()
            action = args.action
            r53 = boto.connect_route53()
            zones = r53.get_all_hosted_zones()['ListHostedZonesResponse']['HostedZones']
            dns_zone = args.dns_zone + '.' if not args.dns_zone.endswith('.') else args.dns_zone
            public_zone = find_public_zone(dns_zone , zones)
            dns_name = args.dns_name + '.' if not args.dns_name.endswith('.') else args.dns_name
            dns_value = args.dns_value
            record_type = args.record_type
    
            if action == "upsert":
                upsert_record(r53, public_zone, dns_name, dns_value, record_type, wait=True)
                sys.exit(0)
    
            if action == "delete":
                delete_record(r53, public_zone, dns_name, dns_value, record_type, wait=True)
                sys.exit(0)
    
            print("only the upser and delete actions are supported !!!")
            sys.exit(1)
    
    
        def find_public_zone(name, zones):
            for zone in zones:
                if zone.get('Name') == name and zone.get('Config', {}).get('PrivateZone') in [True, 'false']:
                    return zone
    
            return None
    
    
        def find_record(r53, zone_id, name, record_type):
            records = r53.get_all_rrsets(zone_id)
    
            for record in records:
                if record.name == name and record.type == record_type:
                    return record
    
            return None
    
    
        def upsert_record(r53, zone, name, record, record_type, ttl=60, wait=False):
            print("Inserting record {}[{}] -> {}; TTL={}".format(name, record_type, record, ttl))
            recordset = boto.route53.record.ResourceRecordSets(connection=r53, hosted_zone_id=zone.get('Id').split('/')[-1])
            recordset.add_change_record('UPSERT', boto.route53.record.Record(
                name=name,
                type=record_type,
                resource_records=[record],
                ttl=ttl
            ))
            changeset = recordset.commit()
    
            change_id = changeset['ChangeResourceRecordSetsResponse']['ChangeInfo']['Id'].split('/')[-1]
    
            while wait:
                status = r53.get_change(change_id)['GetChangeResponse']['ChangeInfo']['Status']
                if status == 'INSYNC':
                    break
    
                sleep(6)
    
    
        def delete_record(r53, zone, name, record, record_type, wait=False):
            print("Deleting record {}[{}] -> {}".format(name, record_type, record))
    
            zone_id = zone.get('Id').split('/')[-1]
            record = find_record(r53, zone_id, name, record_type)
    
            if not record:
                print("No record exists.")
                return
    
            recordset = boto.route53.record.ResourceRecordSets(connection=r53, hosted_zone_id=zone.get('Id').split('/')[-1])
            recordset.add_change_record('DELETE', record)
            changeset = recordset.commit()
    
            change_id = changeset['ChangeResourceRecordSetsResponse']['ChangeInfo']['Id'].split('/')[-1]
    
            while wait:
                status = r53.get_change(change_id)['GetChangeResponse']['ChangeInfo']['Status']
                if status == 'INSYNC':
                    break
    
                sleep(10)
    
    
        if __name__ == "__main__":
            main()
    

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,所以作为“调试”练习,我做了一个

      print zone_id
      

      我注意到该对象是一个 dict / JSON 响应,所以我将代码更改为

      zone_id = self.r53.get_hosted_zone_by_name(self.domain).get("GetHostedZoneResponse").get("HostedZone").get("Id")
      

      这似乎对我有用 - 我现在得到一个 403,但至少应该更容易修复。

      免责声明 - Python 新手,所以不确定这是否真的是正确的方法!

      【讨论】:

        【解决方案4】:

        仅供参考:

        获取 change_id,然后使用 boto 连接 (conn) 检查状态,直到显示“INSYNC”

        例如

         def updateDns(load_balancer_dns):
            r53 = boto.route53.connection.Route53Connection(aws_access_key_id=<access_key>,aws_secret_access_key=<secret_key>)
            zone_id = r53.get_hosted_zone_by_name(<domain_name>)
            print zone_id
            change = boto.route53.record.ResourceRecordSets(connection=r53,hosted_zone_id=zone_id)
            change.add_change_record("UPSERT", boto.route53.record.Record(name=<name>, type="CNAME", resource_records=load_balancer_dns, ttl=300))
            _changes = change.commit()
        
            change_id = _changes["ChangeResourceRecordSetsResponse"]["ChangeInfo"]["Id"].split("/")[-1]
        
            while True:
                status = r53.get_change(change_id)["GetChangeResponse"]["ChangeInfo"]["Status"]
                if status == "INSYNC": break
                sleep(10)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-10-21
          • 1970-01-01
          • 2012-03-31
          • 1970-01-01
          • 1970-01-01
          • 2018-11-16
          • 2016-11-03
          • 1970-01-01
          相关资源
          最近更新 更多