Skip to content

Commit

Permalink
Add implementation of Node IPAM support
Browse files Browse the repository at this point in the history
- Adds `addressesFromPools` to the VSphereVM network device spec
- Creates IPAddressClaims when AddressesFromPools is specified
- IP addresses created by IPAM providers are assigned to vSphere
  machines via the VM metadata
- IPv4 Gateways from IPAddresses (created by IPAM providers) are
  assigned to the Gateway4 field
- IPv6 Gateways from IPAddresses (created by IPAM providers) are assigned
  to the Gateway6 field
- All gateways in the same IP family assigned to a VSphereVM network
  device must be the same.
- This implementation expects that an appropriate gateway for the IP
  family exists for every IPAddress that comes from an IPAM provider.
- Adds the `IPAddressClaimed` Condition to provide visibility of the
  status of IP address acquisition
- Adds the finalizer to prevent IPAMClaims from being deleted early
- IPAddressClaims have an OwnerReference to VSphereVMs to ensure they
  are garbage-collected when the VM is deleted.

Co-authored-by: Aidan Obley <[email protected]>
Co-authored-by: Tyler Schultz <[email protected]>
Co-authored-by: Christian Ang <[email protected]>
Co-authored-by: Edwin Xie <[email protected]>
  • Loading branch information
4 people committed Nov 9, 2022
1 parent 1e47610 commit ef3ece3
Show file tree
Hide file tree
Showing 29 changed files with 1,440 additions and 48 deletions.
48 changes: 48 additions & 0 deletions apis/v1alpha3/networkdevicespec_conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha3

import (
conversion "k8s.io/apimachinery/pkg/conversion"
v1beta1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
)

func Convert_v1beta1_NetworkDeviceSpec_To_v1alpha3_NetworkDeviceSpec(in *v1beta1.NetworkDeviceSpec, out *NetworkDeviceSpec, s conversion.Scope) error {
out.NetworkName = in.NetworkName
out.DeviceName = in.DeviceName
out.DHCP4 = in.DHCP4
out.DHCP6 = in.DHCP6
out.Gateway4 = in.Gateway4
out.Gateway6 = in.Gateway6
out.IPAddrs = in.IPAddrs
out.MTU = in.MTU
out.MACAddr = in.MACAddr
out.Nameservers = in.Nameservers
out.SearchDomains = in.SearchDomains
if in.Routes != nil {
inRoutes, outRoutes := &in.Routes, &out.Routes
*outRoutes = make([]NetworkRouteSpec, len(*inRoutes))
for i := range *inRoutes {
if err := Convert_v1beta1_NetworkRouteSpec_To_v1alpha3_NetworkRouteSpec(&(*inRoutes)[i], &(*outRoutes)[i], s); err != nil {
return err
}
}
} else {
out.Routes = nil
}
return nil
}
3 changes: 3 additions & 0 deletions apis/v1alpha3/vspheremachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ func (src *VSphereMachine) ConvertTo(dstRaw conversion.Hub) error {

dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB
dst.Spec.TagIDs = restored.Spec.TagIDs
for i := range dst.Spec.Network.Devices {
dst.Spec.Network.Devices[i].AddressesFromPools = restored.Spec.Network.Devices[i].AddressesFromPools
}

return nil
}
Expand Down
7 changes: 5 additions & 2 deletions apis/v1alpha3/vspheremachinetemplate_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (src *VSphereMachineTemplate) ConvertTo(dstRaw conversion.Hub) error {
}
dst.Spec.Template.Spec.TagIDs = restored.Spec.Template.Spec.TagIDs
dst.Spec.Template.Spec.AdditionalDisksGiB = restored.Spec.Template.Spec.AdditionalDisksGiB
for i := range dst.Spec.Template.Spec.Network.Devices {
dst.Spec.Template.Spec.Network.Devices[i].AddressesFromPools = restored.Spec.Template.Spec.Network.Devices[i].AddressesFromPools
}

return nil
}
Expand Down Expand Up @@ -69,14 +72,14 @@ func (dst *VSphereMachineTemplateList) ConvertFrom(srcRaw conversion.Hub) error
return Convert_v1beta1_VSphereMachineTemplateList_To_v1alpha3_VSphereMachineTemplateList(src, dst, nil)
}

//nolint
// nolint
func Convert_v1alpha3_ObjectMeta_To_v1beta1_ObjectMeta(in *clusterv1a3.ObjectMeta, out *clusterv1b1.ObjectMeta, s apiconversion.Scope) error {
// wrapping the conversion func to avoid having compile errors due to compileErrorOnMissingConversion()
// more details at https://github.com/kubernetes/kubernetes/issues/98380
return clusterv1a3.Convert_v1alpha3_ObjectMeta_To_v1beta1_ObjectMeta(in, out, s)
}

//nolint
// nolint
func Convert_v1beta1_ObjectMeta_To_v1alpha3_ObjectMeta(in *clusterv1b1.ObjectMeta, out *clusterv1a3.ObjectMeta, s apiconversion.Scope) error {
// wrapping the conversion func to avoid having compile errors due to compileErrorOnMissingConversion()
// more details at https://github.com/kubernetes/kubernetes/issues/98380
Expand Down
3 changes: 3 additions & 0 deletions apis/v1alpha3/vspherevm_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ func (src *VSphereVM) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.TagIDs = restored.Spec.TagIDs
dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB
dst.Status.Host = restored.Status.Host
for i := range dst.Spec.Network.Devices {
dst.Spec.Network.Devices[i].AddressesFromPools = restored.Spec.Network.Devices[i].AddressesFromPools
}

return nil
}
Expand Down
40 changes: 28 additions & 12 deletions apis/v1alpha3/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions apis/v1alpha4/networkdevicespec_conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha4

import (
conversion "k8s.io/apimachinery/pkg/conversion"
v1beta1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
)

func Convert_v1beta1_NetworkDeviceSpec_To_v1alpha4_NetworkDeviceSpec(in *v1beta1.NetworkDeviceSpec, out *NetworkDeviceSpec, s conversion.Scope) error {
out.NetworkName = in.NetworkName
out.DeviceName = in.DeviceName
out.DHCP4 = in.DHCP4
out.DHCP6 = in.DHCP6
out.Gateway4 = in.Gateway4
out.Gateway6 = in.Gateway6
out.IPAddrs = in.IPAddrs
out.MTU = in.MTU
out.MACAddr = in.MACAddr
out.Nameservers = in.Nameservers
out.SearchDomains = in.SearchDomains
if in.Routes != nil {
inRoutes, outRoutes := &in.Routes, &out.Routes
*outRoutes = make([]NetworkRouteSpec, len(*inRoutes))
for i := range *inRoutes {
if err := Convert_v1beta1_NetworkRouteSpec_To_v1alpha4_NetworkRouteSpec(&(*inRoutes)[i], &(*outRoutes)[i], s); err != nil {
return err
}
}
} else {
out.Routes = nil
}
return nil
}
3 changes: 3 additions & 0 deletions apis/v1alpha4/vspheremachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ func (src *VSphereMachine) ConvertTo(dstRaw conversion.Hub) error {

dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB
dst.Spec.TagIDs = restored.Spec.TagIDs
for i := range dst.Spec.Network.Devices {
dst.Spec.Network.Devices[i].AddressesFromPools = restored.Spec.Network.Devices[i].AddressesFromPools
}

return nil
}
Expand Down
7 changes: 5 additions & 2 deletions apis/v1alpha4/vspheremachinetemplate_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (src *VSphereMachineTemplate) ConvertTo(dstRaw conversion.Hub) error {
}
dst.Spec.Template.Spec.TagIDs = restored.Spec.Template.Spec.TagIDs
dst.Spec.Template.Spec.AdditionalDisksGiB = restored.Spec.Template.Spec.AdditionalDisksGiB
for i := range dst.Spec.Template.Spec.Network.Devices {
dst.Spec.Template.Spec.Network.Devices[i].AddressesFromPools = restored.Spec.Template.Spec.Network.Devices[i].AddressesFromPools
}

return nil
}
Expand Down Expand Up @@ -69,14 +72,14 @@ func (dst *VSphereMachineTemplateList) ConvertFrom(srcRaw conversion.Hub) error
return Convert_v1beta1_VSphereMachineTemplateList_To_v1alpha4_VSphereMachineTemplateList(src, dst, nil)
}

//nolint
// nolint
func Convert_v1alpha4_ObjectMeta_To_v1beta1_ObjectMeta(in *clusterv1a4.ObjectMeta, out *clusterv1b1.ObjectMeta, s apiconversion.Scope) error {
// wrapping the conversion func to avoid having compile errors due to compileErrorOnMissingConversion()
// more details at https://github.com/kubernetes/kubernetes/issues/98380
return clusterv1a4.Convert_v1alpha4_ObjectMeta_To_v1beta1_ObjectMeta(in, out, s)
}

//nolint
// nolint
func Convert_v1beta1_ObjectMeta_To_v1alpha4_ObjectMeta(in *clusterv1b1.ObjectMeta, out *clusterv1a4.ObjectMeta, s apiconversion.Scope) error {
// wrapping the conversion func to avoid having compile errors due to compileErrorOnMissingConversion()
// more details at https://github.com/kubernetes/kubernetes/issues/98380
Expand Down
3 changes: 3 additions & 0 deletions apis/v1alpha4/vspherevm_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ func (src *VSphereVM) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.TagIDs = restored.Spec.TagIDs
dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB
dst.Status.Host = restored.Status.Host
for i := range dst.Spec.Network.Devices {
dst.Spec.Network.Devices[i].AddressesFromPools = restored.Spec.Network.Devices[i].AddressesFromPools
}

return nil
}
Expand Down
40 changes: 28 additions & 12 deletions apis/v1alpha4/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions apis/v1beta1/condition_consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,17 @@ const (
// associated to the VSphereDeploymentZone is misconfigured.
DatastoreNotFoundReason = "DatastoreNotFound"
)

const (
// IPAddressClaimedCondition documents the status of claiming an IP address
// from an IPAM provider.
IPAddressClaimedCondition clusterv1.ConditionType = "IPAddressClaimed"

// WaitingForIPAddressReason (Severity=Info) documents that the VSphereVM is
// currently waiting for an IP address to be provisioned.
WaitingForIPAddressReason = "WaitingForIPAddress"

// IPAddressInvalidReason (Severity=Error) documents that the IP address
// provided by the IPAM provider is not valid.
IPAddressInvalidReason = "IPAddressInvalid"
)
7 changes: 7 additions & 0 deletions apis/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package v1beta1
import (
"fmt"

corev1 "k8s.io/api/core/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
)

Expand Down Expand Up @@ -316,6 +317,12 @@ type NetworkDeviceSpec struct {
// addresses with DNS.
// +optional
SearchDomains []string `json:"searchDomains,omitempty"`

// AddressesFromPools is a list of IPAddressPools that should be assigned
// to IPAddressClaims. The machine's cloud-init metadata will be populated
// with IPAddresses fulfilled by an IPAM provider.
// +optional
AddressesFromPools []corev1.TypedLocalObjectReference `json:"addressesFromPools,omitempty"`
}

// NetworkRouteSpec defines a static network route.
Expand Down
4 changes: 4 additions & 0 deletions apis/v1beta1/vspherevm_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const (
// VMFinalizer allows the reconciler to clean up resources associated
// with a VSphereVM before removing it from the API Server.
VMFinalizer = "vspherevm.infrastructure.cluster.x-k8s.io"

// IPClaimFinalizer allows the reconciler to prevent deletion of an
// IPAddressClaim that is in use.
IPAddressClaimFinalizer = "vspherevm.infrastructure.cluster.x-k8s.io/ip-claim-protection"
)

// VSphereVMSpec defines the desired state of VSphereVM.
Expand Down
Loading

0 comments on commit ef3ece3

Please sign in to comment.