-
Notifications
You must be signed in to change notification settings - Fork 21
/
ec2-create-instance.sh
executable file
·297 lines (261 loc) · 10.6 KB
/
ec2-create-instance.sh
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
#!/bin/bash -e
# For docs, see the "Deployment" page in the Dev Guide.
# repo and branch defaults
REPO_URL_DEFAULT="https://github.com/IQSS/dataverse.git"
BRANCH_DEFAULT="develop"
PEM_DEFAULT=${HOME}
VERBOSE_ARG=""
# rocky linux 9.4 official, us-east-1
AWS_AMI_DEFAULT='ami-09fb459fad4613d55'
# let's stick with rocky 8.9 until ITs pass
#AWS_AMI_DEFAULT='ami-0408f4c4a072e3fb9'
usage() {
echo "Usage: $0 -b <branch> -r <repo> -p <pem_path> -g <group_vars> -a <dataverse-ansible branch> -i aws_image -u aws_user -s aws_size -t aws_tag -f aws_security group -e aws_profile -l local_log_path -d -v" 1>&2
echo "default branch is develop"
echo "default repo is https://github.com/IQSS/dataverse"
echo "default .pem location is ${HOME}"
echo "example group_vars may be retrieved from https://raw.githubusercontent.com/GlobalDataverseCommunityConsortium/dataverse-ansible/develop/defaults/main.yml"
echo "default AWS AMI ID is $AWS_AMI_DEFAULT, find the full list at https://rockylinux.org/ami/"
echo "default AWS user is rocky"
echo "default AWS instance size is t3a.large"
echo "default AWS security group is dataverse-sg"
echo "local log path will rsync Payara, Jacoco, Maven and other logs back to the specified path"
echo "-d will destroy ("terminate") the AWS instance once testing and reporting completes"
echo "-v increases Ansible output verbosity"
exit 1
}
while getopts ":a:r:b:g:p:i:s:t:f:e:l:dv" o; do
case "${o}" in
a)
DA_BRANCH=${OPTARG}
;;
r)
REPO_URL=${OPTARG}
;;
b)
BRANCH=${OPTARG}
;;
g)
GRPVRS=${OPTARG}
;;
p)
PEM_PATH=${OPTARG}
;;
i)
AWS_IMAGE=${OPTARG}
;;
u)
AWS_USER=${OPTARG}
;;
s)
AWS_SIZE=${OPTARG}
;;
t)
TAG=${OPTARG}
;;
f)
AWS_SG=${OPTARG}
;;
l)
LOCAL_LOG_PATH=${OPTARG}
;;
e)
AWS_PROFILE=${OPTARG}
;;
d)
DESTROY=true
;;
v)
VERBOSE=true
;;
*)
usage
;;
esac
done
# test for ansible group_vars
if [ ! -z "$GRPVRS" ]; then
GVFILE=$(basename "$GRPVRS")
GVARG="-e @$GVFILE"
#BRANCH=`grep dataverse_branch $GRPVRS |awk '{print $2}'`
echo "using $GRPVRS for extra vars"
echo "deploying $BRANCH from $GRPVRS"
fi
# test for specified GitHub repo
if [ ! -z "$REPO_URL" ]; then
GVARG+=" -e dataverse_repo=$REPO_URL"
echo "using repo $REPO_URL"
fi
# test for specified branch
if [ ! -z "$BRANCH" ]; then
GVARG+=" -e dataverse_branch=$BRANCH"
echo "building branch $BRANCH"
fi
# if no repo and no group_vars, use default repo
if [ -z "$REPO_URL" ] && [ -z "$GRPVRS" ]; then
REPO_URL=$REPO_URL_DEFAULT
echo "using default repo: $REPO_URL"
fi
# if no branch and no group_vars, use default branch
if [ -z "$BRANCH" ] && [ -z "$GRPVRS" ]; then
BRANCH=$BRANCH_DEFAULT
echo "using default branch $BRANCH"
fi
# The AMI ID may change in the future and the way to look it up is with the following command, which takes a long time to run:
# aws ec2 describe-images --owners 'aws-marketplace' --filters 'Name=product-code,Values=aw0evgkw8e5c1q413zgy5pjce' --query 'sort_by(Images, &CreationDate)[-1].[ImageId]' --output 'text'
# To use an AMI, one must subscribe to it via the AWS GUI.
# AMI IDs are specific to the region.
if [ ! -z "$AWS_IMAGE" ]; then
AMI_ID=$AWS_IMAGE
else
AMI_ID="$AWS_AMI_DEFAULT"
fi
echo "using $AMI_ID"
if [ -z "$AWS_USER" ]; then
AWS_USER="rocky"
fi
if [ ! -z "$AWS_SIZE" ]; then
SIZE=$AWS_SIZE
else
SIZE="t3a.large"
fi
echo "using $SIZE"
if [ ! -z "$TAG" ]; then
TAGARG="--tag-specifications ResourceType=instance,Tags=[{Key=name,Value=$TAG}]"
echo "using tag $TAG"
fi
if [ -z "$AWS_SG" ]; then
AWS_SG="dataverse-sg"
fi
echo "using $AWS_SG security group"
# default to dataverse-ansible/develop
if [ -z "$DA_BRANCH" ]; then
DA_BRANCH="develop"
fi
# default to "default" AWS profile
if [ ! -z "$AWS_PROFILE" ]; then
PROFILE="--profile=$AWS_PROFILE"
echo "using profile $PROFILE"
fi
# verbosity
if [ ! -z "$VERBOSE" ]; then
VERBOSE_ARG="-v"
fi
AWS_CLI_VERSION=$(aws --version)
if [[ "$?" -ne 0 ]]; then
echo 'The "aws" program could not be executed. Is it in your $PATH?'
exit 1
fi
# don't check for branch if using group_vars
if [ -z "$GRPVRS" ]; then
if [[ $(git ls-remote --heads $REPO_URL $BRANCH | wc -l) -eq 0 ]]; then
echo "Branch \"$BRANCH\" does not exist at $REPO_URL"
usage
exit 1
fi
fi
GROUP_CHECK=$(aws $PROFILE ec2 describe-security-groups --group-name $AWS_SG)
if [[ "$?" -ne 0 ]]; then
echo "Creating security group \"$AWS_SG\"."
aws $PROFILE ec2 create-security-group --group-name $AWS_SG --description "security group for Dataverse"
aws $PROFILE ec2 authorize-security-group-ingress --group-name $AWS_SG --protocol tcp --port 22 --cidr 0.0.0.0/0
aws $PROFILE ec2 authorize-security-group-ingress --group-name $AWS_SG --protocol tcp --port 80 --cidr 0.0.0.0/0
aws $PROFILE ec2 authorize-security-group-ingress --group-name $AWS_SG --protocol tcp --port 443 --cidr 0.0.0.0/0
aws $PROFILE ec2 authorize-security-group-ingress --group-name $AWS_SG --protocol tcp --port 8080 --cidr 0.0.0.0/0
fi
# were we passed a pem file?
if [ ! -z "$PEM_PATH" ]; then
KEY_NAME=`echo $PEM_PATH | sed 's/\.pem//g'`
echo "using key_name: $KEY_NAME"
elif [ -z "$PEM_PATH" ]; then
RANDOM_STRING="$(uuidgen | cut -c-8)"
KEY_NAME="key-$USER-$RANDOM_STRING"
echo "using key_name: $KEY_NAME"
PRIVATE_KEY=$(aws $PROFILE ec2 create-key-pair --key-name ~/$KEY_NAME --query 'KeyMaterial' --output text)
if [[ $PRIVATE_KEY == '-----BEGIN RSA PRIVATE KEY-----'* ]]; then
PEM_FILE="${HOME}/$KEY_NAME.pem"
printf -- "$PRIVATE_KEY" >$PEM_FILE
chmod 400 $PEM_FILE
echo "Your newly created private key file is \"$PEM_FILE\". Keep it secret. Keep it safe."
KEY_NAME="${HOME}/$KEY_NAME"
else
echo "Could not create key pair. Exiting."
exit 1
fi
fi
echo "Creating EC2 instance"
# TODO: Add some error checking for "ec2 run-instances".
INSTANCE_ID=$(aws $PROFILE ec2 run-instances --image-id $AMI_ID --security-groups $AWS_SG $TAGARG --count 1 --instance-type $SIZE --key-name $KEY_NAME --query 'Instances[0].InstanceId' --block-device-mappings '[ { "DeviceName": "/dev/sda1", "Ebs": { "DeleteOnTermination": true, "VolumeSize": 20 } } ]' | tr -d \")
echo "Instance ID: "$INSTANCE_ID
DESTROY_CMD="aws $PROFILE ec2 terminate-instances --instance-ids $INSTANCE_ID"
echo "When you are done, please terminate your instance with:"
echo "$DESTROY_CMD"
echo "giving instance 90 seconds to wake up..."
sleep 90
echo "End creating EC2 instance"
PUBLIC_DNS=$(aws $PROFILE ec2 describe-instances --instance-ids $INSTANCE_ID --query "Reservations[*].Instances[*].[PublicDnsName]" --output text)
PUBLIC_IP=$(aws $PROFILE ec2 describe-instances --instance-ids $INSTANCE_ID --query "Reservations[*].Instances[*].[PublicIpAddress]" --output text)
USER_AT_HOST="$AWS_USER@${PUBLIC_DNS}"
echo "New instance created with ID \"$INSTANCE_ID\". To ssh into it:"
echo "ssh -i $PEM_FILE $USER_AT_HOST"
echo "Please wait at least 15 minutes while the branch \"$BRANCH\" from $REPO_URL is being deployed."
if [ ! -z "$GRPVRS" ]; then
scp -i $PEM_FILE -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile=/dev/null' -o 'ConnectTimeout=300' $GRPVRS $USER_AT_HOST:$GVFILE
fi
# epel-release is installed first to ensure the latest ansible is installed after
# TODO: Add some error checking for this ssh command.
ssh -T -i $PEM_FILE -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile=/dev/null' -o 'ConnectTimeout=300' $USER_AT_HOST <<EOF
sudo dnf -q -y install epel-release
sudo dnf -q -y install ansible git
git clone -b $DA_BRANCH https://github.com/GlobalDataverseCommunityConsortium/dataverse-ansible.git dataverse
export ANSIBLE_ROLES_PATH=.
ansible-playbook $VERBOSE_ARG -i dataverse/inventory dataverse/dataverse.pb --connection=local $GVARG
EOF
# did AWS go AWOL? Jenkins will check for this file.
ssh-keyscan ${PUBLIC_DNS} >> ~/.ssh/known_hosts
rsync -av -e "ssh -i $PEM_FILE" $AWS_USER@$PUBLIC_DNS:/tmp/ansible_complete ./
if [ ! -z "$LOCAL_LOG_PATH" ]; then
echo "copying logs to $LOCAL_LOG_PATH."
# 1 logdir should exist
mkdir -p $LOCAL_LOG_PATH
# 2 grab logs for local processing in jenkins
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/target/site $LOCAL_LOG_PATH/
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/target/surefire-reports $LOCAL_LOG_PATH/
# 3 grab mvn.out
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/mvn.out $LOCAL_LOG_PATH/
# 4 jacoco
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/target/coverage-it $LOCAL_LOG_PATH/
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/target/coverage-reports/jacoco-unit.exec $LOCAL_LOG_PATH/
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/target/jacoco_merged.exec $LOCAL_LOG_PATH/
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/target/classes $LOCAL_LOG_PATH/
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/opt/dataverse/dataverse/src $LOCAL_LOG_PATH/
# 5 server.logs
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/usr/local/payara*/glassfish/domains/domain1/logs/server.log* $LOCAL_LOG_PATH/
# 6 query_count.out
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/tmp/query_count.out $LOCAL_LOG_PATH/
# 7 install.out and setup-all.*.log
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/tmp/dvinstall/install.out $LOCAL_LOG_PATH/
rsync -av -e "ssh -i $PEM_FILE" --ignore-missing-args $AWS_USER@$PUBLIC_DNS:/tmp/dvinstall/setup-all.*.log $LOCAL_LOG_PATH/
fi
# Port 8080 has been added because Ansible puts a redirect in place
# from HTTP to HTTPS and the cert is invalid (self-signed), forcing
# the user to click through browser warnings.
CLICKABLE_LINK="http://${PUBLIC_DNS}"
echo "Branch $BRANCH from $REPO_URL has been deployed to $CLICKABLE_LINK"
if [ -z "$DESTROY" ]; then
echo "To ssh into the new instance:"
echo "ssh -i $PEM_FILE $USER_AT_HOST"
echo "When you are done, please terminate your instance with:"
echo "$DESTROY_CMD"
if [ -z "$PEM_PATH" ]; then
echo "aws $PROFILE ec2 delete-key-pair --key-name $KEY_NAME"
fi
else
echo "destroying AWS instance"
eval $DESTROY_CMD
if [ -z "$PEM_PATH" ]; then
aws $PROFILE ec2 delete-key-pair --key-name $KEY_NAME
fi
echo "removing EC2 PEM"
rm -f $PEM_FILE
fi