Skip to content

OCPBUGS-88036: Set cluster ownership tag on AzureCluster#590

Open
matzew wants to merge 1 commit into
openshift:mainfrom
matzew:OCPBUGS-88036-azure-ownership-tags
Open

OCPBUGS-88036: Set cluster ownership tag on AzureCluster#590
matzew wants to merge 1 commit into
openshift:mainfrom
matzew:OCPBUGS-88036-azure-ownership-tags

Conversation

@matzew

@matzew matzew commented Jun 10, 2026

Copy link
Copy Markdown
Member

Set the kubernetes.io_cluster.=owned tag on the AzureCluster object via AdditionalTags so that CAPI-created Azure resources are visible to the installer's destroy logic. Azure tag keys do not permit slashes, so underscores and a dot are used instead. Also propagate user-defined resource tags from
Infrastructure.Status.PlatformStatus.Azure.ResourceTags to match MAPI behaviour.

Without this tag, openshift-install destroy cluster cannot identify CAPI-created resources and they are leaked.

Summary by CodeRabbit

  • New Features
    • Added automatic tagging support for Azure cluster infrastructure, including an "owned" tag and the ability to merge custom resource tags for better cluster organization and management.

@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jun 10, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@matzew: This pull request references Jira Issue OCPBUGS-88036, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Set the kubernetes.io_cluster.=owned tag on the AzureCluster object via AdditionalTags so that CAPI-created Azure resources are visible to the installer's destroy logic. Azure tag keys do not permit slashes, so underscores and a dot are used instead. Also propagate user-defined resource tags from
Infrastructure.Status.PlatformStatus.Azure.ResourceTags to match MAPI behaviour.

Without this tag, openshift-install destroy cluster cannot identify CAPI-created resources and they are leaked.

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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@matzew, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 24 minutes and 29 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: c84d9b95-29f6-41be-a8a8-ceca9b8abb34

📥 Commits

Reviewing files that changed from the base of the PR and between 35600b0 and 57f24a7.

📒 Files selected for processing (1)
  • pkg/controllers/infracluster/azure.go

Walkthrough

The newAzureCluster function now constructs an azurev1.Tags map containing an "owned" tag and any configured Azure resource tags, then assigns the map to the AzureClusterSpec AdditionalTags field.

Changes

Resource tag construction and wiring

Layer / File(s) Summary
Azure resource tags construction and wiring
pkg/controllers/infracluster/azure.go
newAzureCluster initializes an azurev1.Tags map with an "owned" cluster tag, conditionally merges configured Azure resource tags from r.Infra.Status.PlatformStatus.Azure.ResourceTags, and wires the combined tags into the AzureClusterSpec via AdditionalTags.

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 12 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Test Structure And Quality ⚠️ Warning No Ginkgo tests added for Azure tag functionality. Existing tests only cover AWS; missing tests for tag setting, merging, overwrite protection, and name sanitization. Add unit tests for newAzureCluster to verify ownership tag format, user tag merging, overwrite protection, and InfrastructureName sanitization.
Microshift Test Compatibility ⚠️ Warning New Ginkgo e2e test in e2e/azure_test.go uses config.openshift.io and machine.openshift.io APIs without MicroShift protection. Add [apigroup:config.openshift.io,machine.openshift.io] to test name, or [Skipped:MicroShift], or wrap with IsMicroShift() check and g.Skip().
Single Node Openshift (Sno) Test Compatibility ⚠️ Warning New e2e test added in azure_test.go assumes multi-node clusters - it creates a worker MachineSet and expects machine provisioning and nodes to reach Ready state, which fails on SNO. Add [Skipped:SingleReplicaTopology] label to test name or guard with exutil.IsSingleNode() check and skip on SNO, as SNO cannot provision additional worker nodes.
✅ Passed checks (12 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: setting a cluster ownership tag on AzureCluster objects, which matches the core functionality added in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All Ginkgo test names are stable: "should be able to run a machine" contains no dynamic content, timestamps, UUIDs, or variable interpolation.
Topology-Aware Scheduling Compatibility ✅ Passed PR only adds metadata tags to AzureCluster infrastructure resource; no scheduling constraints, pod specs, or topology-related changes introduced.
Ote Binary Stdout Contract ✅ Passed Code is in newAzureCluster() method (not process-level). Uses fmt.Sprintf() which returns string, not stdout. No stdout writes found in file.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added. This PR only modifies azure.go controller logic for tag construction. The check does not apply.
No-Weak-Crypto ✅ Passed PR contains no weak crypto usage, custom crypto implementations, or non-constant-time secret comparisons. Changes only involve Azure resource tagging via string formatting and map operations.
Container-Privileges ✅ Passed PR modifies only Go source code for Azure tagging, not container/pod manifests. No privileged settings, hostPID/Network/IPC, or SYS_ADMIN capabilities found.
No-Sensitive-Data-In-Logs ✅ Passed No logging statements that expose sensitive data found. The new code constructs tags and merges user-provided ResourceTags into a map without logging them or any sensitive information.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot requested review from RadekManak and racheljpg June 10, 2026 15:32
@openshift-ci

openshift-ci Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign racheljpg 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controllers/infracluster/azure.go`:
- Around line 245-253: Currently user-provided tags from
r.Infra.Status.PlatformStatus.Azure.ResourceTags are merged into the tags map
after the ownership tag, allowing them to overwrite the ownership key; instead,
populate the tags map with user tags first (iterate ResourceTags and set
tags[t.Key] = t.Value) and only after that set the ownership entry using the
computed key fmt.Sprintf("kubernetes.io_cluster.%s",
r.Infra.Status.InfrastructureName) = "owned" so the ownership tag cannot be
overwritten (adjust code around the tags variable initialization and the loop
over ResourceTags).
- Around line 245-246: The AdditionalTags key generation in newAzureCluster uses
Infra.Status.InfrastructureName directly, which can produce invalid cluster-id
characters; update the newAzureCluster code path (the function that sets
AdditionalTags/ResourceTags) to sanitize/validate
Infra.Status.InfrastructureName to only allow alphanumeric, '-', '.', and '_'
(e.g., strip or replace invalid chars and/or return an error) before composing
fmt.Sprintf("kubernetes.io_cluster.%s", ...). Add a unit test under
pkg/controllers/infracluster (e.g., newazurecluster_test.go) that calls
newAzureCluster (or the tag-generation helper) with various InfrastructureName
inputs (valid and containing bad chars) and asserts the produced AdditionalTags
key equals kubernetes.io_cluster.<sanitized-cluster-id> and that invalid inputs
are handled as expected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: af6215e3-09b8-47ea-a0b6-b5b3618ccc46

📥 Commits

Reviewing files that changed from the base of the PR and between 05c113e and 35600b0.

📒 Files selected for processing (1)
  • pkg/controllers/infracluster/azure.go

Comment thread pkg/controllers/infracluster/azure.go Outdated
Comment on lines +245 to +246
tags := azurev1.Tags{
fmt.Sprintf("kubernetes.io_cluster.%s", r.Infra.Status.InfrastructureName): "owned",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for tests covering Azure cluster tagging and tag format validation

# Search for test files covering newAzureCluster
rg -n --type=go -A 5 -B 2 'newAzureCluster|AdditionalTags' --glob '*_test.go' --glob '**/infracluster/*'

# Search for Azure tag key format patterns in codebase
rg -n --type=go 'kubernetes\.io_cluster\.|kubernetes_io_cluster' 

# Search for tag format documentation or validation
rg -n --type=go 'ResourceTags|AdditionalTags' pkg/controllers/infracluster/

Repository: openshift/cluster-capi-operator

Length of output: 4207


Ensure Azure cluster tag key is compliant and covered by tests

  • pkg/controllers/infracluster/azure.go sets AdditionalTags to kubernetes.io_cluster.<r.Infra.Status.InfrastructureName> (dot, no slashes), matching the repo’s documented kubernetes.io_cluster.<cluster-id> tag expectation used by the image-registry operator.
  • No existing *_test.go under pkg/controllers/infracluster/ was found covering newAzureCluster/AdditionalTags/ResourceTags; add a unit test for this tag generation and ensure InfrastructureName is constrained/sanitized to the documented allowed characters (alphanumeric, -, ., _) so the resulting <cluster-id> won’t violate downstream expectations.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/infracluster/azure.go` around lines 245 - 246, The
AdditionalTags key generation in newAzureCluster uses
Infra.Status.InfrastructureName directly, which can produce invalid cluster-id
characters; update the newAzureCluster code path (the function that sets
AdditionalTags/ResourceTags) to sanitize/validate
Infra.Status.InfrastructureName to only allow alphanumeric, '-', '.', and '_'
(e.g., strip or replace invalid chars and/or return an error) before composing
fmt.Sprintf("kubernetes.io_cluster.%s", ...). Add a unit test under
pkg/controllers/infracluster (e.g., newazurecluster_test.go) that calls
newAzureCluster (or the tag-generation helper) with various InfrastructureName
inputs (valid and containing bad chars) and asserts the produced AdditionalTags
key equals kubernetes.io_cluster.<sanitized-cluster-id> and that invalid inputs
are handled as expected.

Comment thread pkg/controllers/infracluster/azure.go Outdated
Comment on lines +245 to +253
tags := azurev1.Tags{
fmt.Sprintf("kubernetes.io_cluster.%s", r.Infra.Status.InfrastructureName): "owned",
}

if r.Infra.Status.PlatformStatus.Azure != nil {
for _, t := range r.Infra.Status.PlatformStatus.Azure.ResourceTags {
tags[t.Key] = t.Value
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: User tags can overwrite the ownership tag.

User-provided resource tags are merged into the map after the ownership tag, so if a user specifies a tag with key kubernetes.io_cluster.<infraID>, it will overwrite the system-generated ownership tag. According to the PR motivation, the installer's destroy logic relies on this tag to identify CAPI-created resources; overwriting it would cause resource leaks.

🔒 Proposed fix to protect the ownership tag

Insert user tags first, then set the ownership tag to ensure it cannot be overwritten:

-	tags := azurev1.Tags{
-		fmt.Sprintf("kubernetes.io_cluster.%s", r.Infra.Status.InfrastructureName): "owned",
-	}
+	tags := azurev1.Tags{}
 
 	if r.Infra.Status.PlatformStatus.Azure != nil {
 		for _, t := range r.Infra.Status.PlatformStatus.Azure.ResourceTags {
 			tags[t.Key] = t.Value
 		}
 	}
+
+	// Always set the ownership tag last to prevent user overrides
+	tags[fmt.Sprintf("kubernetes.io_cluster.%s", r.Infra.Status.InfrastructureName)] = "owned"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tags := azurev1.Tags{
fmt.Sprintf("kubernetes.io_cluster.%s", r.Infra.Status.InfrastructureName): "owned",
}
if r.Infra.Status.PlatformStatus.Azure != nil {
for _, t := range r.Infra.Status.PlatformStatus.Azure.ResourceTags {
tags[t.Key] = t.Value
}
}
tags := azurev1.Tags{}
if r.Infra.Status.PlatformStatus.Azure != nil {
for _, t := range r.Infra.Status.PlatformStatus.Azure.ResourceTags {
tags[t.Key] = t.Value
}
}
// Always set the ownership tag last to prevent user overrides
tags[fmt.Sprintf("kubernetes.io_cluster.%s", r.Infra.Status.InfrastructureName)] = "owned"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/infracluster/azure.go` around lines 245 - 253, Currently
user-provided tags from r.Infra.Status.PlatformStatus.Azure.ResourceTags are
merged into the tags map after the ownership tag, allowing them to overwrite the
ownership key; instead, populate the tags map with user tags first (iterate
ResourceTags and set tags[t.Key] = t.Value) and only after that set the
ownership entry using the computed key fmt.Sprintf("kubernetes.io_cluster.%s",
r.Infra.Status.InfrastructureName) = "owned" so the ownership tag cannot be
overwritten (adjust code around the tags variable initialization and the loop
over ResourceTags).

Set the kubernetes.io_cluster.<infraID>=owned tag on the AzureCluster
object via AdditionalTags so that CAPI-created Azure resources are
visible to the installer's destroy logic. Azure tag keys do not permit
slashes, so underscores and a dot are used instead. Also propagate
user-defined resource tags from
Infrastructure.Status.PlatformStatus.Azure.ResourceTags to match MAPI
behaviour.

Without this tag, openshift-install destroy cluster cannot identify
CAPI-created resources and they are leaked.

Signed-off-by: Matthias Wessendorf <mwessend@redhat.com>
@matzew matzew force-pushed the OCPBUGS-88036-azure-ownership-tags branch from 35600b0 to 57f24a7 Compare June 10, 2026 16:02
@openshift-ci

openshift-ci Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@matzew: all tests passed!

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

jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants