Skip to content

Commit 2152465

Browse files
Add job to ensure expected GCP integration network is created
Why --- The bats and test-stemcells-ipv4 jobs assume a GCP subnetwork named stemcell-builder-integration-<subnet_int> exists in the bosh-concourse VPC, with a /24 at 10.100.<subnet_int>.0/24, private Google access, and IPV4_ONLY stack type. They also require a matching ingress firewall rule (all-protocol, source CIDR → tags test-stemcells-bats/bat) so that compilation VMs and BAT deployment VMs can reach the BOSH director's NATS server. Until now both resources had to be created and maintained out of band; their absence caused consistent compilation-VM agent timeouts (builds 466–475). What ---- * ci/tasks/gcp/ensure-integration-network.sh - Authenticates via GCP_JSON_KEY service account. - Derives SUBNET_NAME and SUBNET_CIDR from SUBNET_INT. - Captures stderr via mktemp temp file (cleaned up by trap on EXIT) so that gcloud failures are classified: "was not found" → create the resource; anything else → print the error and exit non-zero. This prevents auth/permission/transient API errors from being silently misinterpreted as "resource missing". - Subnetwork: single gcloud describe call captures exit code (for existence) and attributes (for drift detection). Validates network, ipCidrRange, privateIpGoogleAccess, and stackType; exits non-zero with a clear diff on any mismatch. - Firewall rule: same stderr-capture pattern. Validates network, direction, allowed[0].IPProtocol (must be "all"), sourceRanges[0], and disabled (must be False) in one describe call. Validates targetTags in a second describe call, sorting both sides before comparison to be order-insensitive. Both 'test-stemcells-bats' and 'bat' tags are required, mirroring the existing stemcell-builder-integration-22 rule. * ci/tasks/gcp/ensure-integration-network.yml - Concourse task definition. All params (GCP_JSON_KEY, GCP_PROJECT_ID, GCP_REGION, GCP_NETWORK_NAME, SUBNET_INT) are required; no defaults, values are provided explicitly by the pipeline. * ci/pipelines/builder.yml - New infrastructure group containing the new job. - New job ensure-integration-network: * serial: true, manual trigger only. * Gets bosh-stemcells-ci and bosh-integration-image, then runs the task with GCP_REGION=europe-north2 and GCP_NETWORK_NAME=bosh-concourse passed explicitly. * No passed: constraint on existing jobs; run on demand when the subnet/firewall needs to be created or reconciled. Verification ------------ * ytt -f ci/pipelines/builder.yml -f ci/pipelines/vars.yml renders successfully. * fly validate-pipeline -c <rendered> reports "looks good". Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 4a792ed commit 2152465

3 files changed

Lines changed: 135 additions & 1 deletion

File tree

ci/pipelines/builder.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ groups:
4444
- name: docker
4545
jobs:
4646
- build-os-image-stemcell-builder
47+
- name: infrastructure
48+
jobs:
49+
- ensure-integration-network
4750

4851
#@yaml/text-templated-strings
4952
jobs:
@@ -89,6 +92,25 @@ jobs:
8992
get_params:
9093
skip_download: true
9194

95+
#! Manually triggered job that idempotently ensures the GCP subnetwork and
96+
#! firewall rule consumed by deploy-director / cleanup-bats-vms / prepare-bats
97+
#! in the test-stemcells-ipv4 and bats jobs below exist. GCP is the source of
98+
#! truth — no state file is required.
99+
- name: ensure-integration-network
100+
serial: true
101+
plan:
102+
- get: bosh-stemcells-ci
103+
- get: bosh-integration-image
104+
- task: ensure-integration-network
105+
file: bosh-stemcells-ci/ci/tasks/gcp/ensure-integration-network.yml
106+
image: bosh-integration-image
107+
params:
108+
GCP_JSON_KEY: ((gcp_json_key))
109+
GCP_PROJECT_ID: ((gcp_project_id))
110+
GCP_REGION: europe-north2
111+
GCP_NETWORK_NAME: bosh-concourse
112+
SUBNET_INT: (@= data.values.stemcell_details.subnet_int @)
113+
92114
- name: process-high-critical-cves
93115
serial_groups: [log-cves]
94116
plan:
@@ -885,7 +907,6 @@ resource_types:
885907
type: registry-image
886908
source:
887909
repository: frodenas/gcs-resource
888-
889910
#@yaml/text-templated-strings
890911
resources:
891912
- name: daily
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env bash
2+
set -eu -o pipefail
3+
4+
: "${GCP_JSON_KEY:?}"
5+
: "${GCP_PROJECT_ID:?}"
6+
: "${GCP_REGION:?}"
7+
: "${GCP_NETWORK_NAME:?}"
8+
: "${SUBNET_INT:?}"
9+
10+
echo "${GCP_JSON_KEY}" | gcloud auth activate-service-account --key-file - --project "${GCP_PROJECT_ID}"
11+
12+
SUBNET_NAME="stemcell-builder-integration-${SUBNET_INT}"
13+
SUBNET_CIDR="10.100.${SUBNET_INT}.0/24"
14+
15+
# 'bat' => BATS created VM tag
16+
# 'test-stemcells-bats' => director, and compilation VM tag
17+
FIREWALL_TAGS="bat,test-stemcells-bats"
18+
19+
gcloud_stderr="$(mktemp)"
20+
trap 'rm -f "${gcloud_stderr}"' EXIT
21+
22+
echo "Checking for subnet '${SUBNET_NAME}' in region '${GCP_REGION}'..."
23+
current_subnet="$(gcloud compute networks subnets describe "${SUBNET_NAME}" \
24+
--region="${GCP_REGION}" \
25+
--project="${GCP_PROJECT_ID}" \
26+
--format='csv[no-heading](network.basename(),ipCidrRange,privateIpGoogleAccess,stackType)' \
27+
2>"${gcloud_stderr}")" && subnet_exists=true || subnet_exists=false
28+
29+
if ${subnet_exists}; then
30+
expected_subnet="${GCP_NETWORK_NAME},${SUBNET_CIDR},True,IPV4_ONLY"
31+
if [[ "${current_subnet}" != "${expected_subnet}" ]]; then
32+
echo "ERROR: Subnet '${SUBNET_NAME}' exists but is misconfigured."
33+
echo " Expected: ${expected_subnet}"
34+
echo " Actual: ${current_subnet}"
35+
exit 1
36+
fi
37+
echo "Subnet '${SUBNET_NAME}' already exists and matches expected configuration."
38+
elif grep -q "was not found" "${gcloud_stderr}"; then
39+
echo "Creating subnet '${SUBNET_NAME}'..."
40+
gcloud compute networks subnets create "${SUBNET_NAME}" \
41+
--network="${GCP_NETWORK_NAME}" \
42+
--region="${GCP_REGION}" \
43+
--range="${SUBNET_CIDR}" \
44+
--enable-private-ip-google-access \
45+
--stack-type=IPV4_ONLY \
46+
--project="${GCP_PROJECT_ID}"
47+
echo "Subnet '${SUBNET_NAME}' created."
48+
else
49+
echo "ERROR: gcloud describe failed for subnet '${SUBNET_NAME}':"
50+
cat "${gcloud_stderr}" >&2
51+
exit 1
52+
fi
53+
54+
echo "Checking for firewall rule '${SUBNET_NAME}'..."
55+
current_fw="$(gcloud compute firewall-rules describe "${SUBNET_NAME}" \
56+
--project="${GCP_PROJECT_ID}" \
57+
--format='csv[no-heading](network.basename(),direction,allowed[0].IPProtocol,sourceRanges[0],disabled)' \
58+
2>"${gcloud_stderr}")" && fw_exists=true || fw_exists=false
59+
60+
if ${fw_exists}; then
61+
expected_fw="${GCP_NETWORK_NAME},INGRESS,all,${SUBNET_CIDR},False"
62+
if [[ "${current_fw}" != "${expected_fw}" ]]; then
63+
echo "ERROR: Firewall rule '${SUBNET_NAME}' exists but is misconfigured."
64+
echo " Expected: ${expected_fw}"
65+
echo " Actual: ${current_fw}"
66+
exit 1
67+
fi
68+
# Validate target tags independently; sort before comparing since order is not deterministic
69+
current_tags="$(gcloud compute firewall-rules describe "${SUBNET_NAME}" \
70+
--project="${GCP_PROJECT_ID}" \
71+
--format='value(targetTags.list())' \
72+
| tr ',;' '\n' | LC_ALL=C sort | tr '\n' ',' | sed 's/,$//')"
73+
expected_tags="$(printf '%s\n' ${FIREWALL_TAGS//,/ } | LC_ALL=C sort | tr '\n' ',' | sed 's/,$//')"
74+
if [[ "${current_tags}" != "${expected_tags}" ]]; then
75+
echo "ERROR: Firewall rule '${SUBNET_NAME}' has wrong target tags."
76+
echo " Expected: ${expected_tags}"
77+
echo " Actual: ${current_tags}"
78+
exit 1
79+
fi
80+
echo "Firewall rule '${SUBNET_NAME}' already exists and matches expected configuration."
81+
elif grep -q "was not found" "${gcloud_stderr}"; then
82+
echo "Creating firewall rule '${SUBNET_NAME}'..."
83+
gcloud compute firewall-rules create "${SUBNET_NAME}" \
84+
--network="${GCP_NETWORK_NAME}" \
85+
--project="${GCP_PROJECT_ID}" \
86+
--direction=INGRESS \
87+
--priority=1000 \
88+
--allow=all \
89+
--source-ranges="${SUBNET_CIDR}" \
90+
--target-tags="${FIREWALL_TAGS}"
91+
echo "Firewall rule '${SUBNET_NAME}' created."
92+
else
93+
echo "ERROR: gcloud describe failed for firewall rule '${SUBNET_NAME}':"
94+
cat "${gcloud_stderr}" >&2
95+
exit 1
96+
fi
97+
98+
echo "Integration network '${SUBNET_NAME}' is ready."
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
platform: linux
3+
4+
inputs:
5+
- name: bosh-stemcells-ci
6+
7+
params:
8+
GCP_JSON_KEY:
9+
GCP_PROJECT_ID:
10+
GCP_REGION:
11+
GCP_NETWORK_NAME:
12+
SUBNET_INT:
13+
14+
run:
15+
path: bosh-stemcells-ci/ci/tasks/gcp/ensure-integration-network.sh

0 commit comments

Comments
 (0)