Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement DHCP for machine network #53

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Implement DHCP for machine network #53

wants to merge 15 commits into from

Conversation

mcbenjemaa
Copy link
Member

@mcbenjemaa mcbenjemaa commented Jan 8, 2024

THis PR adds:

  • Support DHCP

api/v1alpha1/helpers.go Outdated Show resolved Hide resolved
65278 pushed a commit that referenced this pull request Jan 17, 2024
* add provider manifests and docs

* Update local-providers docs

---------

Co-authored-by: Ludwig Bedacht <ludwig.bedacht@ionos.com>
Co-authored-by: lubedacht <132355999+lubedacht@users.noreply.github.com>
Copy link
Collaborator

@avorima avorima left a comment

Choose a reason for hiding this comment

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

First batch of comments. Didn't look at vmservice yet

api/v1alpha1/helpers.go Outdated Show resolved Hide resolved
api/v1alpha1/helpers.go Outdated Show resolved Hide resolved
api/v1alpha1/helpers.go Outdated Show resolved Hide resolved
api/v1alpha1/proxmoxcluster_types.go Show resolved Hide resolved
api/v1alpha1/proxmoxmachine_types.go Outdated Show resolved Hide resolved
api/v1alpha1/proxmoxmachine_types.go Outdated Show resolved Hide resolved
api/v1alpha1/proxmoxmachine_types.go Outdated Show resolved Hide resolved
internal/controller/proxmoxcluster_controller.go Outdated Show resolved Hide resolved
api/v1alpha1/proxmoxcluster_types.go Show resolved Hide resolved
api/v1alpha1/proxmoxcluster_types.go Outdated Show resolved Hide resolved
@wikkyk
Copy link
Collaborator

wikkyk commented Jan 26, 2024

Rebased and updated copyright headers.

api/v1alpha1/proxmoxcluster_types.go Outdated Show resolved Hide resolved
internal/service/vmservice/bootstrap.go Outdated Show resolved Hide resolved
@wikkyk
Copy link
Collaborator

wikkyk commented Jan 26, 2024

This PR should also update the docs as appropriate.

Copy link
Collaborator

@wikkyk wikkyk left a comment

Choose a reason for hiding this comment

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

First round of reviews.

.github/workflows/lint.yml Outdated Show resolved Hide resolved
func machineHasIPAddress(machine *infrav1alpha1.ProxmoxMachine) bool {
return machine.Status.IPAddresses[infrav1alpha1.DefaultNetworkDevice] != (infrav1alpha1.IPAddress{})
func machineHasIPAddress(machine *infrav1.ProxmoxMachine) bool {
return machine.Status.IPAddresses[infrav1.DefaultNetworkDevice] != (infrav1.IPAddress{})
}

func handleIPAddressForDevice(ctx context.Context, machineScope *scope.MachineScope, device, format string, ipamRef *corev1.TypedLocalObjectReference) (string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this function be refactored so that it always returns an error when it also returns an empty string? To avoid all the if err != nil || ip == "" {.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's very confusing to return an error when creating a new IP claim:

err = machineScope.IPAMHelper.CreateIPAddressClaim(ctx, machineScope.ProxmoxMachine, device, format, machineScope.InfraCluster.Cluster.GetName(), ipamRef)
if err != nil {
return "", errors.Wrapf(err, "unable to create Ip address claim for machine %s", machineScope.Name())
}
return "", nil

also when trying to add a tag:

t, err := machineScope.InfraCluster.ProxmoxClient.TagVM(ctx, vm, ipTag)
if err != nil {
return "", errors.Wrapf(err, "unable to add Ip tag to VirtualMachine %s", machineScope.Name())
}
machineScope.ProxmoxMachine.Status.TaskRef = ptr.To(string(t.UPID))
return "", nil

Another choice is to add a third return as bool, but it's actually the same.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe there should be an error for the "" case that handleIPAddressForDevice would return. Then, the usages where this is an error (i.e. if err != nil || ip == "" {s) could be reduced to the usual if err != nil {. Of course, usages that can handle "" would then need to handle this new error but at least they would have the right context instead of relying on a magic return value.

internal/service/vmservice/vm.go Outdated Show resolved Hide resolved
Copy link

sonarcloud bot commented Feb 2, 2024

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

4 New issues
0 Security Hotspots
85.1% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarCloud

@mcbenjemaa
Copy link
Member Author

I'm ready

Copy link
Collaborator

@avorima avorima left a comment

Choose a reason for hiding this comment

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

Sorry, for the long wait.

| calico | templates/cluster-template-calico.yaml | templates/crs/cni/calico.yaml |
| multiple-vlans | templates/cluster-template-multiple-vlans.yaml | - |
| default | templates/cluster-template.yaml | - |
| Flavor | Tepmlate File | CRS File |
Copy link
Collaborator

Choose a reason for hiding this comment

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

typo: Template

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ensure that DHCP test cases don't set IPAM fields

Comment on lines +156 to +168
// DHCPEnabled returns whether DHCP is enabled.
func (c ClusterNetworkConfig) DHCPEnabled() bool {
switch {
case (c.IPv6Config != nil && ptr.Deref(c.IPv6Config.DHCP, false)) && (c.IPv4Config != nil && ptr.Deref(c.IPv4Config.DHCP, false)):
return true
case (c.IPv6Config != nil && ptr.Deref(c.IPv6Config.DHCP, false)) && c.IPv4Config == nil:
return true
case (c.IPv4Config != nil && ptr.Deref(c.IPv4Config.DHCP, false)) && c.IPv6Config == nil:
return true
default:
return false
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't this just supposed to do this?

Suggested change
// DHCPEnabled returns whether DHCP is enabled.
func (c ClusterNetworkConfig) DHCPEnabled() bool {
switch {
case (c.IPv6Config != nil && ptr.Deref(c.IPv6Config.DHCP, false)) && (c.IPv4Config != nil && ptr.Deref(c.IPv4Config.DHCP, false)):
return true
case (c.IPv6Config != nil && ptr.Deref(c.IPv6Config.DHCP, false)) && c.IPv4Config == nil:
return true
case (c.IPv4Config != nil && ptr.Deref(c.IPv4Config.DHCP, false)) && c.IPv6Config == nil:
return true
default:
return false
}
}
// DHCPEnabled returns true when DHCP is enabled.
func (c ClusterNetworkConfig) DHCPEnabled() bool {
return c.IPv4Config.DHCPEnabled() || c.IPv6Config.DHCPEnabled()
}
// DHCPEnabled returns true when DHCP is enabled.
func (c *IPConfig) DHCPEnabled() bool {
return c != nil && ptr.Deref(c.DHCP, false)
}

I think this way it's easier to understand and you can also use the IPConfig.DHCPEnabled in the controller and vmservice.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem here is we need to check if the cluster has dhcp so we can skip the IPAM pool.

Then, in the machine, we also need to check if the machine has DHCP.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't contradict my proposition

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add a test case for DHCP

if len(nic.DNSServers) != 0 {
config.DNSServers = nic.DNSServers
if len(nics[i].DNSServers) != 0 {
config.DNSServers = nics[i].DNSServers
Copy link
Collaborator

Choose a reason for hiding this comment

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

Either do this:

Suggested change
config.DNSServers = nics[i].DNSServers
conf.DNSServers = nics[i].DNSServers

or pass in the whole AdditionalNetworkDevice into getNetworkConfigDataForDevice to do the override there. Same goes for ipv6 a few lines down.

Comment on lines +270 to +277
if hasDHCPEnabled(scope.InfraCluster.ProxmoxCluster.Spec.IPv4Config,
networkSpec.Default,
infrav1alpha1.DefaultNetworkDevice,
infrav1alpha1.IPV4Format) ||
hasDHCPEnabled(scope.InfraCluster.ProxmoxCluster.Spec.IPv6Config,
networkSpec.Default,
infrav1alpha1.DefaultNetworkDevice,
infrav1alpha1.IPV6Format) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would actually be less code if you move the default interface handling out of hasDHCPEnabled and use a few intermediate variables, e.g.

if dev := networkSpec.Default; scope.InfraCluster.ProxmoxCluster.Spec.DHCPEnabled() || (dev != nil && dev.DHCP4 || dev.DHCP6) {

But more importantly, why is the default device DHCP setting even considered when DHCP is enabled on the cluster?

for _, ip := range net.IPAddresses {
if ip.IPAddressType == "ipv4" && ip.IPAddress != scope.InfraCluster.ProxmoxCluster.Spec.ControlPlaneEndpoint.Host {
ipv4 = ip.IPAddress
} else if ip.IPAddressType == "ipv6" && !strings.Contains(ip.IPAddress, "fe80:") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use netip.Addr.IsLinkLocalUnicast. Substring match for IPv6 is always less accurate than comparing the bits.

// DHCP4 indicates that if DHCP should be used to assign IPv4 addresses.
// DHCP4 enforce device to use DHCP despite the config set in cluster.spec.ipv4Config.
// +optional
DHCP4 bool `json:"dhcp4,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is in the base network device? All permuations of DHCP and IPAM on the default device should be configured in the cluster network config.

This also has the same pointer issue as the cluster dhcp setting.

// DHCP indicates that DHCP should be used to assign IP addresses.
// mutually exclusive with Addresses.
// +optional
// +kubebuilder:default=false
Copy link
Collaborator

@avorima avorima Feb 8, 2024

Choose a reason for hiding this comment

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

This default isn't needed. The behavior stays the same whether it's set to false or null. My pointer request was about making the user-facing API explicit.

@@ -245,3 +245,13 @@ func (c *APIClient) StartVM(ctx context.Context, vm *proxmox.VirtualMachine) (*p
func (c *APIClient) TagVM(ctx context.Context, vm *proxmox.VirtualMachine, tag string) (*proxmox.Task, error) {
return vm.AddTag(ctx, tag)
}

// GetVMNetwork returns a VM network interfaces based on nodeName and vmID.
func (c *APIClient) GetVMNetwork(ctx context.Context, vm *proxmox.VirtualMachine) (iFaces []*proxmox.AgentNetworkIface, err error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: named return values are not used and don't provide any additional context

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.

None yet

6 participants