Skip to content

Conversation

@starbops
Copy link
Member

@starbops starbops commented Dec 12, 2025

IMPORTANT: Please do not create a Pull Request without creating an issue first.

Problem:

If the name of the IPPool CR is not the same as its associated NetworkAttachmentDefinition (NAD) CR, all the VirtualMachineNetworkConfig (vmnetcfg) CR referencing the IPPool cannot be created automatically by the controller.

Solution:

Fix the vmnetcfg validating webhook logic.

Related Issue:

harvester/harvester#9710

Test plan:

  1. Create a single-node v1.7.0 Harvester cluster
  2. Enable the Managed DHCP add-on using the following manifest:
    apiVersion: harvesterhci.io/v1beta1
    kind: Addon
    metadata:
      name: harvester-vm-dhcp-controller
      namespace: harvester-system
      labels:
        addon.harvesterhci.io/experimental: "true"
    spec:
      enabled: true
      repo: https://charts.harvesterhci.io
      version: 1.6.0
      chart: harvester-vm-dhcp-controller
      valuesContent: |
        image:
          repository: starbops/harvester-vm-dhcp-controller
          tag: pool-name-hot-fix-head
        webhook:
          image:
            repository: starbops/harvester-vm-dhcp-webhook
            tag: pool-name-hot-fix-head
        agent:
          image:
            repository: starbops/harvester-vm-dhcp-agent
            tag: pool-name-hot-fix-head
  3. Create a Virtual Machine Network (NAD) called test-net
  4. Create an IPPool called test-pool (the name must be different from its associated NAD's name)
    apiVersion: network.harvesterhci.io/v1alpha1
    kind: IPPool
    metadata:
      name: test-pool
    spec:
     ipv4Config:
       cidr: 192.168.48.0/24   # please change the cidr accordingly to suit your network environment
     networkName: default/test-net
  5. Create a virtual machine test-vm and attach it to the test-net NAD
  6. The virtual machine should eventually get the allocated IP address (it should match the one reflected in the VirtualMachineNetworkConfig CR)

@starbops starbops marked this pull request as ready for review December 29, 2025 06:44
Copilot AI review requested due to automatic review settings December 29, 2025 06:44
@starbops starbops self-assigned this Dec 29, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request fixes the VirtualMachineNetworkConfig (vmnetcfg) validating webhook to properly handle scenarios where the IPPool name differs from its associated NetworkAttachmentDefinition (NAD) name. The fix retrieves the IPPool reference from NAD labels instead of assuming the names match.

Key Changes

  • Modified the webhook validator to read IPPool namespace and name from NAD labels (network.harvesterhci.io/ippool-namespace and network.harvesterhci.io/ippool-name)
  • Added nadCache dependency to the validator to look up NAD resources
  • Added comprehensive unit tests covering different naming scenarios

Reviewed changes

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

File Description
pkg/webhook/vmnetcfg/validator.go Updated validation logic to retrieve IPPool information from NAD labels instead of directly from network name, added NAD cache dependency
pkg/webhook/vmnetcfg/validator_test.go Added new test file with test cases for IPPool/NAD name matching scenarios and error conditions
cmd/webhook/run.go Updated validator constructor call to include nadCache parameter

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

given: input{
vmNetCfg: newTestVirtualMachineNetworkConfigBuilder().
WithNetworkConfig("", "", testNetworkName).Build(),
ipPool: ippool.NewIPPoolBuilder(testNADNamespace, testNADName).Build(),
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

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

The IPPool created in this test is missing the NetworkName configuration. The IPPool should be associated with the network by setting its NetworkName to testNetworkName, similar to how it's done in other tests. Without this, the test doesn't properly reflect the real-world scenario where IPPool references the NAD through its NetworkName field.

Suggested change
ipPool: ippool.NewIPPoolBuilder(testNADNamespace, testNADName).Build(),
ipPool: ippool.NewIPPoolBuilder(testNADNamespace, testNADName).
WithNetworkName(testNetworkName).Build(),

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +56
return fmt.Errorf(
webhook.CreateErr,
vmNetCfg.Kind,
vmNetCfg.Namespace,
vmNetCfg.Name, fmt.Errorf("%s label not found", util.IPPoolNameLabelKey),
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

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

The error formatting here has an issue. The fmt.Errorf call wraps another fmt.Errorf as the last argument, but the format string webhook.CreateErr expects a %w verb, not a nested error. This should be simplified to pass the error message string directly or use a properly formatted error. The current code may not produce the expected error message format.

Suggested change
return fmt.Errorf(
webhook.CreateErr,
vmNetCfg.Kind,
vmNetCfg.Namespace,
vmNetCfg.Name, fmt.Errorf("%s label not found", util.IPPoolNameLabelKey),
err := fmt.Errorf("%s label not found", util.IPPoolNameLabelKey)
return fmt.Errorf(
webhook.CreateErr,
vmNetCfg.Kind,
vmNetCfg.Namespace,
vmNetCfg.Name,
err,

Copilot uses AI. Check for mistakes.
}
ipPoolNamespace, ok := nad.Labels[util.IPPoolNamespaceLabelKey]
if !ok {
ipPoolNamespace = nadNamespace
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

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

There's an inconsistency with how the controller handles the IPPoolNamespaceLabelKey. In the controller's getIPPoolFromNetworkName function, if the IPPoolNamespaceLabelKey label is missing, it returns an error. However, in this validator, if the label is missing, it defaults to nadNamespace. This inconsistency could lead to the validator accepting configurations that the controller will reject. The validator should either match the controller's strict behavior or the controller should adopt this more lenient approach.

Suggested change
ipPoolNamespace = nadNamespace
return fmt.Errorf(
webhook.CreateErr,
vmNetCfg.Kind,
vmNetCfg.Namespace,
vmNetCfg.Name, fmt.Errorf("%s label not found", util.IPPoolNamespaceLabelKey),
)

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

do we support nad and ipool in different namespaces or does it have to be in same namespace. Do we restrict this somewhere ? Any reason behind using nad namespace as ipool namespace in case of namespace does not exist.
Can we return error instead ?

Copy link
Member Author

Choose a reason for hiding this comment

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

do we support nad and ipool in different namespaces or does it have to be in same namespace. Do we restrict this somewhere ?

yes we currently support cross-namespace referencing between nads and ippools. but i gradually realize that this shouldn't be allowed. restricting ippools that can only reference the same namespace nads should be the norm. however, this will be a breaking change for users who have already done so (cross-namespace referencing), and need to be planned carefully.

Any reason behind using nad namespace as ipool namespace in case of namespace does not exist.
Can we return error instead ?

sure we can return an error here. i initially thought it could be handy to set it to the nad's namespace if the namespace label on the nad is missing.

shouldErr: true,
},
},
}
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

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

The test suite is missing a test case for when a NAD exists but lacks the required IPPoolNameLabelKey label. This is an important validation scenario that should be tested to ensure the validator properly rejects VirtualMachineNetworkConfig creation when the NAD is not properly labeled. Consider adding a test case similar to the existing ones that validates this error path.

Copilot uses AI. Check for mistakes.
given: input{
vmNetCfg: newTestVirtualMachineNetworkConfigBuilder().
WithNetworkConfig("", "", testNetworkName).Build(),
ipPool: newTestIPPoolBuilder().Build(),
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

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

The IPPool created in this test is missing the NetworkName configuration. The IPPool should be associated with the network by setting its NetworkName to testNetworkName, similar to how it's done in other tests. Without this, the test doesn't properly reflect the real-world scenario where IPPool references the NAD through its NetworkName field.

Copilot uses AI. Check for mistakes.
given: input{
vmNetCfg: newTestVirtualMachineNetworkConfigBuilder().
WithNetworkConfig("", "", testNetworkName).Build(),
ipPool: newTestIPPoolBuilder().Build(),
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

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

The IPPool created in this test is missing the NetworkName configuration. The IPPool should be associated with the network by setting its NetworkName to testNetworkName. Without this, the test doesn't properly reflect the real-world scenario where IPPool references the NAD through its NetworkName field.

Copilot uses AI. Check for mistakes.
@rrajendran17
Copy link
Contributor

LGTM,Thanks

Copy link
Contributor

@ibrokethecloud ibrokethecloud left a comment

Choose a reason for hiding this comment

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

lgtm. thanks for the fix.

@starbops starbops merged commit 54275d2 into harvester:main Jan 13, 2026
7 checks passed
@starbops
Copy link
Member Author

@mergify backport v1.7

@mergify
Copy link

mergify bot commented Jan 13, 2026

backport v1.7

✅ Backports have been created

Details

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.

3 participants