summaryrefslogtreecommitdiff
path: root/devstack/exercise.sh
blob: e5f8e10ac9aacbd9ea10a0960540b8748743af6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#!/usr/bin/env bash

# **designate.sh**

# Simple Tests to verify designate is running

echo "*********************************************************************"
echo "Begin DevStack Exercise: $0"
echo "*********************************************************************"

# This script exits on an error so that errors don't compound and you see
# only the first error that occurred.
set -o errexit

# Print the commands being run so that we can see the command that triggers
# an error.  It is also useful for following allowing as the install occurs.
set -o xtrace


# Keep track of the current directory
SCRIPT_DIR=$(cd $(dirname "$0") && pwd)

DEVSTACK_DIR=$(cd $SCRIPT_DIR/../..; pwd)/devstack
if [ -x "$HOME/devstack/stack.sh" ]; then
  DEVSTACK_DIR=$HOME/devstack/
fi

# Import common functions
source $DEVSTACK_DIR/functions

# Import configuration
source $DEVSTACK_DIR/openrc admin admin

# Import exercise configuration
source $DEVSTACK_DIR/exerciserc

# Skip if designate is not enabled
is_service_enabled designate || exit 55

# Import settings + designate library
source $SCRIPT_DIR/plugin.sh

# Settings
# ========
source $SCRIPT_DIR/settings

# Used with dig to look up in DNS
DIG_TIMEOUT=30

if [ "$DESIGNATE_BACKEND_DRIVER" == "akamai" ]; then
    # Akamai can be slow to propagate changes out
    DIG_TIMEOUT=300
fi

# used with dig to look up in DNS
DIG_FLAGS="-p $DESIGNATE_SERVICE_PORT_DNS @$DESIGNATE_SERVICE_HOST"

# used with dig to do an AXFR against MDNS
DIG_AXFR_FLAGS="-p $DESIGNATE_SERVICE_PORT_MDNS @$DESIGNATE_SERVICE_HOST AXFR +tcp +nocmd"

# Functions
# =========

function cleanup {
    # Try to cleanup any domains, this is important for backends like
    # Akamai/Dyn, where state is not fully reset between test runs.
    source $DEVSTACK_DIR/openrc admin admin

    designate --all-tenants domain-list -f csv | awk 'BEGIN { FS = "," } ; {print $1}' | \
        tail -n+2 | xargs --no-run-if-empty -n1 designate --all-tenants domain-delete
}
trap cleanup EXIT

function ensure_record_present {
    local record_name=$1
    local record_type=$2
    local record_value=$3

    if [ "$DESIGNATE_BACKEND_DRIVER" = "fake" ] ; then
        # if the backend is fake, there will be no actual DNS records
        return 0
    fi

    if ! timeout $DIG_TIMEOUT sh -c "while ! dig +short $DIG_FLAGS $record_name $record_type | grep \"$record_value\"; do sleep 1; done"; then
        die $LINENO "Error: record $record_name ($record_type) not found in DNS"
    fi

    # Display for debugging
    dig $DIG_FLAGS $record_name $record_type

    return 0
}

function ensure_record_absent {
    local record_name=$1
    local record_type=$2
    local record_value=$3

    if [ "$DESIGNATE_BACKEND_DRIVER" = "fake" ] ; then
        # if the backend is fake, there will be no actual DNS records
        return 0
    fi

    if ! timeout $DIG_TIMEOUT sh -c "while dig +short $DIG_FLAGS $record_name $record_type | grep \"$record_value\"; do sleep 1; done"; then
        # Display for debugging
        dig $DIG_FLAGS $record_name $record_type

        die $LINENO "Error: record $record_name ($record_type) found in DNS, should be absent"
    fi

    return 0
}

# do an AXFR request to MDNS
# if it does not match the expected value, give an error
function verify_axfr_in_mdns {
    # Display for debugging
    dig $DIG_AXFR_FLAGS "$1"
    if dig $DIG_AXFR_FLAGS "$1"; then
        if [ -n "$2" ] ; then
            local axfr_records=$(dig $DIG_AXFR_FLAGS "$1" | grep "$1" | wc -l)
            if [ "$axfr_records" = "$2" ] ; then
                return 0
            else
                die $LINENO "Error: AXFR to MDNS did not return the expected number of records"
            fi
        fi
        return 0
    else
        die $LINENO "Error: AXFR to MDNS did not return a correct response"
    fi
}

# get the domain id (uuid) given the domain name
# if REQUIRED is set, die with an error if name not found
function get_domain_id {
    local domain_name=$1
    local required=$2
    local domain_id=$(designate domain-list | egrep " $domain_name " | get_field 1)
    if [ "$required" = "1" ] ; then
        die_if_not_set $LINENO domain_id "Failure retrieving DOMAIN_ID"
    fi
    echo "$domain_id"
}


# get the domain_name given the id
function get_domain_name {
    designate domain-list | grep "$1" | get_field 2
}

# if the given domain does not exist, it will be created
# the domain_id of the domain will be returned
function get_or_create_domain_id {
    local domainid=$(get_domain_id "$1")
    if [[ -z "$domainid" ]]; then
        designate domain-create --name $1 --email admin@devstack.org --ttl 86400 --description "domain $1" 1>&2
        domainid=$(designate domain-list | grep "$1" | get_field 1)
    fi
    echo $domainid
}

# get the record id (uuid) given the record name and domain id
# if REQUIRED is set, die with an error if name not found
function get_record_id {
    local domain_id=$1
    local record_name=$2
    local record_type=$3
    local required=$4
    local record_id=$(designate record-list $domain_id | egrep " $record_name " | egrep " $record_type " | get_field 1)
    if [ "$required" = "1" ] ; then
        die_if_not_set $LINENO record_id "Failure retrieving RECORD_ID"
    fi
    echo "$record_id"
}

# Testing Servers
# ===============
designate server-list

# NUMBER_OF_RECORDS keeps track of the records we need to get for AXFR
# We start with the number of NS lines returned from server list
# (Header line makes up for SOA + Number of NS record lines)
NUMBER_OF_RECORDS=$(designate server-list -f csv | wc -l)

# Add 1 extra to account for the additional SOA at the end of the AXFR
((NUMBER_OF_RECORDS+=1))

# Testing Domains
# ===============

# List domains
designate domain-list

# Create random domain name
DOMAIN_NAME="exercise-$(openssl rand -hex 4).com."

# Create the domain
designate domain-create --name $DOMAIN_NAME --email devstack@example.org

DOMAIN_ID=$(get_domain_id $DOMAIN_NAME 1)

# Fetch the domain
designate domain-get $DOMAIN_ID

# List the nameservers hosting the domain
designate domain-servers-list $DOMAIN_ID

# Testing Records
# ===============

# Create random record name
A_RECORD_NAME="$(openssl rand -hex 4).${DOMAIN_NAME}"

# Create an A record
designate record-create $DOMAIN_ID --name $A_RECORD_NAME --type A --data 127.0.0.1
((NUMBER_OF_RECORDS++))
A_RECORD_ID=$(get_record_id $DOMAIN_ID $A_RECORD_NAME A)

# Fetch the record
designate record-get $DOMAIN_ID $A_RECORD_ID

# Verify the record is published in DNS
ensure_record_present $A_RECORD_NAME A 127.0.0.1

# -----

# Create random record name
AAAA_RECORD_NAME="$(openssl rand -hex 4).${DOMAIN_NAME}"

# Create an AAAA record
designate record-create $DOMAIN_ID --name $AAAA_RECORD_NAME --type AAAA --data "2607:f0d0:1002:51::4"
((NUMBER_OF_RECORDS++))
AAAA_RECORD_ID=$(get_record_id $DOMAIN_ID $AAAA_RECORD_NAME AAAA)

# Fetch the record
designate record-get $DOMAIN_ID $AAAA_RECORD_ID

# Verify the record is published in DNS
ensure_record_present $AAAA_RECORD_NAME AAAA 2607:f0d0:1002:51::4

# -----

# Create a MX record
designate record-create $DOMAIN_ID --name $DOMAIN_NAME --type MX --priority 5 --data "mail.example.com."
((NUMBER_OF_RECORDS++))
MX_RECORD_ID=$(get_record_id $DOMAIN_ID $DOMAIN_NAME MX)

# Fetch the record
designate record-get $DOMAIN_ID $MX_RECORD_ID

# Verify the record is published in DNS
ensure_record_present $DOMAIN_NAME MX "5 mail.example.com."

# -----

# Create a SRV record
designate record-create $DOMAIN_ID --name _sip._tcp.$DOMAIN_NAME --type SRV --priority 10 --data "5 5060 sip.example.com."
((NUMBER_OF_RECORDS++))
SRV_RECORD_ID=$(get_record_id $DOMAIN_ID _sip._tcp.$DOMAIN_NAME SRV)

# Fetch the record
designate record-get $DOMAIN_ID $SRV_RECORD_ID

# Verify the record is published in DNS
ensure_record_present _sip._tcp.$DOMAIN_NAME SRV "10 5 5060 sip.example.com."

# -----

# Create random record name
CNAME_RECORD_NAME="$(openssl rand -hex 4).${DOMAIN_NAME}"

# Create a CNAME record
designate record-create $DOMAIN_ID --name $CNAME_RECORD_NAME --type CNAME --data $DOMAIN_NAME
((NUMBER_OF_RECORDS++))
CNAME_RECORD_ID=$(get_record_id $DOMAIN_ID $CNAME_RECORD_NAME CNAME)

# Fetch the record
designate record-get $DOMAIN_ID $CNAME_RECORD_ID

# Verify the record is published in DNS
ensure_record_present $CNAME_RECORD_NAME CNAME $DOMAIN_NAME

# -----

# List Records
designate record-list $DOMAIN_ID

# Send an AXFR to MDNS and check for the records returned
verify_axfr_in_mdns $DOMAIN_NAME $NUMBER_OF_RECORDS

# -----

# Delete a Record
designate record-delete $DOMAIN_ID $CNAME_RECORD_ID

# List Records
designate record-list $DOMAIN_ID

# Fetch the record - should be gone
designate record-get $DOMAIN_ID $CNAME_RECORD_ID || echo "good - record was removed"

# verify not in DNS anymore
ensure_record_absent $CNAME_RECORD_NAME CNAME $DOMAIN_NAME

# Testing Domains Delete
# ======================

# Delete the domain
designate domain-delete $DOMAIN_ID

# Fetch the domain - should be gone
designate domain-get $DOMAIN_ID || echo "good - domain was removed"

set +o xtrace
echo "*********************************************************************"
echo "SUCCESS: End DevStack Exercise: $0"
echo "*********************************************************************"