Skip to content

Commit

Permalink
Merge pull request #9 from wenqiq/topic/wenqi/improve-networkinfo-ut
Browse files Browse the repository at this point in the history
Topic/wenqi/improve networkinfo ut
  • Loading branch information
wenqiq authored Oct 29, 2024
2 parents 4357c7d + 392b0c4 commit 8bd34c1
Show file tree
Hide file tree
Showing 114 changed files with 12,218 additions and 2,375 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/makefile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ jobs:
- name: Run test
run: make test

- name: Codecov
uses: codecov/codecov-action@v3
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./.coverage/coverage-unit.out
flags: unit-tests
name: codecov-unit-test
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ golangci-fix: $(GOLANGCI_LINT_BIN)

.PHONY: test
test: manifests generate fmt vet envtest .coverage ## Run tests .
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -gcflags=all=-l ./... -v -coverprofile $(CURDIR)/.coverage/coverage-unit.out ## Prohibit inline optimization when using gomonkey
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -gcflags=all=-l $$(go list ./... | grep -v mock | grep -v e2e | grep -v hack) -v -coverprofile $(CURDIR)/.coverage/coverage-unit.out ## Prohibit inline optimization when using gomonkey


##@ Build

.PHONY: build
build: generate fmt vet ## Build manager binary.
@mkdir -p $(BINDIR)
GOOS=linux go build -o $(BINDIR)/manager $(GOFLAGS) -ldflags '$(LDFLAGS)' cmd/main.go
GOOS=linux go build -o $(BINDIR)/webhookcert $(GOFLAGS) -ldflags '$(LDFLAGS)' cmd/webhookcert/main.go

.PHONY: build-clean
build-clean: generate fmt vet ## Build clean binary.
Expand Down
4 changes: 1 addition & 3 deletions build/image/photon/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
FROM golang:1.22.5 as golang-build
FROM golang:1.22.7 as golang-build

WORKDIR /source

COPY . /source
RUN CGO_ENABLED=0 go build -o manager cmd/main.go
RUN CGO_ENABLED=0 go build -o webhookcert cmd/webhookcert/main.go
RUN CGO_ENABLED=0 go build -o clean cmd_clean/main.go

FROM photon
Expand All @@ -13,7 +12,6 @@ RUN tdnf -y install shadow && \
useradd -s /bin/bash nsx-operator

COPY --from=golang-build /source/manager /usr/local/bin/
COPY --from=golang-build /source/webhookcert /usr/local/bin/
COPY --from=golang-build /source/clean /usr/local/bin/

USER nsx-operator
Expand Down
2 changes: 1 addition & 1 deletion build/yaml/crd/vpc/crd.nsx.vmware.com_ipblocksinfos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ spec:
description: |-
PrivateTGWIPCIDRs is a list of CIDR strings. Each CIDR is a contiguous IP address
spaces represented by network address and prefix length. The visibility of the
IPBlocks is PrivateTWG. Only IPBlocks in default project will be included.
IPBlocks is Private Transit Gateway. Only IPBlocks in default project will be included.
items:
type: string
type: array
Expand Down
12 changes: 12 additions & 0 deletions build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ spec:
default: false
type: boolean
type: object
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
accessMode:
description: Access mode of Subnet, accessible only from within VPC
or from outside VPC.
Expand Down Expand Up @@ -89,6 +92,15 @@ spec:
- message: Value is immutable
rule: self == oldSelf
type: object
x-kubernetes-validations:
- message: DHCPConfig is required once set
rule: '!has(oldSelf.DHCPConfig) || has(self.DHCPConfig)'
- message: ipv4SubnetSize is required once set
rule: '!has(oldSelf.ipv4SubnetSize) || has(self.ipv4SubnetSize)'
- message: accessMode is required once set
rule: '!has(oldSelf.accessMode) || has(self.accessMode)'
- message: ipAddresses is required once set
rule: '!has(oldSelf.ipAddresses) || has(self.ipAddresses)'
status:
description: SubnetStatus defines the observed state of Subnet.
properties:
Expand Down
10 changes: 10 additions & 0 deletions build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ spec:
default: false
type: boolean
type: object
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
accessMode:
description: Access mode of Subnet, accessible only from within VPC
or from outside VPC.
Expand All @@ -79,6 +82,13 @@ spec:
- message: Value is immutable
rule: self == oldSelf
type: object
x-kubernetes-validations:
- message: DHCPConfig is required once set
rule: '!has(oldSelf.DHCPConfig) || has(self.DHCPConfig)'
- message: accessMode is required once set
rule: '!has(oldSelf.accessMode) || has(self.accessMode)'
- message: ipv4SubnetSize is required once set
rule: '!has(oldSelf.ipv4SubnetSize) || has(self.ipv4SubnetSize)'
status:
description: SubnetSetStatus defines the observed state of SubnetSet.
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ spec:
minimum: 16
type: integer
nsxProject:
description: NSX Project the Namespace associated with.
description: NSX Project the Namespace is associated with.
type: string
privateIPs:
description: Private IPs.
Expand All @@ -68,7 +68,7 @@ spec:
type: array
vpc:
description: |-
NSX path of the VPC the Namespace associated with.
NSX path of the VPC the Namespace is associated with.
If VPC is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode
take effect, other fields are ignored.
type: string
Expand Down Expand Up @@ -111,8 +111,9 @@ spec:
type: object
type: array
vpcs:
description: VPCs describes VPC info, now it includes lb Subnet info
which are needed for AKO.
description: |-
VPCs describes VPC info, now it includes Load Balancer Subnet info which are needed
for the Avi Kubernetes Operator (AKO).
items:
description: VPCInfo defines VPC info needed by tenant admin.
properties:
Expand Down
2 changes: 0 additions & 2 deletions build/yaml/samples/nsx_v1alpha1_networkinfo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ apiVersion: crd.nsx.vmware.com/v1alpha1
kind: NetworkInfo
metadata:
creationTimestamp: "2024-05-14T02:14:18Z"
finalizers:
- networkinfo.crd.nsx.vmware.com/finalizer
generation: 2
name: kube-system
namespace: kube-system
Expand Down
4 changes: 2 additions & 2 deletions build/yaml/webhook/certificate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ metadata:
spec:
# $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
dnsNames:
- subnetset.vmware-system-nsx.svc
- subnetset.vmware-system-nsx.svc.cluster.local
- vmware-system-nsx-operator-webhook-service.vmware-system-nsx.svc
- vmware-system-nsx-operator-webhook-service.vmware-system-nsx.svc.cluster.local
issuerRef:
kind: Issuer
name: selfsigned-issuer
Expand Down
28 changes: 24 additions & 4 deletions build/yaml/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ webhooks:
- v1
clientConfig:
service:
name: subnetset
name: vmware-system-nsx-operator-webhook-service
namespace: vmware-system-nsx
# kubebuilder webhookpath.
path: /validate-nsx-vmware-com-v1alpha1-subnetset
path: /validate-crd-nsx-vmware-com-v1alpha1-subnetset
failurePolicy: Fail
name: default.subnetset.validating.nsx.vmware.com
name: default.subnetset.validating.crd.nsx.vmware.com
objectSelector:
matchExpressions:
- { key: nsxoperator.vmware.com/default-subnetset-for, operator: In, values: ["Pod", "VirtualMachine"] }
rules:
- apiGroups:
- nsx.vmware.com
- crd.nsx.vmware.com
apiVersions:
- v1alpha1
operations:
Expand All @@ -30,3 +30,23 @@ webhooks:
resources:
- subnetsets
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: vmware-system-nsx-operator-webhook-service
namespace: vmware-system-nsx
path: /validate-crd-nsx-vmware-com-v1alpha1-addressbinding
failurePolicy: Fail
name: addressbinding.validating.crd.nsx.vmware.com
rules:
- apiGroups:
- crd.nsx.vmware.com
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- addressbindings
sideEffects: None
2 changes: 1 addition & 1 deletion build/yaml/webhook/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ metadata:
app.kubernetes.io/created-by: nsx-operator
app.kubernetes.io/part-of: nsx-operator
app.kubernetes.io/managed-by: kustomize
name: subnetset
name: vmware-system-nsx-operator-webhook-service
namespace: vmware-system-nsx
spec:
ports:
Expand Down
54 changes: 50 additions & 4 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"

"github.com/vmware-tanzu/nsx-operator/pkg/apis/legacy/v1alpha1"
crdv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1"
Expand Down Expand Up @@ -51,6 +52,7 @@ import (
"github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/nsxserviceaccount"
"github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc"
"github.com/vmware-tanzu/nsx-operator/pkg/nsx/util"
pkgutil "github.com/vmware-tanzu/nsx-operator/pkg/util"
)

var (
Expand Down Expand Up @@ -156,6 +158,16 @@ func StartIPAddressAllocationController(mgr ctrl.Manager, ipAddressAllocationSer
}

func startServiceController(mgr manager.Manager, nsxClient *nsx.Client) {
// Generate webhook certificates, and start refreshing webhook certificates periodically
if cf.CoeConfig.EnableVPCNetwork {
if err := pkgutil.GenerateWebhookCerts(); err != nil {
log.Error(err, "Failed to generate webhook certificates")
} else {
log.Info("Successfully generated webhook certificates")
}
go refreshCertPeriodically()
}

// Embed the common commonService to sub-services.
commonService := common.Service{
Client: mgr.GetClient(),
Expand Down Expand Up @@ -213,18 +225,26 @@ func startServiceController(mgr manager.Manager, nsxClient *nsx.Client) {
if err := subnet.StartSubnetController(mgr, subnetService, subnetPortService, vpcService); err != nil {
os.Exit(1)
}
enableWebhook := true
var hookServer webhook.Server
if _, err := os.Stat(config.WebhookCertDir); errors.Is(err, os.ErrNotExist) {
log.Error(err, "server cert not found, disabling webhook server", "cert", config.WebhookCertDir)
enableWebhook = false
} else {
hookServer = webhook.NewServer(webhook.Options{
Port: config.WebhookServerPort,
CertDir: config.WebhookCertDir,
})
if err := mgr.Add(hookServer); err != nil {
log.Error(err, "failed to add hook server")
os.Exit(1)
}
}
if err := subnetset.StartSubnetSetController(mgr, subnetService, subnetPortService, vpcService, enableWebhook); err != nil {
if err := subnetset.StartSubnetSetController(mgr, subnetService, subnetPortService, vpcService, hookServer); err != nil {
os.Exit(1)
}

node.StartNodeController(mgr, nodeService)
staticroutecontroller.StartStaticRouteController(mgr, staticRouteService)
subnetport.StartSubnetPortController(mgr, subnetPortService, subnetService, vpcService)
subnetport.StartSubnetPortController(mgr, subnetPortService, subnetService, vpcService, hookServer)
pod.StartPodController(mgr, subnetPortService, subnetService, vpcService, nodeService)
StartIPAddressAllocationController(mgr, ipAddressAllocationService, vpcService)
networkpolicycontroller.StartNetworkPolicyController(mgr, commonService, vpcService)
Expand All @@ -244,6 +264,15 @@ func electMaster(mgr manager.Manager, nsxClient *nsx.Client) {
log.Info("I'm trying to be elected as master")
<-mgr.Elected()
log.Info("I'm the master now")
// In HA mode, there can be a brief period where both the old and new leader
// operators are active simultaneously. After a time synchronization by NTP,
// the new operator may acquire the lease before the old operator recognizes
// it has lost the lease, leading to a potential race condition. To mitigate this,
// the new master operator is configured to wait for 15 seconds, which is
// slightly longer than the default Leader Election Renew Deadline (10 seconds),
// ensuring a smooth transition.
log.Info("waiting a 15-second delay to let the old instance know that it has lost its lease")
time.Sleep(15 * time.Second)
startServiceController(mgr, nsxClient)
}

Expand Down Expand Up @@ -346,3 +375,20 @@ func updateLicensePeriodically(nsxClient *nsx.Client, interval time.Duration) {
}
}
}

func refreshCertPeriodically() {
ticker := time.NewTicker(30 * 24 * time.Hour) // 30 days
defer ticker.Stop()

for {
select {
case <-ticker.C:
log.Info("Refreshing webhook certificates...")
if err := pkgutil.GenerateWebhookCerts(); err != nil {
log.Error(err, "Failed to refresh webhook certificates")
} else {
log.Info("Successfully refreshed webhook certificates")
}
}
}
}
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ replace (
github.com/vmware-tanzu/nsx-operator/pkg/apis => ./pkg/apis
github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1 => ./pkg/apis/vpc/v1alpha1
github.com/vmware-tanzu/nsx-operator/pkg/client => ./pkg/client
github.com/vmware/vsphere-automation-sdk-go/lib => github.com/yanjunz97/vsphere-automation-sdk-go/lib v0.0.0-20240823072631-de1833ffcf2a
github.com/vmware/vsphere-automation-sdk-go/runtime => github.com/yanjunz97/vsphere-automation-sdk-go/runtime v0.0.0-20240823072631-de1833ffcf2a
github.com/vmware/vsphere-automation-sdk-go/services/nsxt => github.com/yanjunz97/vsphere-automation-sdk-go/services/nsxt v0.0.0-20240823072631-de1833ffcf2a
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp => github.com/yanjunz97/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20240823072631-de1833ffcf2a
github.com/vmware/vsphere-automation-sdk-go/lib => github.com/TaoZou1/vsphere-automation-sdk-go/lib v0.0.0-20241021063737-f38b6d3b0dbf
github.com/vmware/vsphere-automation-sdk-go/runtime => github.com/TaoZou1/vsphere-automation-sdk-go/runtime v0.0.0-20241021063737-f38b6d3b0dbf
github.com/vmware/vsphere-automation-sdk-go/services/nsxt => github.com/TaoZou1/vsphere-automation-sdk-go/services/nsxt v0.0.0-20241021063737-f38b6d3b0dbf
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp => github.com/TaoZou1/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20241021063737-f38b6d3b0dbf
)

require (
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
github.com/TaoZou1/vsphere-automation-sdk-go/lib v0.0.0-20241021063737-f38b6d3b0dbf h1:CIgXOqJ8zhf5fZnb8dYEVjosjGCdPAlBEUkvCqjftuw=
github.com/TaoZou1/vsphere-automation-sdk-go/lib v0.0.0-20241021063737-f38b6d3b0dbf/go.mod h1:ADkX8BkdnvT1Kc9ZfqHaV4qzaaD+9L8Ok2+pxK4xoD8=
github.com/TaoZou1/vsphere-automation-sdk-go/runtime v0.0.0-20241021063737-f38b6d3b0dbf h1:a9gkpsZRX7VaW36p11diiiL8JWAj66IWk6kUU/WqtKQ=
github.com/TaoZou1/vsphere-automation-sdk-go/runtime v0.0.0-20241021063737-f38b6d3b0dbf/go.mod h1:DzLetYAmw1+vj7bqElRWEpuy40WYE/woL3alsymYa/c=
github.com/TaoZou1/vsphere-automation-sdk-go/services/nsxt v0.0.0-20241021063737-f38b6d3b0dbf h1:v0V/aeI0BQC2tqwJsc/kBiCWjDd9Fpj9AkbkSKuiXzE=
github.com/TaoZou1/vsphere-automation-sdk-go/services/nsxt v0.0.0-20241021063737-f38b6d3b0dbf/go.mod h1:NSjO9WqelbsTEDb3pVxpYYz4zjgX0XPp43dKNT4Y+9k=
github.com/TaoZou1/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20241021063737-f38b6d3b0dbf h1:SW+t9M1if2q1kOpthxTZ4Md3WNkyBpQuuxqsNjBA6AM=
github.com/TaoZou1/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20241021063737-f38b6d3b0dbf/go.mod h1:ugk9I4YM62SSAox57l5NAVBCRIkPQ1RNLb3URxyTADc=
github.com/a8m/tree v0.0.0-20210115125333-10a5fd5b637d/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
Expand Down Expand Up @@ -143,14 +151,6 @@ github.com/vmware-tanzu/vm-operator/api v1.8.2/go.mod h1:vauVboD3sQxP+pb28TnI9wf
github.com/vmware/govmomi v0.27.4 h1:5kY8TAkhB20lsjzrjE073eRb8+HixBI29PVMG5lxq6I=
github.com/vmware/govmomi v0.27.4/go.mod h1:daTuJEcQosNMXYJOeku0qdBJP9SOLLWB3Mqz8THtv6o=
github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk=
github.com/yanjunz97/vsphere-automation-sdk-go/lib v0.0.0-20240823072631-de1833ffcf2a h1:nF3PigKL+lN4ECHkgVJIZgLbpLrV6U6wkKHnIHOU9kA=
github.com/yanjunz97/vsphere-automation-sdk-go/lib v0.0.0-20240823072631-de1833ffcf2a/go.mod h1:ysW7/EqFugBY2TcbvlDeRGaYIoG7Cs0i4l4WsMI/RmQ=
github.com/yanjunz97/vsphere-automation-sdk-go/runtime v0.0.0-20240823072631-de1833ffcf2a h1:b08LCEgSR6GSsvQzx2fxVbEXSKRnaGcMUqKjlgwR6xM=
github.com/yanjunz97/vsphere-automation-sdk-go/runtime v0.0.0-20240823072631-de1833ffcf2a/go.mod h1:DzLetYAmw1+vj7bqElRWEpuy40WYE/woL3alsymYa/c=
github.com/yanjunz97/vsphere-automation-sdk-go/services/nsxt v0.0.0-20240823072631-de1833ffcf2a h1:XEgprSLuSKIxr7OPEzBWrlo39ra7pDaWFwAIjK0VV7s=
github.com/yanjunz97/vsphere-automation-sdk-go/services/nsxt v0.0.0-20240823072631-de1833ffcf2a/go.mod h1:aJtyfDKvGyuP1ieRHCLoYjo2XtNZ401XfS7lCd43Bqs=
github.com/yanjunz97/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20240823072631-de1833ffcf2a h1:4FmesihC1B7udmKl7B2giLydxibViMdyldSforV5qbU=
github.com/yanjunz97/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20240823072631-de1833ffcf2a/go.mod h1:FX8UiCgNEOxweA73VZsyKZvMLPFfc70GBc1d4dj0nXI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/vpc/v1alpha1/ipblocksinfo_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type IPBlocksInfo struct {
ExternalIPCIDRs []string `json:"externalIPCIDRs,omitempty"`
// PrivateTGWIPCIDRs is a list of CIDR strings. Each CIDR is a contiguous IP address
// spaces represented by network address and prefix length. The visibility of the
// IPBlocks is PrivateTWG. Only IPBlocks in default project will be included.
// IPBlocks is Private Transit Gateway. Only IPBlocks in default project will be included.
PrivateTGWIPCIDRs []string `json:"privateTGWIPCIDRs,omitempty"`
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/vpc/v1alpha1/subnet_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const (
)

// SubnetSpec defines the desired state of Subnet.
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.DHCPConfig) || has(self.DHCPConfig)", message="DHCPConfig is required once set"
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.ipv4SubnetSize) || has(self.ipv4SubnetSize)", message="ipv4SubnetSize is required once set"
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.accessMode) || has(self.accessMode)", message="accessMode is required once set"
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.ipAddresses) || has(self.ipAddresses)", message="ipAddresses is required once set"
type SubnetSpec struct {
// Size of Subnet based upon estimated workload count.
// +kubebuilder:validation:Maximum:=65536
Expand All @@ -32,6 +36,7 @@ type SubnetSpec struct {
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
IPAddresses []string `json:"ipAddresses,omitempty"`
// DHCPConfig DHCP configuration.
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"`
}

Expand Down
Loading

0 comments on commit 8bd34c1

Please sign in to comment.