Vertex Tools Inventory
Deployment Runbook
Architecture Overview
The inventory job runs as a Cloud Run Job on a configurable schedule inside the target GCP project. It reads from five GCP service APIs, writes six JSON artifacts to a GCS bucket, and promotes them to a latest/ prefix. The OpenICF connector in PingOne IDM reads those artifacts (plus live Dialogflow CX / Vertex AI Agent Engine APIs) to surface AI governance data during reconciliation.
Shell Variables
All commands reference shell variables. Set these in your terminal before running anything. Later steps capture additional values as resources are created.
export PROJECT_ID=<your-gcp-project-id> export REGION=us-central1 export BUCKET_NAME=${PROJECT_ID}-vertex-inventory export JOB_SA_NAME=vertex-inventory-job export JOB_SA_EMAIL=${JOB_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com export AR_REPO=vertex-inventory export IMAGE=${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO}/vertex-tools-inventory:latest export JOB_NAME=vertex-tools-inventory export FLAVOR=both
INVENTORY_CONFIG_JSON environment variable. No config file mount or GCS volume is required.
Prerequisites
Before starting, ensure you have:
- A GCP account with Owner or Editor role on the target project
- The inventory deployment package (
vertex-tools-inventory-deploy-1.0.tar.gz) β contact your Customer Success Outcome Manager (CSOM)
The two prerequisite steps (P1βP2) must complete before Step 1.
P1 Install Required Tools
Install the Google Cloud SDK and Docker. These are the only local dependencies β no Python installation is needed (the job runs in a container).
P1a β Google Cloud SDK
Follow https://cloud.google.com/sdk/docs/install for your operating system, then authenticate:
gcloud auth login
gcloud config set project ${PROJECT_ID}
P1b β Docker
Follow https://docs.docker.com/get-docker/. Verify the daemon is running:
docker info
P2 Enable Required APIs
Enable all GCP APIs used by the job and the deployment pipeline in a single command:
gcloud services enable \
artifactregistry.googleapis.com \
run.googleapis.com \
iam.googleapis.com \
dialogflow.googleapis.com \
aiplatform.googleapis.com \
cloudresourcemanager.googleapis.com \
storage.googleapis.com \
cloudtrace.googleapis.com \
logging.googleapis.com \
cloudbuild.googleapis.com \
--project ${PROJECT_ID}
Step 1 Create the Job Service Account
Create a dedicated service account for the Cloud Run Job. Do not reuse the connector's service account β the job SA requires write permissions that the connector SA should not have.
gcloud iam service-accounts create ${JOB_SA_NAME} \
--display-name="Vertex Tools Inventory Job" \
--project=${PROJECT_ID}
echo "JOB_SA_EMAIL=${JOB_SA_EMAIL}"
Step 2 Grant IAM Roles
The job SA needs five project-level roles. Each covers a distinct collection responsibility:
| Role | Purpose |
|---|---|
roles/dialogflow.viewer | List agents, read webhooks (Dialogflow CX) |
roles/aiplatform.viewer | List reasoning engines (Vertex AI Agent Engine) |
roles/iam.securityReviewer | Read IAM policies for identity binding generation |
roles/cloudtrace.user | Read Cloud Trace spans for activity logs |
roles/logging.viewer | Read Cloud Logging for audit log collection |
for role in \ roles/dialogflow.viewer \ roles/aiplatform.viewer \ roles/iam.securityReviewer \ roles/cloudtrace.user \ roles/logging.viewer; do gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${JOB_SA_EMAIL}" \ --role="$role" \ --condition=None \ --quiet done
add-iam-policy-binding is a no-op if the binding already exists. Safe to re-run.
Step 3 Create the GCS Bucket
gcloud storage buckets create gs://${BUCKET_NAME} \
--location=${REGION} \
--project=${PROJECT_ID} \
--uniform-bucket-level-access
${BUCKET_NAME} is taken, use an alternate:export BUCKET_NAME=vertex-inventory-${PROJECT_ID}
Grant the job SA write access
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
--member="serviceAccount:${JOB_SA_EMAIL}" \
--role="roles/storage.objectAdmin"
Step 4 Create the Artifact Registry Repository
gcloud artifacts repositories create ${AR_REPO} \
--repository-format=docker \
--location=${REGION} \
--project=${PROJECT_ID} \
--description="Vertex Tools Inventory container images"
Step 5 Build & Push the Container Image
5a β Extract the deployment package
tar xzf vertex-tools-inventory-deploy-1.0.tar.gz cd vertex-tools-inventory
5b β Build via Cloud Build
Cloud Build reads the Dockerfile, builds the image, and pushes it to Artifact Registry. No local Docker build is required.
# Configure docker auth for AR (one-time) gcloud auth configure-docker ${REGION}-docker.pkg.dev --quiet # Submit the build gcloud builds submit . \ --tag ${IMAGE} \ --project ${PROJECT_ID} \ --quiet
gcloud artifacts docker images list ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO} --include-tags
Step 6 Create the Cloud Run Job
The job configuration is passed entirely via the INVENTORY_CONFIG_JSON environment variable β no config file mount is needed.
gcloud run jobs create ${JOB_NAME} \
--image=${IMAGE} \
--region=${REGION} \
--project=${PROJECT_ID} \
--service-account=${JOB_SA_EMAIL} \
--set-env-vars="INVENTORY_CONFIG_JSON={\"flavor\":\"${FLAVOR}\",\"fixtures\":false,\"projectIds\":[\"${PROJECT_ID}\"],\"locations\":[\"${REGION}\"],\"output_dir\":\"/tmp/out\",\"bucketName\":\"${BUCKET_NAME}\",\"bucketPrefix\":\"vertex-inventory\",\"writeLatest\":true,\"activityLogEnabled\":true,\"activityLogWindowMinutes\":60}" \
--task-timeout=600 \
--max-retries=1 \
--memory=512Mi
create with update. The deploy.sh script in the deployment package handles this automatically.
Step 7 Create the Cloud Scheduler Trigger
7a β Grant the invoker role
gcloud run jobs add-iam-policy-binding ${JOB_NAME} \
--region=${REGION} \
--member="serviceAccount:${JOB_SA_EMAIL}" \
--role="roles/run.invoker"
7b β Create the schedule
gcloud scheduler jobs create http ${JOB_NAME}-scheduled \
--location=${REGION} \
--schedule="0 */6 * * *" \
--uri="https://${REGION}-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/${PROJECT_ID}/jobs/${JOB_NAME}:run" \
--http-method=POST \
--oauth-service-account-email=${JOB_SA_EMAIL} \
--time-zone="UTC" \
--project=${PROJECT_ID}
Recommended frequencies:
| Schedule | Cron | Use Case |
|---|---|---|
| Hourly | 0 * * * * | High-change environments |
| Every 6 hours | 0 */6 * * * | Most deployments (recommended) |
| Daily | 0 6 * * * | Stable environments |
Step 8 Execute Manually & Verify
8a β Trigger a test execution
gcloud run jobs execute ${JOB_NAME} \
--region=${REGION} \
--wait
gcloud run jobs executions list --job=${JOB_NAME} --region=${REGION}. Common causes: missing IAM roles (re-check Step 2), APIs not enabled (re-check P2), or bucket doesn't exist (re-check Step 3).
8b β Verify GCS artifacts
gcloud storage ls gs://${BUCKET_NAME}/vertex-inventory/latest/
Expected β six files:
8c β Inspect manifest.json
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/manifest.json \
| python3 -m json.tool
agentCount, identityBindingCount, and serviceAccountCount are non-zero. generatedAt reflects the current timestamp. warnings contains only expected entries (group expansion warning is normal in v1).
8d β Inspect agents.json
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/agents.json \
| python3 -m json.tool | head -40
Confirm projectId matches ${PROJECT_ID}, flavor values match expected agent types, and resourceName paths are fully qualified.
8e β Inspect identity-bindings.json
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/identity-bindings.json \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{len(d)} bindings'); print(set(b['principalType'] for b in d))"
8f β Inspect activity-logs.json
gcloud storage cat gs://${BUCKET_NAME}/vertex-inventory/latest/activity-logs.json \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{len(d)} records'); print(set(r['event_type'] for r in d) if d else 'empty')"
If activity logs are empty and you expect agent activity, check the manifest activityLogWarnings for diagnostic messages (e.g. NO_TRACE_TELEMETRY means agent telemetry is not enabled).
Updating the Image
After receiving an updated deployment package:
# Extract updated package tar xzf vertex-tools-inventory-deploy-1.1.tar.gz cd vertex-tools-inventory # Build and push gcloud builds submit . \ --tag ${IMAGE} \ --project ${PROJECT_ID} \ --quiet # Update the Cloud Run Job to use the new image gcloud run jobs update ${JOB_NAME} \ --image=${IMAGE} \ --region=${REGION} \ --project=${PROJECT_ID} # Execute to verify gcloud run jobs execute ${JOB_NAME} \ --region=${REGION} \ --wait
Teardown
The deployment package includes a teardown.sh script that removes all resources in reverse order with confirmation prompts. To run non-interactively:
# Interactive (confirms each resource) ./teardown.sh # Non-interactive ./teardown.sh --force
Resource Summary
| Resource | Variable / Name |
|---|---|
| Cloud Run Job | ${JOB_NAME} β vertex-tools-inventory |
| Job Service Account | ${JOB_SA_EMAIL} β vertex-inventory-job@β¦ |
| Inventory GCS Bucket | ${BUCKET_NAME} β ${PROJECT_ID}-vertex-inventory |
| Artifact Registry Repo | ${AR_REPO} β vertex-inventory |
| Container Image | ${IMAGE} β ${REGION}-docker.pkg.dev/β¦ |
| Cloud Scheduler | ${JOB_NAME}-scheduled |
| Schedule | Every 6 hours (0 */6 * * *) |
| Runtime | Python 3.12 (container) |
| Task timeout | 600s |
| Memory | 512 Mi |
| Max retries | 1 |