Skip to content

feat: tag E2E job infrastructure resource groups with jobID - #7436

Open
Ghazi Alchammat (galchammat) wants to merge 1 commit into
Azure:mainfrom
galchammat:feat/e2e-jobid-cost-tags
Open

Ghazi Alchammat (galchammat) wants to merge 1 commit into
Azure:mainfrom
galchammat:feat/e2e-jobid-cost-tags

Conversation

@galchammat

@galchammat Ghazi Alchammat (galchammat) commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

AROSLSRE-2394

What

Tags the infrastructure resource groups a DEV E2E Prow job creates with jobID.aro-hcp-ci.redhat.com=<BUILD_ID>, the same key the e2e framework already sets on test resource groups. A job opts in by setting RUN_COST_TAG_VALUE in its openshift/release configuration; the literal BUILD_ID resolves to this job's Prow build ID, because ci-operator configuration cannot expand $(BUILD_ID) itself:

Resource groups Mechanism
Service and management AKS node resource groups the build-config-override Go generator, invoked by hack/ci/build-config-override.sh, sets svc.aks.tags / mgmt.aks.tags to the values ci00/ci01 otherwise inherit from config/config.yaml plus the run cost tag; AKS copies cluster tags onto node resource groups
Regional, service and management resource groups hack/ci/provision-environment.sh resolves the same RUN_COST_TAG_VALUE and passes templatize's --resource-group-tags, set in full on resource groups the run creates

Both consumers read RUN_COST_TAG_VALUE from the environment they already share, so no tag handoff file is needed.

Why

Cost Management tag inheritance is enabled on the five E2E subscriptions (AROSLSRE-2276), so a resource group's tags reach the usage records of everything inside it. In a sampled run, AKS node resource groups were about 84% of the cost and templatize-created groups 5%; neither carried a run identifier. With them tagged, one Cost Management filter shows most of a job's spend across subscriptions.

Behavior and safety

  • Opt-in is per job: jobs that do not set RUN_COST_TAG_VALUE — including long-lived environments such as cspr that source the same override script — are never tagged, so shared clusters never carry the ID of whichever job deployed them last.
  • A tag value with characters outside [A-Za-z0-9._-], including whitespace, is rejected; RUN_COST_TAG_VALUE=BUILD_ID without BUILD_ID set is an error in both the generator and the provisioning shell.
  • Templatize sets --resource-group-tags in full only on resource groups the run creates. On an existing group each extra tag only replaces a key the group already carries, in any key casing; a group never gains a tag it did not have. ensureResourceGroupExists creates a group only on 404 and returns other Get errors, so a transient failure can no longer re-create, and re-tag, an existing group.

CI configuration change: this modifies the CI-invoked scripts hack/ci/build-config-override.sh and hack/ci/provision-environment.sh. A companion openshift/release PR (openshift/release#87928) declares RUN_COST_TAG_VALUE in the provision environment step and enables it for the dev e2e-parallel jobs.

Testing

  • Unit tests: tag validation (options_test.go); extra tags with persist rules on created and existing groups (arm_test.go); ensureResourceGroupExists against a fake ARM server, covering 404 create, existing-group preservation, re-stamping a carried key, untagged groups gaining nothing, and no writes on 401/403/429/500 (arm_resourcegroup_test.go).
  • Run cost tag resolution (override_test.go, cmd_test.go): sentinel resolution, explicit values, no opt-in, and rejection of invalid values; the sourced build-config-override.sh adapter end-to-end, including that no handoff file is published.
  • Rendered the ci01 configuration through templatize with the generated override: both svc.aks.tags and mgmt.aks.tags contain the job ID. aks-cluster-create and the Bicep csvTagsToObject parsers accept the dotted key.
  • go build, go vet, go test -race and golangci-lint on the changed packages.

To verify a run, query Resource Graph for resource groups with tag jobID.aro-hcp-ci.redhat.com equal to the job's build ID in the E2E infrastructure subscription. Usage records pick up inherited tags within about 24 hours.

Non-goals

  • HCP clusters' RP-managed resource groups (worker VMs and disks, about 9% of the sampled run) stay untagged. Tagging them from the test client costs extra ARM reads on every cluster GET; propagating tags in the RP, as AKS does for node resource groups, would cover them and also benefit customers.
  • Shared and pooled resources (leased identity containers, global Key Vault, registries, slot certificates) are never tagged with a job ID.
  • Historical charges are not retagged.

PR Checklist

  • PR is scoped to a single task (no mixed concerns)
  • Title follows Conventional Commits format
  • Summary explains the "Why" behind the change
  • Linked to relevant ticket/issue
  • Screenshots included (if dashboards or other UI changes) — not applicable
  • Self-reviewed the diff
  • CI/CD checks are passing (ignore Tide)
  • Draft PR used for WIP (if applicable)
  • Commit history is clean (rebased/squashed)
  • Tricky code blocks are commented
  • Specific reviewers tagged
  • All comment threads resolved before merge

Copilot AI balanced review requested due to automatic review settings October 8, 2026 21:25
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification

This PR uses the pipeline controller for second-stage tests. Selection and triggering follow the repository configuration.

Use /test ? to list jobs and /pipeline help for commands.

@openshift-ci openshift-ci Bot added do-not-merge/work-in-progress area/ci Automatically applied by owners-label for area/ci area/docs Automatically applied by owners-label for area/docs area/test Automatically applied by owners-label for area/test area/tooling Automatically applied by owners-label for area/tooling labels Oct 8, 2026
@openshift-ci

openshift-ci Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Job-ID validation and case-insensitive tag protection have correctness gaps, and the new resource-group safety branches lack direct coverage.

3 open findings
What changed in this PR

Adds Prow job-ID tags to E2E-owned Azure resource groups for cross-subscription cost attribution.

Changes:

  • Adds creation-only resource-group tags to templatize.
  • Tags per-run AKS infrastructure from CI scripts.
  • Tags RP-managed HCP resource groups during creation and cleanup.
File Description
tooling/​templatize/​pkg/​pipeline/​run.go Adds resource-group creation tags to run options.
tooling/​templatize/​pkg/​pipeline/​arm.go Applies tags only during resource-group creation.
tooling/​templatize/​pkg/​pipeline/​arm_test.go Tests creation-tag composition.
tooling/​templatize/​pkg/​pipeline/​arm_stack.go Passes tags to ARM stack resource groups.
tooling/​templatize/​cmd/​entrypoint/​run/​options.go Adds and validates the tagging CLI flag.
tooling/​templatize/​cmd/​entrypoint/​run/​options_test.go Tests tag validation.
test/​util/​framework/​per_test_framework.go Discovers and tags managed resource groups.
test/​util/​framework/​managed_resource_group_tags.go Implements managed-group job tagging.
test/​util/​framework/​managed_resource_group_tags_test.go Tests tagging helpers and ownership matching.
test/​util/​framework/​helpers_v20261001preview.go Tags managed groups after cluster creation.
test/​util/​framework/​helpers_v20260901preview.go Tags managed groups after cluster creation.
test/​util/​framework/​helpers_v20260630preview.go Tags managed groups after cluster creation.
test/​util/​framework/​helpers_v20251223preview.go Tags managed groups after cluster creation.
test/​util/​framework/​helpers_v20240610preview.go Tags managed groups after cluster creation.
test/​util/​framework/​deployment_helper.go Tags groups created by HCP Bicep deployments.
hack/​ci/​provision-environment.sh Passes job tags to templatize.
hack/​ci/​build-config-override.sh Adds job tags to per-run AKS configuration.
docs/​ci/​execution.md Documents cost-attribution behavior.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread hack/ci/build-config-override.sh Outdated
Comment thread test/util/framework/managed_resource_group_tags.go Outdated
Comment thread tooling/templatize/pkg/pipeline/arm.go
Copilot AI balanced review requested due to automatic review settings October 10, 2026 11:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Direct and asynchronous cluster-creation paths remain untagged until teardown, leaving their lifetime costs unattributed.

1 open finding
3 resolved since last review

🧠 Review effort: Balanced

Comment thread test/util/framework/helpers_v20240610preview.go Outdated
Copilot AI balanced review requested due to automatic review settings October 10, 2026 11:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The AKS tag replacement is case-sensitive and can retain a stale differently-cased job-ID tag.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Comment thread hack/ci/build-config-override.sh Outdated
Copilot AI balanced review requested due to automatic review settings October 10, 2026 12:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-cutting CI and resource-cleanup behavior requires human approval after the draft is finalized and pending checks complete.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@sajeelirkal

Copy link
Copy Markdown

/test all

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-parallel

@roivaz

Copy link
Copy Markdown
Collaborator

Ghazi Alchammat (@galchammat) I would drop the HCP managed resource group tagging from this PR and merge the rest, given that managed group spend is a tiny fraction of the cost compared with AKS spend.
The approach of tagging HCP MRGs from the test client side requires extra ARM calls on every cluster GET, plus listing every RG in the subscription during cleanup and Bicep hooks. That adds unnecessary latency, read pressure on shared subscriptions, and is ultimately best-effort.

Instead, what we could do is implement tag propagation directly in the RP, same way AKS does. This would also benefit our customers, who would be able to apply tags and have them propagated to their HCP managed resource groups. I would check with the 1p/CS teams about the feasibility of implementing this.

What to drop from the PR:

  • The RP client policy (managedResourceGroupJobIDPolicy)

  • The post-Bicep hook in CreateBicepTemplateAndWait and pre-cleanup hook in deleteCreatedResources

  • Supporting test framework code and tests for managed-RG tagging

There's another issue with the PR as it is: it conflicts with #7502, which moves the build-config-override.sh shell script into go code in the test binary. You will need to rework this PR to apply the override logic to the new go code and wait until #7502 merges.

@roivaz

Copy link
Copy Markdown
Collaborator

/hold

Changes requested. Also conflicts with #7502.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Required CI results remain unconfirmed for the provisioning-script and resource-group creation changes.

0 open findings

🧠 Review effort: Balanced

@galchammat

Copy link
Copy Markdown
Collaborator Author

roi (@roivaz) Dropped the managed resource group tagging and its supporting code. The port onto #7502's Go generator is ready (diff on top of #7502); I'll swap it into this PR once #7502 merges.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-parallel

Copilot AI balanced review requested due to automatic review settings October 21, 2026 15:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

CI provisioning and shared-resource tagging need human validation, alongside fixes to publication ordering and its regression test.

2 open issues

Review effort: Balanced

Comment thread test/cmd/aro-hcp-tests/infra/build-config-override/cmd.go Outdated
Comment thread test/cmd/aro-hcp-tests/infra/build-config-override/cmd_test.go Outdated
@openshift-ci

openshift-ci Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: galchammat
Once this PR has been reviewed and has the lgtm label, please assign geoberle for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sajeelirkal

Copy link
Copy Markdown

roi (roi (@roivaz)) Dropped the managed resource group tagging and its supporting code. The port onto #7502's Go generator is ready (diff on top of #7502); I'll swap it into this PR once #7502 merges.

#7502 is now merged

@galchammat

Copy link
Copy Markdown
Collaborator Author

/test integration

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-parallel

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-parallel

@galchammat

Copy link
Copy Markdown
Collaborator Author

/retest unrelated failure

@galchammat

Copy link
Copy Markdown
Collaborator Author

/retest

Comment thread tooling/templatize/pkg/pipeline/arm.go Outdated
Comment on lines +396 to +402
func newResourceGroupTags(creationTags map[string]string, persist bool) map[string]*string {
tags := make(map[string]*string, len(creationTags))
for key, value := range creationTags {
tags[key] = to.Ptr(value)
}
return computeResourceGroupTags(tags, persist)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't wrap the function. Extend computeResourceGroupTags to adapt it to the new behavior instead. Also, any particular reason we don't want these cost tags reconciled instead of just applied during resource group creation?

flags.StringVar(&opts.MSIMockCatalog, "msi-mock-pool-catalog", opts.MSIMockCatalog, "MSI mock catalog (default source-dir/dev-infrastructure/openshift-ci/msi-mock-pool.yaml)")
flags.StringVar(&opts.ARMHelperCatalog, "arm-helper-pool-catalog", opts.ARMHelperCatalog, "ARM helper catalog (default source-dir/dev-infrastructure/openshift-ci/arm-helper-pool.yaml)")
flags.StringVar(&opts.HypershiftOverlay, "hypershift-override-file", opts.HypershiftOverlay, "Hypershift overlay (default shared-dir/hypershift-image-overrides.yaml)")
flags.StringVar(&opts.TemplatizeSettings, "templatize-settings", opts.TemplatizeSettings, "Templatize settings deciding per-run environments (default source-dir/tooling/templatize/settings.yaml)")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walking the whole config file to find just the AKS tags that are set looks way too complex. All other overrides blindly overwrite the config key value, let's just do the same with the AKS tags - check what tags are being set today for ci00/ci01 envs and just overwrite the whole config key with those and the new cost tag.

flags.StringVar(&opts.ARMHelperCatalog, "arm-helper-pool-catalog", opts.ARMHelperCatalog, "ARM helper catalog (default source-dir/dev-infrastructure/openshift-ci/arm-helper-pool.yaml)")
flags.StringVar(&opts.HypershiftOverlay, "hypershift-override-file", opts.HypershiftOverlay, "Hypershift overlay (default shared-dir/hypershift-image-overrides.yaml)")
flags.StringVar(&opts.TemplatizeSettings, "templatize-settings", opts.TemplatizeSettings, "Templatize settings deciding per-run environments (default source-dir/tooling/templatize/settings.yaml)")
flags.StringVar(&opts.ServiceConfig, "service-config", opts.ServiceConfig, "Service config providing effective AKS tags (default source-dir/config/config.yaml)")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other overrides are opt-in via environment variables in the openshift/release configuration - do the same here. Include a RUN_COST_TAG_VALUE env variable in the job configuration and use it, then you don't need to discover it by parsing the settings.yaml file. Keep it simple.

flags.StringVar(&opts.HypershiftOverlay, "hypershift-override-file", opts.HypershiftOverlay, "Hypershift overlay (default shared-dir/hypershift-image-overrides.yaml)")
flags.StringVar(&opts.TemplatizeSettings, "templatize-settings", opts.TemplatizeSettings, "Templatize settings deciding per-run environments (default source-dir/tooling/templatize/settings.yaml)")
flags.StringVar(&opts.ServiceConfig, "service-config", opts.ServiceConfig, "Service config providing effective AKS tags (default source-dir/config/config.yaml)")
flags.StringVar(&opts.RunCostTagFile, "run-cost-tag-file", opts.RunCostTagFile, "File receiving the run cost tag for the provisioning shell (default shared-dir/run-cost-tag.env)")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the step has an opt-in RUN_COST_TAG_VALUE env variable you won't need this either.

Attribute each DEV E2E Prow job's infrastructure spend by tagging the resource
groups it creates with jobID.aro-hcp-ci.redhat.com=<BUILD_ID>. Cost
Management tag inheritance on the E2E subscriptions applies the tag to usage
records of everything inside them.

- jobs opt in by setting RUN_COST_TAG_VALUE; the literal BUILD_ID resolves
  to this job's Prow build ID, because ci-operator configuration cannot
  expand $(BUILD_ID) itself
- the config override generator adds the tag to the service and management
  AKS cluster tags, replacing the whole tags key with the values ci00/ci01
  otherwise inherit from config/config.yaml; AKS copies them onto each node
  resource group
- templatize's --resource-group-tags set the tags on resource groups a run
  creates; on an existing group they only replace tag keys the group already
  carries, so shared groups never gain a run-scoped tag
- build-config-override and provision-environment.sh both resolve
  RUN_COST_TAG_VALUE from the same environment, so no tag handoff file is
  needed
- the offline command test clears RUN_COST_TAG_VALUE and BUILD_ID, which
  Prow sets, with the other CI inputs it isolates (AROSLSRE-2394)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-parallel

@openshift-ci

openshift-ci Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Ghazi Alchammat (@galchammat): The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-parallel 3071de3 link true /test e2e-parallel

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci Automatically applied by owners-label for area/ci area/docs Automatically applied by owners-label for area/docs area/test Automatically applied by owners-label for area/test area/tooling Automatically applied by owners-label for area/tooling do-not-merge/hold

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants