]> git.proxmox.com Git - mirror_acme.sh.git/blame - dnsapi/dns_openstack.sh
Merge pull request #3734 from acmesh-official/dev
[mirror_acme.sh.git] / dnsapi / dns_openstack.sh
CommitLineData
aad9afad
AB
1#!/usr/bin/env sh
2
3# OpenStack Designate API plugin
4#
5# This requires you to have OpenStackClient and python-desginateclient
6# installed.
7#
8# You will require Keystone V3 credentials loaded into your environment, which
9# could be either password or v3applicationcredential type.
10#
11# Author: Andy Botting <andy@andybotting.com>
12
13######## Public functions #####################
14
15# Usage: dns_openstack_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
16dns_openstack_add() {
17 fulldomain=$1
18 txtvalue=$2
19 _debug fulldomain "$fulldomain"
20 _debug txtvalue "$txtvalue"
21
22 _dns_openstack_credentials || return $?
23 _dns_openstack_check_setup || return $?
24 _dns_openstack_find_zone || return $?
25 _dns_openstack_get_recordset || return $?
26 _debug _recordset_id "$_recordset_id"
27 if [ -n "$_recordset_id" ]; then
28 _dns_openstack_get_records || return $?
29 _debug _records "$_records"
30 fi
31 _dns_openstack_create_recordset || return $?
32}
33
34# Usage: dns_openstack_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
35# Remove the txt record after validation.
36dns_openstack_rm() {
37 fulldomain=$1
38 txtvalue=$2
39 _debug fulldomain "$fulldomain"
40 _debug txtvalue "$txtvalue"
41
42 _dns_openstack_credentials || return $?
43 _dns_openstack_check_setup || return $?
44 _dns_openstack_find_zone || return $?
45 _dns_openstack_get_recordset || return $?
46 _debug _recordset_id "$_recordset_id"
47 if [ -n "$_recordset_id" ]; then
48 _dns_openstack_get_records || return $?
49 _debug _records "$_records"
50 fi
51 _dns_openstack_delete_recordset || return $?
52}
53
54#################### Private functions below ##################################
55
56_dns_openstack_create_recordset() {
57
58 if [ -z "$_recordset_id" ]; then
59 _info "Creating a new recordset"
60 if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record "$txtvalue" "$_zone_id" "$fulldomain."); then
61 _err "No recordset ID found after create"
62 return 1
63 fi
64 else
65 _info "Updating existing recordset"
66 # Build new list of --record <rec> args for update
67 _record_args="--record $txtvalue"
68 for _rec in $_records; do
69 _record_args="$_record_args --record $_rec"
70 done
71 # shellcheck disable=SC2086
72 if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then
73 _err "Recordset update failed"
74 return 1
75 fi
76 fi
77
78 _max_retries=60
79 _sleep_sec=5
80 _retry_times=0
81 while [ "$_retry_times" -lt "$_max_retries" ]; do
82 _retry_times=$(_math "$_retry_times" + 1)
83 _debug3 _retry_times "$_retry_times"
84
85 _record_status=$(openstack recordset show -c status -f value "$_zone_id" "$_recordset_id")
86 _info "Recordset status is $_record_status"
87 if [ "$_record_status" = "ACTIVE" ]; then
88 return 0
89 elif [ "$_record_status" = "ERROR" ]; then
90 return 1
91 else
92 _sleep $_sleep_sec
93 fi
94 done
95
96 _err "Recordset failed to become ACTIVE"
97 return 1
98}
99
100_dns_openstack_delete_recordset() {
101
102 if [ "$_records" = "$txtvalue" ]; then
103 _info "Only one record found, deleting recordset"
104 if ! openstack recordset delete "$_zone_id" "$fulldomain." >/dev/null; then
105 _err "Failed to delete recordset"
106 return 1
107 fi
108 else
109 _info "Found existing records, updating recordset"
110 # Build new list of --record <rec> args for update
111 _record_args=""
112 for _rec in $_records; do
113 if [ "$_rec" = "$txtvalue" ]; then
114 continue
115 fi
116 _record_args="$_record_args --record $_rec"
117 done
118 # shellcheck disable=SC2086
119 if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then
120 _err "Recordset update failed"
121 return 1
122 fi
123 fi
124}
125
126_dns_openstack_get_root() {
127 # Take the full fqdn and strip away pieces until we get an exact zone name
128 # match. For example, _acme-challenge.something.domain.com might need to go
129 # into something.domain.com or domain.com
130 _zone_name=$1
131 _zone_list=$2
132 while [ "$_zone_name" != "" ]; do
133 _zone_name="$(echo "$_zone_name" | sed 's/[^.]*\.*//')"
134 echo "$_zone_list" | while read -r id name; do
135 if _startswith "$_zone_name." "$name"; then
136 echo "$id"
137 fi
138 done
139 done | _head_n 1
140}
141
142_dns_openstack_find_zone() {
143 if ! _zone_list="$(openstack zone list -c id -c name -f value)"; then
144 _err "Can't list zones. Check your OpenStack credentials"
145 return 1
146 fi
147 _debug _zone_list "$_zone_list"
148
149 if ! _zone_id="$(_dns_openstack_get_root "$fulldomain" "$_zone_list")"; then
150 _err "Can't find a matching zone. Check your OpenStack credentials"
151 return 1
152 fi
153 _debug _zone_id "$_zone_id"
154}
155
156_dns_openstack_get_records() {
157 if ! _records=$(openstack recordset show -c records -f value "$_zone_id" "$fulldomain."); then
158 _err "Failed to get records"
159 return 1
160 fi
161 return 0
162}
163
164_dns_openstack_get_recordset() {
165 if ! _recordset_id=$(openstack recordset list -c id -f value --name "$fulldomain." "$_zone_id"); then
166 _err "Failed to get recordset"
167 return 1
168 fi
169 return 0
170}
171
172_dns_openstack_check_setup() {
173 if ! _exists openstack; then
174 _err "OpenStack client not found"
175 return 1
176 fi
177}
178
179_dns_openstack_credentials() {
180 _debug "Check OpenStack credentials"
181
182 # If we have OS_AUTH_URL already set in the environment, then assume we want
183 # to use those, otherwise use stored credentials
184 if [ -n "$OS_AUTH_URL" ]; then
185 _debug "OS_AUTH_URL env var found, using environment"
186 else
187 _debug "OS_AUTH_URL not found, loading stored credentials"
188 OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}"
189 OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}"
190 OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}"
191 OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}"
192 OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}"
193 OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}"
194 OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}"
195 OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}"
196 OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}"
197 OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}"
198 OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}"
199 OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}"
200 OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}"
201 fi
202
203 # Check each var and either save or clear it depending on whether its set.
204 # The helps us clear out old vars in the case where a user may want
205 # to switch between password and app creds
206 _debug "OS_AUTH_URL" "$OS_AUTH_URL"
207 if [ -n "$OS_AUTH_URL" ]; then
208 export OS_AUTH_URL
209 _saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL"
210 else
211 unset OS_AUTH_URL
212 _clearaccountconf SAVED_OS_AUTH_URL
213 fi
214
215 _debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION"
216 if [ -n "$OS_IDENTITY_API_VERSION" ]; then
217 export OS_IDENTITY_API_VERSION
218 _saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION"
219 else
220 unset OS_IDENTITY_API_VERSION
221 _clearaccountconf SAVED_OS_IDENTITY_API_VERSION
222 fi
223
224 _debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE"
225 if [ -n "$OS_AUTH_TYPE" ]; then
226 export OS_AUTH_TYPE
227 _saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE"
228 else
229 unset OS_AUTH_TYPE
230 _clearaccountconf SAVED_OS_AUTH_TYPE
231 fi
232
233 _debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID"
234 if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then
235 export OS_APPLICATION_CREDENTIAL_ID
236 _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID"
237 else
238 unset OS_APPLICATION_CREDENTIAL_ID
239 _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID
240 fi
241
242 _secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET"
243 if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
244 export OS_APPLICATION_CREDENTIAL_SECRET
245 _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET"
246 else
247 unset OS_APPLICATION_CREDENTIAL_SECRET
248 _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET
249 fi
250
251 _debug "OS_USERNAME" "$OS_USERNAME"
252 if [ -n "$OS_USERNAME" ]; then
253 export OS_USERNAME
254 _saveaccountconf_mutable OS_USERNAME "$OS_USERNAME"
255 else
256 unset OS_USERNAME
257 _clearaccountconf SAVED_OS_USERNAME
258 fi
259
260 _secure_debug "OS_PASSWORD" "$OS_PASSWORD"
261 if [ -n "$OS_PASSWORD" ]; then
262 export OS_PASSWORD
263 _saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD"
264 else
265 unset OS_PASSWORD
266 _clearaccountconf SAVED_OS_PASSWORD
267 fi
268
269 _debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME"
270 if [ -n "$OS_PROJECT_NAME" ]; then
271 export OS_PROJECT_NAME
272 _saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME"
273 else
274 unset OS_PROJECT_NAME
275 _clearaccountconf SAVED_OS_PROJECT_NAME
276 fi
277
278 _debug "OS_PROJECT_ID" "$OS_PROJECT_ID"
279 if [ -n "$OS_PROJECT_ID" ]; then
280 export OS_PROJECT_ID
281 _saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID"
282 else
283 unset OS_PROJECT_ID
284 _clearaccountconf SAVED_OS_PROJECT_ID
285 fi
286
287 _debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME"
288 if [ -n "$OS_USER_DOMAIN_NAME" ]; then
289 export OS_USER_DOMAIN_NAME
290 _saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME"
291 else
292 unset OS_USER_DOMAIN_NAME
293 _clearaccountconf SAVED_OS_USER_DOMAIN_NAME
294 fi
295
296 _debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
297 if [ -n "$OS_USER_DOMAIN_ID" ]; then
298 export OS_USER_DOMAIN_ID
299 _saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID"
300 else
301 unset OS_USER_DOMAIN_ID
302 _clearaccountconf SAVED_OS_USER_DOMAIN_ID
303 fi
304
305 _debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME"
306 if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then
307 export OS_PROJECT_DOMAIN_NAME
308 _saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME"
309 else
310 unset OS_PROJECT_DOMAIN_NAME
311 _clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME
312 fi
313
314 _debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID"
315 if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then
316 export OS_PROJECT_DOMAIN_ID
317 _saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID"
318 else
319 unset OS_PROJECT_DOMAIN_ID
320 _clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID
321 fi
322
323 if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then
324 # Application Credential auth
325 if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
326 _err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID"
327 _err "and OS_APPLICATION_CREDENTIAL_SECRET must be set."
328 _err "Please check your credentials and try again."
329 return 1
330 fi
331 else
332 # Password auth
333 if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then
334 _err "OpenStack username or password not found."
335 _err "Please check your credentials and try again."
336 return 1
337 fi
338
339 if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then
340 _err "When using password authentication, OS_PROJECT_NAME or"
341 _err "OS_PROJECT_ID must be set."
342 _err "Please check your credentials and try again."
343 return 1
344 fi
345 fi
346
347 return 0
348}