Skip to content

Commit 792b14f

Browse files
committed
Add tests for aws-wrapper. Fix bugs.
1 parent 62beafa commit 792b14f

File tree

6 files changed

+1545
-117
lines changed

6 files changed

+1545
-117
lines changed

modules/bash-commons/src/aws-wrapper.sh

+24-19
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,34 @@ set -e
77

88
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/log.sh"
99
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/aws.sh"
10-
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/assertions.sh"
10+
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/assert.sh"
1111

12-
# Get the name of the ASG this EC2 Instance is in
12+
# Get the name of the ASG this EC2 Instance is in. This is done by looking up the instance's tags. This method will
13+
# wait up until the specified number of retries if the tags or instances are not yet available.
1314
function aws_wrapper_get_asg_name {
15+
local readonly max_retries="$1"
16+
local readonly sleep_between_retries="$2"
17+
1418
local instance_id
1519
instance_id=$(aws_get_instance_id)
1620

1721
local instance_region
1822
instance_region=$(aws_get_instance_region)
1923

20-
aws_wrapper_get_instance_tag "$instance_id" "$instance_region" "aws:autoscaling:groupName"
24+
aws_wrapper_get_instance_tag "$instance_id" "$instance_region" "aws:autoscaling:groupName" "$max_retries" "$sleep_between_retries"
2125
}
2226

2327
# Look up the tags for the specified Instance and extract the value for the specified tag key
2428
function aws_wrapper_get_instance_tag {
2529
local readonly instance_id="$1"
2630
local readonly instance_region="$2"
2731
local readonly tag_key="$3"
28-
29-
local readonly max_retries=60
30-
local readonly sleep_between_retries=5
32+
local readonly max_retries="${4:-60}"
33+
local readonly sleep_between_retries="${5:-5}"
3134

3235
for (( i=0; i<"$max_retries"; i++ )); do
3336
local tags
34-
tags=$(aws_wrapper_wait_for_instance_tags "$instance_id" "$instance_region")
37+
tags=$(aws_wrapper_wait_for_instance_tags "$instance_id" "$instance_region" "$max_retries" "$sleep_between_retries")
3538
assert_not_empty_or_null "$tags" "tags for Instance $instance_id in $instance_region"
3639

3740
local tag_value
@@ -57,12 +60,11 @@ function aws_wrapper_get_instance_tag {
5760
function aws_wrapper_wait_for_instance_tags {
5861
local readonly instance_id="$1"
5962
local readonly instance_region="$2"
63+
local readonly max_retries="${3:-60}"
64+
local readonly sleep_between_retries="${4:-5}"
6065

6166
log_info "Looking up tags for Instance $instance_id in $instance_region"
6267

63-
local readonly max_retries=60
64-
local readonly sleep_between_retries=5
65-
6668
for (( i=0; i<"$max_retries"; i++ )); do
6769
local tags
6870
tags=$(aws_get_instance_tags "$instance_id" "$instance_region")
@@ -88,9 +90,8 @@ function aws_wrapper_wait_for_instance_tags {
8890
function aws_wrapper_get_asg_size {
8991
local readonly asg_name="$1"
9092
local readonly aws_region="$2"
91-
92-
local readonly max_retries=60
93-
local readonly sleep_between_retries=5
93+
local readonly max_retries="${3:-60}"
94+
local readonly sleep_between_retries="${4:-5}"
9495

9596
for (( i=0; i<"$max_retries"; i++ )); do
9697
log_info "Looking up the size of the Auto Scaling Group $asg_name in $aws_region"
@@ -121,12 +122,12 @@ function aws_wrapper_get_asg_size {
121122
function aws_wrapper_wait_for_instances_in_asg {
122123
local readonly asg_name="$1"
123124
local readonly aws_region="$2"
125+
local readonly max_retries="${3:-60}"
126+
local readonly sleep_between_retries="${4:-5}"
124127

125128
local asg_size
126-
asg_size=$(aws_wrapper_get_asg_size "$asg_name" "$aws_region")
127-
128-
local readonly max_retries=60
129-
local readonly sleep_between_retries=5
129+
asg_size=$(aws_wrapper_get_asg_size "$asg_name" "$aws_region" "$max_retries" "$sleep_between_retries")
130+
assert_not_empty_or_null "$asg_size" "size of ASG $asg_name in $aws_region"
130131

131132
log_info "Looking up Instances in ASG $asg_name in $aws_region"
132133
for (( i=0; i<"$max_retries"; i++ )); do
@@ -157,9 +158,11 @@ function aws_wrapper_get_ips_in_asg {
157158
local readonly asg_name="$1"
158159
local readonly aws_region="$2"
159160
local readonly use_public_ips="$3"
161+
local readonly max_retries="${4:-60}"
162+
local readonly sleep_between_retries="${5:-5}"
160163

161164
local instances
162-
instances=$(aws_describe_instances_in_asg "$asg_name" "$aws_region")
165+
instances=$(aws_wrapper_wait_for_instances_in_asg "$asg_name" "$aws_region" "$max_retries" "$sleep_between_retries")
163166
assert_not_empty_or_null "$instances" "Get info about Instances in ASG $asg_name in $aws_region"
164167

165168
local readonly ip_param=$([[ "$use_public_ips" == "true" ]] && echo "PublicIpAddress" || echo "PrivateIpAddress")
@@ -172,9 +175,11 @@ function aws_wrapper_get_hostnames_in_asg {
172175
local readonly asg_name="$1"
173176
local readonly aws_region="$2"
174177
local readonly use_public_hostnames="$3"
178+
local readonly max_retries="${4:-60}"
179+
local readonly sleep_between_retries="${5:-5}"
175180

176181
local instances
177-
instances=$(aws_wrapper_wait_for_instances_in_asg "$asg_name" "$aws_region")
182+
instances=$(aws_wrapper_wait_for_instances_in_asg "$asg_name" "$aws_region" "$max_retries" "$sleep_between_retries")
178183
assert_not_empty_or_null "$instances" "Get info about Instances in ASG $asg_name in $aws_region"
179184

180185
local readonly hostname_param=$([[ "$use_public_hostnames" == "true" ]] && echo "PublicDnsName" || echo "PrivateDnsName")

test/aws-cli.bats

+2-22
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,12 @@ source "$BATS_TEST_DIRNAME/../modules/bash-commons/src/aws.sh"
44
load "test-helper"
55
load "aws-helper"
66

7-
readonly MOTO_TMP_DIR="/tmp/moto"
8-
readonly MOTO_PID_FILE_PATH="$MOTO_TMP_DIR/moto.pid"
9-
107
function setup {
11-
mkdir -p "$MOTO_TMP_DIR"
12-
13-
# Start moto server if it isn't already running
14-
if [[ ! -f "$MOTO_PID_FILE_PATH" ]]; then
15-
moto_server &
16-
echo "$!" > "$MOTO_PID_FILE_PATH"
17-
18-
# Sleep a bit to give moto a chance to start
19-
sleep 1
20-
fi
8+
start_moto
219
}
2210

2311
function teardown {
24-
# Stop moto if it's running
25-
if [[ -f "$MOTO_PID_FILE_PATH" ]]; then
26-
local readonly pid=$(cat "$MOTO_PID_FILE_PATH")
27-
kill "$pid" 2>&1 > /dev/null
28-
rm -f "$MOTO_PID_FILE_PATH"
29-
30-
# Sleep a bit to give moto a chance to stop
31-
sleep 1
32-
fi
12+
stop_moto
3313
}
3414

3515
@test "aws_get_instance_tags empty" {

test/aws-ec2-metadata.bats

+23-76
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,60 @@
11
#!/usr/bin/env bats
22

3-
readonly bash_commons_src_path="$BATS_TEST_DIRNAME/../modules/bash-commons/src"
4-
source "$bash_commons_src_path/aws.sh"
5-
source "$bash_commons_src_path/string.sh"
3+
source "$BATS_TEST_DIRNAME/../modules/bash-commons/src/aws.sh"
64
load "test-helper"
5+
load "aws-helper"
76

8-
readonly EC2_METADATA_MOCK_APP_PATH="$BATS_TEST_DIRNAME/ec2-metadata-mock/ec2-metadata-mock.py"
9-
readonly EC2_METADATA_MOCK_TMP_DIR="/tmp/ec2-metadata-mock"
10-
readonly EC2_METADATA_MOCK_PID_PATH="$EC2_METADATA_MOCK_TMP_DIR/ec2-metadata-mock.pid"
11-
readonly EC2_METADATA_MOCK_LOG_FILE_PATH="$EC2_METADATA_MOCK_TMP_DIR/ec2-metadata-mock.log"
12-
13-
# Set env vars for ec2-metadata-mock
14-
export meta_data_local_ipv4="11.22.33.44"
15-
export meta_data_public_ipv4="55.66.77.88"
16-
export meta_data_local_hostname="ip-10-251-50-12.ec2.internal"
17-
export meta_data_public_hostname="ec2-203-0-113-25.compute-1.amazonaws.com"
18-
export meta_data_instance_id="i-1234567890abcdef0"
19-
7+
readonly local_ipv4="11.22.33.44"
8+
readonly public_ipv4="55.66.77.88"
9+
readonly local_hostname="ip-10-251-50-12.ec2.internal"
10+
readonly public_hostname="ec2-203-0-113-25.compute-1.amazonaws.com"
11+
readonly instance_id="i-1234567890abcdef0"
2012
readonly mock_region="us-west-1"
21-
export meta_data_placement__availability_zone="${mock_region}b"
22-
export dynamic_data_instance_identity__document=$(cat <<END_HEREDOC
23-
{
24-
"devpayProductCodes" : null,
25-
"marketplaceProductCodes" : [ "1abc2defghijklm3nopqrs4tu" ],
26-
"availabilityZone" : "$meta_data_placement__availability_zone",
27-
"privateIp" : "$meta_data_local_ipv4",
28-
"version" : "2017-09-30",
29-
"instanceId" : "$meta_data_instance_id",
30-
"billingProducts" : null,
31-
"instanceType" : "t2.micro",
32-
"accountId" : "123456789012",
33-
"imageId" : "ami-5fb8c835",
34-
"pendingTime" : "2016-11-19T16:32:11Z",
35-
"architecture" : "x86_64",
36-
"kernelId" : null,
37-
"ramdiskId" : null,
38-
"region" : "$mock_region"
39-
}
40-
END_HEREDOC
41-
)
13+
readonly availability_zone="${mock_region}b"
4214

43-
# Configure the server so we can run a mock EC2 metadata endpoint on port 80 with the metadata endpoint's special IP.
4415
function setup {
45-
local config
46-
config=$(ifconfig)
47-
48-
mkdir -p "$EC2_METADATA_MOCK_TMP_DIR"
49-
50-
# Use ifconfig and iptables to allow us to run a mock server on 169.254.169.254 and on port 80. These steps are
51-
# based on https://github.com/NYTimes/mock-ec2-metadata. Note #1: we can't use that project directly as it doesn't
52-
# support most EC2 metadata endpoints. Note #2: try to make this code idempotent so we don't try to create the same
53-
# configuration multiple times.
54-
if ! string_multiline_contains "$config" "lo:1"; then
55-
ifconfig lo:1 inet 169.254.169.254 netmask 255.255.255.255 up
56-
echo 1 > /proc/sys/net/ipv4/ip_forward
57-
iptables -t nat -A OUTPUT -p tcp -d 169.254.169.254/32 --dport 80 -j DNAT --to-destination 169.254.169.254:8111
58-
iptables-save
59-
fi
60-
61-
# Start ec2-metadata-mock if it isn't already running
62-
if [[ ! -f "$EC2_METADATA_MOCK_PID_PATH" ]]; then
63-
FLASK_APP="$EC2_METADATA_MOCK_APP_PATH" flask run --host=0.0.0.0 --port=8111 2>&1 > "$EC2_METADATA_MOCK_LOG_FILE_PATH" &
64-
echo "$!" > "$EC2_METADATA_MOCK_PID_PATH"
65-
66-
# Sleep a bit to give Flask a chance to start
67-
sleep 1
68-
fi
16+
start_ec2_metadata_mock \
17+
"$local_ipv4" \
18+
"$public_ipv4" \
19+
"$local_hostname" \
20+
"$public_hostname" \
21+
"$instance_id" \
22+
"$mock_region" \
23+
"$availability_zone"
6924
}
7025

7126
function teardown {
72-
# Stop ec2-metadata-mock if it's running
73-
if [[ -f "$EC2_METADATA_MOCK_PID_PATH" ]]; then
74-
local readonly pid=$(cat "$EC2_METADATA_MOCK_PID_PATH")
75-
kill "$pid" 2>&1 > "$EC2_METADATA_MOCK_LOG_FILE_PATH"
76-
rm -f "$EC2_METADATA_MOCK_PID_PATH"
77-
78-
# Sleep a bit to give Flask a chance to stop
79-
sleep 1
80-
fi
27+
stop_ec2_metadata_mock
8128
}
8229

8330
@test "aws_get_instance_private_ip" {
8431
run aws_get_instance_private_ip
8532
assert_success
86-
assert_output "$meta_data_local_ipv4"
33+
assert_output "$local_ipv4"
8734
}
8835

8936
@test "aws_get_instance_public_ip" {
9037
run aws_get_instance_public_ip
9138
assert_success
92-
assert_output "$meta_data_public_ipv4"
39+
assert_output "$public_ipv4"
9340
}
9441

9542
@test "aws_get_instance_private_hostname" {
9643
run aws_get_instance_private_hostname
9744
assert_success
98-
assert_output "$meta_data_local_hostname"
45+
assert_output "$local_hostname"
9946
}
10047

10148
@test "aws_get_instance_public_hostname" {
10249
run aws_get_instance_public_hostname
10350
assert_success
104-
assert_output "$meta_data_public_hostname"
51+
assert_output "$public_hostname"
10552
}
10653

10754
@test "aws_get_instance_id" {
10855
run aws_get_instance_id
10956
assert_success
110-
assert_output "$meta_data_instance_id"
57+
assert_output "$instance_id"
11158
}
11259

11360
@test "aws_get_instance_region" {
@@ -119,6 +66,6 @@ function teardown {
11966
@test "aws_get_ec2_instance_availability_zone" {
12067
run aws_get_ec2_instance_availability_zone
12168
assert_success
122-
assert_output "$meta_data_placement__availability_zone"
69+
assert_output "$availability_zone"
12370
}
12471

0 commit comments

Comments
 (0)