Skip to content

feat(frontend): reject duplicate subnet, NSG, and MRG on cluster create#6004

Open
JakobGray wants to merge 2 commits into
Azure:mainfrom
JakobGray:cluster-install-admission
Open

feat(frontend): reject duplicate subnet, NSG, and MRG on cluster create#6004
JakobGray wants to merge 2 commits into
Azure:mainfrom
JakobGray:cluster-install-admission

Conversation

@JakobGray

Copy link
Copy Markdown
Collaborator

What

  • Prefetch subscription clusters and node pools in newClusterAdmissionContext
  • Add admitClusterManagedResourceGroupName, admitClusterSubnetResourceID, and admitClusterNetworkSecurityGroupResourceID (CREATE only)
  • Add NSG same-subscription and not-in-MRG rules to static validation (parity with validateAroHcpClusterNetworkSecurityGroupResourceId)

This change closes the following gaps in validation during cluster create between CS and ARO-HCP:

  • Duplicate MRG in subscription
  • Duplicate subnet on another cluster
  • Duplicate subnet on another cluster’s node pool
  • Duplicate NSG on another cluster
  • NSG in wrong subscription
  • NSG in managed RG

These mirror checks done in CS before a cluster create is accepted:

  • validateAroHcpClusterNetworkSecurityGroupResourceId
  • validateManagedResourceGroupUniqueness
  • validateSubnetUniqueness
  • validateNsgUniqueness

These checks are best-effort. Race conditions are possible for clusters admitted at the same time.

Why

Cluster Service no longer returns synchronous 400s for platform uniqueness checks after async CS create migration. Move those checks to the frontend so invalid cluster PUTs fail at admission time with the same error messages CS used in performSpecValidation.

Testing

Added unit tests for new functions. Modified integration tests where new errors were occurring because they are now being caught by the admission validation. Tested against existing E2E tests around subnet/NSG/MRG reuse between clusters (test/e2e/cluster_nsg_subnet_reuse.go and test/e2e/clusters_sharing_resgroup.go)

Special notes for your reviewer

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 graph/UI/metrics changes)
  • 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

If E2E tests are included:

  • E2E tests follow Principles of Good E2E Test Case Design
  • If new E2E use case is covered (via a new test or new check/verifier),
    demonstrate that the test is able to detect a defect/error and fail with
    proper error message and logs which communicates nature of the problem.

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown

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

@JakobGray JakobGray force-pushed the cluster-install-admission branch from d8f9ac9 to 6e76b7c Compare July 10, 2026 03:23
@JakobGray JakobGray marked this pull request as ready for review July 10, 2026 03:24
Copilot AI review requested due to automatic review settings July 10, 2026 03:24
@openshift-ci openshift-ci Bot requested review from deads2k and geoberle July 10, 2026 03:24

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.

Pull request overview

This PR moves several platform “uniqueness” and NSG placement checks (previously enforced by Cluster Service) into the frontend’s admission/static validation so invalid cluster creates fail early with consistent error messages.

Changes:

  • Prefetch subscription-scoped clusters and node pools during cluster CREATE admission and add best-effort checks rejecting duplicate managed RG, subnet, and NSG usage across clusters/node pools.
  • Extend static validation so networkSecurityGroupId must be in the same subscription and must not be in the cluster’s managed resource group.
  • Update unit/integration tests and test artifacts to reflect newly enforced CREATE-time validation behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test-integration/frontend/artifacts/FrontendCRUD/Cluster/experimental-features-no-afec/04-httpCreate-cluster-with-4.19/create-with-4.19.json Updates test create payload resource IDs to avoid conflicts with new admission checks.
internal/validation/validate_cluster.go Adds NSG “same subscription” and “not in managed RG” checks at the cluster-level validation layer.
internal/validation/validate_cluster_comprehensive_test.go Adds/adjusts validation test coverage for new NSG subscription/RG constraints.
internal/validation/hcpopenshiftcluster_test.go Updates test cluster setup to include an NSG ID consistent with the new rules.
internal/admission/admit_cluster.go Introduces CREATE-only cross-cluster/nodepool uniqueness admission checks for MRG/subnet/NSG.
internal/admission/admit_cluster_test.go Adds unit tests verifying the new CREATE-only admission checks.
frontend/pkg/frontend/cluster.go Prefetches subscription clusters and their node pools to populate the admission context on CREATE.

Comment on lines +287 to +288
existingSubnet := existing.CustomerProperties.Platform.SubnetID
if strings.EqualFold(subnetID, existingSubnet.String()) {
Comment on lines +299 to +300
nodePoolSubnet := nodePool.Properties.Platform.SubnetID
if strings.EqualFold(subnetID, nodePoolSubnet.String()) {
Comment thread internal/admission/admit_cluster.go Outdated
Comment on lines +329 to +330
existingNSG := existing.CustomerProperties.Platform.NetworkSecurityGroupID
if strings.EqualFold(nsgID, existingNSG.String()) {
Comment thread internal/admission/admit_cluster.go Outdated
Comment on lines +282 to +284
subnetPath := fldPath.Child("subnetId")
subnetID := newObj.SubnetID.String()
var errs field.ErrorList
Comment on lines +324 to +326
nsgPath := fldPath.Child("networkSecurityGroupId")
nsgID := newObj.NetworkSecurityGroupID.String()
var errs field.ErrorList
Cluster Service no longer returns synchronous 400s for platform
uniqueness checks after async CS create migration. Move those checks to
the frontend so invalid cluster PUTs fail at admission time with the same
error messages CS used in performSpecValidation. These checks are best-effort
and may not catch concurrent creates.

- Prefetch subscription clusters and node pools in newClusterAdmissionContext
- Add admitClusterManagedResourceGroupName, admitClusterSubnetResourceID,
  and admitClusterNetworkSecurityGroupResourceID (CREATE only)
- Add NSG same-subscription and not-in-MRG rules to static validation
  (parity with validateAroHcpClusterNetworkSecurityGroupResourceId)
Copilot AI review requested due to automatic review settings July 10, 2026 04:17
@JakobGray JakobGray force-pushed the cluster-install-admission branch from 6e76b7c to 03e5c54 Compare July 10, 2026 04:17

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Comment on lines +287 to +288
existingSubnet := existing.CustomerProperties.Platform.SubnetID
if strings.EqualFold(subnetID, existingSubnet.String()) {
Comment on lines +299 to +300
nodePoolSubnet := nodePool.Properties.Platform.SubnetID
if strings.EqualFold(subnetID, nodePoolSubnet.String()) {
Comment on lines +329 to +330
existingNSG := existing.CustomerProperties.Platform.NetworkSecurityGroupID
if strings.EqualFold(nsgID, existingNSG.String()) {
Comment thread internal/admission/admit_cluster.go Outdated
Comment thread internal/admission/admit_cluster.go
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 10, 2026 05:23

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Comment on lines +286 to +296
for _, existing := range admissionContext.SubscriptionClusters {
existingSubnet := existing.CustomerProperties.Platform.SubnetID
if strings.EqualFold(subnetID, existingSubnet.String()) {
errs = append(errs, field.Invalid(
subnetPath,
subnetID,
fmt.Sprintf("Subnet '%s' is already in use by another cluster", subnetID),
))
break
}
}
Comment on lines +298 to +308
for _, nodePool := range admissionContext.SubscriptionNodePools {
nodePoolSubnet := nodePool.Properties.Platform.SubnetID
if strings.EqualFold(subnetID, nodePoolSubnet.String()) {
errs = append(errs, field.Invalid(
subnetPath,
subnetID,
fmt.Sprintf("Subnet '%s' is already in use by another cluster", subnetID),
))
break
}
}
Comment on lines +327 to +337
for _, existing := range admissionContext.SubscriptionClusters {
existingNSG := existing.CustomerProperties.Platform.NetworkSecurityGroupID
if strings.EqualFold(nsgID, existingNSG.String()) {
errs = append(errs, field.Invalid(
nsgPath,
nsgID,
fmt.Sprintf("Network Security Group '%s' is already in use by another cluster", nsgID),
))
break
}
}
@JakobGray JakobGray requested a review from miguelsorianod July 10, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants