Skip to content

How to label forwarding rules quickly

Imported from Confluence

Content may be outdated. Verify before following any procedures. View original | Last updated: September 2024

Recently, I had to label forwarding rules in our projects to track billing, and provide better granular visibility to network resources spend. One resource that can help us reach this goal is the forwarding rules in GCP.
Normally, we would label the resource with Terraform, but we noticed that this resource already exists and was created automatically by GKE when resources related to load balancing were provisioned. See example: GCP Console - Frontends.

The purpose of this wiki is to:

  • document the script that I used in labelling the forwarding rules automatically, as it is not managed in our Terraform setup.
  • create a reference script available for tweaking, in case we have a situation to label resources also setup like this forwarding rule resource like in DEVOPSBLN-5428

Info

This helps us quickly label all existing forwarding rules, and use the same naming convention across all projects for forwarding rule labels.

Steps

  1. Below is the dry-run script. Do not skip this step. Test first. Copy this script and paste it into cloud shell. 
cat << 'EOF' > label_forwarding_rules_dry_run.sh
#!/bin/bash

# Define the user-supplied labels as individual key-value pairs in an array
declare -A LABELS=(
  ["env"]="dev"
  ["tu"]="agp"
  ["product"]="growth"
)

# Convert the labels array into a format that gcloud expects (key=value,key=value,...)
LABEL_STRING=""
for key in "${!LABELS[@]}"; do
  LABEL_STRING+="$key=${LABELS[$key]},"
done

# Remove the trailing comma from the label string
LABEL_STRING=${LABEL_STRING%,}

# List all forwarding rules with name, region, and description
gcloud compute forwarding-rules list --format="json(name, region, description)" | jq -c '.[]' | while read -r rule; do
  # Extract name, region, and description
  NAME=$(echo "$rule" | jq -r '.name')
  REGION=$(echo "$rule" | jq -r '.region' | sed 's/null//')  # Remove null if present
  DESCRIPTION=$(echo "$rule" | jq -r '.description')

  # Default sub-product to empty
  SUB_PRODUCT=""

  # Check if description contains "kubernetes.io/ingress-name" or "kubernetes.io/service-name"
  if echo "$DESCRIPTION" | grep -q '"kubernetes.io/ingress-name"'; then
    # Extract the value of "kubernetes.io/ingress-name" and take the part before "/"
    SUB_PRODUCT=$(echo "$DESCRIPTION" | jq -r '."kubernetes.io/ingress-name"' | cut -d'/' -f1)
  elif echo "$DESCRIPTION" | grep -q '"kubernetes.io/service-name"'; then
    # Extract the value of "kubernetes.io/service-name" and take the part before "/"
    SUB_PRODUCT=$(echo "$DESCRIPTION" | jq -r '."kubernetes.io/service-name"' | cut -d'/' -f1)
  elif echo "$DESCRIPTION" | grep -q '"k8sResource"'; then
    # Extract the value of "k8sResource" and take the part after the last "/"
    SUB_PRODUCT=$(echo "$DESCRIPTION" | jq -r '."k8sResource"' | awk -F'/' '{print $NF}')
  fi

  # Check if SUB_PRODUCT was found and add it to the labels string
  if [ -n "$SUB_PRODUCT" ]; then
    echo "Parsed sub-product: $SUB_PRODUCT from forwarding rule: $NAME"
    LABEL_STRING_WITH_SUB_PRODUCT="$LABEL_STRING,sub-product=$SUB_PRODUCT"
  else
    echo "No valid sub-product found for forwarding rule: $NAME"
    LABEL_STRING_WITH_SUB_PRODUCT="$LABEL_STRING"
  fi

  # Dry run - Just print the command that would be executed
  if [ -z "$REGION" ]; then
    # For global forwarding rules
    echo "[Dry run] Updating global forwarding rule: $NAME with labels: $LABEL_STRING_WITH_SUB_PRODUCT"
  else
    # For regional forwarding rules
    echo "[Dry run] Updating regional forwarding rule: $NAME in region: $REGION with labels: $LABEL_STRING_WITH_SUB_PRODUCT"
  fi
done
EOF
  1. copy this script and paste it into cloud shell. For example, it adds labels like: "env=dev,product=growth,tu=agp,sub-product=gateway-api-pub" as required.
  2. adjust the labels for env, product, and tu as is relevant to you (i.e. depending on the project).
  3. Make the dry_run script executable: chmod +x label_all_forwarding_rules_dry_run.sh
  4. install jq in cloud shell (if it is not already installed): sudo apt-get install jq
  5. run dry-run script: sh /.label_all_forwarding_rules_dry_run.sh. This tests if your script will do what it should
  6. The output of the dry-run script should look like this:
john_adedigba@cloudshell:~ (agp-growth-dev-fm)$ sh ./label_all_forwarding_rules_dry_run.sh
Parsed sub-product: gateway-api-pub from forwarding rule: gkegw1-6u2i-gateway-api-pub-gateway-api-pub-4qsehgdsck55
[Dry run] Updating global forwarding rule: gkegw1-6u2i-gateway-api-pub-gateway-api-pub-4qsehgdsck55 with labels: env=dev,product=growth,tu=agp,sub-product=gateway-api-pub
Parsed sub-product: gateway-api-pub from forwarding rule: gkegw1-6u2i-gateway-api-pub-gateway-api-pub-8glf19p5qlwe
[Dry run] Updating global forwarding rule: gkegw1-6u2i-gateway-api-pub-gateway-api-pub-8glf19p5qlwe with labels: env=dev,product=growth,tu=agp,sub-product=gateway-api-pub
Parsed sub-product: mmp-postback-staging from forwarding rule: k8s2-fs-6u2ivoh7-mmp-postback-st-mmp-postback-service--gflsnnc7
[Dry run] Updating global forwarding rule: k8s2-fs-6u2ivoh7-mmp-postback-st-mmp-postback-service--gflsnnc7 with labels: env=dev,product=growth,tu=agp,sub-product=mmp-postback-staging
Parsed sub-product: monitoring from forwarding rule: a2876b0f4231644b8a5c5fe76979a1fe
[Dry run] Updating regional forwarding rule: a2876b0f4231644b8a5c5fe76979a1fe in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=monitoring
Parsed sub-product: ingress-nginx-prv from forwarding rule: a30281ba9b6a34d8fbdfc038efca1b8f
[Dry run] Updating regional forwarding rule: a30281ba9b6a34d8fbdfc038efca1b8f in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=ingress-nginx-prv
Parsed sub-product: ingress-nginx-prv from forwarding rule: a57ffe95f2a4b4d7db0f108cf0130d43
[Dry run] Updating regional forwarding rule: a57ffe95f2a4b4d7db0f108cf0130d43 in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=ingress-nginx-prv
Parsed sub-product: kafka from forwarding rule: a9676767f7b1b476c8fd770831f8182d
[Dry run] Updating regional forwarding rule: a9676767f7b1b476c8fd770831f8182d in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=kafka
Parsed sub-product: ingress-nginx-pub from forwarding rule: a9f6e1322fd924eb898f369c72658e11
[Dry run] Updating regional forwarding rule: a9f6e1322fd924eb898f369c72658e11 in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=ingress-nginx-pub
Parsed sub-product: gateway-api-prv from forwarding rule: gkegw1-6u2i-gateway-api-prv-gateway-api-prv-jpzu6sqplh0g
[Dry run] Updating regional forwarding rule: gkegw1-6u2i-gateway-api-prv-gateway-api-prv-jpzu6sqplh0g in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=gateway-api-prv
Parsed sub-product: gateway-api-prv from forwarding rule: gkegw1-6u2i-gateway-api-prv-gateway-api-prv-zs196jb1nrbx
[Dry run] Updating regional forwarding rule: gkegw1-6u2i-gateway-api-prv-gateway-api-prv-zs196jb1nrbx in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=gateway-api-prv
Parsed sub-product: gateway-userstore-rilb-psc1 from forwarding rule: gkegw1-6u2i-user-store-gateway-userstore-rilb-psc1-9feg96ngf58v
[Dry run] Updating regional forwarding rule: gkegw1-6u2i-user-store-gateway-userstore-rilb-psc1-9feg96ngf58v in region: https://www.googleapis.com/compute/v1/projects/agp-growth-dev-fm/regions/us-east1 with labels: env=dev,product=growth,tu=agp,sub-product=gateway-userstore-rilb-psc1
  1. Do the same steps as in 1 with the actual run script. The script now runs: gcloud compute forwarding-rules update, labelling all forwarding rules appropriately.
cat << 'EOF' > label_all_forwarding_rules.sh
#!/bin/bash

# Define the user-supplied labels as individual key-value pairs in an array
declare -A LABELS=(
  ["env"]="dev"
  ["tu"]="agp"
  ["product"]="growth"
)

# Convert the labels array into a format that gcloud expects (key=value,key=value,...)
LABEL_STRING=""
for key in "${!LABELS[@]}"; do
  LABEL_STRING+="$key=${LABELS[$key]},"
done

# Remove the trailing comma from the label string
LABEL_STRING=${LABEL_STRING%,}

# List all forwarding rules with name, region, and description
gcloud compute forwarding-rules list --format="json(name, region, description)" | jq -c '.[]' | while read -r rule; do
  # Extract name, region, and description
  NAME=$(echo "$rule" | jq -r '.name')
  REGION=$(echo "$rule" | jq -r '.region' | sed 's/null//')  # Remove null if present
  DESCRIPTION=$(echo "$rule" | jq -r '.description')

  # Default sub-product to empty
  SUB_PRODUCT=""

  # Check if description contains "kubernetes.io/ingress-name" or "kubernetes.io/service-name"
  if echo "$DESCRIPTION" | grep -q '"kubernetes.io/ingress-name"'; then
    # Extract the value of "kubernetes.io/ingress-name" and take the part before "/"
    SUB_PRODUCT=$(echo "$DESCRIPTION" | jq -r '."kubernetes.io/ingress-name"' | cut -d'/' -f1)
  elif echo "$DESCRIPTION" | grep -q '"kubernetes.io/service-name"'; then
    # Extract the value of "kubernetes.io/service-name" and take the part before "/"
    SUB_PRODUCT=$(echo "$DESCRIPTION" | jq -r '."kubernetes.io/service-name"' | cut -d'/' -f1)
  elif echo "$DESCRIPTION" | grep -q '"k8sResource"'; then
    # Extract the value of "k8sResource" and take the part after the last "/"
    SUB_PRODUCT=$(echo "$DESCRIPTION" | jq -r '."k8sResource"' | awk -F'/' '{print $NF}')
  fi

  # Check if SUB_PRODUCT was found and add it to the labels string
  if [ -n "$SUB_PRODUCT" ]; then
    echo "Parsed sub-product: $SUB_PRODUCT from forwarding rule: $NAME"
    LABEL_STRING_WITH_SUB_PRODUCT="$LABEL_STRING,sub-product=$SUB_PRODUCT"
  else
    echo "No valid sub-product found for forwarding rule: $NAME"
    LABEL_STRING_WITH_SUB_PRODUCT="$LABEL_STRING"
  fi

  # Apply labels to forwarding rule
  if [ -z "$REGION" ]; then
    # For global forwarding rules
    echo "Updating global forwarding rule: $NAME with labels: $LABEL_STRING_WITH_SUB_PRODUCT"
    gcloud compute forwarding-rules update "$NAME" --global --update-labels $LABEL_STRING_WITH_SUB_PRODUCT
  else
    # For regional forwarding rules
    echo "Updating regional forwarding rule: $NAME in region: $REGION with labels: $LABEL_STRING_WITH_SUB_PRODUCT"
    gcloud compute forwarding-rules update "$NAME" --region "$REGION" --update-labels $LABEL_STRING_WITH_SUB_PRODUCT
  fi

  # Check if the update was successful
  if [ $? -eq 0 ]; then
    echo "Labels applied successfully to $NAME"
  else
    echo "Failed to apply labels to $NAME"
  fi
done
EOF