-
Notifications
You must be signed in to change notification settings - Fork 45
/
Copy pathsetup.sh
executable file
·419 lines (351 loc) · 14.1 KB
/
setup.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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
#!/bin/sh
# BBB Application Infrastructure deployment script
# Author: David Surey - suredavi@amazon.de
# Disclaimer: NOT FOR PRODUCTION USE - Only for demo and testing purposes
# Color codes for output formatting
# Using printf to ensure proper escape sequence interpretation
RED=$(printf '\033[0;31m')
GREEN=$(printf '\033[0;32m')
YELLOW=$(printf '\033[1;33m')
BLUE=$(printf '\033[0;34m')
NC=$(printf '\033[0m')
# Logging configuration
LOG_LEVEL=${LOG_LEVEL:-"INFO"} # Default to INFO if not set
LOG_FILE="/tmp/bbb-setup-$(date +%Y%m%d-%H%M%S).log"
# Get numeric value for log level
get_log_level_value() {
case $1 in
"DEBUG") echo 0 ;;
"INFO") echo 1 ;;
"WARN") echo 2 ;;
"ERROR") echo 3 ;;
*) echo 1 ;; # Default to INFO
esac
}
# Logging function
log() {
level=$1
shift
message=$*
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Check if level meets minimum level
current_level=$(get_log_level_value "$level")
minimum_level=$(get_log_level_value "$LOG_LEVEL")
if [ "$current_level" -lt "$minimum_level" ]; then
return 2
fi
# Color selection based on level
case $level in
"DEBUG") color=$BLUE ;;
"INFO") color=$GREEN ;;
"WARN") color=$YELLOW ;;
"ERROR") color=$RED ;;
*) color=$NC ;;
esac
# Output to console with color
printf "%s [%s%s%s] %s\n" "$timestamp" "$color" "$level" "$NC" "$message"
# Output to log file without color
printf "%s [%s] %s\n" "$timestamp" "$level" "$message" >> "$LOG_FILE"
# Exit on ERROR level messages
if [ "$level" = "ERROR" ]; then
exit 1
fi
}
debug_exec() {
if [ "$LOG_LEVEL" = "DEBUG" ]; then
"$@" 2>&1 | tee -a "$LOG_FILE"
else
"$@" >/dev/null 2>&1
fi
}
# Function to monitor CloudFormation stack events in real-time
monitor_stack() {
local stack_name=$1
local last_event_time
last_event_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
log "DEBUG" "Starting stack monitoring for: $stack_name"
while true; do
events=$(aws cloudformation describe-stack-events \
--profile "$BBBPROFILE" \
--stack-name "$stack_name" \
--query 'StackEvents[?contains(ResourceStatus, `IN_PROGRESS`) || contains(ResourceStatus, `COMPLETE`) || contains(ResourceStatus, `FAILED`)]')
echo "$events" | jq -r --arg timestamp "$last_event_time" '.[] | select(.Timestamp > $timestamp) | "\(.Timestamp) [\(.LogicalResourceId)] \(.ResourceStatus) - \(.ResourceStatusReason // "No reason provided")"' | while read -r line; do
log "DEBUG" "$line"
done
# Get stack status
stack_status=$(aws cloudformation describe-stacks \
--profile "$BBBPROFILE" \
--stack-name "$stack_name" \
--query 'Stacks[0].StackStatus' \
--output text)
if [[ ! $stack_status =~ .*IN_PROGRESS$ ]]; then
if [[ $stack_status =~ .*FAILED$ || $stack_status =~ .*ROLLBACK.* ]]; then
log "ERROR" "Stack deployment failed with status: $stack_status"
return 1
elif [[ $stack_status =~ .*COMPLETE$ ]]; then
log "INFO" "Stack deployment completed successfully with status: $stack_status"
return 0
fi
fi
last_event_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
sleep 5
done
}
# Modified deployment function
deploy_stack() {
local stack_name=$1
local template=$2
shift 2
local params=("$@")
log "INFO" "Starting deployment for stack: $stack_name"
log "DEBUG" "Using template: $template"
if aws cloudformation deploy \
--profile "$BBBPROFILE" \
--stack-name "$stack_name" \
"${params[@]}" \
--template "$template" \
--no-fail-on-empty-changeset; then
monitor_stack "$stack_name"
return $?
else
log "ERROR" "Failed to initiate stack deployment for $stack_name"
return 1
fi
}
# Input validation function
validate_input() {
param_name=$1
param_value=$2
if [ -z "$param_value" ]; then
log "ERROR" "Parameter ${param_name} is required but not provided"
fi
}
# Usage information
usage() {
echo "Usage: $0 -p <aws-profile> -e <operator-email> -h <hosted-zone> -s <stack-name> -d <domain-name>"
echo "Options:"
echo " -p : AWS Profile"
echo " -e : Operator Email"
echo " -h : Hosted Zone"
echo " -s : Stack Name"
echo " -d : Domain Name"
echo " -l : Log Level (DEBUG|INFO|WARN|ERROR) - default: INFO"
exit 1
}
# Initialize variables
BBBPROFILE=""
OPERATOREMAIL=""
HOSTEDZONE=""
BBBSTACK=""
DOMAIN=""
# Parse command line arguments
while getopts "p:e:h:s:d:l:" opt; do
case $opt in
p) BBBPROFILE="$OPTARG" ;;
e) OPERATOREMAIL="$OPTARG" ;;
h) HOSTEDZONE="$OPTARG" ;;
s) BBBSTACK="$OPTARG" ;;
d) DOMAIN="$OPTARG" ;;
l)
case $OPTARG in
DEBUG|INFO|WARN|ERROR) LOG_LEVEL="$OPTARG" ;;
*) log "ERROR" "Invalid log level: $OPTARG. Valid levels are: DEBUG INFO WARN ERROR" ;;
esac
;;
*) log "ERROR" "Invalid option -$OPTARG" ;;
esac
done
# Validate all required parameters
log "DEBUG" "Validating input parameters..."
validate_input "AWS Profile" "$BBBPROFILE"
validate_input "Operator Email" "$OPERATOREMAIL"
validate_input "Hosted Zone" "$HOSTEDZONE"
validate_input "Stack Name" "$BBBSTACK"
validate_input "Domain" "$DOMAIN"
# Validate email format using grep
if ! echo "$OPERATOREMAIL" | grep -E "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$" > /dev/null; then
log "ERROR" "Invalid email format: $OPERATOREMAIL"
fi
# Check for required tools
log "DEBUG" "Checking required tools..."
if ! debug_exec command -v aws; then
log "ERROR" "aws CLI is not installed"
fi
if ! debug_exec docker ps; then
log "ERROR" "Docker is not running or not installed"
fi
if ! debug_exec command -v jq; then
log "ERROR" "jq is not installed"
fi
# Main execution starts here
log "INFO" "Starting BBB deployment with AWS Profile: $BBBPROFILE"
log "INFO" "##################################################"
# Deploy Prerequisites
log "INFO" "Deploying Prerequisites for BBB Environment"
BBBPREPSTACK="${BBBSTACK}-Sources"
if ! debug_exec deploy_stack "$BBBPREPSTACK" \
"./templates/bbb-on-aws-buildbuckets.template.yaml"; then
log "ERROR" "Failed to deploy prerequisites stack"
fi
# Get source bucket
SOURCE=$(aws cloudformation describe-stack-resources \
--profile "$BBBPROFILE" \
--stack-name "$BBBPREPSTACK" \
--query "StackResources[?ResourceType=='AWS::S3::Bucket'].PhysicalResourceId" \
--output text)
log "DEBUG" "Source bucket: $SOURCE"
# Copy files to S3
log "INFO" "Copying files to S3 bucket"
if [ -d "./templates" ] && [ -d "./scripts" ]; then
log "DEBUG" "Syncing templates and scripts to S3"
debug_exec aws s3 sync --profile="$BBBPROFILE" --exclude=".DS_Store" ./templates "s3://$SOURCE"
debug_exec aws s3 sync --profile="$BBBPROFILE" --exclude=".DS_Store" ./scripts "s3://$SOURCE"
else
log "ERROR" "Required source directories (templates/ or scripts/) are missing"
fi
# Deploy registry stack
deploy_registry_stack() {
log "INFO" "Deploying ECR registry stack..."
BBBECRSTACK="${BBBSTACK}-registry"
if ! debug_exec deploy_stack "$BBBECRSTACK" \
"./templates/bbb-on-aws-registry.template.yaml" \
--capabilities CAPABILITY_IAM; then
log "ERROR" "Failed to deploy ECR registry stack"
return 1
fi
log "INFO" "ECR registry stack deployed successfully"
return 0
}
# Deploy the registry stack
log "INFO" "Deploying ECR registry stack"
if ! debug_exec deploy_registry_stack; then
log "ERROR" "Failed to deploy ECR registry stack"
exit 1
fi
# Get repository information and mirror images
log "INFO" "Getting repository information and mirroring images"
GREENLIGHTIMAGE=$(aws ecr describe-repositories --profile="$BBBPROFILE" --query 'repositories[?contains(repositoryName, `greenlight`)].repositoryName' --output text)
SCALELITEIMAGE=$(aws ecr describe-repositories --profile="$BBBPROFILE" --query 'repositories[?contains(repositoryName, `scalelite`)].repositoryName' --output text)
SCALELITEREGISTRY=$(aws ecr describe-repositories --profile="$BBBPROFILE" --query 'repositories[?contains(repositoryName, `scalelite`)].repositoryUri' --output text)
GREENLIGHTREGISTRY=$(aws ecr describe-repositories --profile="$BBBPROFILE" --query 'repositories[?contains(repositoryName, `greenlight`)].repositoryUri' --output text)
log "INFO" "##################################################"
log "INFO" "Mirror docker images to ECR for further usage"
log "INFO" "##################################################"
SCALELITEIMAGETAGS=("BBBScaleliteNginxImageTag" "BBBScaleliteApiImageTag" "BBBScalelitePollerImageTag" "BBBScaleliteImporterImageTag")
GREENLIGHTIMAGETAGS=("BBBgreenlightImageTag")
# Authenticate with ECR
if ! debug_exec aws ecr get-login-password --profile="$BBBPROFILE" | debug_exec docker login --username AWS --password-stdin "$SCALELITEREGISTRY"; then
log "ERROR" "Failed to authenticate with Scalelite ECR registry"
fi
if ! debug_exec aws ecr get-login-password --profile="$BBBPROFILE" | debug_exec docker login --username AWS --password-stdin "$GREENLIGHTREGISTRY"; then
log "ERROR" "Failed to authenticate with Greenlight ECR registry"
fi
# Process Scalelite images
for IMAGETAG in "${SCALELITEIMAGETAGS[@]}"
do
TAGVALUE=$(jq -r ".Parameters.$IMAGETAG" bbb-on-aws-param.json)
log "DEBUG" "Processing Scalelite image with tag: $TAGVALUE"
debug_exec docker pull --platform linux/amd64 "$SCALELITEIMAGE:$TAGVALUE"
debug_exec docker tag "$SCALELITEIMAGE:$TAGVALUE" "$SCALELITEREGISTRY:$TAGVALUE"
debug_exec docker push "$SCALELITEREGISTRY:$TAGVALUE"
done
for IMAGETAG in "${GREENLIGHTIMAGETAGS[@]}"
do
TAGVALUE=$(jq -r ".Parameters.$IMAGETAG" bbb-on-aws-param.json)
log "DEBUG" "Processing Greenlight image with tag: $TAGVALUE"
debug_exec docker pull --platform linux/amd64 "$GREENLIGHTIMAGE:$TAGVALUE"
debug_exec docker tag "$GREENLIGHTIMAGE:$TAGVALUE" "$GREENLIGHTREGISTRY:$TAGVALUE"
debug_exec docker push "$GREENLIGHTREGISTRY:$TAGVALUE"
done
log "INFO" "##################################################"
log "INFO" "Registry Preparation finished"
log "INFO" "##################################################"
# Final deployment
log "INFO" "Deploying main BBB infrastructure"
if ! debug_exec deploy_stack "$BBBSTACK" \
"./bbb-on-aws-root.template.yaml" \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
"BBBOperatorEMail=$OPERATOREMAIL" \
"BBBStackBucketStack=$BBBSTACK-Sources" \
"BBBDomainName=$DOMAIN" \
"BBBHostedZone=$HOSTEDZONE" \
"BBBECRStack=$BBBSTACK-registry" \
$(jq -r '.Parameters | to_entries | map("\(.key)=\(.value)") | join(" ")' bbb-on-aws-param.json); then
log "ERROR" "Main infrastructure deployment failed"
fi
# Set the initial admin password for the environment
log "INFO" "Setting the initial admin password"
log "INFO" "##################################################"
# Get the secrets
log "DEBUG" "Retrieving administrator credentials from Secrets Manager"
ADMIN_SECRET=$(debug_exec aws secretsmanager list-secrets \
--profile "$BBBPROFILE" \
--filter Key="name",Values="BBBAdministratorlogin" \
--query 'SecretList[0].Name' \
--output text)
if [ -z "$ADMIN_SECRET" ]; then
log "ERROR" "Failed to retrieve admin secret from Secrets Manager"
fi
ADMIN_PASSWORD=$(debug_exec aws secretsmanager get-secret-value \
--profile "$BBBPROFILE" \
--secret-id "$ADMIN_SECRET" \
--query 'SecretString' \
--output text | jq -r '.password')
ADMIN_LOGIN=$(debug_exec aws secretsmanager get-secret-value \
--profile "$BBBPROFILE" \
--secret-id "$ADMIN_SECRET" \
--query 'SecretString' \
--output text | jq -r '.username')
if [ -z "$ADMIN_PASSWORD" ] || [ -z "$ADMIN_LOGIN" ]; then
log "ERROR" "Failed to retrieve admin credentials"
exit 1
fi
# Get the cluster information
log "DEBUG" "Retrieving ECS cluster information"
ECS_CLUSTERS=$(debug_exec aws ecs --profile="$BBBPROFILE" list-clusters)
ECS_CLUSTER=$(echo "$ECS_CLUSTERS" | jq -r '.clusterArns[0] | split("/") | .[1]')
if [ -z "$ECS_CLUSTER" ]; then
log "ERROR" "Failed to retrieve ECS cluster information"
fi
# Get Greenlight service and task
log "DEBUG" "Retrieving Greenlight service information"
GREENLIGHT_SERVICE=$(debug_exec aws ecs list-services \
--profile "$BBBPROFILE" \
--cluster "$ECS_CLUSTER" \
--query "serviceArns[?contains(@, 'BBBgreenlightService')]" \
--output text | xargs -n 1 basename)
if [ -z "$GREENLIGHT_SERVICE" ]; then
log "ERROR" "Failed to retrieve Greenlight service"
fi
log "DEBUG" "Retrieving Greenlight task information"
GREENLIGHT_TASK=$(debug_exec aws ecs list-tasks \
--profile "$BBBPROFILE" \
--cluster "$ECS_CLUSTER" \
--service "$GREENLIGHT_SERVICE" \
--output text | awk -F"/" '{print $NF}' | rev | awk -F"/" '{print $1}' | rev)
if [ -z "$GREENLIGHT_TASK" ]; then
log "ERROR" "Failed to retrieve Greenlight task"
fi
# Create admin user in Greenlight
log "INFO" "Creating admin user in Greenlight..."
output=$(debug_exec aws ecs execute-command \
--profile="$BBBPROFILE" \
--cluster "$ECS_CLUSTER" \
--task "$GREENLIGHT_TASK" \
--container greenlight \
--interactive \
--command "bundle exec rake admin:create[\"bbbadmin\",\"${ADMIN_LOGIN}\",\"${ADMIN_PASSWORD}\"]" 2>&1)
if echo "$output" | grep -q "Email has already been taken"; then
log "DEBUG" "Admin user already exists, continuing..."
elif echo "$output" | grep -q "error\|Error\|ERROR" && ! echo "$output" | grep -q "Email has already been taken"; then
log "ERROR" "Failed to create admin user: $output"
exit 1
else
log "INFO" "Admin user created successfully"
fi
log "INFO" "Admin user creation process completed"
log "INFO" "##################################################"
log "INFO" "Deployment completed successfully"
log "INFO" "Log file available at: $LOG_FILE"
exit 0