Monitor and Manage Google Cloud Resources
Solution for Monitor and Manage Google Cloud Resources. 1 lab: ARC101. Fast copy-paste commands for Google Cloud.
ARC101 — Monitor and Manage Google Cloud Resources: Challenge Lab
Estimated time: 1 hour 15 minutes
# 🚀 Monitor and Manage Google Cloud Resources: Challenge Lab > ⚠️ **Disclaimer:** This is an independent, community-made walkthrough built to help you understand why each step works. Attempt the challenge yourself first. This guide is provided for educational purposes only and is not affiliated with or endorsed by Google Cloud or Google Cloud Skills Boost. Always follow the official Google Cloud and Qwiklabs terms of service, lab instructions, and usage policies. > > **Walkthrough by Orbit of
clear
CYAN='\e[1;36m'
YELLOW='\e[1;33m'
GREEN='\e[1;32m'
MAGENTA='\e[1;35m'
RED='\e[1;31m'
RESET='\e[0m'
BOLD='\e[1m'
echo -e "${MAGENTA}${BOLD}--- Part 1: Infrastructure & IAM Prep ---${RESET}"
# Auto-detect project
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
echo -e "${CYAN}Detected Project ID:${RESET} $PROJECT_ID"
# Ask for the required variables from your lab panel
echo -e "\n${YELLOW}Please enter the required variables from your lab panel:${RESET}"
read -p "Bucket Name: " BUCKET_NAME
read -p "Topic Name: " TOPIC_NAME
read -p "Function Name: " FUNCTION_NAME
read -p "Region: " REGION
read -p "User 2 Email Address: " USER_2
read -p "Alert Email Address: " ALERT_EMAIL
# Export variables so Command 2 can use them in the same tab
export BUCKET_NAME TOPIC_NAME FUNCTION_NAME REGION USER_2 ALERT_EMAIL
echo -e "\n1️⃣ ${BOLD}Task 1 & 2 — Creating Infrastructure...${RESET}"
# Create the required bucket
gcloud storage buckets create gs://$BUCKET_NAME --location=$REGION
# Create the Pub/Sub topic
gcloud pubsub topics create $TOPIC_NAME
echo -e "\n2️⃣ ${BOLD}Task 1 & 2 — Applying IAM Permissions...${RESET}"
# Grant User 2 access at the project level (Viewer)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="user:$USER_2" \
--role="roles/viewer" --quiet
# Apply strict Eventarc IAM permissions
# 1. Grant Pub/Sub Publisher role to Cloud Storage service account
GCS_SA=$(gsutil kms serviceaccount -p $PROJECT_ID)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$GCS_SA" \
--role="roles/pubsub.publisher" --quiet
# 2. Grant Eventarc Event Receiver role to Compute Engine default service account
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${PROJECT_NUMBER}[email protected]" \
--role="roles/eventarc.eventReceiver" --quiet
echo -e "\n${GREEN}✅ Part 1 completed successfully!${RESET}"
echo -e "${YELLOW}📌 IMPORTANT: Return to the lab page and click 'Check my progress' for Tasks 1 & 2 before running Command 2 of 2.${RESET}"clear
CYAN='\e[1;36m'
YELLOW='\e[1;33m'
GREEN='\e[1;32m'
MAGENTA='\e[1;35m'
RED='\e[1;31m'
RESET='\e[0m'
BOLD='\e[1m'
echo -e "\n3️⃣ ${BOLD}Task 3 — Creating & Deploying the Thumbnail Cloud Run Function...${RESET}"
mkdir -p ~/thumbnail_app
cd ~/thumbnail_app
cat > index.js <<EOF
/* globals exports, require */
//jshint strict: false
//jshint esversion: 6
"use strict";
const crc32 = require("fast-crc32c");
const { Storage } = require('@google-cloud/storage');
const gcs = new Storage();
const { PubSub } = require('@google-cloud/pubsub');
const imagemagick = require("imagemagick-stream");
exports.thumbnail = (event, context) => {
const fileName = event.name;
const bucketName = event.bucket;
const size = "64x64"
const bucket = gcs.bucket(bucketName);
const topicName = "${TOPIC_NAME}";
const pubsub = new PubSub();
if ( fileName.search("64x64_thumbnail") == -1 ){
var filename_split = fileName.split('.');
var filename_ext = filename_split[filename_split.length - 1];
var filename_without_ext = fileName.substring(0, fileName.length - filename_ext.length );
if (filename_ext.toLowerCase() == 'png' || filename_ext.toLowerCase() == 'jpg'){
console.log(\`Processing Original: gs://\${bucketName}/\${fileName}\`);
const gcsObject = bucket.file(fileName);
let newFilename = filename_without_ext + size + '_thumbnail.' + filename_ext;
let gcsNewObject = bucket.file(newFilename);
let srcStream = gcsObject.createReadStream();
let dstStream = gcsNewObject.createWriteStream();
let resize = imagemagick().resize(size).quality(90);
srcStream.pipe(resize).pipe(dstStream);
return new Promise((resolve, reject) => {
dstStream
.on("error", (err) => {
console.log(\`Error: \${err}\`);
reject(err);
})
.on("finish", () => {
console.log(\`Success: \${fileName} → \${newFilename}\`);
gcsNewObject.setMetadata(
{
contentType: 'image/'+ filename_ext.toLowerCase()
}, function(err, apiResponse) {});
pubsub
.topic(topicName)
.publisher()
.publish(Buffer.from(newFilename))
.then(messageId => {
console.log(\`Message \${messageId} published.\`);
})
.catch(err => {
console.error('ERROR:', err);
});
});
});
}
}
};
EOF
cat > package.json <<EOF
{
"name": "thumbnails",
"version": "1.0.0",
"description": "Create Thumbnail of uploaded image",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"@google-cloud/pubsub": "^2.0.0",
"@google-cloud/storage": "^5.0.0",
"fast-crc32c": "1.0.4",
"imagemagick-stream": "4.1.1"
},
"devDependencies": {},
"engines": {
"node": ">=4.3.2"
}
}
EOF
echo -e "${YELLOW}Waiting 60 seconds to guarantee all IAM policies have propagated...${RESET}"
sleep 60
echo -e "${YELLOW}Deploying Cloud Run Function (Restricted to 1 instance)...${RESET}"
deploy_success=false
for i in 1 2 3; do
echo -e "${CYAN}Deployment Attempt $i of 3...${RESET}"
if gcloud functions deploy $FUNCTION_NAME \
--gen2 \
--runtime=nodejs22 \
--region=$REGION \
--source=. \
--entry-point=thumbnail \
--trigger-bucket=$BUCKET_NAME \
--max-instances=1 \
--quiet; then
deploy_success=true
echo -e "${GREEN}✅ Function deployed successfully!${RESET}"
break
else
echo -e "${RED}⚠️ Deployment failed (IAM delay). Waiting 45 seconds before next try...${RESET}"
sleep 45
fi
done
echo -e "\n4️⃣ ${BOLD}Task 4 — Testing Infrastructure & Creating Alert Policy...${RESET}"
wget -q https://storage.googleapis.com/cloud-training/arc101/travel.jpg
gcloud storage cp travel.jpg gs://$BUCKET_NAME/ 2>/dev/null
CHANNEL_ID=$(gcloud beta monitoring channels create \
--display-name="Personal Email" \
--type=email \
--channel-labels=email_address=${ALERT_EMAIL} \
--format="value(name)")
cat > active-instances-policy.json <<EOF
{
"displayName": "Active Cloud Run Function Instances",
"combiner": "OR",
"conditions": [
{
"displayName": "Cloud Function Active Instances",
"conditionThreshold": {
"filter": "resource.type=\"cloud_function\" AND metric.type=\"cloudfunctions.googleapis.com/function/active_instances\"",
"aggregations": [
{
"alignmentPeriod": "60s",
"perSeriesAligner": "ALIGN_MAX"
}
],
"comparison": "COMPARISON_GT",
"thresholdValue": 0,
"duration": "0s"
}
}
],
"notificationChannels": ["$CHANNEL_ID"]
}
EOF
gcloud alpha monitoring policies create --policy-from-file="active-instances-policy.json" --quiet
echo -e "${GREEN}✅ Alerting Policy created successfully!${RESET}"
echo -e "\n${MAGENTA}${BOLD}╔════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${MAGENTA}${BOLD}║ 🎉 AUTOMATION COMPLETED SUCCESSFULLY 🎉 ║${RESET}"
echo -e "${MAGENTA}${BOLD}╚════════════════════════════════════════════════════════════╝${RESET}"