Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions api/v1alpha1/vspheredistributednetwork_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ const (
IPAssignmentModeNone IPAssignmentModeType = "none"
)

// VSphereDistributedNetworkIPRange is the static IP range for a VSphereDistributedNetwork.
type VSphereDistributedNetworkIPRange struct {
// address is the starting IPv4 or IPv6 address of the range.
// +kubebuilder:validation:XValidation:rule="self.matches('^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$') || self.matches('^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$')",message="Address must be a valid IPv4 or IPv6 address"
// +kubebuilder:validation:MinLength=2
// +kubebuilder:validation:MaxLength=45
// +required
Address string `json:"address,omitempty"`

// count is the number of addresses in the range when using static range assignment.
// +kubebuilder:validation:Minimum=1
// +required
Count int64 `json:"count,omitempty"`
}

// VSphereDistributedNetworkCondition describes the state of a VSphereDistributedNetwork at a certain point.
type VSphereDistributedNetworkCondition struct {
// Type is the type of VSphereDistributedNetwork condition.
Expand Down Expand Up @@ -65,6 +80,12 @@ type VSphereDistributedNetworkCondition struct {
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" patchStrategy:"replace"`
}

// +kubebuilder:validation:XValidation:rule="(has(self.ipAssignmentMode) && (self.ipAssignmentMode == 'dhcp' || self.ipAssignmentMode == 'none')) ? (!has(self.gateway) || self.gateway == '') : true",message="Gateway must be empty when IpAssignmentMode is dhcp or none"
// +kubebuilder:validation:XValidation:rule="(has(self.ipAssignmentMode) && (self.ipAssignmentMode == 'dhcp' || self.ipAssignmentMode == 'none')) ? (!has(self.subnetMask) || self.subnetMask == '') : true",message="SubnetMask must be empty when IpAssignmentMode is dhcp or none"
// +kubebuilder:validation:XValidation:rule="(has(self.ipAssignmentMode) && (self.ipAssignmentMode == 'dhcp' || self.ipAssignmentMode == 'none')) ? (!has(self.addressRanges) || size(self.addressRanges) == 0) : true",message="AddressRanges must be empty when IpAssignmentMode is dhcp or none"
// +kubebuilder:validation:XValidation:rule="(has(self.ipAssignmentMode) && (self.ipAssignmentMode == 'dhcp' || self.ipAssignmentMode == 'none')) ? (!has(self.ipPools) || size(self.ipPools) == 0) : true",message="IPPools must be empty when IpAssignmentMode is dhcp or none"
// +kubebuilder:validation:XValidation:rule="(!has(self.ipAssignmentMode) || self.ipAssignmentMode == 'staticpool') ? (has(self.gateway) && self.gateway != '') : true",message="Gateway is required when IpAssignmentMode is staticpool"
// +kubebuilder:validation:XValidation:rule="(!has(self.ipAssignmentMode) || self.ipAssignmentMode == 'staticpool') ? (has(self.subnetMask) && self.subnetMask != '') : true",message="SubnetMask is required when IpAssignmentMode is staticpool"
// VSphereDistributedNetworkSpec defines the desired state of VSphereDistributedNetwork.
type VSphereDistributedNetworkSpec struct {
// PortGroupID is an existing vSphere Distributed PortGroup identifier.
Comment thread
ammujumdar-bcom marked this conversation as resolved.
Expand All @@ -77,6 +98,9 @@ type VSphereDistributedNetworkSpec struct {
// fields should be empty/unset. When using IPAssignmentModeNone, no IPv4 IP will be assigned
// and no DHCP client will be configured.
// Note: For IPv6 address assignment, see IPv6AssignmentMode.
// +kubebuilder:validation:Enum=dhcp;staticpool;none
// +kubebuilder:default:=staticpool
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ipAssignmentMode is immutable"
// +optional
//
//nolint:kubeapilinter // Stable v1alpha1 retention: avoid MaxLength (would tighten validation). Avoid pointer (optionalfields).
Expand All @@ -94,23 +118,34 @@ type VSphereDistributedNetworkSpec struct {

// IPPools references list of IPPool objects. This field should only be set when using
// IPAssignmentModeStaticPool. For all other modes (IPAssignmentModeDHCP, IPAssignmentModeNone), this should be set
// to an empty list.
// to an empty list.
// When addressRanges is non-empty, the operator reconciles ipPools against those ranges:
// references that do not correspond to any address range are removed, new references are added
// where needed, and every retained reference (including ones that already matched a range) is reconciled.
//
//nolint:kubeapilinter // Stable v1alpha1 retention: avoid MaxItems (would tighten validation). Avoid omitempty (requiredfields wire shape).
IPPools []IPPoolReference `json:"ipPools"`

// Gateway is the gateway to use for network interfaces. This field should only be set when using
// IPAssignmentModeStaticPool. For all other modes (IPAssignmentModeDHCP, IPAssignmentModeNone), this should be set
// to an empty string.
// to an empty string.
// Note: The regex pattern performs IPv4 validation but also allows an empty string for backward compatibility.
// +kubebuilder:validation:Pattern="^(|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$"
// +kubebuilder:default:=""
// +optional
//
//nolint:kubeapilinter // Stable v1alpha1 retention: avoid MaxLength (would tighten validation). Avoid omitempty (requiredfields wire shape).
//nolint:kubeapilinter // Stable v1alpha1 retention: avoid MaxLength (would tighten validation). Keep stable wire shape: emit empty string rather than omitting key.
Gateway string `json:"gateway"`

// SubnetMask is the subnet mask to use for network interfaces. This field should only be set when using
// IPAssignmentModeStaticPool. For all other modes (IPAssignmentModeDHCP, IPAssignmentModeNone), this should be set
// to an empty string.
// to an empty string.
// Note: The regex pattern performs IPv4 validation but also allows an empty string for backward compatibility.
// +kubebuilder:validation:Pattern="^(|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$"
// +kubebuilder:default:=""
// +optional
//
//nolint:kubeapilinter // Stable v1alpha1 retention: avoid MaxLength (would tighten validation). Avoid omitempty (requiredfields wire shape).
//nolint:kubeapilinter // Stable v1alpha1 retention: avoid MaxLength (would tighten validation). Keep stable wire shape: emit empty string rather than omitting key.
SubnetMask string `json:"subnetMask"`

// IPv6Gateway is the IPv6 gateway to use for network interfaces. This field should only
Expand All @@ -129,6 +164,15 @@ type VSphereDistributedNetworkSpec struct {
// +kubebuilder:validation:Minimum=0
// +kubebuilder:validation:Maximum=128
IPv6Prefix *int32 `json:"ipv6Prefix,omitempty"`

// addressRanges is a list of IP ranges for static IP assignment.
Comment thread
ammujumdar-bcom marked this conversation as resolved.
// When non-empty, the operator reconciles ipPools against this list: IPPool references that do
// not map to any range here are removed, new references are added for ranges that require them,
// and all references that remain are reconciled (including those that already mapped to a range).
// +optional
// +kubebuilder:validation:MaxItems=1024
// +listType=atomic
AddressRanges []VSphereDistributedNetworkIPRange `json:"addressRanges,omitempty"`
}

// VLANType represents the type of VLAN configuration
Expand Down Expand Up @@ -291,6 +335,7 @@ type VSphereDistributedNetworkStatus struct {
// +genclient:nonNamespaced
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster
// +kubebuilder:validation:XValidation:rule="size(self.metadata.name) <= 253 && self.metadata.name.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$')",message="metadata.name must be a lowercase RFC 1123 DNS subdomain (alphanumeric or '-' or '.', each segment starting/ending with alphanumeric; max 253 characters)"

// VSphereDistributedNetwork represents schema for a network backed by a vSphere Distributed PortGroup on vSphere
// Distributed switch.
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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