generated from CDCgov/template
-
Notifications
You must be signed in to change notification settings - Fork 6
/
quick-start.sh
executable file
·354 lines (299 loc) · 14.8 KB
/
quick-start.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
#!/bin/bash
################################################################################
#
# This script is used to setup gcloud authentication for GitHub Actions.
# It is based on the following guide: https://github.com/google-github-actions/auth#setup
#
################################################################################
### Functions ###
# Colorize text
colorize() {
gum style --foreground "$1" "$2"
}
# Print pink text
pink() {
colorize 212 "$1"
}
# Run a command with a spinner
spin() {
local -r title="${1}"
shift 1
gum spin -s line --title "${title}" -- $@
}
# Enter to continue
enter_to_continue() {
echo "Press $(pink 'Enter') when you're done."
echo
read
}
# Check if user has access to billing accounts and select one if they do
enable_billing() {
BILLING_ACCOUNT_COUNT=$(gcloud beta billing accounts list --format json | jq '. | length')
while [ "$BILLING_ACCOUNT_COUNT" = "0" ]; do
echo "You don't have any $(pink 'billing accounts') yet."
echo "If you are responsible for billing, please create one in the Google Cloud Console at https://console.cloud.google.com/billing."
echo "If you are not responsible for billing, please ask your billing admin to create one for you."
echo "Press $(pink 'Enter') to continue once the billing account is created. Type $(pink 'exit') to exit the script."
read SHOULD_CONTINUE
if [ "$SHOULD_CONTINUE" = "exit" ]; then
exit 1
else
BILLING_ACCOUNT_COUNT=$(gcloud beta billing accounts list --format json | jq '. | length')
fi
done
echo "You have $(pink $BILLING_ACCOUNT_COUNT) billing account(s)."
echo "Please select the $(pink 'billing account') you want to use for this project."
echo
BILLING_ACCOUNT_ID=$(gcloud beta billing accounts list --format="csv(displayName,name)" | gum table -w 25,25 | cut -d ',' -f 2)
}
# Link the selected billing account to the selected project
link_billing_account() {
spin "Linking $(pink 'project') to billing account..." gcloud beta billing projects link "${PROJECT_ID}" --billing-account="${BILLING_ACCOUNT_ID}"
}
### Main ###
# Install gum
if ! command -v gum &> /dev/null; then
echo "Installing gum..."
go install github.com/charmbracelet/gum@v0.8
fi
clear
# Intro text
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "Welcome to the $(pink 'PHDI Google Cloud') setup script!"
echo "This script will help you setup $(pink 'gcloud') authentication for GitHub Actions."
echo "We need some info from you to get started."
echo
# Check if new project, create a project if needed and get the project ID
if gum confirm "Do you already have a $(pink 'Project') in Google Cloud Platform?"; then
NEW_PROJECT=false
echo "We will now get the ID of your existing Google Cloud $(pink 'project')."
echo "A window will open asking you to authorize the gcloud CLI. Please click '$(pink 'Authorize')'."
enter_to_continue
echo "Please select the $(pink 'project') you want to use:"
PROJECT_NAME=$(gcloud projects list --format="value(name)" | gum choose)
PROJECT_ID=$(gcloud projects list --filter="name:${PROJECT_NAME}" --format="value(projectId)")
echo "You selected $(pink "${PROJECT_NAME}") with ID $(pink "${PROJECT_ID}")."
echo
# Check if billing is enabled, enable billing if needed and link billing account to project
BILLING_ENABLED=$(gcloud beta billing projects describe "${PROJECT_ID}" --format="value(billingEnabled)")
if [[ "${BILLING_ENABLED}" == "False" ]]; then
enable_billing
link_billing_account
fi
else
NEW_PROJECT=true
echo "Thank you! We will now attempt to create a new Google Cloud $(pink 'project') for you."
echo "A window will open asking you to authorize the gcloud CLI. Please click '$(pink 'Authorize')'."
enter_to_continue
# Check if billing is enabled, enable billing if needed
enable_billing
PROJECT_NAME=$(gum input --prompt="Please enter a name for a new $(pink 'Project'). " --placeholder="Project name")
PROJECT_ID=$(echo $PROJECT_NAME | awk '{print tolower($0)}')-$(date +"%s")
spin "Creating $(pink 'project')..." gcloud projects create $PROJECT_ID --name="${PROJECT_NAME}"
# Link billing account to project
link_billing_account
fi
# Set the current project to the PROJECT_ID specified above
spin "Setting gcloud default $(pink 'project')..." gcloud config set project "${PROJECT_ID}"
# Enable necessary APIs
spin "Enabling $(pink 'gcloud APIs') (this may take a few minutes)..." gcloud services enable \
compute.googleapis.com \
iam.googleapis.com \
cloudresourcemanager.googleapis.com \
iamcredentials.googleapis.com \
sts.googleapis.com \
serviceusage.googleapis.com
# Prompt for region, zone, and Smarty creds
echo "Please select the $(pink 'region') you would like to deploy to."
echo "More info: https://cloud.google.com/compute/docs/regions-zones/regions-zones"
echo
REGION=$(gum choose "us-east1" "us-east4" "us-central1" "us-west1" "us-west2" "us-west3")
echo "Please select the $(pink 'zone') you would like to deploy to."
echo
ZONE=$(gcloud compute zones list --filter="name~'${REGION}'" --format="value(name)" | gum choose)
echo "Please enter the $(pink 'Authorization ID') of your Smarty Street Account."
echo "More info: https://www.smarty.com/docs/cloud/authentication"
echo
SMARTY_AUTH_ID=$(gum input --placeholder="Authorization ID")
echo "Please enter the $(pink 'Authorization Token') of your Smarty Street Account."
echo "More info: https://www.smarty.com/docs/cloud/authentication"
echo
SMARTY_AUTH_TOKEN=$(gum input --placeholder="Authorization Token")
# Login to gh CLI
echo "Project ID $(pink 'set')!"
echo "We will now login to the $(pink 'GitHub CLI')."
echo "Copy the provided code, press $(pink 'Enter') and then $(pink 'click') the link that will be printed."
echo "If you are not already logged in to GitHub, you will be prompted to do so."
echo "If your account has $(pink '2FA') enabled, you will be prompted to enter a 2FA code (this is $(pink 'different') from the code you copied)."
echo "After logging in, paste the code into the input and follow the prompts to authorize the GitHub CLI."
echo "Then return to this terminal!"
enter_to_continue
gh auth login --hostname github.com -p https -w
GITHUB_USER=$(gh api user -q '.login')
# Check if repo already forked, fork if needed, get repository name
echo "In order to create your own pipeline, you will need your own copy of the $(pink 'CDCgov/phdi-google-cloud') GitHub repository."
echo "This is done by $(pink '"forking"') the repository."
echo "If you haven't already forked the repository, we will do that now."
echo
if gum confirm "Have you already forked the $(pink 'phdi-google-cloud') repository on GitHub?"; then
echo "Please choose repository you would like to use:"
echo
REPO_NAME=$(gh repo list --fork --json name --jq ".[].name" | gum choose)
GITHUB_REPO="${GITHUB_USER}/${REPO_NAME}"
else
if gum confirm "Would you like to fork into an organization or your personal account?" --affirmative="Organization" --negative="Personal account"; then
echo "Please choose organization you would like to fork into:"
echo
ORG_NAME="--org $(gh api user/orgs -q '.[].login' | gum choose)"
else
ORG_NAME=""
fi
spin "Forking repository..." gh repo fork ${ORG_NAME} CDCgov/phdi-google-cloud
GITHUB_REPO="${GITHUB_USER}/phdi-google-cloud"
fi
echo "GitHub repository $(pink 'set')!"
echo
### Set up Workload Identity ###
# Create a service account
spin "Creating service account..." gcloud iam service-accounts create github \
--project "${PROJECT_ID}" \
--display-name "github"
# Get the service account ID and set some variables
SERVICE_ACCOUNT_ID=$(gcloud iam service-accounts list \
--project="${PROJECT_ID}" \
--filter="displayName:github" \
--format="value(email)")
# Grant the service account the owner role on the project
spin "Granting service account owner role..." gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SERVICE_ACCOUNT_ID}" \
--role="roles/owner"
if [ "$NEW_PROJECT" = true ]; then
spin "Waiting for service account to be ready (this will take a minute)..." sleep 60
fi
# Create a Workload Identity Pool
spin "Creating workload identity pool..." gcloud iam workload-identity-pools create github \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="github"
# Get the full ID of the Workload Identity Pool
WORKLOAD_IDENTITY_POOL_ID=$(gcloud iam workload-identity-pools describe github \
--project="${PROJECT_ID}" \
--location="global" \
--format="value(name)")
# Create a Workload Identity Provider in that pool
spin "Creating workload identity provider..." gcloud iam workload-identity-pools providers create-oidc github \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github" \
--display-name="github" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"
# Allow authentications from the Workload Identity Provider originating from your repository to impersonate the Service Account created above
spin "Adding IAM policy binding for GitHub repo..." gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT_ID}" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${GITHUB_REPO}"
# Extract the Workload Identity Provider resource name
WORKLOAD_IDENTITY_PROVIDER=$(gcloud iam workload-identity-pools providers describe github \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github" \
--format="value(name)")
echo "Workload Identity Federation setup $(pink 'complete')!"
echo
### GitHub Actions ###
# Set up GitHub Secrets
spin "Setting PROJECT_ID..." gh -R "${GITHUB_REPO}" secret set PROJECT_ID --body "${PROJECT_ID}"
spin "Setting SERVICE_ACCOUNT_ID..." gh -R "${GITHUB_REPO}" secret set SERVICE_ACCOUNT_ID --body "${SERVICE_ACCOUNT_ID}"
spin "Setting WORKLOAD_IDENTITY_PROVIDER..." gh -R "${GITHUB_REPO}" secret set WORKLOAD_IDENTITY_PROVIDER --body "${WORKLOAD_IDENTITY_PROVIDER}"
spin "Setting REGION..." gh -R "${GITHUB_REPO}" secret set REGION --body "${REGION}"
spin "Setting ZONE..." gh -R "${GITHUB_REPO}" secret set ZONE --body "${ZONE}"
spin "Setting SMARTY_AUTH_ID..." gh -R "${GITHUB_REPO}" secret set SMARTY_AUTH_ID --body "${SMARTY_AUTH_ID}"
spin "Setting SMARTY_AUTH_TOKEN..." gh -R "${GITHUB_REPO}" secret set SMARTY_AUTH_TOKEN --body "${SMARTY_AUTH_TOKEN}"
echo "Repository secrets $(pink 'set')!"
echo
# Create dev environment in GitHub
spin "Creating $(pink 'dev') environment..." gh api -X PUT "repos/${GITHUB_REPO}/environments/dev" --silent
# Enable GitHub Actions
echo "To deploy your new pipeline, you'll need to enable $(pink 'GitHub Workflows')."
echo "Please open https://github.com/${GITHUB_REPO}/actions in a new tab."
echo "Click the green button to enable $(pink 'GitHub Workflows')."
enter_to_continue
WORKFLOWS_ENABLED=$(gh api -X GET "repos/${GITHUB_REPO}/actions/workflows" -q '.total_count')
while [ "$WORKFLOWS_ENABLED" = "0" ]; do
echo "Looks like that didn't work! Please try again."
echo "Please open https://github.com/${GITHUB_REPO}/actions in a new tab."
echo "Click the green button to enable $(pink 'GitHub Workflows')."
echo "Press $(pink 'Enter') when you're done. Type $(pink 'exit') to exit the script."
echo
read SHOULD_CONTINUE
if [ "$SHOULD_CONTINUE" = "exit" ]; then
exit 1
else
WORKFLOWS_ENABLED=$(gh api -X GET "repos/${GITHUB_REPO}/actions/workflows" -q '.total_count')
fi
done
# Run Terraform Setup workflow
echo "We will now run the $(pink 'Terraform Setup') workflow."
echo "This will create the necessary storage account for Terraform in Google Cloud."
echo
spin "Waiting for $(pink 'Workload Identity') to be ready (this will take a minute)..." sleep 60
spin "Starting Terraform Setup workflow..." gh -R "${GITHUB_REPO}" workflow run terraformSetup.yaml
echo
# Watch Terraform Setup workflow until complete
TF_SETUP_STARTED=$(gh -R "${GITHUB_REPO}" run list --workflow=terraformSetup.yaml --json databaseId -q ". | length")
CHECK_COUNT=0
while [ "$TF_SETUP_STARTED" = "0" ]; do
if [ "$CHECK_COUNT" -gt 60 ]; then
echo "Looks like that didn't work! Please contact the PHDI team for help."
exit 1
fi
spin "Waiting for Terraform Setup workflow to start..." sleep 1
TF_SETUP_STARTED=$(gh -R "${GITHUB_REPO}" run list --workflow=terraformSetup.yaml --json databaseId -q ". | length")
CHECK_COUNT=$((CHECK_COUNT+1))
done
TF_SETUP_WORKFLOW_ID=$(gh -R "${GITHUB_REPO}" run list --workflow=terraformSetup.yaml -L 1 --json databaseId -q ".[0].databaseId")
gh -R "${GITHUB_REPO}" run watch $TF_SETUP_WORKFLOW_ID
# Check for Terraform Setup workflow success
TF_SETUP_SUCCESS=$(gh -R "${GITHUB_REPO}" run list --workflow=terraformSetup.yaml --json conclusion -q '.[].conclusion')
if [ "$TF_SETUP_SUCCESS" != "success" ]; then
echo "Looks like that didn't work! Please contact the PHDI team for help."
exit 1
fi
# Run deployment workflow
echo "We will now run the $(pink 'Terraform Deploy') workflow."
echo "This will deploy the infrastructure to your Google Cloud project."
echo
spin "Running Terraform Deploy workflow..." gh -R "${GITHUB_REPO}" workflow run deployment.yaml -f environment=dev
echo
# Watch deployment workflow until complete
DEPLOYMENT_STARTED=$(gh -R "${GITHUB_REPO}" run list --workflow=deployment.yaml --json databaseId -q ". | length")
CHECK_COUNT=0
while [ "$DEPLOYMENT_STARTED" = "0" ]; do
if [ "$CHECK_COUNT" -gt 60 ]; then
echo "Looks like that didn't work! Please contact the PHDI team for help."
exit 1
fi
spin "Waiting for deployment workflow to start..." sleep 1
DEPLOYMENT_STARTED=$(gh -R "${GITHUB_REPO}" run list --workflow=deployment.yaml --json databaseId -q ". | length")
CHECK_COUNT=$((CHECK_COUNT+1))
done
DEPLOYMENT_WORKFLOW_ID=$(gh -R "${GITHUB_REPO}" run list --workflow=deployment.yaml -L 1 --json databaseId -q ".[0].databaseId")
gh -R "${GITHUB_REPO}" run watch $DEPLOYMENT_WORKFLOW_ID
# Check for deployment workflow success
DEPLOY_SUCCESS=$(gh -R "${GITHUB_REPO}" run list --workflow=deployment.yaml --json conclusion -q '.[].conclusion')
if [ "$DEPLOY_SUCCESS" != "success" ]; then
echo "Looks like that didn't work! Please contact the PHDI team for help."
echo "To view the status of your workflows, go to https://github.com/${GITHUB_REPO}/actions."
echo
exit 1
fi
# Sendoff
clear
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "Quick start $(pink 'complete')! You can view your forked repository at https://github.com/${GITHUB_REPO}"
echo
echo "Your infrastructure is $(pink 'deployed')!"
echo "To trigger your new pipeline, upload a file to the $(pink 'phdi-dev-phi') bucket at this link:"
echo "https://console.cloud.google.com/storage/browser"
echo
echo "Thanks for using the $(pink 'PHDI Google Cloud') quick start script!"
echo