· 9 years ago · Oct 01, 2016, 11:12 AM
1#!/bin/bash
2
3local CONF="$LE_WORKING_DIR/dnsapi/dns-route53-python.conf"
4[ -r "$CONF" ] && . $CONF
5
6if [ -z "$AWS" ]; then
7 AWS=`which aws 2>/dev/null`
8fi
9
10#Usage: add _acme-challenge.www.domain.com "XKrx...."
11dns-route53-python-add() {
12 if [ -z "$AWS" ]; then
13 _err "AWS not found. Please install globally using PIP or update AWS variable in $CONF"
14 return 1
15 fi
16
17 if [ ! -x "$AWS" ]; then
18 _err "AWS binary located at '$AWS' is not executable. Cannot continue."
19 return 1
20 fi
21
22 PROFILE=""
23 [ ! -z "$AWS53_PROFILE" ] && PROFILE="--profile $AWS53_PROFILE"
24 if ! $AWS configure $PROFILE list | grep -q access_key; then
25 _err "AWS is not configured with an access_key."
26 return 1
27 fi
28
29 if ! $AWS configure $PROFILE list | grep -q secret_key; then
30 _err "AWS is not configured with a secret_key."
31 return 1
32 fi
33
34 fulldomain=$1
35 _find_root $fulldomain
36 if [ $? -gt 0 ]; then
37 _err "ZoneID could not be determined"
38 _err "Failed to change DNS"
39 return 1
40 fi
41
42 # Update txtvalue to have \" at the beginning and end for JSON encoding
43 txtvalue=\\\"`echo $2 | sed -e 's/"$//' -e 's/^"//'`\\\"
44 _debug txtvalue $txtvalue
45
46 # generate JSON update code
47 JSONFILE=$(mktemp)
48 echo '{"Changes": [{"Action": "UPSERT", "ResourceRecordSet": {"Name": "'$fulldomain'", "Type": "TXT", "TTL": 300, "ResourceRecords": [{"Value": "'$txtvalue'"}]}}]}' > $JSONFILE
49 _debug JSONFILE $JSONFILE
50
51 ERRFILE=$(mktemp)
52 _info "Submitting request to change DNS for $fulldomain TXT record to $txtvalue"
53 _debug "----JSON----"
54 [ ! -z "$DEBUG" ] && cat $JSONFILE
55 _debug "----JSON----"
56 RESULT=`$AWS --output text $PROFILE route53 change-resource-record-sets --hosted-zone-id $_domain_id --change-batch file://$JSONFILE 2>$ERRFILE | grep "CHANGEINFO"`
57 _debug RESULT "$RESULT"
58 rm -f $JSONFILE
59
60 LINES=`wc -l < $ERRFILE`
61 if [ $LINES -gt 0 ]; then
62 _info "Error output of AWS command:"
63 cat $ERRFILE
64 fi
65 rm -f $ERRFILE
66
67 RESULT_STATUS_CODE=`echo $RESULT | awk '{ print $3; }'`
68 _debug RESULT_STATUS_CODE "$RESULT_STATUS_CODE"
69 CHANGE_ID=`echo $RESULT | awk '{ print $2; }'`
70 _debug CHANGE_ID "$CHANGE_ID"
71
72 # If we find a pending state, loop until we find a insync state.
73 if [ "$RESULT_STATUS_CODE" == "PENDING" ]; then
74 _info "State of change request is $RESULT_STATUS_CODE."
75 for run in {1..3}
76 do
77 sleep 15
78 _check-changeid $CHANGE_ID
79 _info "State of change request is $RESULT_STATUS_CODE."
80 [ "$RESULT_STATUS_CODE" == "INSYNC" ] && break;
81 done
82 fi
83
84 # final state check. If INSYNC, then success, otherwise failure.
85 if [ "$RESULT_STATUS_CODE" == "INSYNC" ]; then
86 _debug "Result status code $RESULT_STATUS_CODE found. DNS added."
87 _info "DNS added."
88 return 0
89 else
90 _err "Failed to change DNS"
91 return 1
92 fi
93}
94
95#################### Private functions bellow ##################################
96
97
98#Usage: _find_root _acme-challenge.www.domain.com
99#returns
100# _sub_domain=_acme-challenge.www
101# _domain=domain.com
102# _domain_id=Z20IC834500000
103_find_root() {
104 local domain=$1
105 local i=2
106 local p=1
107 local h
108 while [ '1' ]; do
109 local h=$(printf $domain | rev | cut -d . -f-$i | rev)
110 if [ -z "$h" ] ; then
111 #not valid
112 return 1
113 fi
114
115 if _test_domain $h; then
116 if [ ! -z $_domain_id ]; then
117 _sub_domain=$(printf $domain | cut -d . -f 1-$p)
118 _domain=$h
119 return 0
120 fi
121 fi
122 p=$i
123 let "i+=1"
124 done
125 return 1
126}
127
128#Usage: _test_domain domain.com
129_test_domain() {
130 local basedomain=$1
131 local errfile=$(mktemp)
132 _info "Searching for ZoneID for $basedomain"
133 _domain_id=`$AWS --output text $PROFILE route53 list-hosted-zones-by-name --dns-name $basedomain 2>$errfile | grep "HOSTEDZONES" | awk '{ print $3; }' | sed -r 's/\/hostedzone\/([A-Z0-9]+)/\1/'`
134 _debug _domain_id $_domain_id
135 local errorcount=`wc -l < $errfile`
136 return $errorcount
137}
138
139#Usage: _check-changeid /change/C30DVTKZ000000
140_check-changeid() {
141 # aws --output text route53 get-change --id /change/C30DVTKZ000000
142 RESULT=`$AWS --output text $PROFILE route53 get-change --id $1`
143 _debug RESULT "$RESULT"
144 # CHANGEINFO /change/C30DVTKZ000000 PENDING 2016-03-08T19:15:48.323Z
145 RESULT_STATUS_CODE=`echo $RESULT | awk '{ print $3; }'`
146 _debug RESULT_STATUS_CODE "$RESULT_STATUS_CODE"
147}
148
149_debug() {
150
151 if [ -z "$DEBUG" ] ; then
152 return
153 fi
154
155 if [ -z "$2" ] ; then
156 echo $1
157 else
158 echo "$1"="$2"
159 fi
160}
161
162_info() {
163 if [ -z "$2" ] ; then
164 echo "$1"
165 else
166 echo "$1"="$2"
167 fi
168}
169
170_err() {
171 if [ -z "$2" ] ; then
172 echo "$1" >&2
173 else
174 echo "$1"="$2" >&2
175 fi
176}