Skip to content

Instantly share code, notes, and snippets.

@tedwardd
Created May 29, 2025 18:53
Show Gist options
  • Save tedwardd/f23f3769c95de417b96677ce8ab944d2 to your computer and use it in GitHub Desktop.
Save tedwardd/f23f3769c95de417b96677ce8ab944d2 to your computer and use it in GitHub Desktop.
#!/bin/bash
##############################################################################
## Preflight check for a given project to ensure it is in a state where
## it can be shutdown
##
## Checks the following:
## - What assets are present, ignoring $ignored_assets
## - Ignore known assets from specific asset types
## - If WIF pools are present
## - If Secrets are present
##
## Requirements:
## - gcloud CLI
## - Config file with required_apis and ignored_assets
##
## Usage:
## ./preflight.sh <project_id>
##############################################################################
# Change if needed to the path of your config options file
config_file="./preflight_config"
# Get the project ID from the command line
project_id="${1}"
if [[ -z "${project_id}" ]]; then
echo "Usage: $0 <project_id>"
exit 1
fi
# Source the config file
# shellcheck source=./config_options
[[ -f "${config_file}" ]] && source "${config_file}" || {
echo "Config file ${config_file} not found"
exit 1
}
# Get list of resources based on provided assetType
get_assets() {
asset_type="${1}"
gcloud asset list -q --project="${project_id}" --asset-types="${asset_type}" --format="value(name)"
}
# Accept asset_type and list of assets and run function based on asset_type
filter_assets() {
asset_type="${1}"
assets="${2}"
case "${asset_type}" in
"dataplex.googleapis.com/EntryGroup")
for entrygroup in "${ignored_entrygroups[@]}"; do
assets=$(echo "${assets}" | grep -v "${entrygroup}")
done
;;
"compute.googleapis.com/SslPolicy")
for ssl_policy in "${ignored_ssl_policies[@]}"; do
assets=$(echo "${assets}" | grep -v "${ssl_policy}")
done
;;
"iam.googleapis.com/Role")
for role in "${ignored_roles[@]}"; do
assets=$(echo "${assets}" | grep -v "${role}")
done
;;
"storage.googleapis.com/Bucket")
for bucket in "${ignored_buckets[@]}"; do
assets=$(echo "${assets}" | grep -v "${bucket}")
done
;;
esac
echo "${assets}"
}
# Check if the project exists
if ! gcloud projects describe "${project_id}" &>/dev/null; then
echo "Project ${project_id} does not exist"
exit 1
fi
# Enable a given API or return 1
enable_api() {
if ! gcloud services enable "${1}" -q --project="${project_id}" &>/dev/null; then
return 1
fi
}
# Returns a list of unique asset types for a given project or return 1
get_asset_types() {
asset_types=$(gcloud asset list -q --project="${project_id}" --format="value(assetType)" | sort -u)
if [[ -z "${asset_types}" ]] || [[ "${asset_types}" == "" ]]; then
return 1
fi
echo "${asset_types}"
}
# Fetch the list of pools and return them or return 1
list_pools() {
if ! pools=$(
gcloud iam workload-identity-pools list -q --location global --project="${project_id}" --format="value(name)"
); then
return 1
fi
if [[ -n "${pools}" ]] && [[ "${pools}" != "" ]]; then
echo "${pools}"
fi
}
# Check if a value is in a list
check_value_in_list() {
local value="${1}"
local list="${2}"
if ! echo "${list}" | grep -q "${value}"; then
return 1
fi
}
# List project secrets or return 1
list_secrets() {
secrets=$(gcloud secrets list -q --project="${project_id}" --format="value(name)")
if [[ -z "${secrets}" ]]; then
return 1
fi
echo "${secrets}"
}
# Enable required APIs or exit on failure
for api in "${required_apis[@]}"; do
if ! enable_api "${api}"; then
echo "Failed to enable ${api} API"
exit 1
fi
done
## Assets ####################################################################
# Get the list of assets or print error and exit
if ! project_assets=$(get_asset_types); then
echo "Failed to get assets for project ${project_id}"
exit 1
fi
# Check for ignored assets
for asset in "${ingored_assets[@]}"; do
if check_value_in_list "${asset}" "${project_assets}"; then
# Remove the ignored asset from the list
project_assets=$(echo "${project_assets}" | grep -v "${asset}")
fi
done
# Get length of project_assets after removing ignored assets
asset_count=$(wc -l <<<"${project_assets}")
# Print the number of assets found as well as the assets themselves
echo "Unique asset types found: $((asset_count))"
echo "Asset types with potentially active resources:"
if [[ -n "${project_assets}" ]]; then
while read -r asset; do
assets=$(get_assets "${asset}")
assets=$(filter_assets "${asset}" "${assets}")
if [[ -z "${assets}" ]]; then
continue
fi
echo " - ${asset}"
while read -r asset; do
echo " - ${asset}"
done <<<"${assets}"
done <<<"${project_assets}"
fi
## WIF Pools #################################################################
# Get pools, display count and list pool names if any else return error and
# exit
if pools=$(list_pools); then
pool_count=0
# For some reason list_pools returns an empty string when no pools are found
# This works around that for now
# TODO: Investigate why list_pools returns an empty string when no pools are found
if [[ "${pools}" != "" ]]; then
pool_count=$(wc -l <<<"${pools}")
fi
echo "WIF pools found: $((pool_count))"
if [[ -n "${pools}" ]]; then
while read -r pool; do
echo " - ${pool}"
done <<<"${pools}"
fi
else
echo "Failed to list pools for project ${project_id}"
exit 1
fi
## Secrets ###################################################################
# Get secrets, display count and list secret names if any else return error
# and exit
if secrets=$(list_secrets); then
secret_count=$(wc -l <<<"${secrets}")
echo "Secrets found: $((secret_count))"
if [[ -n "${secrets}" ]]; then
while read -r secret; do
echo " - ${secret}"
done <<<"${secrets}"
fi
else
echo "Failed to list secrets for project ${project_id}"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment