From fdca797c7e8caffbcc5e8c2ce97057f05ef9350a Mon Sep 17 00:00:00 2001 From: Deng Yun Date: Tue, 18 Jun 2024 11:33:30 +0000 Subject: [PATCH 01/23] Add a PHONY target code-generator in Makefile Add a PHONY target code-generator to download code-generator locally, this will help calling "make generated" to automatically generate code. --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0924b3df6..643127c06 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,11 @@ KUSTOMIZE = $(shell pwd)/bin/kustomize kustomize: ## Download kustomize locally if necessary. $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7) -generated: +.PHONY: code-generator +code-generator: ## Download code-generator locally if necessary. + go mod download k8s.io/code-generator@v0.27.1 + +generated: code-generator ./hack/update-codegen.sh ENVTEST = $(shell pwd)/bin/setup-envtest From 447a35c5a1645164e610248167c401ffbecbd405 Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Thu, 20 Jun 2024 17:50:43 +0800 Subject: [PATCH 02/23] Add back caller to log Signed-off-by: Xie Zheng --- pkg/logger/logger.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index adb1bdd40..0554faf1e 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -65,7 +65,8 @@ func ZapLogger(cfDebug bool, cfLogLevel int) logr.Logger { zapcore.AddSync(zapcore.Lock(os.Stdout)), zapcore.Level(-1*logLevel), ) - zapLogger := zap.New(core) + zapLogger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) + defer zapLogger.Sync() return zapr.NewLogger(zapLogger) From eb2323c8e1919b136587042d52eedcc414996894 Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Thu, 20 Jun 2024 14:21:22 +0800 Subject: [PATCH 03/23] Refactor GC Extract common func GenericGarbageCollector; Define interface GarbageCollector and let every Reconcile implement it; In every controller, just call common.GcOnce(r) following reconcile; Use set.Difference method instead of iterating in GC; Trim redundancy in unit tests. Signed-off-by: Xie Zheng --- pkg/controllers/common/types.go | 6 ++ pkg/controllers/common/utils.go | 20 +++++ pkg/controllers/ippool/ippool_controller.go | 59 ++++++------- .../ippool/ippool_controller_test.go | 26 ++---- .../networkinfo/networkinfo_controller.go | 81 ++++++++---------- .../networkpolicy/networkpolicy_controller.go | 69 +++++++--------- .../nsxserviceaccount_controller.go | 54 ++++++------ .../nsxserviceaccount_controller_test.go | 9 +- pkg/controllers/pod/pod_controller.go | 65 ++++++--------- .../securitypolicy_controller.go | 68 +++++++-------- .../securitypolicy_controller_test.go | 25 ++---- .../staticroute/staticroute_controller.go | 82 +++++++++---------- .../staticroute_controller_test.go | 26 ++---- pkg/controllers/subnet/subnet_controller.go | 73 ++++++++--------- .../subnet/subnet_controller_test.go | 20 +---- .../subnetport/subnetport_controller.go | 66 +++++++-------- .../subnetport/subnetport_controller_test.go | 15 ++-- .../subnetset/subnetset_controller.go | 73 ++++++++--------- 18 files changed, 362 insertions(+), 475 deletions(-) diff --git a/pkg/controllers/common/types.go b/pkg/controllers/common/types.go index 02d78f409..e5c8a4392 100644 --- a/pkg/controllers/common/types.go +++ b/pkg/controllers/common/types.go @@ -1,6 +1,7 @@ package common import ( + "context" "time" ctrl "sigs.k8s.io/controller-runtime" @@ -41,3 +42,8 @@ const ( ReasonFailDelete = "FailDelete" ReasonFailUpdate = "FailUpdate" ) + +// GarbageCollector interface with collectGarbage method +type GarbageCollector interface { + CollectGarbage(ctx context.Context) +} diff --git a/pkg/controllers/common/utils.go b/pkg/controllers/common/utils.go index c394819a0..79a3898c6 100644 --- a/pkg/controllers/common/utils.go +++ b/pkg/controllers/common/utils.go @@ -6,6 +6,7 @@ import ( "fmt" "strings" "sync" + "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -141,3 +142,22 @@ func GetVirtualMachineNameForSubnetPort(subnetPort *v1alpha1.SubnetPort) (string func NumReconcile() int { return MaxConcurrentReconciles } + +func GenericGarbageCollector(cancel chan bool, timeout time.Duration, f func(ctx context.Context)) { + ctx := context.Background() + ticker := time.NewTicker(timeout) + defer ticker.Stop() + + for { + select { + case <-cancel: + return + case <-ticker.C: + f(ctx) + } + } +} + +func GcOnce(gc GarbageCollector, once *sync.Once) { + once.Do(func() { go GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, gc.CollectGarbage) }) +} diff --git a/pkg/controllers/ippool/ippool_controller.go b/pkg/controllers/ippool/ippool_controller.go index e17ff3e31..85e0c9722 100644 --- a/pkg/controllers/ippool/ippool_controller.go +++ b/pkg/controllers/ippool/ippool_controller.go @@ -8,7 +8,6 @@ import ( "fmt" "regexp" "sync" - "time" "github.com/pkg/errors" v1 "k8s.io/api/core/v1" @@ -117,7 +116,8 @@ func (r *IPPoolReconciler) setReadyStatusTrue(ctx *context.Context, ippool *v1al func (r *IPPoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.IPPoolGarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + obj := &v1alpha2.IPPool{} log.Info("reconciling ippool CR", "ippool", req.NamespacedName) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) @@ -267,44 +267,31 @@ func (r *IPPoolReconciler) Start(mgr ctrl.Manager) error { return nil } -// IPPoolGarbageCollector collect ippool which has been removed from crd. -// cancel is used to break the loop during UT -func (r *IPPoolReconciler) IPPoolGarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage implements the interface GarbageCollector method. +func (r *IPPoolReconciler) CollectGarbage(ctx context.Context) { log.Info("ippool garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxIPPoolSet := r.Service.ListIPPoolID() - if len(nsxIPPoolSet) == 0 { - continue - } - ipPoolList := &v1alpha2.IPPoolList{} - err := r.Client.List(ctx, ipPoolList) - if err != nil { - log.Error(err, "failed to list ip pool CR") - continue - } + nsxIPPoolSet := r.Service.ListIPPoolID() + if len(nsxIPPoolSet) == 0 { + return + } - CRIPPoolSet := sets.NewString() - for _, ipp := range ipPoolList.Items { - CRIPPoolSet.Insert(string(ipp.UID)) - } + ipPoolList := &v1alpha2.IPPoolList{} + if err := r.Client.List(ctx, ipPoolList); err != nil { + log.Error(err, "failed to list ippool CR") + return + } + CRIPPoolSet := sets.New[string]() + for _, ipa := range ipPoolList.Items { + CRIPPoolSet.Insert(string(ipa.UID)) + } - log.V(2).Info("ippool garbage collector", "nsxIPPoolSet", nsxIPPoolSet, "CRIPPoolSet", CRIPPoolSet) + log.V(2).Info("ippool garbage collector", "nsxIPPoolSet", nsxIPPoolSet, "CRIPPoolSet", CRIPPoolSet) - for elem := range nsxIPPoolSet { - if CRIPPoolSet.Has(elem) { - continue - } - log.Info("GC collected ip pool CR", "UID", elem) - err = r.Service.DeleteIPPool(types.UID(elem)) - if err != nil { - log.Error(err, "failed to delete ip pool CR", "UID", elem) - } + diffSet := nsxIPPoolSet.Difference(CRIPPoolSet) + for elem := range diffSet { + log.Info("GC collected ippool CR", "UID", elem) + if err := r.Service.DeleteIPPool(types.UID(elem)); err != nil { + log.Error(err, "failed to delete ippool CR", "UID", elem) } } } diff --git a/pkg/controllers/ippool/ippool_controller_test.go b/pkg/controllers/ippool/ippool_controller_test.go index e179adfef..b46a853b8 100644 --- a/pkg/controllers/ippool/ippool_controller_test.go +++ b/pkg/controllers/ippool/ippool_controller_test.go @@ -7,8 +7,8 @@ import ( "context" "errors" "reflect" + "sync" "testing" - "time" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -114,6 +114,11 @@ func TestIPPoolReconciler_Reconcile(t *testing.T) { ctx := context.Background() req := controllerruntime.Request{NamespacedName: types.NamespacedName{Namespace: "dummy", Name: "dummy"}} + // common.GcOnce do nothing + var once sync.Once + pat := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) + defer pat.Reset() + // not found errNotFound := errors.New("not found") k8sClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).Return(errNotFound) @@ -244,7 +249,6 @@ func TestReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPPool", func(_ *ippool.IPPoolService, UID interface{}) error { return nil }) - cancel := make(chan bool) defer patch.Reset() mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -263,11 +267,7 @@ func TestReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.IPPoolGarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -287,11 +287,7 @@ func TestReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.IPPoolGarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() @@ -304,11 +300,7 @@ func TestReconciler_GarbageCollector(t *testing.T) { return nil }) k8sClient.EXPECT().List(ctx, policyList).Return(nil).Times(0) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.IPPoolGarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) } func TestReconciler_Start(t *testing.T) { diff --git a/pkg/controllers/networkinfo/networkinfo_controller.go b/pkg/controllers/networkinfo/networkinfo_controller.go index 6640021ed..06e62de74 100644 --- a/pkg/controllers/networkinfo/networkinfo_controller.go +++ b/pkg/controllers/networkinfo/networkinfo_controller.go @@ -6,7 +6,6 @@ package networkinfo import ( "context" "sync" - "time" corev1 "k8s.io/api/core/v1" apimachineryruntime "k8s.io/apimachinery/pkg/runtime" @@ -44,7 +43,7 @@ type NetworkInfoReconciler struct { func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), commonservice.GCInterval) }) + common.GcOnce(r, &once) obj := &v1alpha1.NetworkInfo{} log.Info("reconciling NetworkInfo CR", "NetworkInfo", req.NamespacedName) @@ -212,59 +211,49 @@ func (r *NetworkInfoReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector logic for nsx-vpc is that: +// CollectGarbage logic for nsx-vpc is that: // 1. list all current existing namespace in kubernetes // 2. list all the nsx-vpc in vpcStore // 3. loop all the nsx-vpc to get its namespace, check if the namespace still exist // 4. if ns do not exist anymore, delete the nsx-vpc resource -func (r *NetworkInfoReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// it implements the interface GarbageCollector method. +func (r *NetworkInfoReconciler) CollectGarbage(ctx context.Context) { log.Info("VPC garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - // read all nsx-vpc from vpc store - nsxVPCList := r.Service.ListVPC() - if len(nsxVPCList) == 0 { - continue - } + // read all nsx-vpc from vpc store + nsxVPCList := r.Service.ListVPC() + if len(nsxVPCList) == 0 { + return + } - // read all namespaces from k8s - namespaces := &corev1.NamespaceList{} - err := r.Client.List(ctx, namespaces) - if err != nil { - log.Error(err, "failed to list k8s namespaces") - continue - } + // read all namespaces from k8s + namespaces := &corev1.NamespaceList{} + err := r.Client.List(ctx, namespaces) + if err != nil { + log.Error(err, "failed to list k8s namespaces") + return + } + nsSet := sets.NewString() + for _, ns := range namespaces.Items { + nsSet.Insert(ns.Name) + } - nsSet := sets.NewString() - for _, ns := range namespaces.Items { - nsSet.Insert(ns.Name) + for i := len(nsxVPCList) - 1; i >= 0; i-- { + nsxVPCNamespace := getNamespaceFromNSXVPC(&nsxVPCList[i]) + if nsSet.Has(nsxVPCNamespace) { + continue } - for _, elem := range nsxVPCList { - // for go lint Implicit memory aliasing in for loop - // this limitation is fixed after golang 1.22, should remove the temp var after upgrading to 1.22 - tempElem := elem - nsxVPCNamespace := getNamespaceFromNSXVPC(&tempElem) - if nsSet.Has(nsxVPCNamespace) { - continue - } - - log.V(1).Info("GC collected nsx VPC object", "ID", elem.Id, "Namespace", nsxVPCNamespace) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeNetworkInfo) - err = r.Service.DeleteVPC(*elem.Path) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeNetworkInfo) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeNetworkInfo) - if err := r.Service.DeleteIPBlockInVPC(elem); err != nil { - log.Error(err, "failed to delete private ip blocks for VPC", "VPC", *elem.DisplayName) - } - log.Info("deleted private ip blocks for VPC", "VPC", *elem.DisplayName) + elem := nsxVPCList[i] + log.Info("GC collected nsx VPC object", "ID", elem.Id, "Namespace", nsxVPCNamespace) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeNetworkInfo) + err = r.Service.DeleteVPC(*elem.Path) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeNetworkInfo) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeNetworkInfo) + if err := r.Service.DeleteIPBlockInVPC(elem); err != nil { + log.Error(err, "failed to delete private ip blocks for VPC", "VPC", *elem.DisplayName) } + log.Info("deleted private ip blocks for VPC", "VPC", *elem.DisplayName) } } } diff --git a/pkg/controllers/networkpolicy/networkpolicy_controller.go b/pkg/controllers/networkpolicy/networkpolicy_controller.go index ef9de805b..3e7eda8dc 100644 --- a/pkg/controllers/networkpolicy/networkpolicy_controller.go +++ b/pkg/controllers/networkpolicy/networkpolicy_controller.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "sync" - "time" v1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" @@ -70,7 +69,7 @@ func deleteSuccess(r *NetworkPolicyReconciler, _ *context.Context, o *networking func (r *NetworkPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) networkPolicy := &networkingv1.NetworkPolicy{} log.Info("reconciling networkpolicy", "networkpolicy", req.NamespacedName) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) @@ -147,46 +146,36 @@ func (r *NetworkPolicyReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector collect networkpolicy which has been removed from K8s. -// cancel is used to break the loop during UT -func (r *NetworkPolicyReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxPolicySet := r.Service.ListNetworkPolicyID() - if len(nsxPolicySet) == 0 { - continue - } - policyList := &networkingv1.NetworkPolicyList{} - err := r.Client.List(ctx, policyList) - if err != nil { - log.Error(err, "failed to list NetworkPolicy") - continue - } +// CollectGarbage collect networkpolicy which has been removed from K8s. +// it implements the interface GarbageCollector method. +func (r *NetworkPolicyReconciler) CollectGarbage(ctx context.Context) { + log.Info("networkpolicy garbage collector started") + nsxPolicySet := r.Service.ListNetworkPolicyID() + if len(nsxPolicySet) == 0 { + return + } + policyList := &networkingv1.NetworkPolicyList{} + err := r.Client.List(ctx, policyList) + if err != nil { + log.Error(err, "failed to list NetworkPolicy") + return + } - CRPolicySet := sets.NewString() - for _, policy := range policyList.Items { - CRPolicySet.Insert(r.Service.BuildNetworkPolicyAllowPolicyID(string(policy.UID))) - CRPolicySet.Insert(r.Service.BuildNetworkPolicyIsolationPolicyID(string(policy.UID))) - } + CRPolicySet := sets.New[string]() + for _, policy := range policyList.Items { + CRPolicySet.Insert(r.Service.BuildNetworkPolicyAllowPolicyID(string(policy.UID))) + CRPolicySet.Insert(r.Service.BuildNetworkPolicyIsolationPolicyID(string(policy.UID))) + } - for elem := range nsxPolicySet { - if CRPolicySet.Has(elem) { - continue - } - log.V(1).Info("GC collected NetworkPolicy", "ID", elem) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) - err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeNetworkPolicy) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) - } + diffSet := nsxPolicySet.Difference(CRPolicySet) + for elem := range diffSet { + log.V(1).Info("GC collected NetworkPolicy", "ID", elem) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) + err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeNetworkPolicy) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } } } diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go index c24abd1d3..ca14aa1e5 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "sync" - "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -39,6 +38,8 @@ var ( ResultRequeue = common.ResultRequeue ResultRequeueAfter5mins = common.ResultRequeueAfter5mins MetricResType = common.MetricResTypeNSXServiceAccount + count = uint16(0) + ca []byte once sync.Once ) @@ -68,7 +69,8 @@ type NSXServiceAccountReconciler struct { // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile func (r *NSXServiceAccountReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + obj := &nsxvmwarecomv1alpha1.NSXServiceAccount{} log.Info("reconciling CR", "nsxserviceaccount", req.NamespacedName) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) @@ -170,36 +172,26 @@ func (r *NSXServiceAccountReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector collect NSXServiceAccount which has been removed from crd. -// cancel is used to break the loop during UT -func (r *NSXServiceAccountReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - count := uint16(0) - ca := r.Service.NSXConfig.GetCACert() - log.Info("garbage collector started") - for { - nsxServiceAccountList := &nsxvmwarecomv1alpha1.NSXServiceAccountList{} - var gcSuccessCount, gcErrorCount uint32 - var err error - nsxServiceAccountUIDSet := r.Service.ListNSXServiceAccountRealization() - if len(nsxServiceAccountUIDSet) == 0 { - goto gcWait - } - err = r.Client.List(ctx, nsxServiceAccountList) - if err != nil { - log.Error(err, "failed to list NSXServiceAccount CR") - goto gcWait - } - gcSuccessCount, gcErrorCount = r.garbageCollector(nsxServiceAccountUIDSet, nsxServiceAccountList) - log.V(1).Info("gc collects NSXServiceAccount CR", "success", gcSuccessCount, "error", gcErrorCount) - count, ca = r.validateRealized(count, ca, nsxServiceAccountList) - gcWait: - select { - case <-cancel: - return - case <-time.After(timeout): - } +// CollectGarbage collect NSXServiceAccount which has been removed from crd. +// it implements the interface GarbageCollector method. +func (r *NSXServiceAccountReconciler) CollectGarbage(ctx context.Context) { + log.Info("nsx service account garbage collector started") + ca = r.Service.NSXConfig.GetCACert() + nsxServiceAccountList := &nsxvmwarecomv1alpha1.NSXServiceAccountList{} + var gcSuccessCount, gcErrorCount uint32 + var err error + nsxServiceAccountUIDSet := r.Service.ListNSXServiceAccountRealization() + if len(nsxServiceAccountUIDSet) == 0 { + return + } + err = r.Client.List(ctx, nsxServiceAccountList) + if err != nil { + log.Error(err, "failed to list NSXServiceAccount CR") + return } + gcSuccessCount, gcErrorCount = r.garbageCollector(nsxServiceAccountUIDSet, nsxServiceAccountList) + log.V(1).Info("gc collects NSXServiceAccount CR", "success", gcSuccessCount, "error", gcErrorCount) + count, ca = r.validateRealized(count, ca, nsxServiceAccountList) } func (r *NSXServiceAccountReconciler) validateRealized(count uint16, ca []byte, nsxServiceAccountList *nsxvmwarecomv1alpha1.NSXServiceAccountList) (uint16, []byte) { diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go index 8451e591a..73c4c30a6 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go @@ -513,7 +513,7 @@ func TestNSXServiceAccountReconciler_Reconcile(t *testing.T) { patches := tt.prepareFunc(t, r, ctx) defer patches.Reset() } - + var once sync.Once patches2 := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) defer patches2.Reset() @@ -594,17 +594,12 @@ func TestNSXServiceAccountReconciler_GarbageCollector(t *testing.T) { } r.Service.SetUpStore() ctx := context.TODO() - cancel := make(chan bool) if tt.prepareFunc != nil { patches := tt.prepareFunc(t, r, ctx) defer patches.Reset() } - go func() { - time.Sleep(50 * time.Millisecond) - cancel <- true - }() - r.GarbageCollector(cancel, 100*time.Millisecond) + r.CollectGarbage(ctx) }) } } diff --git a/pkg/controllers/pod/pod_controller.go b/pkg/controllers/pod/pod_controller.go index 90117a647..0e8b94ba3 100644 --- a/pkg/controllers/pod/pod_controller.go +++ b/pkg/controllers/pod/pod_controller.go @@ -9,7 +9,6 @@ import ( "os" "strings" "sync" - "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" @@ -52,7 +51,8 @@ type PodReconciler struct { func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + pod := &v1.Pod{} log.Info("reconciling pod", "pod", req.NamespacedName) @@ -198,45 +198,34 @@ func (r *PodReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector collect Pod which has been removed from crd. -// cancel is used to break the loop during UT -func (r *PodReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage collect Pod which has been removed from crd. +func (r *PodReconciler) CollectGarbage(ctx context.Context) { log.Info("pod garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForPod() - if len(nsxSubnetPortSet) == 0 { - continue - } - podList := &v1.PodList{} - err := r.Client.List(ctx, podList) - if err != nil { - log.Error(err, "failed to list Pod") - continue - } + nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForPod() + if len(nsxSubnetPortSet) == 0 { + return + } + podList := &v1.PodList{} + err := r.Client.List(ctx, podList) + if err != nil { + log.Error(err, "failed to list Pod") + return + } - PodSet := sets.NewString() - for _, pod := range podList.Items { - PodSet.Insert(string(pod.UID)) - } + PodSet := sets.New[string]() + for _, pod := range podList.Items { + PodSet.Insert(string(pod.UID)) + } - for elem := range nsxSubnetPortSet { - if PodSet.Has(elem) { - continue - } - log.V(1).Info("GC collected Pod", "UID", elem) - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypePod) - err = r.SubnetPortService.DeleteSubnetPort(types.UID(elem)) - if err != nil { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypePod) - } else { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypePod) - } + diffSet := nsxSubnetPortSet.Difference(PodSet) + for elem := range diffSet { + log.V(1).Info("GC collected Pod", "UID", elem) + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypePod) + err = r.SubnetPortService.DeleteSubnetPort(types.UID(elem)) + if err != nil { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypePod) + } else { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypePod) } } } diff --git a/pkg/controllers/securitypolicy/securitypolicy_controller.go b/pkg/controllers/securitypolicy/securitypolicy_controller.go index 5eb796348..4e9a8612e 100644 --- a/pkg/controllers/securitypolicy/securitypolicy_controller.go +++ b/pkg/controllers/securitypolicy/securitypolicy_controller.go @@ -10,7 +10,6 @@ import ( "os" "reflect" "sync" - "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -90,7 +89,8 @@ func deleteSuccess(r *SecurityPolicyReconciler, _ *context.Context, o *v1alpha1. func (r *SecurityPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + obj := &v1alpha1.SecurityPolicy{} log.Info("reconciling securitypolicy CR", "securitypolicy", req.NamespacedName) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) @@ -288,45 +288,35 @@ func (r *SecurityPolicyReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector collect securitypolicy which has been removed from k8s. -// cancel is used to break the loop during UT -func (r *SecurityPolicyReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxPolicySet := r.Service.ListSecurityPolicyID() - if len(nsxPolicySet) == 0 { - continue - } - policyList := &v1alpha1.SecurityPolicyList{} - err := r.Client.List(ctx, policyList) - if err != nil { - log.Error(err, "failed to list SecurityPolicy CR") - continue - } +// CollectGarbage collect securitypolicy which has been removed from k8s, +// it implements the interface GarbageCollector method. +func (r *SecurityPolicyReconciler) CollectGarbage(ctx context.Context) { + log.Info("security policy garbage collector started") + nsxPolicySet := r.Service.ListSecurityPolicyID() + if len(nsxPolicySet) == 0 { + return + } + policyList := &v1alpha1.SecurityPolicyList{} + err := r.Client.List(ctx, policyList) + if err != nil { + log.Error(err, "failed to list SecurityPolicy CR") + return + } - CRPolicySet := sets.NewString() - for _, policy := range policyList.Items { - CRPolicySet.Insert(string(policy.UID)) - } + CRPolicySet := sets.New[string]() + for _, policy := range policyList.Items { + CRPolicySet.Insert(string(policy.UID)) + } - for elem := range nsxPolicySet { - if CRPolicySet.Has(elem) { - continue - } - log.V(1).Info("GC collected SecurityPolicy CR", "UID", elem) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) - err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeSecurityPolicy) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) - } + diffSet := nsxPolicySet.Difference(CRPolicySet) + for elem := range diffSet { + log.V(1).Info("GC collected SecurityPolicy CR", "UID", elem) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) + err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeSecurityPolicy) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) } } } diff --git a/pkg/controllers/securitypolicy/securitypolicy_controller_test.go b/pkg/controllers/securitypolicy/securitypolicy_controller_test.go index a1dde2325..3b217f05c 100644 --- a/pkg/controllers/securitypolicy/securitypolicy_controller_test.go +++ b/pkg/controllers/securitypolicy/securitypolicy_controller_test.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "reflect" + "sync" "testing" "time" @@ -158,6 +159,11 @@ func TestSecurityPolicyReconciler_Reconcile(t *testing.T) { ctx := context.Background() req := controllerruntime.Request{NamespacedName: types.NamespacedName{Namespace: "dummy", Name: "dummy"}} + // common.GcOnce do nothing + var once sync.Once + pat := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) + defer pat.Reset() + // not found errNotFound := errors.New("not found") k8sClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).Return(errNotFound) @@ -244,7 +250,6 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteSecurityPolicy", func(_ *securitypolicy.SecurityPolicyService, UID interface{}, isVpcCleanup bool) error { return nil }) - cancel := make(chan bool) defer patch.Reset() mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -263,11 +268,7 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -287,11 +288,7 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() @@ -304,11 +301,7 @@ func TestSecurityPolicyReconciler_GarbageCollector(t *testing.T) { return nil }) k8sClient.EXPECT().List(ctx, policyList).Return(nil).Times(0) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) } func TestSecurityPolicyReconciler_Start(t *testing.T) { diff --git a/pkg/controllers/staticroute/staticroute_controller.go b/pkg/controllers/staticroute/staticroute_controller.go index a0d7c554d..c358f0160 100644 --- a/pkg/controllers/staticroute/staticroute_controller.go +++ b/pkg/controllers/staticroute/staticroute_controller.go @@ -10,7 +10,6 @@ import ( "reflect" "strings" "sync" - "time" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -77,7 +76,8 @@ func deleteSuccess(r *StaticRouteReconciler, _ *context.Context, o *v1alpha1.Sta func (r *StaticRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), commonservice.GCInterval) }) + common.GcOnce(r, &once) + obj := &v1alpha1.StaticRoute{} log.Info("reconciling staticroute CR", "staticroute", req.NamespacedName) metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, common.MetricResTypeStaticRoute) @@ -225,54 +225,46 @@ func (r *StaticRouteReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector collect staticroute which has been removed from crd. -// cancel is used to break the loop during UT -func (r *StaticRouteReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() - log.Info("garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxStaticRouteList := r.Service.ListStaticRoute() - if len(nsxStaticRouteList) == 0 { - continue - } +// CollectGarbage collect staticroute which has been removed from crd. +// it implements the interface GarbageCollector method. +func (r *StaticRouteReconciler) CollectGarbage(ctx context.Context) { + log.Info("static route garbage collector started") + nsxStaticRouteList := r.Service.ListStaticRoute() + if len(nsxStaticRouteList) == 0 { + return + } - crdStaticRouteList := &v1alpha1.StaticRouteList{} - err := r.Client.List(ctx, crdStaticRouteList) - if err != nil { - log.Error(err, "failed to list static route CR") + crdStaticRouteList := &v1alpha1.StaticRouteList{} + err := r.Client.List(ctx, crdStaticRouteList) + if err != nil { + log.Error(err, "failed to list static route CR") + return + } + + crdStaticRouteSet := sets.NewString() + for _, sr := range crdStaticRouteList.Items { + crdStaticRouteSet.Insert(string(sr.UID)) + } + + for _, e := range nsxStaticRouteList { + elem := e + UID := r.Service.GetUID(elem) + if UID == nil { continue } - - crdStaticRouteSet := sets.NewString() - for _, sr := range crdStaticRouteList.Items { - crdStaticRouteSet.Insert(string(sr.UID)) + if crdStaticRouteSet.Has(*UID) { + continue } - for _, e := range nsxStaticRouteList { - elem := e - UID := r.Service.GetUID(elem) - if UID == nil { - continue - } - if crdStaticRouteSet.Has(*UID) { - continue - } - - log.V(1).Info("GC collected StaticRoute CR", "UID", elem) - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeStaticRoute) - // get orgId, projectId, staticrouteId from path "/orgs//projects//vpcs//static-routes/" - path := strings.Split(*elem.Path, "/") - err = r.Service.DeleteStaticRouteByPath(path[2], path[4], path[6], *elem.Id) - if err != nil { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeStaticRoute) - } else { - metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeStaticRoute) - } + log.V(1).Info("GC collected StaticRoute CR", "UID", elem) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeStaticRoute) + // get orgId, projectId, staticrouteId from path "/orgs//projects//vpcs//static-routes/" + path := strings.Split(*elem.Path, "/") + err = r.Service.DeleteStaticRouteByPath(path[2], path[4], path[6], *elem.Id) + if err != nil { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeStaticRoute) + } else { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeStaticRoute) } } } diff --git a/pkg/controllers/staticroute/staticroute_controller_test.go b/pkg/controllers/staticroute/staticroute_controller_test.go index 1b58f70a9..925cfc46e 100644 --- a/pkg/controllers/staticroute/staticroute_controller_test.go +++ b/pkg/controllers/staticroute/staticroute_controller_test.go @@ -7,8 +7,8 @@ import ( "context" "errors" "reflect" + "sync" "testing" - "time" gomonkey "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -176,6 +176,11 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { ctx := context.Background() req := controllerruntime.Request{NamespacedName: types.NamespacedName{Namespace: "dummy", Name: "dummy"}} + // common.GcOnce do nothing + var once sync.Once + pat := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) + defer pat.Reset() + // not found errNotFound := errors.New("not found") k8sClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).Return(errNotFound) @@ -299,7 +304,6 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRouteByPath", func(_ *staticroute.StaticRouteService, orgId string, projectId string, vpcId string, uid string) error { return nil }) - cancel := make(chan bool) defer patch.Reset() mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -318,11 +322,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -344,11 +344,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() @@ -360,11 +356,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { return nil }) k8sClient.EXPECT().List(ctx, srList).Return(nil).Times(0) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) } func TestStaticRouteReconciler_Start(t *testing.T) { diff --git a/pkg/controllers/subnet/subnet_controller.go b/pkg/controllers/subnet/subnet_controller.go index 3308718a0..8ff9d641d 100644 --- a/pkg/controllers/subnet/subnet_controller.go +++ b/pkg/controllers/subnet/subnet_controller.go @@ -6,7 +6,6 @@ import ( "fmt" "reflect" "sync" - "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" @@ -54,7 +53,8 @@ type SubnetReconciler struct { func (r *SubnetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + obj := &v1alpha1.Subnet{} log.Info("reconciling subnet CR", "subnet", req.NamespacedName) metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerSyncTotal, MetricResTypeSubnet) @@ -310,48 +310,41 @@ func (r *SubnetReconciler) Start(mgr ctrl.Manager) error { return nil } -func (r *SubnetReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage implements the interface GarbageCollector method. +func (r *SubnetReconciler) CollectGarbage(ctx context.Context) { log.Info("subnet garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - crdSubnetList := &v1alpha1.SubnetList{} - err := r.Client.List(ctx, crdSubnetList) - if err != nil { - log.Error(err, "failed to list subnet CR") - continue - } - var nsxSubnetList []*model.VpcSubnet - for _, subnet := range crdSubnetList.Items { - nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnet(string(subnet.UID))...) - } - if len(nsxSubnetList) == 0 { - continue - } + crdSubnetList := &v1alpha1.SubnetList{} + err := r.Client.List(ctx, crdSubnetList) + if err != nil { + log.Error(err, "failed to list subnet CR") + return + } + var nsxSubnetList []*model.VpcSubnet + for _, subnet := range crdSubnetList.Items { + nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnet(string(subnet.UID))...) + } + if len(nsxSubnetList) == 0 { + return + } - crdSubnetIDs := sets.NewString() - for _, sr := range crdSubnetList.Items { - crdSubnetIDs.Insert(string(sr.UID)) - } + crdSubnetIDs := sets.NewString() + for _, sr := range crdSubnetList.Items { + crdSubnetIDs.Insert(string(sr.UID)) + } - for _, elem := range nsxSubnetList { - uid := util.FindTag(elem.Tags, servicecommon.TagScopeSubnetCRUID) - if crdSubnetIDs.Has(uid) { - continue - } + for _, elem := range nsxSubnetList { + uid := util.FindTag(elem.Tags, servicecommon.TagScopeSubnetCRUID) + if crdSubnetIDs.Has(uid) { + continue + } - log.Info("GC collected Subnet CR", "UID", elem) - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeSubnet) - err = r.SubnetService.DeleteSubnet(*elem) - if err != nil { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeSubnet) - } else { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeSubnet) - } + log.Info("GC collected Subnet CR", "UID", elem) + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeSubnet) + err = r.SubnetService.DeleteSubnet(*elem) + if err != nil { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, common.MetricResTypeSubnet) + } else { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, common.MetricResTypeSubnet) } } } diff --git a/pkg/controllers/subnet/subnet_controller_test.go b/pkg/controllers/subnet/subnet_controller_test.go index 28c9d6062..5e118afa1 100644 --- a/pkg/controllers/subnet/subnet_controller_test.go +++ b/pkg/controllers/subnet/subnet_controller_test.go @@ -4,7 +4,6 @@ import ( "context" "reflect" "testing" - "time" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -45,7 +44,6 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "DeleteSubnet", func(_ *subnet.SubnetService, subnet model.VpcSubnet) error { return nil }) - cancel := make(chan bool) mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) @@ -64,11 +62,7 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has same item as k8s cache patch.Reset() @@ -90,11 +84,7 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) // local store has no item patch.Reset() @@ -106,10 +96,6 @@ func TestSubnetReconciler_GarbageCollector(t *testing.T) { return nil }) k8sClient.EXPECT().List(ctx, srList).Return(nil).Times(1) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(ctx) patch.Reset() } diff --git a/pkg/controllers/subnetport/subnetport_controller.go b/pkg/controllers/subnetport/subnetport_controller.go index 6c4998dd7..73f68adb5 100644 --- a/pkg/controllers/subnetport/subnetport_controller.go +++ b/pkg/controllers/subnetport/subnetport_controller.go @@ -11,7 +11,6 @@ import ( "reflect" "strings" "sync" - "time" vmv1alpha1 "github.com/vmware-tanzu/vm-operator/api/v1alpha1" v1 "k8s.io/api/core/v1" @@ -63,7 +62,8 @@ type SubnetPortReconciler struct { // +kubebuilder:rbac:groups=nsx.vmware.com,resources=subnetports/finalizers,verbs=update func (r *SubnetPortReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + subnetPort := &v1alpha1.SubnetPort{} log.Info("reconciling subnetport CR", "subnetport", req.NamespacedName) @@ -237,45 +237,35 @@ func (r *SubnetPortReconciler) Start(mgr ctrl.Manager) error { return nil } -// GarbageCollector collect SubnetPort which has been removed from crd. -// cancel is used to break the loop during UT -func (r *SubnetPortReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage collect SubnetPort which has been removed from crd. +// it implements the interface GarbageCollector method. +func (r *SubnetPortReconciler) CollectGarbage(ctx context.Context) { log.Info("subnetport garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } - nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForCR() - if len(nsxSubnetPortSet) == 0 { - continue - } - subnetPortList := &v1alpha1.SubnetPortList{} - err := r.Client.List(ctx, subnetPortList) - if err != nil { - log.Error(err, "failed to list SubnetPort CR") - continue - } + nsxSubnetPortSet := r.SubnetPortService.ListNSXSubnetPortIDForCR() + if len(nsxSubnetPortSet) == 0 { + return + } + subnetPortList := &v1alpha1.SubnetPortList{} + err := r.Client.List(ctx, subnetPortList) + if err != nil { + log.Error(err, "failed to list SubnetPort CR") + return + } - CRSubnetPortSet := sets.NewString() - for _, subnetPort := range subnetPortList.Items { - CRSubnetPortSet.Insert(string(subnetPort.UID)) - } + CRSubnetPortSet := sets.New[string]() + for _, subnetPort := range subnetPortList.Items { + CRSubnetPortSet.Insert(string(subnetPort.UID)) + } - for elem := range nsxSubnetPortSet { - if CRSubnetPortSet.Has(elem) { - continue - } - log.V(1).Info("GC collected SubnetPort CR", "UID", elem) - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnetPort) - err = r.SubnetPortService.DeleteSubnetPort(types.UID(elem)) - if err != nil { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetPort) - } else { - metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetPort) - } + diffSet := nsxSubnetPortSet.Difference(CRSubnetPortSet) + for elem := range diffSet { + log.V(1).Info("GC collected SubnetPort CR", "UID", elem) + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteTotal, MetricResTypeSubnetPort) + err = r.SubnetPortService.DeleteSubnetPort(types.UID(elem)) + if err != nil { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetPort) + } else { + metrics.CounterInc(r.SubnetPortService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetPort) } } } diff --git a/pkg/controllers/subnetport/subnetport_controller_test.go b/pkg/controllers/subnetport/subnetport_controller_test.go index 122b4174a..9af96e523 100644 --- a/pkg/controllers/subnetport/subnetport_controller_test.go +++ b/pkg/controllers/subnetport/subnetport_controller_test.go @@ -3,8 +3,9 @@ package subnetport import ( "context" "errors" + "reflect" + "sync" "testing" - "time" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" @@ -78,6 +79,11 @@ func TestSubnetPortReconciler_Reconcile(t *testing.T) { }) defer patchesGetSubnetByPath.Reset() + // common.GcOnce do nothing + var once sync.Once + pat := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) + defer pat.Reset() + // not found errNotFound := errors.New("not found") k8sClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).Return(errNotFound) @@ -292,7 +298,6 @@ func TestSubnetPortReconciler_GarbageCollector(t *testing.T) { return nil }) defer patchesDeleteSubnetPort.Reset() - cancel := make(chan bool) mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) r := &SubnetPortReconciler{ @@ -308,9 +313,5 @@ func TestSubnetPortReconciler_GarbageCollector(t *testing.T) { a.Items[0].UID = "1234" return nil }) - go func() { - time.Sleep(1 * time.Second) - cancel <- true - }() - r.GarbageCollector(cancel, time.Second) + r.CollectGarbage(context.Background()) } diff --git a/pkg/controllers/subnetset/subnetset_controller.go b/pkg/controllers/subnetset/subnetset_controller.go index a2feed64c..b50fa42b6 100644 --- a/pkg/controllers/subnetset/subnetset_controller.go +++ b/pkg/controllers/subnetset/subnetset_controller.go @@ -6,7 +6,6 @@ import ( "fmt" "reflect" "sync" - "time" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" v1 "k8s.io/api/core/v1" @@ -52,7 +51,8 @@ type SubnetSetReconciler struct { func (r *SubnetSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Use once.Do to ensure gc is called only once - once.Do(func() { go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) }) + common.GcOnce(r, &once) + obj := &v1alpha1.SubnetSet{} log.Info("reconciling subnetset CR", "subnetset", req.NamespacedName) metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerSyncTotal, MetricResTypeSubnetSet) @@ -240,50 +240,41 @@ func (r *SubnetSetReconciler) setupWithManager(mgr ctrl.Manager) error { Complete(r) } -// GarbageCollector collect Subnet which there is no port attached on it. -// cancel is used to break the loop during UT -func (r *SubnetSetReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { - ctx := context.Background() +// CollectGarbage collect Subnet which there is no port attached on it. +// it implements the interface GarbageCollector method. +func (r *SubnetSetReconciler) CollectGarbage(ctx context.Context) { log.Info("subnetset garbage collector started") - for { - select { - case <-cancel: - return - case <-time.After(timeout): - } + subnetSetList := &v1alpha1.SubnetSetList{} + err := r.Client.List(ctx, subnetSetList) + if err != nil { + log.Error(err, "failed to list SubnetSet CR") + return + } + var nsxSubnetList []*model.VpcSubnet + for _, subnetSet := range subnetSetList.Items { + nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnetSet(string(subnetSet.UID))...) + } + if len(nsxSubnetList) == 0 { + return + } - subnetSetList := &v1alpha1.SubnetSetList{} - err := r.Client.List(ctx, subnetSetList) - if err != nil { - log.Error(err, "failed to list SubnetSet CR") - continue - } - var nsxSubnetList []*model.VpcSubnet - for _, subnetSet := range subnetSetList.Items { - nsxSubnetList = append(nsxSubnetList, r.SubnetService.ListSubnetCreatedBySubnetSet(string(subnetSet.UID))...) + subnetSetIDs := sets.New[string]() + for _, subnetSet := range subnetSetList.Items { + if err := r.DeleteSubnetForSubnetSet(subnetSet, true); err != nil { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) + } else { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) } - if len(nsxSubnetList) == 0 { + subnetSetIDs.Insert(string(subnetSet.UID)) + } + for _, subnet := range nsxSubnetList { + if !r.SubnetService.IsOrphanSubnet(*subnet, subnetSetIDs) { continue } - - subnetSetIDs := sets.New[string]() - for _, subnetSet := range subnetSetList.Items { - if err := r.DeleteSubnetForSubnetSet(subnetSet, true); err != nil { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) - } else { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) - } - subnetSetIDs.Insert(string(subnetSet.UID)) - } - for _, subnet := range nsxSubnetList { - if !r.SubnetService.IsOrphanSubnet(*subnet, subnetSetIDs) { - continue - } - if err := r.SubnetService.DeleteSubnet(*subnet); err != nil { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) - } else { - metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) - } + if err := r.SubnetService.DeleteSubnet(*subnet); err != nil { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResTypeSubnetSet) + } else { + metrics.CounterInc(r.SubnetService.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResTypeSubnetSet) } } } From e783972a072bb89edf60721b118b52fa50aa9441 Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Wed, 15 May 2024 16:42:06 +0800 Subject: [PATCH 04/23] Add networkinfo e2e testcase Signed-off-by: Xie Zheng --- test/e2e/framework.go | 61 ++++- .../customize_networkconfig_updated.yaml | 20 ++ test/e2e/manifest/testVPC/shared_ns.yaml | 17 ++ test/e2e/manifest/testVPC/update_ns.yaml | 8 + test/e2e/nsx_networkinfo_test.go | 229 ++++++++++++++++++ test/e2e/nsx_vpc_test.go | 149 ------------ 6 files changed, 324 insertions(+), 160 deletions(-) create mode 100644 test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml create mode 100644 test/e2e/manifest/testVPC/shared_ns.yaml create mode 100644 test/e2e/manifest/testVPC/update_ns.yaml create mode 100644 test/e2e/nsx_networkinfo_test.go delete mode 100644 test/e2e/nsx_vpc_test.go diff --git a/test/e2e/framework.go b/test/e2e/framework.go index 0dcb4ed26..0111303f9 100644 --- a/test/e2e/framework.go +++ b/test/e2e/framework.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "net" + "net/url" "os/exec" "regexp" "strings" @@ -26,9 +27,8 @@ import ( ) const ( - defaultTimeout = 200 * time.Second - verifyNoneExistTimeout = 15 * time.Second - crdVersion = "v1alpha1" + defaultTimeout = 200 * time.Second + PolicyAPI = "policy/api/v1" ) type Status int @@ -340,22 +340,21 @@ func (data *TestData) waitForCRReadyOrDeleted(timeout time.Duration, cr string, return nil } -func (data *TestData) getCRProperties(timeout time.Duration, crType, crName, namespace, key string) (string, error) { +func (data *TestData) getCRPropertiesByJson(timeout time.Duration, crType, crName, namespace, key string) (string, error) { value := "" err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, timeout, false, func(ctx context.Context) (bool, error) { - cmd := fmt.Sprintf("kubectl get %s %s -n %s -o yaml | grep %s", crType, crName, namespace, key) + cmd := fmt.Sprintf("kubectl get %s %s -n %s -o json | jq '%s'", crType, crName, namespace, key) log.Printf("%s", cmd) rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, cmd) if err != nil || rc != 0 { return false, fmt.Errorf("error when running the following command `%s` on master Node: %v, %s", cmd, err, stdout) } else { - parts := strings.Split(stdout, ":") - if len(parts) != 2 { - return false, fmt.Errorf("failed to read attribute from output %s", stdout) - } else { - value = parts[1] - return true, nil + // check if 'null' in stdout + if strings.Contains(stdout, "null") { + return false, nil } + value = stdout + return true, nil } }) if err != nil { @@ -370,6 +369,10 @@ func (data *TestData) getCRResource(timeout time.Duration, cr string, namespace crs := map[string]string{} err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, timeout, false, func(ctx context.Context) (bool, error) { cmd := fmt.Sprintf("kubectl get %s -n %s", cr, namespace) + // check if name is nil + if cr == "namespaces" { + cmd = fmt.Sprintf("kubectl get %s %s", cr, namespace) + } log.Printf("%s", cmd) rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, cmd) if err != nil || rc != 0 { @@ -388,6 +391,9 @@ func (data *TestData) getCRResource(timeout time.Duration, cr string, namespace continue } uid_cmd := fmt.Sprintf("kubectl get %s %s -n %s -o yaml | grep uid", cr, parts[0], namespace) + if cr == "namespaces" { + uid_cmd = fmt.Sprintf("kubectl get %s %s -o yaml | grep uid", cr, parts[0]) + } log.Printf("trying to get uid for cr: %s", uid_cmd) rc, stdout, _, err := RunCommandOnNode(clusterInfo.masterNodeName, uid_cmd) if err != nil || rc != 0 { @@ -724,3 +730,36 @@ func (data *TestData) waitForResourceExistById(namespace string, resourceType st func (data *TestData) waitForResourceExistOrNot(namespace string, resourceType string, resourceName string, shouldExist bool) error { return data.waitForResourceExist(namespace, resourceType, "display_name", resourceName, shouldExist) } + +func (data *TestData) waitForResourceExistByPath(pathPolicy string, shouldExist bool) error { + err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, defaultTimeout, false, func(ctx context.Context) (bool, error) { + exist := true + + fullURL := PolicyAPI + pathPolicy + fullURL = strings.ReplaceAll(fullURL, "\"", "") + fullURL = strings.ReplaceAll(fullURL, "\n", "") + fullURL = strings.ReplaceAll(fullURL, "\r", "") + _, err := url.Parse(fullURL) + if err != nil { + fmt.Println("Invalid URL:", err) + return false, err + } + + resp, err := testData.nsxClient.Client.Cluster.HttpGet(fullURL) + if err != nil { + if !shouldExist { + return true, nil + } + return false, err + } + id, ok := resp["id"].(string) + if !ok || id == "" { + exist = false + } + if exist != shouldExist { + return false, nil + } + return true, nil + }) + return err +} diff --git a/test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml b/test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml new file mode 100644 index 000000000..a718cd518 --- /dev/null +++ b/test/e2e/manifest/testVPC/customize_networkconfig_updated.yaml @@ -0,0 +1,20 @@ +# This file is used in testing customized VPC case, +# it support customer to define its own VPC network config. +apiVersion: nsx.vmware.com/v1alpha1 +kind: VPCNetworkConfiguration +metadata: + name: selfdefinedconfig +spec: + defaultGatewayPath: /infra/tier-0s/PLR + # nsx-operator-ci would replace '{edge-cluster-id}' with real edge-cluster-id of testbed + edgeClusterPath: /infra/sites/default/enforcement-points/default/edge-clusters/{edge-cluster-id} + defaultIPv4SubnetSize: 26 + nsxtProject: /orgs/default/projects/nsx_operator_e2e_test + externalIPv4Blocks: + - /infra/ip-blocks/e2e_test_external_ip_blk + privateIPv4CIDRs: + - 172.29.0.0/16 + - 172.39.0.0/16 + - 172.49.0.0/16 + defaultSubnetAccessMode: Public + \ No newline at end of file diff --git a/test/e2e/manifest/testVPC/shared_ns.yaml b/test/e2e/manifest/testVPC/shared_ns.yaml new file mode 100644 index 000000000..c653e0acd --- /dev/null +++ b/test/e2e/manifest/testVPC/shared_ns.yaml @@ -0,0 +1,17 @@ +# This file is used in testing shared VPC case, +# it create a namespace with customized network config for VPC. +apiVersion: v1 +kind: Namespace +metadata: + annotations: + nsx.vmware.com/vpc_network_config: selfdefinedconfig + name: shared-vpc-ns-0 + +--- +apiVersion: v1 +kind: Namespace +metadata: + annotations: + nsx.vmware.com/vpc_network_config: selfdefinedconfig + nsx.vmware.com/shared_vpc_namespace: shared-vpc-ns-0 + name: shared-vpc-ns-1 diff --git a/test/e2e/manifest/testVPC/update_ns.yaml b/test/e2e/manifest/testVPC/update_ns.yaml new file mode 100644 index 000000000..fe2bccd36 --- /dev/null +++ b/test/e2e/manifest/testVPC/update_ns.yaml @@ -0,0 +1,8 @@ +# This file is used in testing shared VPC case, +# it create a namespace with customized network config for VPC. +apiVersion: v1 +kind: Namespace +metadata: + annotations: + nsx.vmware.com/vpc_network_config: selfdefinedconfig + name: update-ns \ No newline at end of file diff --git a/test/e2e/nsx_networkinfo_test.go b/test/e2e/nsx_networkinfo_test.go new file mode 100644 index 000000000..1d242b56d --- /dev/null +++ b/test/e2e/nsx_networkinfo_test.go @@ -0,0 +1,229 @@ +package e2e + +import ( + "log" + "path/filepath" + "strings" + "testing" +) + +const ( + NetworkInfoCRType = "networkinfoes" + NSCRType = "namespaces" + PrivateIPBlockNSXType = "IpAddressBlock" + + InfraVPCNamespace = "kube-system" + SharedInfraVPCNamespace = "kube-public" + + DefaultPrivateCIDR1 = "172.28.0.0" + DefaultPrivateCIDR2 = "172.38.0.0" + InfraPrivateCIDR1 = "172.27.0.0" + InfraPrivateCIDR2 = "172.37.0.0" + CustomizedPrivateCIDR1 = "172.29.0.0" + CustomizedPrivateCIDR2 = "172.39.0.0" + CustomizedPrivateCIDR3 = "172.39.0.0" +) + +func verifyCRCreated(t *testing.T, crtype string, ns string, expect int) (string, string) { + // there should be one networkinfo created + resources, err := testData.getCRResource(defaultTimeout, crtype, ns) + // only one networkinfo should be created under ns using default network config + if len(resources) != expect { + log.Printf("NetworkInfo list %s size not the same as expected %d", resources, expect) + panic("NetworkInfo CR creation verify failed") + } + assertNil(t, err) + + cr_name, cr_uid := "", "" + // waiting for CR to be ready + for k, v := range resources { + cr_name = k + cr_uid = strings.TrimSpace(v) + } + + return cr_name, cr_uid +} + +func verifyCRDeleted(t *testing.T, crtype string, ns string) { + res, _ := testData.getCRResource(defaultTimeout, crtype, ns) + assertTrue(t, len(res) == 0, "NetworkInfo CR %s should be deleted", crtype) +} + +func verifyPrivateIPBlockCreated(t *testing.T, ns, id string) { + err := testData.waitForResourceExistById(ns, PrivateIPBlockNSXType, id, true) + assertNil(t, err) +} + +func verifyPrivateIPBlockDeleted(t *testing.T, ns, id string) { + err := testData.waitForResourceExistById(ns, PrivateIPBlockNSXType, id, false) + assertNil(t, err) +} + +// Test Customized NetworkInfo +func TestCustomizedNetworkInfo(t *testing.T) { + // Create customized networkconfig + ncPath, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig.yaml") + _ = applyYAML(ncPath, "") + nsPath, _ := filepath.Abs("./manifest/testVPC/customize_ns.yaml") + _ = applyYAML(nsPath, "") + + defer deleteYAML(nsPath, "") + defer deleteYAML(ncPath, "") + + ns := "customized-ns" + + networkinfo_name, _ := verifyCRCreated(t, NetworkInfoCRType, ns, 1) + _, ns_uid := verifyCRCreated(t, NSCRType, ns, 1) + + vpcPath, _ := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].vpcPath") + err := testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) + + //verify private ipblocks created for vpc + p_ipb_id1 := ns_uid + "_" + CustomizedPrivateCIDR1 + p_ipb_id2 := ns_uid + "_" + CustomizedPrivateCIDR2 + + verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) + verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) +} + +// Test Infra NetworkInfo +func TestInfraNetworkInfo(t *testing.T) { + // Check namespace cr existence + _, ns_uid := verifyCRCreated(t, NSCRType, InfraVPCNamespace, 1) + // Check networkinfo cr existence + networkinfo_name, _ := verifyCRCreated(t, NetworkInfoCRType, InfraVPCNamespace, 1) + + vpcPath, _ := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, InfraVPCNamespace, ".vpcs[0].vpcPath") + err := testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) + + //verify private ipblocks created for vpc + p_ipb_id1 := ns_uid + "_" + InfraPrivateCIDR1 + p_ipb_id2 := ns_uid + "_" + InfraPrivateCIDR2 + + verifyPrivateIPBlockCreated(t, InfraVPCNamespace, p_ipb_id1) + verifyPrivateIPBlockCreated(t, InfraVPCNamespace, p_ipb_id2) + + // kube-public vpcpath should be the same as kube-system vpcpath + networkinfo_name = SharedInfraVPCNamespace + vpcPath2, err := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, SharedInfraVPCNamespace, + ".vpcs[0].vpcPath") + assertNil(t, err) + assertTrue(t, vpcPath == vpcPath2, "vpcPath %s should be the same as vpcPath2 %s", vpcPath, vpcPath2) +} + +// Test Default NetworkInfo +func TestDefaultNetworkInfo(t *testing.T) { + // If no annotation on namespace, then NetworkInfo will use default network config to create vpc under each ns + ns := "networkinfo-default-1" + setupTest(t, ns) + defer teardownTest(t, ns, defaultTimeout) + + // Check namespace cr existence + _, ns_uid := verifyCRCreated(t, NSCRType, ns, 1) + // Check networkinfo cr existence + networkinfo_name, _ := verifyCRCreated(t, NetworkInfoCRType, ns, 1) + + vpcPath, _ := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].vpcPath") + err := testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) + + //verify private ipblocks created for vpc, id is nsuid + cidr + p_ipb_id1 := ns_uid + "_" + DefaultPrivateCIDR1 + p_ipb_id2 := ns_uid + "_" + DefaultPrivateCIDR2 + + verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) + verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) + + // delete namespace and check all resources are deleted + err = testData.deleteNamespace(ns, defaultTimeout) + assertNil(t, err) + verifyCRDeleted(t, NetworkInfoCRType, ns) + verifyCRDeleted(t, NSCRType, ns) + err = testData.waitForResourceExistByPath(vpcPath, false) + assertNil(t, err) + verifyPrivateIPBlockDeleted(t, ns, p_ipb_id1) + verifyPrivateIPBlockDeleted(t, ns, p_ipb_id2) +} + +// ns1 share vpc with ns, delete ns1, vpc should not be deleted +func TestSharedNetworkInfo(t *testing.T) { + ns := "shared-vpc-ns-0" + ns1 := "shared-vpc-ns-1" + + nsPath, _ := filepath.Abs("./manifest/testVPC/shared_ns.yaml") + _ = applyYAML(nsPath, "") + defer deleteYAML(nsPath, "") + + // Check namespace cr existence + _, ns_uid := verifyCRCreated(t, NSCRType, ns, 1) + _, _ = verifyCRCreated(t, NSCRType, ns1, 1) + // Check networkinfo cr existence + networkinfo_name, _ := verifyCRCreated(t, NetworkInfoCRType, ns, 1) + networkinfo_name_1, _ := verifyCRCreated(t, NetworkInfoCRType, ns1, 1) + + vpcPath, _ := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].vpcPath") + err := testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) + vpcPath1, _ := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name_1, ns1, ".vpcs[0].vpcPath") + err = testData.waitForResourceExistByPath(vpcPath1, true) + assertNil(t, err) + + assertTrue(t, vpcPath == vpcPath1, "vpcPath %s should be the same as vpcPath2 %s", vpcPath, vpcPath1) + + //verify private ipblocks created for vpc, id is nsuid + cidr + p_ipb_id1 := ns_uid + "_" + CustomizedPrivateCIDR1 + p_ipb_id2 := ns_uid + "_" + CustomizedPrivateCIDR2 + + verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) + verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) + + // delete ns1 and check vpc not deleted + err = testData.deleteNamespace(ns1, defaultTimeout) + assertNil(t, err) + verifyCRDeleted(t, NetworkInfoCRType, ns1) + verifyCRDeleted(t, NSCRType, ns1) + err = testData.waitForResourceExistByPath(vpcPath, true) + assertNil(t, err) + verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) + verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) +} + +// update vpcnetworkconfig, and check vpc is updated +func TestUpdateVPCNetworkconfigNetworkInfo(t *testing.T) { + ns := "update-ns" + + nsPath, _ := filepath.Abs("./manifest/testVPC/update_ns.yaml") + _ = applyYAML(nsPath, "") + defer deleteYAML(nsPath, "") + + vncPathOriginal, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig.yaml") + defer applyYAML(vncPathOriginal, "") + + // Check namespace cr existence + _, ns_uid := verifyCRCreated(t, NSCRType, ns, 1) + // Check networkinfo cr existence + networkinfo_name, _ := verifyCRCreated(t, NetworkInfoCRType, ns, 1) + + privateIPv4CIDRs, err := testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].privateIPv4CIDRs") + assertTrue(t, strings.Contains(privateIPv4CIDRs, CustomizedPrivateCIDR1), "privateIPv4CIDRs %s should contain %s", privateIPv4CIDRs, CustomizedPrivateCIDR1) + assertTrue(t, strings.Contains(privateIPv4CIDRs, CustomizedPrivateCIDR2), "privateIPv4CIDRs %s should contain %s", privateIPv4CIDRs, CustomizedPrivateCIDR1) + assertNil(t, err) + + //verify private ipblocks created for vpc, id is nsuid + cidr + p_ipb_id1 := ns_uid + "_" + CustomizedPrivateCIDR1 + p_ipb_id2 := ns_uid + "_" + CustomizedPrivateCIDR2 + + verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) + verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) + + vncPath, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig_updated.yaml") + _ = applyYAML(vncPath, "") + + privateIPv4CIDRs, err = testData.getCRPropertiesByJson(defaultTimeout, NetworkInfoCRType, networkinfo_name, ns, ".vpcs[0].privateIPv4CIDRs") + assertTrue(t, strings.Contains(privateIPv4CIDRs, CustomizedPrivateCIDR3), "privateIPv4CIDRs %s should contain %s", privateIPv4CIDRs, CustomizedPrivateCIDR3) + assertNil(t, err) + p_ipb_id3 := ns_uid + "_" + CustomizedPrivateCIDR3 + verifyPrivateIPBlockCreated(t, ns, p_ipb_id3) +} diff --git a/test/e2e/nsx_vpc_test.go b/test/e2e/nsx_vpc_test.go deleted file mode 100644 index 08c3669d8..000000000 --- a/test/e2e/nsx_vpc_test.go +++ /dev/null @@ -1,149 +0,0 @@ -package e2e - -import ( - "log" - "path/filepath" - "strings" - "testing" -) - -const ( - VPCCRType = "vpcs" - VPCNSXType = "Vpc" - PrivateIPBlockNSXType = "IpAddressBlock" - - InfraVPCNamespace = "kube-system" - SharedInfraVPCNamespace = "kube-public" - - DefaultPrivateCIDR1 = "172.28.0.0" - DefaultPrivateCIDR2 = "172.38.0.0" - InfraPrivateCIDR1 = "172.27.0.0" - InfraPrivateCIDR2 = "172.37.0.0" - CustomizedPrivateCIDR1 = "172.29.0.0" - CustomizedPrivateCIDR2 = "172.39.0.0" -) - -var ( - verify_keys = []string{"defaultSNATIP", "lbSubnetCIDR", "lbSubnetPath", "nsxResourcePath"} -) - -func verifyVPCCRCreated(t *testing.T, ns string, expect int) (string, string) { - // there should be one vpc created - resources, err := testData.getCRResource(defaultTimeout, VPCCRType, ns) - // only one vpc should be created under ns using default network config - if len(resources) != expect { - log.Printf("VPC list %s size not the same as expected %d", resources, expect) - panic("VPC CR creation verify failed") - } - assertNil(t, err) - - var vpc_name, vpc_uid string = "", "" - // waiting for CR to be ready - for k, v := range resources { - vpc_name = k - vpc_uid = strings.TrimSpace(v) - } - - return vpc_name, vpc_uid -} - -func verifyPrivateIPBlockCreated(t *testing.T, ns, id string) { - err := testData.waitForResourceExistById(ns, PrivateIPBlockNSXType, id, true) - assertNil(t, err) -} - -func verifyVPCCRProperties(t *testing.T, ns, vpc_name string) { - for _, key := range verify_keys { - value, err := testData.getCRProperties(defaultTimeout, VPCCRType, vpc_name, ns, key) - assertNil(t, err) - if strings.TrimSpace(value) == "" { - log.Printf("failed to read key %s for VPC %s", key, vpc_name) - panic("failed to read attribute from VPC CR") - } - } -} - -// Test Customized VPC -func TestCustomizedVPC(t *testing.T) { - // Create customized networkconfig - ncPath, _ := filepath.Abs("./manifest/testVPC/customize_networkconfig.yaml") - _ = applyYAML(ncPath, "") - nsPath, _ := filepath.Abs("./manifest/testVPC/customize_ns.yaml") - _ = applyYAML(nsPath, "") - - defer deleteYAML(nsPath, "") - defer deleteYAML(ncPath, "") - - ns := "customized-ns" - - vpc_name, vpc_uid := verifyVPCCRCreated(t, ns, 1) - - err := testData.waitForCRReadyOrDeleted(defaultTimeout, VPCCRType, ns, vpc_name, Ready) - assertNil(t, err, "Error when waiting for VPC %s", vpc_name) - - verifyVPCCRProperties(t, ns, vpc_name) - - // Check nsx-t resource existing, nsx vpc is using vpc cr uid as id - err = testData.waitForResourceExistById(ns, VPCNSXType, vpc_uid, true) - assertNil(t, err) - - //verify private ipblocks created for vpc - p_ipb_id1 := vpc_uid + "_" + CustomizedPrivateCIDR1 - p_ipb_id2 := vpc_uid + "_" + CustomizedPrivateCIDR2 - - verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) - verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) -} - -// Test Infra VPC -func TestInfraVPC(t *testing.T) { - // there should be one shared vpc created under namespace kube-system - vpc_name, vpc_uid := verifyVPCCRCreated(t, InfraVPCNamespace, 1) - - err := testData.waitForCRReadyOrDeleted(defaultTimeout, VPCCRType, InfraVPCNamespace, vpc_name, Ready) - assertNil(t, err, "Error when waiting for VPC %s", vpc_name) - - verifyVPCCRProperties(t, InfraVPCNamespace, vpc_name) - - // Check nsx-t resource existing, nsx vpc is using vpc cr uid as id - err = testData.waitForResourceExistById(InfraVPCNamespace, VPCNSXType, vpc_uid, true) - assertNil(t, err) - - //verify private ipblocks created for vpc - p_ipb_id1 := vpc_uid + "_" + InfraPrivateCIDR1 - p_ipb_id2 := vpc_uid + "_" + InfraPrivateCIDR2 - - verifyPrivateIPBlockCreated(t, InfraVPCNamespace, p_ipb_id1) - verifyPrivateIPBlockCreated(t, InfraVPCNamespace, p_ipb_id2) - - // there should be no VPC exist under namespace kube-public - _, _ = verifyVPCCRCreated(t, SharedInfraVPCNamespace, 0) -} - -// Test Default VPC -func TestDefaultVPC(t *testing.T) { - // If no annotation on namespace, then VPC will use default network config to create - // VPC under each ns - ns := "vpc-default-1" - setupTest(t, ns) - defer teardownTest(t, ns, defaultTimeout) - - // Check vpc cr existence - vpc_name, vpc_uid := verifyVPCCRCreated(t, ns, 1) - - err := testData.waitForCRReadyOrDeleted(defaultTimeout, VPCCRType, ns, vpc_name, Ready) - assertNil(t, err, "Error when waiting for VPC %s", vpc_name) - - verifyVPCCRProperties(t, ns, vpc_name) - - // Check nsx-t resource existing, nsx vpc is using vpc cr uid as id - err = testData.waitForResourceExistById(ns, VPCNSXType, vpc_uid, true) - assertNil(t, err) - - //verify private ipblocks created for vpc - p_ipb_id1 := vpc_uid + "_" + DefaultPrivateCIDR1 - p_ipb_id2 := vpc_uid + "_" + DefaultPrivateCIDR2 - - verifyPrivateIPBlockCreated(t, ns, p_ipb_id1) - verifyPrivateIPBlockCreated(t, ns, p_ipb_id2) -} From 03d11e09a97bd5437084508103646e683720110c Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Mon, 24 Jun 2024 16:23:23 +0800 Subject: [PATCH 05/23] Caller skip 0 Don't skip func in caller of log. Add color to the caller filename. Signed-off-by: Xie Zheng --- pkg/logger/logger.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 0554faf1e..613d04216 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -11,7 +11,12 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" ) -const logTmFmtWithMS = "2006-01-02 15:04:05.000" +const ( + logTmFmtWithMS = "2006-01-02 15:04:05.000" + // ANSI escape codes for coloring + colorReset = "\033[0m" + colorYellow = "\033[33m" +) var ( Log logr.Logger @@ -19,7 +24,7 @@ var ( enc.AppendString(t.Format(logTmFmtWithMS)) } customCallerEncoder = func(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString(caller.TrimmedPath()) + enc.AppendString(colorYellow + caller.TrimmedPath() + colorReset) } ) @@ -65,7 +70,7 @@ func ZapLogger(cfDebug bool, cfLogLevel int) logr.Logger { zapcore.AddSync(zapcore.Lock(os.Stdout)), zapcore.Level(-1*logLevel), ) - zapLogger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) + zapLogger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(0)) defer zapLogger.Sync() From 8b76e09798fdbba8e27611b0ff97cad9c7e97266 Mon Sep 17 00:00:00 2001 From: Deng Yun Date: Tue, 18 Jun 2024 11:29:02 +0000 Subject: [PATCH 06/23] Refactor subnet subnetset CRD 1.Remove subnet CRD unused DHCP options since these fields are not used, so not expose to uesers. 2.Add gatewayAddresses and DHCPServerAddresses into the subnet CRD status field, also adding them in subnet field of subnetset CRD. 3.Rename status ipAddress to networkAddresses --- build/yaml/crd/nsx.vmware.com_subnets.yaml | 34 +++++------------ build/yaml/crd/nsx.vmware.com_subnetsets.yaml | 37 +++++-------------- .../nsx.vmware.com/v1alpha1/subnet_types.go | 22 +++-------- .../v1alpha1/subnetset_types.go | 6 ++- .../v1alpha1/zz_generated.deepcopy.go | 35 ++++++++++++++---- pkg/apis/v1alpha1/subnet_types.go | 22 +++-------- pkg/apis/v1alpha1/subnetset_types.go | 6 ++- pkg/apis/v1alpha1/zz_generated.deepcopy.go | 35 ++++++++++++++---- pkg/controllers/subnet/subnet_controller.go | 11 +++++- pkg/nsx/services/subnet/subnet.go | 7 +++- test/e2e/nsx_subnet_test.go | 6 +-- 11 files changed, 108 insertions(+), 113 deletions(-) diff --git a/build/yaml/crd/nsx.vmware.com_subnets.yaml b/build/yaml/crd/nsx.vmware.com_subnets.yaml index 7d5de517b..fe7898881 100644 --- a/build/yaml/crd/nsx.vmware.com_subnets.yaml +++ b/build/yaml/crd/nsx.vmware.com_subnets.yaml @@ -51,30 +51,6 @@ spec: DHCPConfig: description: DHCPConfig DHCP configuration. properties: - dhcpRelayConfigPath: - description: DHCPRelayConfigPath is policy path of DHCP-relay-config. - type: string - dhcpV4PoolSize: - default: 80 - description: DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - By default, 80% of IPv4 IPs will be reserved for DHCP. Configure - 0 if no pool is required. - maximum: 100 - minimum: 0 - type: integer - dhcpV6PoolSize: - default: 2000 - description: DHCPV6PoolSize number of IPs to be reserved for DHCP - ranges. By default, 2000 IPv6 IPs will be reserved for DHCP. - type: integer - dnsClientConfig: - description: DNSClientConfig holds DNS configurations. - properties: - dnsServersIPs: - items: - type: string - type: array - type: object enableDHCP: default: false type: boolean @@ -116,6 +92,10 @@ spec: status: description: SubnetStatus defines the observed state of Subnet. properties: + DHCPServerAddresses: + items: + type: string + type: array conditions: items: description: Condition defines condition of custom resource. @@ -144,7 +124,11 @@ spec: - type type: object type: array - ipAddresses: + gatewayAddresses: + items: + type: string + type: array + networkAddreses: items: type: string type: array diff --git a/build/yaml/crd/nsx.vmware.com_subnetsets.yaml b/build/yaml/crd/nsx.vmware.com_subnetsets.yaml index aac120f98..912d1a93b 100644 --- a/build/yaml/crd/nsx.vmware.com_subnetsets.yaml +++ b/build/yaml/crd/nsx.vmware.com_subnetsets.yaml @@ -51,30 +51,6 @@ spec: DHCPConfig: description: DHCPConfig DHCP configuration. properties: - dhcpRelayConfigPath: - description: DHCPRelayConfigPath is policy path of DHCP-relay-config. - type: string - dhcpV4PoolSize: - default: 80 - description: DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - By default, 80% of IPv4 IPs will be reserved for DHCP. Configure - 0 if no pool is required. - maximum: 100 - minimum: 0 - type: integer - dhcpV6PoolSize: - default: 2000 - description: DHCPV6PoolSize number of IPs to be reserved for DHCP - ranges. By default, 2000 IPv6 IPs will be reserved for DHCP. - type: integer - dnsClientConfig: - description: DNSClientConfig holds DNS configurations. - properties: - dnsServersIPs: - items: - type: string - type: array - type: object enableDHCP: default: false type: boolean @@ -142,15 +118,20 @@ spec: description: SubnetInfo defines the observed state of a single Subnet of a SubnetSet. properties: - ipAddresses: + DHCPServerAddresses: + items: + type: string + type: array + gatewayAddresses: + items: + type: string + type: array + networkAddresses: items: type: string type: array nsxResourcePath: type: string - required: - - ipAddresses - - nsxResourcePath type: object type: array type: object diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go index 5473a8021..d84391965 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go @@ -30,9 +30,11 @@ type SubnetSpec struct { // SubnetStatus defines the observed state of Subnet. type SubnetStatus struct { - NSXResourcePath string `json:"nsxResourcePath,omitempty"` - IPAddresses []string `json:"ipAddresses,omitempty"` - Conditions []Condition `json:"conditions,omitempty"` + NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NetworkAddresses []string `json:"networkAddreses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` + Conditions []Condition `json:"conditions,omitempty"` } // +genclient @@ -78,20 +80,6 @@ type StaticIPAllocation struct { type DHCPConfig struct { // +kubebuilder:default:=false EnableDHCP bool `json:"enableDHCP,omitempty"` - // DHCPRelayConfigPath is policy path of DHCP-relay-config. - DHCPRelayConfigPath string `json:"dhcpRelayConfigPath,omitempty"` - // DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - // By default, 80% of IPv4 IPs will be reserved for DHCP. - // Configure 0 if no pool is required. - // +kubebuilder:default:=80 - // +kubebuilder:validation:Maximum:=100 - // +kubebuilder:validation:Minimum:=0 - DHCPV4PoolSize int `json:"dhcpV4PoolSize,omitempty"` - // DHCPV6PoolSize number of IPs to be reserved for DHCP ranges. - // By default, 2000 IPv6 IPs will be reserved for DHCP. - // +kubebuilder:default:=2000 - DHCPV6PoolSize int `json:"dhcpV6PoolSize,omitempty"` - DNSClientConfig DNSClientConfig `json:"dnsClientConfig,omitempty"` } // DNSClientConfig holds DNS configurations. diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go index 5c6864893..23df555bb 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go @@ -24,8 +24,10 @@ type SubnetSetSpec struct { // SubnetInfo defines the observed state of a single Subnet of a SubnetSet. type SubnetInfo struct { - NSXResourcePath string `json:"nsxResourcePath"` - IPAddresses []string `json:"ipAddresses"` + NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` } // SubnetSetStatus defines the observed state of SubnetSet. diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go index 7acaa6a5c..74ddbb492 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go @@ -48,7 +48,6 @@ func (in *Condition) DeepCopy() *Condition { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DHCPConfig) DeepCopyInto(out *DHCPConfig) { *out = *in - in.DNSClientConfig.DeepCopyInto(&out.DNSClientConfig) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPConfig. @@ -907,8 +906,18 @@ func (in *Subnet) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetInfo) DeepCopyInto(out *SubnetInfo) { *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses *out = make([]string, len(*in)) copy(*out, *in) } @@ -1089,7 +1098,7 @@ func (in *SubnetSet) DeepCopyInto(out *SubnetSet) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -1147,7 +1156,7 @@ func (in *SubnetSetList) DeepCopyObject() runtime.Object { func (in *SubnetSetSpec) DeepCopyInto(out *SubnetSetSpec) { *out = *in out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) + out.DHCPConfig = in.DHCPConfig } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetSpec. @@ -1198,7 +1207,7 @@ func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { copy(*out, *in) } out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) + out.DHCPConfig = in.DHCPConfig } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. @@ -1214,8 +1223,18 @@ func (in *SubnetSpec) DeepCopy() *SubnetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses *out = make([]string, len(*in)) copy(*out, *in) } diff --git a/pkg/apis/v1alpha1/subnet_types.go b/pkg/apis/v1alpha1/subnet_types.go index 5473a8021..d84391965 100644 --- a/pkg/apis/v1alpha1/subnet_types.go +++ b/pkg/apis/v1alpha1/subnet_types.go @@ -30,9 +30,11 @@ type SubnetSpec struct { // SubnetStatus defines the observed state of Subnet. type SubnetStatus struct { - NSXResourcePath string `json:"nsxResourcePath,omitempty"` - IPAddresses []string `json:"ipAddresses,omitempty"` - Conditions []Condition `json:"conditions,omitempty"` + NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NetworkAddresses []string `json:"networkAddreses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` + Conditions []Condition `json:"conditions,omitempty"` } // +genclient @@ -78,20 +80,6 @@ type StaticIPAllocation struct { type DHCPConfig struct { // +kubebuilder:default:=false EnableDHCP bool `json:"enableDHCP,omitempty"` - // DHCPRelayConfigPath is policy path of DHCP-relay-config. - DHCPRelayConfigPath string `json:"dhcpRelayConfigPath,omitempty"` - // DHCPV4PoolSize IPs in % to be reserved for DHCP ranges. - // By default, 80% of IPv4 IPs will be reserved for DHCP. - // Configure 0 if no pool is required. - // +kubebuilder:default:=80 - // +kubebuilder:validation:Maximum:=100 - // +kubebuilder:validation:Minimum:=0 - DHCPV4PoolSize int `json:"dhcpV4PoolSize,omitempty"` - // DHCPV6PoolSize number of IPs to be reserved for DHCP ranges. - // By default, 2000 IPv6 IPs will be reserved for DHCP. - // +kubebuilder:default:=2000 - DHCPV6PoolSize int `json:"dhcpV6PoolSize,omitempty"` - DNSClientConfig DNSClientConfig `json:"dnsClientConfig,omitempty"` } // DNSClientConfig holds DNS configurations. diff --git a/pkg/apis/v1alpha1/subnetset_types.go b/pkg/apis/v1alpha1/subnetset_types.go index 5c6864893..23df555bb 100644 --- a/pkg/apis/v1alpha1/subnetset_types.go +++ b/pkg/apis/v1alpha1/subnetset_types.go @@ -24,8 +24,10 @@ type SubnetSetSpec struct { // SubnetInfo defines the observed state of a single Subnet of a SubnetSet. type SubnetInfo struct { - NSXResourcePath string `json:"nsxResourcePath"` - IPAddresses []string `json:"ipAddresses"` + NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` } // SubnetSetStatus defines the observed state of SubnetSet. diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go index 7acaa6a5c..74ddbb492 100644 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go @@ -48,7 +48,6 @@ func (in *Condition) DeepCopy() *Condition { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DHCPConfig) DeepCopyInto(out *DHCPConfig) { *out = *in - in.DNSClientConfig.DeepCopyInto(&out.DNSClientConfig) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPConfig. @@ -907,8 +906,18 @@ func (in *Subnet) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetInfo) DeepCopyInto(out *SubnetInfo) { *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses *out = make([]string, len(*in)) copy(*out, *in) } @@ -1089,7 +1098,7 @@ func (in *SubnetSet) DeepCopyInto(out *SubnetSet) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -1147,7 +1156,7 @@ func (in *SubnetSetList) DeepCopyObject() runtime.Object { func (in *SubnetSetSpec) DeepCopyInto(out *SubnetSetSpec) { *out = *in out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) + out.DHCPConfig = in.DHCPConfig } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetSpec. @@ -1198,7 +1207,7 @@ func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { copy(*out, *in) } out.AdvancedConfig = in.AdvancedConfig - in.DHCPConfig.DeepCopyInto(&out.DHCPConfig) + out.DHCPConfig = in.DHCPConfig } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. @@ -1214,8 +1223,18 @@ func (in *SubnetSpec) DeepCopy() *SubnetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { *out = *in - if in.IPAddresses != nil { - in, out := &in.IPAddresses, &out.IPAddresses + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses *out = make([]string, len(*in)) copy(*out, *in) } diff --git a/pkg/controllers/subnet/subnet_controller.go b/pkg/controllers/subnet/subnet_controller.go index 3308718a0..a93d5c5bd 100644 --- a/pkg/controllers/subnet/subnet_controller.go +++ b/pkg/controllers/subnet/subnet_controller.go @@ -157,13 +157,20 @@ func (r *SubnetReconciler) updateSubnetStatus(obj *v1alpha1.Subnet) error { if nsxSubnet == nil { return errors.New("failed to get NSX Subnet from store") } - obj.Status.IPAddresses = obj.Status.IPAddresses[:0] + obj.Status.NetworkAddresses = obj.Status.NetworkAddresses[:0] + obj.Status.GatewayAddresses = obj.Status.GatewayAddresses[:0] + obj.Status.DHCPServerAddresses = obj.Status.DHCPServerAddresses[:0] statusList, err := r.SubnetService.GetSubnetStatus(nsxSubnet) if err != nil { return err } for _, status := range statusList { - obj.Status.IPAddresses = append(obj.Status.IPAddresses, *status.NetworkAddress) + obj.Status.NetworkAddresses = append(obj.Status.NetworkAddresses, *status.NetworkAddress) + obj.Status.GatewayAddresses = append(obj.Status.GatewayAddresses, *status.GatewayAddress) + // DHCPServerAddress is only for the subnet with DHCP enabled + if status.DhcpServerAddress != nil { + obj.Status.DHCPServerAddresses = append(obj.Status.DHCPServerAddresses, *status.DhcpServerAddress) + } } obj.Status.NSXResourcePath = *nsxSubnet.Path return nil diff --git a/pkg/nsx/services/subnet/subnet.go b/pkg/nsx/services/subnet/subnet.go index 3177a74bf..afc589a3f 100644 --- a/pkg/nsx/services/subnet/subnet.go +++ b/pkg/nsx/services/subnet/subnet.go @@ -264,7 +264,12 @@ func (service *SubnetService) UpdateSubnetSetStatus(obj *v1alpha1.SubnetSet) err NSXResourcePath: *subnet.Path, } for _, status := range statusList { - subnetInfo.IPAddresses = append(subnetInfo.IPAddresses, *status.NetworkAddress) + subnetInfo.NetworkAddresses = append(subnetInfo.NetworkAddresses, *status.NetworkAddress) + subnetInfo.GatewayAddresses = append(subnetInfo.GatewayAddresses, *status.GatewayAddress) + // DHCPServerAddress is only for the subnet with DHCP enabled + if status.DhcpServerAddress != nil { + subnetInfo.DHCPServerAddresses = append(subnetInfo.DHCPServerAddresses, *status.DhcpServerAddress) + } } subnetInfoList = append(subnetInfoList, subnetInfo) } diff --git a/test/e2e/nsx_subnet_test.go b/test/e2e/nsx_subnet_test.go index c88bc0fa0..f89b56408 100644 --- a/test/e2e/nsx_subnet_test.go +++ b/test/e2e/nsx_subnet_test.go @@ -244,7 +244,7 @@ func sharedSubnetSet(t *testing.T) { // 5. Check Subnet CIDR contains SubnetPort IP. portIP := net.ParseIP(strings.Split(port.Status.NetworkInterfaceConfig.IPAddresses[0].IPAddress, "/")[0]) - _, subnetCIDR, err := net.ParseCIDR(subnetSet.Status.Subnets[0].IPAddresses[0]) + _, subnetCIDR, err := net.ParseCIDR(subnetSet.Status.Subnets[0].NetworkAddresses[0]) assertNil(t, err) assertTrue(t, subnetCIDR.Contains(portIP)) } @@ -270,7 +270,7 @@ func SubnetCIDR(t *testing.T) { assertNil(t, err) allocatedSubnet, err := testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) assertNil(t, err) - targetCIDR := allocatedSubnet.Status.IPAddresses[0] + targetCIDR := allocatedSubnet.Status.NetworkAddresses[0] err = testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Delete(context.TODO(), subnet.Name, v1.DeleteOptions{}) assertNil(t, err) @@ -293,5 +293,5 @@ func SubnetCIDR(t *testing.T) { assertNil(t, err) allocatedSubnet, err = testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) assertNil(t, err) - assert.Equal(t, targetCIDR, allocatedSubnet.Status.IPAddresses[0]) + assert.Equal(t, targetCIDR, allocatedSubnet.Status.NetworkAddresses[0]) } From 8bd60fbe6a2d5c2cba7496a88c4cdecdf4bd7e7a Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Wed, 26 Jun 2024 10:59:14 +0800 Subject: [PATCH 07/23] Fix bug, should not delete customize_networkconfig Fix NetworkInfoCRType networkinfos instead of networkinfoes Signed-off-by: Xie Zheng --- test/e2e/nsx_networkinfo_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/e2e/nsx_networkinfo_test.go b/test/e2e/nsx_networkinfo_test.go index 1d242b56d..de628682e 100644 --- a/test/e2e/nsx_networkinfo_test.go +++ b/test/e2e/nsx_networkinfo_test.go @@ -8,7 +8,7 @@ import ( ) const ( - NetworkInfoCRType = "networkinfoes" + NetworkInfoCRType = "networkinfos" NSCRType = "namespaces" PrivateIPBlockNSXType = "IpAddressBlock" @@ -68,7 +68,6 @@ func TestCustomizedNetworkInfo(t *testing.T) { _ = applyYAML(nsPath, "") defer deleteYAML(nsPath, "") - defer deleteYAML(ncPath, "") ns := "customized-ns" From c43a94e863a0b7271c4f4a06f54b896356403102 Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Thu, 20 Jun 2024 16:55:17 +0800 Subject: [PATCH 08/23] Log NSX API errors with NSXApiError utility function Previously, the log `nsx-system nsx-ncp-d7d769f8b-dm7b6 nsx-operator 2024-06-20 08:31:55.547 ERROR failed to create VPC {"Project": "nsx_operator_e2e_test", "Namespace": "kube-system", "error": "com.vmware.vapi.std.errors.invalid_request"}` `invalid_request` is not readable to users, we try to parse it to nsx api error or return the original if failed to parse. The new log `nsx-system nsx-ncp-bd4cbdf45-qxwdp nsx-operator 2024-06-20 09:07:49.825 ERROR failed to create VPC {"Project": "nsx_operator_e2e_test", "Namespace": "kube-system", "error": "nsx error: Edge cluster [[/infra/sites/default/enforcement-points/default/edge-clusters/{edge-cluster-id}]] must be associated with a project /orgs/default/projects/nsx_operator_e2e_test."}` is more friendly to user. Signed-off-by: Xie Zheng --- pkg/nsx/services/ippool/ippool.go | 3 + pkg/nsx/services/node/node.go | 2 + pkg/nsx/services/nsxserviceaccount/cluster.go | 11 ++++ .../services/realizestate/realize_state.go | 2 + pkg/nsx/services/securitypolicy/firewall.go | 6 ++ pkg/nsx/services/staticroute/staticroute.go | 3 + pkg/nsx/services/subnet/subnet.go | 7 +++ pkg/nsx/services/subnetport/subnetport.go | 4 ++ pkg/nsx/services/vpc/vpc.go | 18 ++++++ pkg/nsx/util/utils.go | 57 +++++++++++++++++++ 10 files changed, 113 insertions(+) diff --git a/pkg/nsx/services/ippool/ippool.go b/pkg/nsx/services/ippool/ippool.go index 3d3ada89c..2cfd2a67e 100644 --- a/pkg/nsx/services/ippool/ippool.go +++ b/pkg/nsx/services/ippool/ippool.go @@ -137,9 +137,11 @@ func (service *IPPoolService) Apply(nsxIPPool *model.IpAddressPool, nsxIPSubnets } else { err = service.NSXClient.ProjectInfraClient.Patch(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, *infraIPPool, &EnforceRevisionCheckParam) + err = util.NSXApiError(err) } } else if IPPoolType == common.IPPoolTypePublic { err = service.NSXClient.InfraClient.Patch(*infraIPPool, &EnforceRevisionCheckParam) + err = util.NSXApiError(err) } else { err = util.NoEffectiveOption{Desc: "not valid IPPool type"} } @@ -233,6 +235,7 @@ func (service *IPPoolService) acquireCidr(obj *v1alpha2.IPPool, subnetRequest *v return "", err } m, err := service.NSXClient.RealizedEntitiesClient.List(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, intentPath, nil) + err = util.NSXApiError(err) if err != nil { return "", err } diff --git a/pkg/nsx/services/node/node.go b/pkg/nsx/services/node/node.go index f5e69ae82..7d66d7582 100644 --- a/pkg/nsx/services/node/node.go +++ b/pkg/nsx/services/node/node.go @@ -9,6 +9,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/logger" servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" ) var ( @@ -82,6 +83,7 @@ func (service *NodeService) SyncNodeStore(nodeName string, deleted bool) error { // node.NodeStore.Apply(updatedNode) } nodeResults, err := service.NSXClient.HostTransPortNodesClient.List("default", "default", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { return fmt.Errorf("failed to list HostTransportNodes: %s", err) } diff --git a/pkg/nsx/services/nsxserviceaccount/cluster.go b/pkg/nsx/services/nsxserviceaccount/cluster.go index d0302126b..d527d1006 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster.go @@ -26,6 +26,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" "github.com/vmware-tanzu/nsx-operator/pkg/util" ) @@ -191,6 +192,7 @@ func (s *NSXServiceAccountService) RestoreRealizedNSXServiceAccount(ctx context. return fmt.Errorf("PI/CCP doesn't match") } _, err := s.NSXClient.ClusterControlPlanesClient.Get(siteId, enforcementpointId, normalizedClusterName) + err = nsxutil.NSXApiError(err) if err == nil { return fmt.Errorf("CCP store is not synchronized") } @@ -240,6 +242,7 @@ func (s *NSXServiceAccountService) createPIAndCCP(normalizedClusterName string, CertificatePem: &cert, Tags: common.ConvertTagsToMPTags(s.buildBasicTags(obj)), }) + err = nsxutil.NSXApiError(err) if err != nil { return "", err } @@ -260,6 +263,7 @@ func (s *NSXServiceAccountService) createPIAndCCP(normalizedClusterName string, NodeId: existingClusterId, Tags: s.buildBasicTags(obj), }) + err = nsxutil.NSXApiError(err) if err != nil { return "", err } @@ -332,6 +336,7 @@ func (s *NSXServiceAccountService) DeleteNSXServiceAccount(ctx context.Context, if isDeleteCCP { cascade := true if err := s.NSXClient.ClusterControlPlanesClient.Delete(siteId, enforcementpointId, normalizedClusterName, &cascade); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "ClusterControlPlane", normalizedClusterName) return err } @@ -342,11 +347,13 @@ func (s *NSXServiceAccountService) DeleteNSXServiceAccount(ctx context.Context, if piobj := s.PrincipalIdentityStore.GetByKey(normalizedClusterName); isDeletePI && (piobj != nil) { pi := piobj.(mpmodel.PrincipalIdentity) if err := s.NSXClient.PrincipalIdentitiesClient.Delete(*pi.Id); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name) return err } if pi.CertificateId != nil && *pi.CertificateId != "" { if err := s.NSXClient.CertificatesClient.Delete(*pi.CertificateId); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name, "Certificate", *pi.CertificateId) return err } @@ -433,6 +440,7 @@ func (s *NSXServiceAccountService) updatePIAndCCPCert(normalizedClusterName, uid ccp := ccpObj.(model.ClusterControlPlane) ccp.Certificate = &cert if ccp, err := s.NSXClient.ClusterControlPlanesClient.Update(siteId, enforcementpointId, normalizedClusterName, ccp); err != nil { + err = nsxutil.NSXApiError(err) return err } else { s.ClusterControlPlaneStore.Add(ccp) @@ -449,18 +457,21 @@ func (s *NSXServiceAccountService) updatePIAndCCPCert(normalizedClusterName, uid PemEncoded: &cert, }) if err != nil { + err = nsxutil.NSXApiError(err) return err } if pi, err = s.NSXClient.PrincipalIdentitiesClient.Updatecertificate(mpmodel.UpdatePrincipalIdentityCertificateRequest{ CertificateId: certList.Results[0].Id, PrincipalIdentityId: pi.Id, }); err != nil { + err = nsxutil.NSXApiError(err) return err } else { s.PrincipalIdentityStore.Add(pi) } if oldCertId != "" { if err := s.NSXClient.CertificatesClient.Delete(oldCertId); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name, "Old Certificate", *pi.CertificateId) } } diff --git a/pkg/nsx/services/realizestate/realize_state.go b/pkg/nsx/services/realizestate/realize_state.go index 29cd1b02f..8fef3bf8a 100644 --- a/pkg/nsx/services/realizestate/realize_state.go +++ b/pkg/nsx/services/realizestate/realize_state.go @@ -12,6 +12,7 @@ import ( "k8s.io/client-go/util/retry" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" ) type RealizeStateService struct { @@ -43,6 +44,7 @@ func (service *RealizeStateService) CheckRealizeState(backoff wait.Backoff, inte return !IsRealizeStateError(err) }, func() error { results, err := service.NSXClient.RealizedEntitiesClient.List(vpcInfo.OrgID, vpcInfo.ProjectID, intentPath, nil) + err = nsxutil.NSXApiError(err) if err != nil { return err } diff --git a/pkg/nsx/services/securitypolicy/firewall.go b/pkg/nsx/services/securitypolicy/firewall.go index bc00165fa..34c5f15a7 100644 --- a/pkg/nsx/services/securitypolicy/firewall.go +++ b/pkg/nsx/services/securitypolicy/firewall.go @@ -499,6 +499,7 @@ func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1 // 3.Create/update SecurityPolicy together with groups, rules under VPC level and project groups, shares. err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create or update SecurityPolicy in VPC") return err @@ -526,6 +527,7 @@ func (service *SecurityPolicyService) createOrUpdateSecurityPolicy(obj *v1alpha1 return err } err = service.NSXClient.InfraClient.Patch(*infraSecurityPolicy, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create or update SecurityPolicy") return err @@ -732,6 +734,7 @@ func (service *SecurityPolicyService) deleteSecurityPolicy(obj interface{}, isVp // 3.Create/update SecurityPolicy together with groups, rules under VPC level and project groups, shares. err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to delete SecurityPolicy in VPC") return err @@ -759,6 +762,7 @@ func (service *SecurityPolicyService) deleteSecurityPolicy(obj interface{}, isVp return err } err = service.NSXClient.InfraClient.Patch(*infraSecurityPolicy, &EnforceRevisionCheckParam) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to delete SecurityPolicy") return err @@ -805,8 +809,10 @@ func (service *SecurityPolicyService) createOrUpdateGroups(obj *v1alpha1.Securit vpcId := (*vpcInfo).VPCID err = service.NSXClient.VpcGroupClient.Patch(orgId, projectId, vpcId, *group.Id, *group) + err = nsxutil.NSXApiError(err) } else { err = service.NSXClient.GroupClient.Patch(getDomain(service), *group.Id, *group) + err = nsxutil.NSXApiError(err) } } diff --git a/pkg/nsx/services/staticroute/staticroute.go b/pkg/nsx/services/staticroute/staticroute.go index 88ab588df..f0962ddd7 100644 --- a/pkg/nsx/services/staticroute/staticroute.go +++ b/pkg/nsx/services/staticroute/staticroute.go @@ -83,6 +83,7 @@ func (service *StaticRouteService) CreateOrUpdateStaticRoute(namespace string, o return err } staticRoute, err := service.NSXClient.StaticRouteClient.Get(vpc[0].OrgID, vpc[0].ProjectID, vpc[0].ID, *nsxStaticRoute.Id) + err = nsxutil.NSXApiError(err) if err != nil { return err } @@ -95,6 +96,7 @@ func (service *StaticRouteService) CreateOrUpdateStaticRoute(namespace string, o func (service *StaticRouteService) patch(orgId string, projectId string, vpcId string, st *model.StaticRoutes) error { err := service.NSXClient.StaticRouteClient.Patch(orgId, projectId, vpcId, *st.Id, *st) + err = nsxutil.NSXApiError(err) if err != nil { return err } @@ -109,6 +111,7 @@ func (service *StaticRouteService) DeleteStaticRouteByPath(orgId string, project } if err := staticRouteClient.Delete(orgId, projectId, vpcId, *staticroute.Id); err != nil { + err = nsxutil.NSXApiError(err) return err } if err := service.StaticRouteStore.Delete(staticroute); err != nil { diff --git a/pkg/nsx/services/subnet/subnet.go b/pkg/nsx/services/subnet/subnet.go index afc589a3f..0ece82fde 100644 --- a/pkg/nsx/services/subnet/subnet.go +++ b/pkg/nsx/services/subnet/subnet.go @@ -111,10 +111,12 @@ func (service *SubnetService) createOrUpdateSubnet(obj client.Object, nsxSubnet return "", err } if err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam); err != nil { + err = nsxutil.NSXApiError(err) return "", err } // Get Subnet from NSX after patch operation as NSX renders several fields like `path`/`parent_path`. if *nsxSubnet, err = service.NSXClient.SubnetsClient.Get(vpcInfo.OrgID, vpcInfo.ProjectID, vpcInfo.VPCID, *nsxSubnet.Id); err != nil { + err = nsxutil.NSXApiError(err) return "", err } realizeService := realizestate.InitializeRealizeState(service.Service) @@ -151,6 +153,7 @@ func (service *SubnetService) DeleteSubnet(nsxSubnet model.VpcSubnet) error { return err } if err = service.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam); err != nil { + err = nsxutil.NSXApiError(err) // Subnets that are not deleted successfully will finally be deleted by GC. log.Error(err, "failed to delete Subnet", "ID", *nsxSubnet.Id) return err @@ -198,12 +201,14 @@ func (service *SubnetService) IsOrphanSubnet(subnet model.VpcSubnet, subnetsetID func (service *SubnetService) DeleteIPAllocation(orgID, projectID, vpcID, subnetID string) error { ipAllocations, err := service.NSXClient.IPAllocationClient.List(orgID, projectID, vpcID, subnetID, ipPoolID, nil, nil, nil, nil, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get ip-allocations", "Subnet", subnetID) return err } for _, alloc := range ipAllocations.Results { if err = service.NSXClient.IPAllocationClient.Delete(orgID, projectID, vpcID, subnetID, ipPoolID, *alloc.Id); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete ip-allocation", "Subnet", subnetID, "ip-alloc", *alloc.Id) return err } @@ -218,6 +223,7 @@ func (service *SubnetService) GetSubnetStatus(subnet *model.VpcSubnet) ([]model. return nil, err } statusList, err := service.NSXClient.SubnetStatusClient.List(param.OrgID, param.ProjectID, param.VPCID, *subnet.Id) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get subnet status") return nil, err @@ -236,6 +242,7 @@ func (service *SubnetService) getIPPoolUsage(nsxSubnet *model.VpcSubnet) (*model return nil, err } ipPool, err := service.NSXClient.IPPoolClient.Get(param.OrgID, param.ProjectID, param.VPCID, *nsxSubnet.Id, ipPoolID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get ip-pool", "Subnet", *nsxSubnet.Id) return nil, err diff --git a/pkg/nsx/services/subnetport/subnetport.go b/pkg/nsx/services/subnetport/subnetport.go index 1069278cb..5bc8cc426 100644 --- a/pkg/nsx/services/subnetport/subnetport.go +++ b/pkg/nsx/services/subnetport/subnetport.go @@ -103,6 +103,7 @@ func (service *SubnetPortService) CreateOrUpdateSubnetPort(obj interface{}, nsxS return nil, err } err = service.NSXClient.PortClient.Patch(subnetInfo.OrgID, subnetInfo.ProjectID, subnetInfo.VPCID, subnetInfo.ID, *nsxSubnetPort.Id, *nsxSubnetPort) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create or update subnet port", "nsxSubnetPort.Id", *nsxSubnetPort.Id, "nsxSubnetPath", *nsxSubnet.Path) return nil, err @@ -188,6 +189,7 @@ func (service *SubnetPortService) GetSubnetPortState(obj interface{}, nsxSubnetP } nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID := nsxutil.ParseVPCPath(nsxSubnetPath) nsxSubnetPortState, err := service.NSXClient.PortStateClient.Get(nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID, string(uid), nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get subnet port state", "nsxSubnetPortID", uid, "nsxSubnetPath", nsxSubnetPath) return nil, err @@ -203,6 +205,7 @@ func (service *SubnetPortService) DeleteSubnetPort(uid types.UID) error { } nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID := nsxutil.ParseVPCPath(*nsxSubnetPort.Path) err := service.NSXClient.PortClient.Delete(nsxOrgID, nsxProjectID, nsxVPCID, nsxSubnetID, string(uid)) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to delete subnetport", "nsxSubnetPort.Path", *nsxSubnetPort.Path) return err @@ -234,6 +237,7 @@ func (service *SubnetPortService) GetGatewayPrefixForSubnetPort(obj *v1alpha1.Su } // TODO: if the port is not the first on the same subnet, try to get the info from existing realized subnetport CR to avoid query NSX API again. statusList, err := service.NSXClient.SubnetStatusClient.List(subnetInfo.OrgID, subnetInfo.ProjectID, subnetInfo.VPCID, subnetInfo.ID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get subnet status") return "", -1, err diff --git a/pkg/nsx/services/vpc/vpc.go b/pkg/nsx/services/vpc/vpc.go index c619c6a64..415b92773 100644 --- a/pkg/nsx/services/vpc/vpc.go +++ b/pkg/nsx/services/vpc/vpc.go @@ -248,6 +248,7 @@ func (s *VPCService) DeleteVPC(path string) error { } if err := vpcClient.Delete(pathInfo.OrgID, pathInfo.ProjectID, pathInfo.VPCID); err != nil { + err = nsxutil.NSXApiError(err) return err } vpc.MarkedForDelete = &MarkedForDelete @@ -264,6 +265,7 @@ func (s *VPCService) deleteIPBlock(path string) error { parts := strings.Split(path, "/") log.Info("deleting private ip block", "ORG", parts[2], "Project", parts[4], "ID", parts[7]) if err := ipblockClient.Delete(parts[2], parts[4], parts[7]); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete ip block", "Path", path) return err } @@ -326,6 +328,7 @@ func (s *VPCService) CreateOrUpdatePrivateIPBlock(obj *v1alpha1.NetworkInfo, nsO log.Info("creating ip block", "IPBlock", block.Id, "VPC", obj.Name) // can not find private ip block from store, create one _err := s.NSXClient.IPBlockClient.Patch(nc.Org, nc.NsxtProject, *block.Id, block) + _err = nsxutil.NSXApiError(_err) if _err != nil { message := fmt.Sprintf("failed to create private ip block for cidr %s for VPC %s", pCidr, obj.Name) ipblockError := errors.New(message) @@ -334,6 +337,7 @@ func (s *VPCService) CreateOrUpdatePrivateIPBlock(obj *v1alpha1.NetworkInfo, nsO } ignoreIpblockUsage := true createdBlock, err := s.NSXClient.IPBlockClient.Get(nc.Org, nc.NsxtProject, *block.Id, &ignoreIpblockUsage) + err = nsxutil.NSXApiError(err) if err != nil { // created by can not get, ignore this error log.Info("failed to read ip blocks from NSX", "Project", nc.NsxtProject, "IPBlock", block.Id) @@ -372,6 +376,7 @@ func (s *VPCService) getSharedVPCNamespaceFromNS(ns string) (string, error) { Name: ns, Namespace: ns, }, obj); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to fetch namespace", "Namespace", ns) return "", err } @@ -396,6 +401,7 @@ func (s *VPCService) getNetworkconfigNameFromNS(ns string) (string, error) { Name: ns, Namespace: ns, }, obj); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "failed to fetch namespace", "Namespace", ns) return "", err } @@ -436,6 +442,7 @@ func (s *VPCService) GetDefaultSNATIP(vpc model.Vpc) (string, error) { pageSize := int64(1000) markedForDelete := false results, err := ruleClient.List(info.OrgID, info.ProjectID, info.VPCID, common.DefaultSNATID, cursor, &markedForDelete, nil, &pageSize, nil, nil) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to read SNAT rule list to get default SNAT ip", "VPC", vpc.Id) return "", err @@ -461,6 +468,7 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) { } subnet, err := subnetsClient.Get(info.OrgID, info.ProjectID, info.VPCID, common.AVISubnetLBID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to read AVI subnet", "VPC", vpc.Id) return "", "", err @@ -468,6 +476,7 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) { path := *subnet.Path statusList, err := statusClient.List(info.OrgID, info.ProjectID, info.VPCID, common.AVISubnetLBID) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to read AVI subnet status", "VPC", vpc.Id) return "", "", err @@ -490,6 +499,7 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * nsObj := &v1.Namespace{} // get name obj if err := s.Client.Get(ctx, types.NamespacedName{Name: obj.Namespace}, nsObj); err != nil { + err = nsxutil.NSXApiError(err) log.Error(err, "unable to fetch namespace", "name", obj.Namespace) return nil, nil, err } @@ -560,11 +570,13 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * log.Info("creating NSX VPC", "VPC", *createdVpc.Id) err = s.NSXClient.VPCClient.Patch(nc.Org, nc.NsxtProject, *createdVpc.Id, *createdVpc) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create VPC", "Project", nc.NsxtProject, "Namespace", obj.Namespace) // TODO: this seems to be a nsx bug, in some case, even if nsx returns failed but the object is still created. log.Info("try to read VPC although VPC creation failed", "VPC", *createdVpc.Id) failedVpc, rErr := s.NSXClient.VPCClient.Get(nc.Org, nc.NsxtProject, *createdVpc.Id) + rErr = nsxutil.NSXApiError(rErr) if rErr != nil { // failed to read, but already created, we consider this scenario as success, but store may not sync with nsx log.Info("confirmed VPC is not created", "VPC", createdVpc.Id) @@ -577,6 +589,7 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * // get the created vpc from nsx, it contains the path of the resources newVpc, err := s.NSXClient.VPCClient.Get(nc.Org, nc.NsxtProject, *createdVpc.Id) + err = nsxutil.NSXApiError(err) if err != nil { // failed to read, but already created, we consider this scenario as success, but store may not sync with nsx log.Error(err, "failed to read VPC object after creating or updating", "VPC", createdVpc.Id) @@ -730,11 +743,13 @@ func (service *VPCService) CreateOrUpdateAVIRule(vpc *model.Vpc, namespace strin } err = service.NSXClient.VPCRuleClient.Patch(orgId, projectId, *vpc.Id, spId, *newrule.Id, *newrule) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create avi rule", "rule", newrule) return err } nsxrule, err := service.NSXClient.VPCRuleClient.Get(orgId, projectId, *vpc.Id, spId, *newrule.Id) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get avi rule", "rule", nsxrule) return err @@ -783,10 +798,12 @@ func (service *VPCService) createAVIGroup(orgId string, projectId string, vpcId group.DisplayName = common.String(groupId) err := service.NSXClient.VpcGroupClient.Patch(orgId, projectId, vpcId, groupId, group) + err = nsxutil.NSXApiError(err) if err != nil { return &group, err } nsxgroup, err := service.NSXClient.VpcGroupClient.Get(orgId, projectId, vpcId, groupId) + err = nsxutil.NSXApiError(err) return &nsxgroup, err } @@ -862,6 +879,7 @@ func (service *VPCService) checkAVISecurityPolicyExist(orgId string, projectId s return true } nsxtsp, err := service.NSXClient.VPCSecurityClient.Get(orgId, projectId, vpcId, spId) + err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to get avi security policy", "key", key) return false diff --git a/pkg/nsx/util/utils.go b/pkg/nsx/util/utils.go index 768a1242b..2c26f18d4 100644 --- a/pkg/nsx/util/utils.go +++ b/pkg/nsx/util/utils.go @@ -311,6 +311,63 @@ func DumpHttpRequest(request *http.Request) { log.V(2).Info("http request", "url", request.URL, "body", string(body), "head", request.Header) } +// NSXApiError processes an error and returns a formatted NSX API error message if applicable. +// If the processed API error is nil, return the original error +func NSXApiError(err error) error { + if err == nil { + return err + } + apierror, _ := DumpAPIError(err) + if apierror == nil { + return err + } + return fmt.Errorf("nsx error code: %d, message: %s, details: %s, related error: %s", + safeInt(apierror.ErrorCode), safeString(apierror.ErrorMessage), safeString(apierror.Details), + relatedErrorsToString(apierror.RelatedErrors)) +} + +func relatedErrorToString(err *model.RelatedApiError) string { + if err == nil { + return "nil" + } + + return fmt.Sprintf( + "{Details: %s, ErrorCode: %d, ErrorMessage: %s, ModuleName: %s}", + safeString(err.Details), + safeInt(err.ErrorCode), + safeString(err.ErrorMessage), + safeString(err.ModuleName), + ) +} + +func relatedErrorsToString(errors []model.RelatedApiError) string { + if errors == nil { + return "nil" + } + + var errorStrings []string + for i := 0; i < len(errors); i++ { + currentErr := errors[i] + errorStrings = append(errorStrings, relatedErrorToString(¤tErr)) + } + + return fmt.Sprintf("[%s]", strings.Join(errorStrings, ", ")) +} + +func safeString(ptr *string) string { + if ptr == nil { + return "" + } + return *ptr +} + +func safeInt(ptr *int64) int64 { + if ptr == nil { + return 0 + } + return *ptr +} + // if ApiError is nil, check ErrorTypeEnum, such as ServiceUnavailable // if both return value are nil, the error is not on the list // there is no httpstatus, ApiError does't include it From 3a1fc16c5765877fca957df2a56d87fb00e5f708 Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Thu, 16 May 2024 11:09:22 +0800 Subject: [PATCH 09/23] Add IPAddressAllocation CRD Signed-off-by: Xie Zheng --- .../nsx.vmware.com_ipaddressallocations.yaml | 109 +++++++++++ .../nsx_v1alpha1_ipaddressallocation.yaml | 10 + .../v1alpha1/ipaddressallocation_types.go | 63 ++++++ .../v1alpha1/zz_generated.deepcopy.go | 89 +++++++++ .../v1alpha1/ipaddressallocation_types.go | 63 ++++++ pkg/apis/v1alpha1/zz_generated.deepcopy.go | 89 +++++++++ .../v1alpha1/fake/fake_ipaddressallocation.go | 128 ++++++++++++ .../fake/fake_nsx.vmware.com_client.go | 4 + .../v1alpha1/generated_expansion.go | 2 + .../v1alpha1/ipaddressallocation.go | 182 ++++++++++++++++++ .../v1alpha1/nsx.vmware.com_client.go | 5 + .../informers/externalversions/generic.go | 2 + .../nsx.vmware.com/v1alpha1/interface.go | 7 + .../v1alpha1/ipaddressallocation.go | 77 ++++++++ .../v1alpha1/expansion_generated.go | 8 + .../v1alpha1/ipaddressallocation.go | 86 +++++++++ 16 files changed, 924 insertions(+) create mode 100644 build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml create mode 100644 build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml create mode 100644 pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go create mode 100644 pkg/apis/v1alpha1/ipaddressallocation_types.go create mode 100644 pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ipaddressallocation.go create mode 100644 pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ipaddressallocation.go create mode 100644 pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ipaddressallocation.go create mode 100644 pkg/client/listers/nsx.vmware.com/v1alpha1/ipaddressallocation.go diff --git a/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml b/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml new file mode 100644 index 000000000..476fa42d6 --- /dev/null +++ b/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml @@ -0,0 +1,109 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ipaddressallocations.nsx.vmware.com +spec: + group: nsx.vmware.com + names: + kind: IPAddressAllocation + listKind: IPAddressAllocationList + plural: ipaddressallocations + singular: ipaddressallocation + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: IPAddressBlockVisibility of IPAddressAllocation + jsonPath: .spec.ip_address_block_visibility + name: IPAddressBlockVisibility + type: string + - description: CIDRs for the IPAddressAllocation + jsonPath: .status.cidr + name: CIDR + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: IPAddressAllocation is the Schema for the IP allocation API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IPAddressAllocationSpec defines the desired state of IPAddressAllocation. + properties: + allocation_size: + description: AllocationSize specifies the size of IP CIDR to be allocated. + type: integer + ip_address_block_visibility: + default: Private + description: IPAddressBlockVisibility specifies the visibility of + the IPBlocks to allocate IP addresses. Can be External, Private + or Project. + enum: + - External + - Private + - Project + type: string + type: object + status: + description: IPAddressAllocationStatus defines the observed state of IPAddressAllocation. + properties: + CIDR: + description: CIDR is the allocated CIDR + type: string + conditions: + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + required: + - CIDR + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml b/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml new file mode 100644 index 000000000..c56cebd7f --- /dev/null +++ b/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml @@ -0,0 +1,10 @@ +apiVersion: nsx.vmware.com/v1alpha1 +kind: IPAddressAllocation +metadata: + name: guestcluster-workers-a + namespace: sc-a +spec: + ip_address_block_visibility: Private + allocation_size: 26 +status: + CIDR: 172.26.1.0/28 \ No newline at end of file diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go new file mode 100644 index 000000000..6a50925c5 --- /dev/null +++ b/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go @@ -0,0 +1,63 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type IPAddressVisibility string + +const ( + IPAddressVisibilityExternal = "External" + IPAddressVisibilityPrivate = "Private" + IPAddressVisibilityProject = "Project" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// IPAddressAllocation is the Schema for the IP allocation API. +// +kubebuilder:printcolumn:name="IPAddressBlockVisibility",type=string,JSONPath=`.spec.ip_address_block_visibility`,description="IPAddressBlockVisibility of IPAddressAllocation" +// +kubebuilder:printcolumn:name="CIDR",type=string,JSONPath=`.status.cidr`,description="CIDRs for the IPAddressAllocation" +type IPAddressAllocation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec IPAddressAllocationSpec `json:"spec"` + Status IPAddressAllocationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPAddressAllocationList contains a list of IPAddressAllocation. +type IPAddressAllocationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPAddressAllocation `json:"items"` +} + +// IPAddressAllocationSpec defines the desired state of IPAddressAllocation. +type IPAddressAllocationSpec struct { + // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External, Private or Project. + // +kubebuilder:validation:Enum=External;Private;Project + // +kubebuilder:default=Private + // +optional + IPAddressBlockVisibility IPAddressVisibility `json:"ip_address_block_visibility,omitempty"` + // AllocationSize specifies the size of IP CIDR to be allocated. + AllocationSize int `json:"allocation_size,omitempty"` +} + +// IPAddressAllocationStatus defines the observed state of IPAddressAllocation. +type IPAddressAllocationStatus struct { + // CIDR is the allocated CIDR + CIDR string `json:"CIDR"` + Conditions []Condition `json:"conditions,omitempty"` +} + +func init() { + SchemeBuilder.Register(&IPAddressAllocation{}, &IPAddressAllocationList{}) +} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go index 74ddbb492..5919f2d28 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go @@ -1395,3 +1395,92 @@ func (in *VPCState) DeepCopy() *VPCState { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. +func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { + if in == nil { + return nil + } + out := new(IPAddressAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPAddressAllocation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. +func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { + if in == nil { + return nil + } + out := new(IPAddressAllocationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. +func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { + if in == nil { + return nil + } + out := new(IPAddressAllocationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. +func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { + if in == nil { + return nil + } + out := new(IPAddressAllocationStatus) + in.DeepCopyInto(out) + return out +} \ No newline at end of file diff --git a/pkg/apis/v1alpha1/ipaddressallocation_types.go b/pkg/apis/v1alpha1/ipaddressallocation_types.go new file mode 100644 index 000000000..6a50925c5 --- /dev/null +++ b/pkg/apis/v1alpha1/ipaddressallocation_types.go @@ -0,0 +1,63 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type IPAddressVisibility string + +const ( + IPAddressVisibilityExternal = "External" + IPAddressVisibilityPrivate = "Private" + IPAddressVisibilityProject = "Project" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// IPAddressAllocation is the Schema for the IP allocation API. +// +kubebuilder:printcolumn:name="IPAddressBlockVisibility",type=string,JSONPath=`.spec.ip_address_block_visibility`,description="IPAddressBlockVisibility of IPAddressAllocation" +// +kubebuilder:printcolumn:name="CIDR",type=string,JSONPath=`.status.cidr`,description="CIDRs for the IPAddressAllocation" +type IPAddressAllocation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec IPAddressAllocationSpec `json:"spec"` + Status IPAddressAllocationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPAddressAllocationList contains a list of IPAddressAllocation. +type IPAddressAllocationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPAddressAllocation `json:"items"` +} + +// IPAddressAllocationSpec defines the desired state of IPAddressAllocation. +type IPAddressAllocationSpec struct { + // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External, Private or Project. + // +kubebuilder:validation:Enum=External;Private;Project + // +kubebuilder:default=Private + // +optional + IPAddressBlockVisibility IPAddressVisibility `json:"ip_address_block_visibility,omitempty"` + // AllocationSize specifies the size of IP CIDR to be allocated. + AllocationSize int `json:"allocation_size,omitempty"` +} + +// IPAddressAllocationStatus defines the observed state of IPAddressAllocation. +type IPAddressAllocationStatus struct { + // CIDR is the allocated CIDR + CIDR string `json:"CIDR"` + Conditions []Condition `json:"conditions,omitempty"` +} + +func init() { + SchemeBuilder.Register(&IPAddressAllocation{}, &IPAddressAllocationList{}) +} diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go index 74ddbb492..5919f2d28 100644 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go @@ -1395,3 +1395,92 @@ func (in *VPCState) DeepCopy() *VPCState { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. +func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { + if in == nil { + return nil + } + out := new(IPAddressAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPAddressAllocation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. +func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { + if in == nil { + return nil + } + out := new(IPAddressAllocationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. +func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { + if in == nil { + return nil + } + out := new(IPAddressAllocationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. +func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { + if in == nil { + return nil + } + out := new(IPAddressAllocationStatus) + in.DeepCopyInto(out) + return out +} \ No newline at end of file diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ipaddressallocation.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ipaddressallocation.go new file mode 100644 index 000000000..8829426a0 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_ipaddressallocation.go @@ -0,0 +1,128 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeIPAddressAllocations implements IPAddressAllocationInterface +type FakeIPAddressAllocations struct { + Fake *FakeNsxV1alpha1 + ns string +} + +var ipaddressallocationsResource = v1alpha1.SchemeGroupVersion.WithResource("ipaddressallocations") + +var ipaddressallocationsKind = v1alpha1.SchemeGroupVersion.WithKind("IPAddressAllocation") + +// Get takes name of the iPAddressAllocation, and returns the corresponding iPAddressAllocation object, and an error if there is any. +func (c *FakeIPAddressAllocations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(ipaddressallocationsResource, c.ns, name), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// List takes label and field selectors, and returns the list of IPAddressAllocations that match those selectors. +func (c *FakeIPAddressAllocations) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPAddressAllocationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(ipaddressallocationsResource, ipaddressallocationsKind, c.ns, opts), &v1alpha1.IPAddressAllocationList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.IPAddressAllocationList{ListMeta: obj.(*v1alpha1.IPAddressAllocationList).ListMeta} + for _, item := range obj.(*v1alpha1.IPAddressAllocationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested iPAddressAllocations. +func (c *FakeIPAddressAllocations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(ipaddressallocationsResource, c.ns, opts)) + +} + +// Create takes the representation of a iPAddressAllocation and creates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *FakeIPAddressAllocations) Create(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.CreateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(ipaddressallocationsResource, c.ns, iPAddressAllocation), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// Update takes the representation of a iPAddressAllocation and updates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *FakeIPAddressAllocations) Update(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(ipaddressallocationsResource, c.ns, iPAddressAllocation), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeIPAddressAllocations) UpdateStatus(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (*v1alpha1.IPAddressAllocation, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(ipaddressallocationsResource, "status", c.ns, iPAddressAllocation), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} + +// Delete takes name of the iPAddressAllocation and deletes it. Returns an error if one occurs. +func (c *FakeIPAddressAllocations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(ipaddressallocationsResource, c.ns, name, opts), &v1alpha1.IPAddressAllocation{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIPAddressAllocations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(ipaddressallocationsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.IPAddressAllocationList{}) + return err +} + +// Patch applies the patch and returns the patched iPAddressAllocation. +func (c *FakeIPAddressAllocations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPAddressAllocation, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ipaddressallocationsResource, c.ns, name, pt, data, subresources...), &v1alpha1.IPAddressAllocation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.IPAddressAllocation), err +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go index 716efe23a..f073f5a3c 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go @@ -15,6 +15,10 @@ type FakeNsxV1alpha1 struct { *testing.Fake } +func (c *FakeNsxV1alpha1) IPAddressAllocations(namespace string) v1alpha1.IPAddressAllocationInterface { + return &FakeIPAddressAllocations{c, namespace} +} + func (c *FakeNsxV1alpha1) IPPools(namespace string) v1alpha1.IPPoolInterface { return &FakeIPPools{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go index c5942e151..cfc317984 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go @@ -5,6 +5,8 @@ package v1alpha1 +type IPAddressAllocationExpansion interface{} + type IPPoolExpansion interface{} type NSXServiceAccountExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ipaddressallocation.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ipaddressallocation.go new file mode 100644 index 000000000..532bbacf0 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/ipaddressallocation.go @@ -0,0 +1,182 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// IPAddressAllocationsGetter has a method to return a IPAddressAllocationInterface. +// A group's client should implement this interface. +type IPAddressAllocationsGetter interface { + IPAddressAllocations(namespace string) IPAddressAllocationInterface +} + +// IPAddressAllocationInterface has methods to work with IPAddressAllocation resources. +type IPAddressAllocationInterface interface { + Create(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.CreateOptions) (*v1alpha1.IPAddressAllocation, error) + Update(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (*v1alpha1.IPAddressAllocation, error) + UpdateStatus(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (*v1alpha1.IPAddressAllocation, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.IPAddressAllocation, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.IPAddressAllocationList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPAddressAllocation, err error) + IPAddressAllocationExpansion +} + +// iPAddressAllocations implements IPAddressAllocationInterface +type iPAddressAllocations struct { + client rest.Interface + ns string +} + +// newIPAddressAllocations returns a IPAddressAllocations +func newIPAddressAllocations(c *NsxV1alpha1Client, namespace string) *iPAddressAllocations { + return &iPAddressAllocations{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the iPAddressAllocation, and returns the corresponding iPAddressAllocation object, and an error if there is any. +func (c *iPAddressAllocations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Get(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of IPAddressAllocations that match those selectors. +func (c *iPAddressAllocations) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.IPAddressAllocationList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.IPAddressAllocationList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested iPAddressAllocations. +func (c *iPAddressAllocations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a iPAddressAllocation and creates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *iPAddressAllocations) Create(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.CreateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Post(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPAddressAllocation). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a iPAddressAllocation and updates it. Returns the server's representation of the iPAddressAllocation, and an error, if there is any. +func (c *iPAddressAllocations) Update(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(iPAddressAllocation.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPAddressAllocation). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *iPAddressAllocations) UpdateStatus(ctx context.Context, iPAddressAllocation *v1alpha1.IPAddressAllocation, opts v1.UpdateOptions) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(iPAddressAllocation.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(iPAddressAllocation). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the iPAddressAllocation and deletes it. Returns an error if one occurs. +func (c *iPAddressAllocations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *iPAddressAllocations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("ipaddressallocations"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched iPAddressAllocation. +func (c *iPAddressAllocations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.IPAddressAllocation, err error) { + result = &v1alpha1.IPAddressAllocation{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("ipaddressallocations"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go index 88726804e..5c50677e3 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go @@ -15,6 +15,7 @@ import ( type NsxV1alpha1Interface interface { RESTClient() rest.Interface + IPAddressAllocationsGetter IPPoolsGetter NSXServiceAccountsGetter NetworkInfosGetter @@ -31,6 +32,10 @@ type NsxV1alpha1Client struct { restClient rest.Interface } +func (c *NsxV1alpha1Client) IPAddressAllocations(namespace string) IPAddressAllocationInterface { + return newIPAddressAllocations(c, namespace) +} + func (c *NsxV1alpha1Client) IPPools(namespace string) IPPoolInterface { return newIPPools(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 0e3ae7c62..7f49f905c 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -41,6 +41,8 @@ func (f *genericInformer) Lister() cache.GenericLister { func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { // Group=nsx.vmware.com, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("ipaddressallocations"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().IPAddressAllocations().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("ippools"): return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().IPPools().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("nsxserviceaccounts"): diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go index 423a9fbbc..835cd1514 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go @@ -11,6 +11,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // IPAddressAllocations returns a IPAddressAllocationInformer. + IPAddressAllocations() IPAddressAllocationInformer // IPPools returns a IPPoolInformer. IPPools() IPPoolInformer // NSXServiceAccounts returns a NSXServiceAccountInformer. @@ -42,6 +44,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// IPAddressAllocations returns a IPAddressAllocationInformer. +func (v *version) IPAddressAllocations() IPAddressAllocationInformer { + return &iPAddressAllocationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // IPPools returns a IPPoolInformer. func (v *version) IPPools() IPPoolInformer { return &iPPoolInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ipaddressallocation.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ipaddressallocation.go new file mode 100644 index 000000000..ff1e7c99a --- /dev/null +++ b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/ipaddressallocation.go @@ -0,0 +1,77 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// IPAddressAllocationInformer provides access to a shared informer and lister for +// IPAddressAllocations. +type IPAddressAllocationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.IPAddressAllocationLister +} + +type iPAddressAllocationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewIPAddressAllocationInformer constructs a new informer for IPAddressAllocation type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewIPAddressAllocationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredIPAddressAllocationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredIPAddressAllocationInformer constructs a new informer for IPAddressAllocation type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredIPAddressAllocationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NsxV1alpha1().IPAddressAllocations(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NsxV1alpha1().IPAddressAllocations(namespace).Watch(context.TODO(), options) + }, + }, + &nsxvmwarecomv1alpha1.IPAddressAllocation{}, + resyncPeriod, + indexers, + ) +} + +func (f *iPAddressAllocationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredIPAddressAllocationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *iPAddressAllocationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&nsxvmwarecomv1alpha1.IPAddressAllocation{}, f.defaultInformer) +} + +func (f *iPAddressAllocationInformer) Lister() v1alpha1.IPAddressAllocationLister { + return v1alpha1.NewIPAddressAllocationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go index fcaca97ac..f9e197206 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go @@ -5,6 +5,14 @@ package v1alpha1 +// IPAddressAllocationListerExpansion allows custom methods to be added to +// IPAddressAllocationLister. +type IPAddressAllocationListerExpansion interface{} + +// IPAddressAllocationNamespaceListerExpansion allows custom methods to be added to +// IPAddressAllocationNamespaceLister. +type IPAddressAllocationNamespaceListerExpansion interface{} + // IPPoolListerExpansion allows custom methods to be added to // IPPoolLister. type IPPoolListerExpansion interface{} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/ipaddressallocation.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/ipaddressallocation.go new file mode 100644 index 000000000..cb5a8feb2 --- /dev/null +++ b/pkg/client/listers/nsx.vmware.com/v1alpha1/ipaddressallocation.go @@ -0,0 +1,86 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// IPAddressAllocationLister helps list IPAddressAllocations. +// All objects returned here must be treated as read-only. +type IPAddressAllocationLister interface { + // List lists all IPAddressAllocations in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) + // IPAddressAllocations returns an object that can list and get IPAddressAllocations. + IPAddressAllocations(namespace string) IPAddressAllocationNamespaceLister + IPAddressAllocationListerExpansion +} + +// iPAddressAllocationLister implements the IPAddressAllocationLister interface. +type iPAddressAllocationLister struct { + indexer cache.Indexer +} + +// NewIPAddressAllocationLister returns a new IPAddressAllocationLister. +func NewIPAddressAllocationLister(indexer cache.Indexer) IPAddressAllocationLister { + return &iPAddressAllocationLister{indexer: indexer} +} + +// List lists all IPAddressAllocations in the indexer. +func (s *iPAddressAllocationLister) List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.IPAddressAllocation)) + }) + return ret, err +} + +// IPAddressAllocations returns an object that can list and get IPAddressAllocations. +func (s *iPAddressAllocationLister) IPAddressAllocations(namespace string) IPAddressAllocationNamespaceLister { + return iPAddressAllocationNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// IPAddressAllocationNamespaceLister helps list and get IPAddressAllocations. +// All objects returned here must be treated as read-only. +type IPAddressAllocationNamespaceLister interface { + // List lists all IPAddressAllocations in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) + // Get retrieves the IPAddressAllocation from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.IPAddressAllocation, error) + IPAddressAllocationNamespaceListerExpansion +} + +// iPAddressAllocationNamespaceLister implements the IPAddressAllocationNamespaceLister +// interface. +type iPAddressAllocationNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all IPAddressAllocations in the indexer for a given namespace. +func (s iPAddressAllocationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.IPAddressAllocation, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.IPAddressAllocation)) + }) + return ret, err +} + +// Get retrieves the IPAddressAllocation from the indexer for a given namespace and name. +func (s iPAddressAllocationNamespaceLister) Get(name string) (*v1alpha1.IPAddressAllocation, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("ipaddressallocation"), name) + } + return obj.(*v1alpha1.IPAddressAllocation), nil +} From 51292b6dd0d3de1bd448576f47fead181756fe36 Mon Sep 17 00:00:00 2001 From: Deng Yun Date: Wed, 26 Jun 2024 16:30:19 +0800 Subject: [PATCH 10/23] Format subnetset types filed and fix subnet types typo 1.Format subnetset types files to align struct var fields 2.Fix subnet type networkaddresses filed name typo --- build/yaml/crd/nsx.vmware.com_subnets.yaml | 2 +- pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go | 2 +- pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go | 2 +- pkg/apis/v1alpha1/subnet_types.go | 2 +- pkg/apis/v1alpha1/subnetset_types.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/yaml/crd/nsx.vmware.com_subnets.yaml b/build/yaml/crd/nsx.vmware.com_subnets.yaml index fe7898881..4b3af9df8 100644 --- a/build/yaml/crd/nsx.vmware.com_subnets.yaml +++ b/build/yaml/crd/nsx.vmware.com_subnets.yaml @@ -128,7 +128,7 @@ spec: items: type: string type: array - networkAddreses: + networkAddresses: items: type: string type: array diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go index d84391965..47553cd10 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/subnet_types.go @@ -31,7 +31,7 @@ type SubnetSpec struct { // SubnetStatus defines the observed state of Subnet. type SubnetStatus struct { NSXResourcePath string `json:"nsxResourcePath,omitempty"` - NetworkAddresses []string `json:"networkAddreses,omitempty"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` GatewayAddresses []string `json:"gatewayAddresses,omitempty"` DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` Conditions []Condition `json:"conditions,omitempty"` diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go index 23df555bb..3d8883355 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/subnetset_types.go @@ -24,7 +24,7 @@ type SubnetSetSpec struct { // SubnetInfo defines the observed state of a single Subnet of a SubnetSet. type SubnetInfo struct { - NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NSXResourcePath string `json:"nsxResourcePath,omitempty"` NetworkAddresses []string `json:"networkAddresses,omitempty"` GatewayAddresses []string `json:"gatewayAddresses,omitempty"` DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` diff --git a/pkg/apis/v1alpha1/subnet_types.go b/pkg/apis/v1alpha1/subnet_types.go index d84391965..47553cd10 100644 --- a/pkg/apis/v1alpha1/subnet_types.go +++ b/pkg/apis/v1alpha1/subnet_types.go @@ -31,7 +31,7 @@ type SubnetSpec struct { // SubnetStatus defines the observed state of Subnet. type SubnetStatus struct { NSXResourcePath string `json:"nsxResourcePath,omitempty"` - NetworkAddresses []string `json:"networkAddreses,omitempty"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` GatewayAddresses []string `json:"gatewayAddresses,omitempty"` DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` Conditions []Condition `json:"conditions,omitempty"` diff --git a/pkg/apis/v1alpha1/subnetset_types.go b/pkg/apis/v1alpha1/subnetset_types.go index 23df555bb..3d8883355 100644 --- a/pkg/apis/v1alpha1/subnetset_types.go +++ b/pkg/apis/v1alpha1/subnetset_types.go @@ -24,7 +24,7 @@ type SubnetSetSpec struct { // SubnetInfo defines the observed state of a single Subnet of a SubnetSet. type SubnetInfo struct { - NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NSXResourcePath string `json:"nsxResourcePath,omitempty"` NetworkAddresses []string `json:"networkAddresses,omitempty"` GatewayAddresses []string `json:"gatewayAddresses,omitempty"` DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` From d1b2a542fc80d05294e4e3350dd0241f7b792a7b Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Mon, 1 Jul 2024 15:24:31 +0800 Subject: [PATCH 11/23] Sync with the latest vsphere-automation-sdk-go Signed-off-by: Xie Zheng --- go.mod | 10 +++++++--- go.sum | 18 ++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 0fd988151..bc94941b3 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,11 @@ replace ( github.com/vmware-tanzu/nsx-operator/pkg/apis => ./pkg/apis github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1 => ./pkg/apis/v1alpha1 github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2 => ./pkg/apis/v1alpha2 - github.com/vmware-tanzu/nsx-operator/pkg/client => ./pkg/client + github.com/vmware-tanzu/nsx-operator/pkg/client => ./pkg/client + github.com/vmware/vsphere-automation-sdk-go/lib => github.com/zhengxiexie/vsphere-automation-sdk-go/lib v0.7.3-0.20240628090521-3ad1af047210 + github.com/vmware/vsphere-automation-sdk-go/runtime => github.com/zhengxiexie/vsphere-automation-sdk-go/runtime v0.7.3-0.20240628090521-3ad1af047210 + github.com/vmware/vsphere-automation-sdk-go/services/nsxt => github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt v0.12.3-0.20240628090521-3ad1af047210 + github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp => github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt-mp v0.6.3-0.20240628090521-3ad1af047210 ) require ( @@ -14,6 +18,7 @@ require ( github.com/apparentlymart/go-cidr v1.1.0 github.com/deckarep/golang-set v1.8.0 github.com/go-logr/logr v1.3.0 + github.com/go-logr/zapr v1.2.4 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 @@ -28,7 +33,7 @@ require ( github.com/vmware-tanzu/vm-operator/api v1.8.2 github.com/vmware/govmomi v0.27.4 github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0 - github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0 + github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.1-0.20240611083326-25a4e1834c4d github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.12.0 github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.6.0 go.uber.org/automaxprocs v1.5.3 @@ -53,7 +58,6 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gibson042/canonicaljson-go v1.0.3 // indirect - github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect diff --git a/go.sum b/go.sum index e9a5b9a89..d9138e776 100644 --- a/go.sum +++ b/go.sum @@ -177,24 +177,22 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240102061654-537b080e159f h1:EV4eiUQr3QpUGfTtqdVph0+bmE+3cj0aNJpd9n2qTdo= -github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240102061654-537b080e159f/go.mod h1:dzob8tUzpAREQPtbbjQs4b1UyQDR37B2TiIdg8WJSRM= github.com/vmware-tanzu/vm-operator/api v1.8.2 h1:7cZHVusqAmAMFWvsiU7X5xontxdjasknI/sVfe0p0Z4= github.com/vmware-tanzu/vm-operator/api v1.8.2/go.mod h1:vauVboD3sQxP+pb28TnI9wfrj+0nH2zSEc9Q7AzWJ54= 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/vmware/vsphere-automation-sdk-go/lib v0.7.0 h1:pT+oqJ8FD5eUBQkl+e7LZwwtbwPvW5kDyyGXvt66gOM= -github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0/go.mod h1:f3+6YVZpNcK2pYyiQ94BoHWmjMj9BnYav0vNFuTiDVM= -github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0 h1:pSBxa9Agh6bgW8Hr0A1eQxuwnxGTnuAVox8iQb023hg= -github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0/go.mod h1:qdzEFm2iK3dvlmm99EYYNxs70HbzuiHyENFD24Ps8fQ= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.12.0 h1:+kcDO69bfIB87KZUAYQ4AqrXlnZhpZz+QwzIB+TseqU= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.12.0/go.mod h1:upLH9b9zpG86P0wwO4+gREf0lBXr8gYcs7P1FRZ9n30= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.6.0 h1:+jS0YH9dEp8rC00SsaY5feFpVgp4Lu0YBnBe3T7zfqo= -github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.6.0/go.mod h1:ugk9I4YM62SSAox57l5NAVBCRIkPQ1RNLb3URxyTADc= 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= +github.com/zhengxiexie/vsphere-automation-sdk-go/lib v0.7.3-0.20240628090521-3ad1af047210 h1:ZdoS46cHwnmPh4bs6OxlllI6PX92Z4a3qm428s4f93c= +github.com/zhengxiexie/vsphere-automation-sdk-go/lib v0.7.3-0.20240628090521-3ad1af047210/go.mod h1:CNBmjJmN8Mja3FRhLN4q6n9qhiBfxvq3Uij8t7r6370= +github.com/zhengxiexie/vsphere-automation-sdk-go/runtime v0.7.3-0.20240628090521-3ad1af047210 h1:vYtG51i9JqSO06oJlDa23riTvMP2ppnQ72FdhoJVtGQ= +github.com/zhengxiexie/vsphere-automation-sdk-go/runtime v0.7.3-0.20240628090521-3ad1af047210/go.mod h1:DzLetYAmw1+vj7bqElRWEpuy40WYE/woL3alsymYa/c= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt v0.12.3-0.20240628090521-3ad1af047210 h1:sclbs9AnzZ6gb8apIUQJI5rqx/SixhoCAu5O1mUcxoY= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt v0.12.3-0.20240628090521-3ad1af047210/go.mod h1:RACl1XoB+anHOOgmYjM72zJAKOtr1gNkx2u+ZLt93D8= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt-mp v0.6.3-0.20240628090521-3ad1af047210 h1:34H/XVcNwNYrkdcBNrqOC298XL17idkjvp1kr5HWoHc= +github.com/zhengxiexie/vsphere-automation-sdk-go/services/nsxt-mp v0.6.3-0.20240628090521-3ad1af047210/go.mod h1:ur/ob18hNxdaK42eug61vyiq7rbLQJhnOngdQSvgr54= go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= From acaab9881f84e0aa31cdd9fd8cfc046042c6b3c8 Mon Sep 17 00:00:00 2001 From: Wenying Dong Date: Mon, 8 Jul 2024 14:46:50 +0800 Subject: [PATCH 12/23] [CRD] Add field vpcPath in VPCNetworkConfiguration --- .../crd/nsx.vmware.com_vpcnetworkconfigurations.yaml | 5 +++++ .../samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml | 10 ++++++++++ .../v1alpha1/vpcnetworkconfiguration_types.go | 5 +++++ pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go | 5 +++++ 4 files changed, 25 insertions(+) diff --git a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml index 23b96a849..9589a5af9 100644 --- a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml +++ b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml @@ -94,6 +94,11 @@ spec: context in logs. Less than or equal to 8 characters. maxLength: 8 type: string + vpc: + description: NSX path of the VPC the Namespace associated with. If + vpc is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + take effect, other fields are ignored. + type: string type: object status: description: VPCNetworkConfigurationStatus defines the observed state diff --git a/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml b/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml index c19703c2f..cba5a787f 100644 --- a/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml +++ b/build/yaml/samples/nsx_v1alpha1_vpcnetworkconfigurations.yaml @@ -13,3 +13,13 @@ spec: - 172.26.0.0/16 - 172.36.0.0/16 defaultSubnetAccessMode: Private +--- +# Sample to create VPCNetworkConfiguration CR using a pre-created NSX VPC. +apiVersion: nsx.vmware.com/v1alpha1 +kind: VPCNetworkConfiguration +metadata: + name: vpc-network-config-with-pre-created-vpc +spec: + vpc: /orgs/default/projects/proj-1/vpcs/vpc-1 + defaultIPv4SubnetSize: 28 + defaultSubnetAccessMode: Private diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go index 9ba4babbc..23355f5f9 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go @@ -46,6 +46,11 @@ type VPCNetworkConfigurationSpec struct { // +kubebuilder:validation:MaxLength=8 // +optional ShortID string `json:"shortID,omitempty"` + // NSX path of the VPC the Namespace associated with. + // If vpc is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + // take effect, other fields are ignored. + // +optional + VPC string `json:"vpc,omitempty"` } // VPCNetworkConfigurationStatus defines the observed state of VPCNetworkConfiguration diff --git a/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go index 9ba4babbc..23355f5f9 100644 --- a/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go +++ b/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go @@ -46,6 +46,11 @@ type VPCNetworkConfigurationSpec struct { // +kubebuilder:validation:MaxLength=8 // +optional ShortID string `json:"shortID,omitempty"` + // NSX path of the VPC the Namespace associated with. + // If vpc is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + // take effect, other fields are ignored. + // +optional + VPC string `json:"vpc,omitempty"` } // VPCNetworkConfigurationStatus defines the observed state of VPCNetworkConfiguration From 8573d720ba22e77f4a3a92123389d5d4996b7968 Mon Sep 17 00:00:00 2001 From: Tao Zou Date: Wed, 10 Jul 2024 10:11:09 +0800 Subject: [PATCH 13/23] Get path info from store while deleting staticroute In previous version, controller tried to get org/project/vpc info from vpc service. But vpc service may delete vpc before staticroute. Read org/project/vpc from staticroute path --- .../staticroute/staticroute_controller.go | 2 +- .../staticroute/staticroute_controller_test.go | 10 +++++----- pkg/nsx/services/staticroute/staticroute.go | 14 ++++++++++---- pkg/nsx/services/staticroute/staticroute_test.go | 16 ++++++---------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/pkg/controllers/staticroute/staticroute_controller.go b/pkg/controllers/staticroute/staticroute_controller.go index c358f0160..dc247c0f4 100644 --- a/pkg/controllers/staticroute/staticroute_controller.go +++ b/pkg/controllers/staticroute/staticroute_controller.go @@ -113,7 +113,7 @@ func (r *StaticRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) if controllerutil.ContainsFinalizer(obj, commonservice.StaticRouteFinalizerName) { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeStaticRoute) // TODO, update the value from 'default' to actual value, get OrgID, ProjectID, VPCID depending on obj.Namespace from vpc store - if err := r.Service.DeleteStaticRoute(req.Namespace, string(obj.UID)); err != nil { + if err := r.Service.DeleteStaticRoute(string(obj.UID)); err != nil { log.Error(err, "delete failed, would retry exponentially", "staticroute", req.NamespacedName) deleteFail(r, &ctx, obj, &err) return ResultRequeue, err diff --git a/pkg/controllers/staticroute/staticroute_controller_test.go b/pkg/controllers/staticroute/staticroute_controller_test.go index 925cfc46e..cd82388b5 100644 --- a/pkg/controllers/staticroute/staticroute_controller_test.go +++ b/pkg/controllers/staticroute/staticroute_controller_test.go @@ -205,7 +205,7 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { return nil }) - patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, uid string) error { assert.FailNow(t, "should not be called") return nil }) @@ -223,7 +223,7 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { v1sp.Finalizers = []string{common.StaticRouteFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, uid string) error { return nil }) _, ret = r.Reconcile(ctx, req) @@ -238,7 +238,7 @@ func TestStaticRouteReconciler_Reconcile(t *testing.T) { v1sp.Finalizers = []string{common.StaticRouteFinalizerName} return nil }) - patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, uid string) error { return errors.New("delete failed") }) @@ -333,7 +333,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { a = append(a, model.StaticRoutes{Id: &id, Tags: tag2}) return a }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, uid string) error { assert.FailNow(t, "should not be called") return nil }) @@ -351,7 +351,7 @@ func TestStaticRouteReconciler_GarbageCollector(t *testing.T) { patch.ApplyMethod(reflect.TypeOf(service), "ListStaticRoute", func(_ *staticroute.StaticRouteService) []model.StaticRoutes { return []model.StaticRoutes{} }) - patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, namespace string, uid string) error { + patch.ApplyMethod(reflect.TypeOf(service), "DeleteStaticRoute", func(_ *staticroute.StaticRouteService, uid string) error { assert.FailNow(t, "should not be called") return nil }) diff --git a/pkg/nsx/services/staticroute/staticroute.go b/pkg/nsx/services/staticroute/staticroute.go index f0962ddd7..4b8c23e4f 100644 --- a/pkg/nsx/services/staticroute/staticroute.go +++ b/pkg/nsx/services/staticroute/staticroute.go @@ -14,6 +14,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" + "github.com/vmware-tanzu/nsx-operator/pkg/util" ) type StaticRouteService struct { @@ -134,12 +135,17 @@ func (service *StaticRouteService) GetUID(staticroute *model.StaticRoutes) *stri } -func (service *StaticRouteService) DeleteStaticRoute(namespace string, uid string) error { - vpc := service.VPCService.ListVPCInfo(namespace) - if len(vpc) == 0 { +func (service *StaticRouteService) DeleteStaticRoute(uid string) error { + id := String(util.GenerateID(uid, "sr", "", "")) + staticroute := service.StaticRouteStore.GetByKey(*id) + if staticroute == nil { return nil } - return service.DeleteStaticRouteByPath(vpc[0].OrgID, vpc[0].ProjectID, vpc[0].ID, uid) + vpcResourceInfo, err := common.ParseVPCResourcePath(*staticroute.Path) + if err != nil { + return err + } + return service.DeleteStaticRouteByPath(vpcResourceInfo.OrgID, vpcResourceInfo.ProjectID, vpcResourceInfo.ID, *id) } func (service *StaticRouteService) ListStaticRoute() []*model.StaticRoutes { diff --git a/pkg/nsx/services/staticroute/staticroute_test.go b/pkg/nsx/services/staticroute/staticroute_test.go index c66fe4757..a8f49123f 100644 --- a/pkg/nsx/services/staticroute/staticroute_test.go +++ b/pkg/nsx/services/staticroute/staticroute_test.go @@ -128,25 +128,21 @@ func TestStaticRouteService_DeleteStaticRoute(t *testing.T) { t.Error(err) } - id := "vpc-1" - sr1 := &model.StaticRoutes{Id: &id} + uid := "uid-123" + id := "sr_uid-123" + path := "/orgs/default/projects/project-1/vpcs/vpc-1" + sr1 := &model.StaticRoutes{Id: &id, Path: &path} returnservice.StaticRouteStore.Add(sr1) - patches := gomonkey.ApplyMethod(reflect.TypeOf(returnservice.VPCService), "ListVPCInfo", func(_ common.VPCServiceProvider, ns string) []common.VPCResourceInfo { - id := "vpc-1" - return []common.VPCResourceInfo{{OrgID: "default", ProjectID: "project-1", VPCID: "vpc-1", ID: id}} - }) - // no record found mockStaticRouteclient.EXPECT().Delete(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Times(0) - err = returnservice.DeleteStaticRoute("123", "vpc1") + err = returnservice.DeleteStaticRoute(id) assert.Equal(t, err, nil) - defer patches.Reset() // delete record mockStaticRouteclient.EXPECT().Delete("default", "project-1", "vpc-1", id).Return(nil).Times(1) - err = returnservice.DeleteStaticRoute("123", id) + err = returnservice.DeleteStaticRoute(uid) assert.Equal(t, err, nil) srs := returnservice.StaticRouteStore.List() assert.Equal(t, len(srs), 0) From c52e7ce3e339c83deea3707f7b8284a7f5cb1915 Mon Sep 17 00:00:00 2001 From: Wenqi Qiu Date: Fri, 12 Jul 2024 10:05:00 +0800 Subject: [PATCH 14/23] Update controller-gen version to 0.14 Signed-off-by: Wenqi Qiu --- Makefile | 2 +- build/yaml/crd/nsx.vmware.com_ippools.yaml | 63 ++-- .../yaml/crd/nsx.vmware.com_networkinfos.yaml | 20 +- .../nsx.vmware.com_nsxserviceaccounts.yaml | 84 +++-- .../crd/nsx.vmware.com_securitypolicies.yaml | 353 +++++++++--------- .../yaml/crd/nsx.vmware.com_staticroutes.yaml | 28 +- .../yaml/crd/nsx.vmware.com_subnetports.yaml | 28 +- build/yaml/crd/nsx.vmware.com_subnets.yaml | 28 +- build/yaml/crd/nsx.vmware.com_subnetsets.yaml | 28 +- ...x.vmware.com_vpcnetworkconfigurations.yaml | 46 ++- .../v1alpha1/zz_generated.deepcopy.go | 186 ++++----- .../v1alpha2/zz_generated.deepcopy.go | 1 - pkg/apis/v1alpha1/zz_generated.deepcopy.go | 186 ++++----- pkg/apis/v1alpha2/zz_generated.deepcopy.go | 1 - 14 files changed, 550 insertions(+), 504 deletions(-) diff --git a/Makefile b/Makefile index 643127c06..ab698bf39 100644 --- a/Makefile +++ b/Makefile @@ -146,7 +146,7 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi CONTROLLER_GEN = $(shell pwd)/bin/controller-gen .PHONY: controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.0) + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0) KUSTOMIZE = $(shell pwd)/bin/kustomize .PHONY: kustomize diff --git a/build/yaml/crd/nsx.vmware.com_ippools.yaml b/build/yaml/crd/nsx.vmware.com_ippools.yaml index e6cf505c4..7656d50b6 100644 --- a/build/yaml/crd/nsx.vmware.com_ippools.yaml +++ b/build/yaml/crd/nsx.vmware.com_ippools.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: ippools.nsx.vmware.com spec: group: nsx.vmware.com @@ -21,14 +20,19 @@ spec: description: IPPool is the Schema for the ippools API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -42,8 +46,9 @@ spec: properties: ipFamily: default: IPv4 - description: IPFamily defines the IP family type for this subnet, - could be IPv4 or IPv6. This is optional, the default is IPv4. + description: |- + IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. + This is optional, the default is IPv4. enum: - IPv4 - IPv6 @@ -68,10 +73,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: @@ -134,14 +139,19 @@ spec: description: IPPool is the Schema for the ippools API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -155,8 +165,9 @@ spec: properties: ipFamily: default: IPv4 - description: IPFamily defines the IP family type for this subnet, - could be IPv4 or IPv6. This is optional, the default is IPv4. + description: |- + IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. + This is optional, the default is IPv4. enum: - IPv4 - IPv6 @@ -187,10 +198,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_networkinfos.yaml b/build/yaml/crd/nsx.vmware.com_networkinfos.yaml index c8aa22ab5..165830583 100644 --- a/build/yaml/crd/nsx.vmware.com_networkinfos.yaml +++ b/build/yaml/crd/nsx.vmware.com_networkinfos.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: networkinfos.nsx.vmware.com spec: group: nsx.vmware.com @@ -21,14 +20,19 @@ spec: description: NetworkInfo is used to report the network information for a namespace. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object diff --git a/build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml b/build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml index 050ca15c3..b29d33835 100644 --- a/build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml +++ b/build/yaml/crd/nsx.vmware.com_nsxserviceaccounts.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: nsxserviceaccounts.nsx.vmware.com spec: group: nsx.vmware.com @@ -21,14 +20,19 @@ spec: description: NSXServiceAccount is the Schema for the nsxserviceaccounts API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -50,46 +54,47 @@ spec: clusterName: type: string conditions: - description: 'Represents the realization status of a NSXServiceAccount''s - current state. Known .status.conditions.type is: "Realized"' + description: |- + Represents the realization status of a NSXServiceAccount's current state. + Known .status.conditions.type is: "Realized" items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -103,11 +108,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/build/yaml/crd/nsx.vmware.com_securitypolicies.yaml b/build/yaml/crd/nsx.vmware.com_securitypolicies.yaml index 188b90a70..d93dc4c2a 100644 --- a/build/yaml/crd/nsx.vmware.com_securitypolicies.yaml +++ b/build/yaml/crd/nsx.vmware.com_securitypolicies.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: securitypolicies.nsx.vmware.com spec: group: nsx.vmware.com @@ -21,14 +20,19 @@ spec: description: SecurityPolicy is the Schema for the securitypolicies API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -36,7 +40,8 @@ spec: description: SecurityPolicySpec defines the desired state of SecurityPolicy. properties: appliedTo: - description: AppliedTo is a list of policy targets to apply rules. + description: |- + AppliedTo is a list of policy targets to apply rules. Policy level 'Applied To' will take precedence over rule level. items: description: SecurityPolicyTarget defines the target endpoints to @@ -49,25 +54,25 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -79,11 +84,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -94,25 +98,25 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -124,11 +128,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -149,8 +152,9 @@ spec: rule. type: string appliedTo: - description: AppliedTo is a list of rule targets. Policy level - 'Applied To' will take precedence over rule level. + description: |- + AppliedTo is a list of rule targets. + Policy level 'Applied To' will take precedence over rule level. items: description: SecurityPolicyTarget defines the target endpoints to apply SecurityPolicy. @@ -163,8 +167,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -172,17 +176,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -194,11 +197,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -210,8 +212,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -219,17 +221,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -241,11 +242,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -266,8 +266,9 @@ spec: by an AppliedTo. properties: cidr: - description: CIDR is a string representing the IP - Block. A valid example is "192.168.1.1/24". + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". type: string required: - cidr @@ -281,8 +282,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -290,17 +291,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -312,11 +312,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -328,8 +327,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -337,17 +336,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -359,11 +357,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -375,8 +372,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -384,17 +381,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -406,11 +402,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -440,8 +435,9 @@ spec: x-kubernetes-int-or-string: true protocol: default: TCP - description: Protocol(TCP, UDP) is the protocol to match - traffic. It is TCP by default. + description: |- + Protocol(TCP, UDP) is the protocol to match traffic. + It is TCP by default. type: string type: object type: array @@ -460,8 +456,9 @@ spec: by an AppliedTo. properties: cidr: - description: CIDR is a string representing the IP - Block. A valid example is "192.168.1.1/24". + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". type: string required: - cidr @@ -475,8 +472,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -484,17 +481,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -506,11 +502,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -522,8 +517,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -531,17 +526,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -553,11 +547,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -569,8 +562,8 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -578,17 +571,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -600,11 +592,10 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic @@ -625,10 +616,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_staticroutes.yaml b/build/yaml/crd/nsx.vmware.com_staticroutes.yaml index b53ef56e7..9837d7b18 100644 --- a/build/yaml/crd/nsx.vmware.com_staticroutes.yaml +++ b/build/yaml/crd/nsx.vmware.com_staticroutes.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: staticroutes.nsx.vmware.com spec: group: nsx.vmware.com @@ -30,14 +29,19 @@ spec: description: StaticRoute is the Schema for the staticroutes API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -74,10 +78,10 @@ spec: description: StaticRouteCondition defines condition of StaticRoute. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_subnetports.yaml b/build/yaml/crd/nsx.vmware.com_subnetports.yaml index 60e241516..0072b9348 100644 --- a/build/yaml/crd/nsx.vmware.com_subnetports.yaml +++ b/build/yaml/crd/nsx.vmware.com_subnetports.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: subnetports.nsx.vmware.com spec: group: nsx.vmware.com @@ -34,14 +33,19 @@ spec: description: SubnetPort is the Schema for the subnetports API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -70,10 +74,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_subnets.yaml b/build/yaml/crd/nsx.vmware.com_subnets.yaml index 4b3af9df8..378566315 100644 --- a/build/yaml/crd/nsx.vmware.com_subnets.yaml +++ b/build/yaml/crd/nsx.vmware.com_subnets.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: subnets.nsx.vmware.com spec: group: nsx.vmware.com @@ -34,14 +33,19 @@ spec: description: Subnet is the Schema for the subnets API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -101,10 +105,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_subnetsets.yaml b/build/yaml/crd/nsx.vmware.com_subnetsets.yaml index 912d1a93b..19433a202 100644 --- a/build/yaml/crd/nsx.vmware.com_subnetsets.yaml +++ b/build/yaml/crd/nsx.vmware.com_subnetsets.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: subnetsets.nsx.vmware.com spec: group: nsx.vmware.com @@ -34,14 +33,19 @@ spec: description: SubnetSet is the Schema for the subnetsets API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -90,10 +94,10 @@ spec: description: Condition defines condition of custom resource. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: diff --git a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml index 23b96a849..09d187b94 100644 --- a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml +++ b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: vpcnetworkconfigurations.nsx.vmware.com spec: group: nsx.vmware.com @@ -35,35 +34,43 @@ spec: API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object spec: - description: VPCNetworkConfigurationSpec defines the desired state of - VPCNetworkConfiguration. There is a default VPCNetworkConfiguration - that applies to Namespaces do not have a VPCNetworkConfiguration assigned. - When a field is not set in a Namespace's VPCNetworkConfiguration, the - Namespace will use the value in the default VPCNetworkConfiguration. + description: |- + VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. + There is a default VPCNetworkConfiguration that applies to Namespaces + do not have a VPCNetworkConfiguration assigned. When a field is not set + in a Namespace's VPCNetworkConfiguration, the Namespace will use the value + in the default VPCNetworkConfiguration. properties: defaultGatewayPath: description: PolicyPath of Tier0 or Tier0 VRF gateway. type: string defaultIPv4SubnetSize: default: 26 - description: Default size of Subnet based upon estimated workload - count. Defaults to 26. + description: |- + Default size of Subnet based upon estimated workload count. + Defaults to 26. type: integer defaultSubnetAccessMode: - description: DefaultSubnetAccessMode defines the access mode of the - default SubnetSet for PodVM and VM. Must be Public or Private. + description: |- + DefaultSubnetAccessMode defines the access mode of the default SubnetSet for PodVM and VM. + Must be Public or Private. enum: - Public - Private @@ -90,8 +97,9 @@ spec: minItems: 0 type: array shortID: - description: ShortID specifies Identifier to use when displaying VPC - context in logs. Less than or equal to 8 characters. + description: |- + ShortID specifies Identifier to use when displaying VPC context in logs. + Less than or equal to 8 characters. maxLength: 8 type: string type: object diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go index 5919f2d28..63704edcd 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ @@ -80,6 +79,102 @@ func (in *DNSClientConfig) DeepCopy() *DNSClientConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. +func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { + if in == nil { + return nil + } + out := new(IPAddressAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPAddressAllocation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. +func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { + if in == nil { + return nil + } + out := new(IPAddressAllocationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. +func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { + if in == nil { + return nil + } + out := new(IPAddressAllocationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. +func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { + if in == nil { + return nil + } + out := new(IPAddressAllocationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IPBlock) DeepCopyInto(out *IPBlock) { *out = *in @@ -1395,92 +1490,3 @@ func (in *VPCState) DeepCopy() *VPCState { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. -func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { - if in == nil { - return nil - } - out := new(IPAddressAllocation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]IPAddressAllocation, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. -func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { - if in == nil { - return nil - } - out := new(IPAddressAllocationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. -func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { - if in == nil { - return nil - } - out := new(IPAddressAllocationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. -func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { - if in == nil { - return nil - } - out := new(IPAddressAllocationStatus) - in.DeepCopyInto(out) - return out -} \ No newline at end of file diff --git a/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go index 718fa64e9..fc55d8d0d 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go index 5919f2d28..63704edcd 100644 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ @@ -80,6 +79,102 @@ func (in *DNSClientConfig) DeepCopy() *DNSClientConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. +func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { + if in == nil { + return nil + } + out := new(IPAddressAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPAddressAllocation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. +func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { + if in == nil { + return nil + } + out := new(IPAddressAllocationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. +func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { + if in == nil { + return nil + } + out := new(IPAddressAllocationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. +func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { + if in == nil { + return nil + } + out := new(IPAddressAllocationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IPBlock) DeepCopyInto(out *IPBlock) { *out = *in @@ -1395,92 +1490,3 @@ func (in *VPCState) DeepCopy() *VPCState { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. -func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { - if in == nil { - return nil - } - out := new(IPAddressAllocation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]IPAddressAllocation, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. -func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { - if in == nil { - return nil - } - out := new(IPAddressAllocationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. -func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { - if in == nil { - return nil - } - out := new(IPAddressAllocationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. -func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { - if in == nil { - return nil - } - out := new(IPAddressAllocationStatus) - in.DeepCopyInto(out) - return out -} \ No newline at end of file diff --git a/pkg/apis/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/v1alpha2/zz_generated.deepcopy.go index 718fa64e9..fc55d8d0d 100644 --- a/pkg/apis/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha2/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright © 2024 VMware, Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ From 4b98a10bf99595c35a23bd10529580df64db657a Mon Sep 17 00:00:00 2001 From: Tao Zou Date: Thu, 18 Jul 2024 15:14:37 +0800 Subject: [PATCH 15/23] Add support for PrincipalIdentity Add support for PrincipalIdentity. Log unsupported type. Return error if CasttoPointer result is nil. --- pkg/nsx/services/common/store.go | 3 +++ pkg/nsx/util/utils.go | 5 +++++ pkg/nsx/util/utils_test.go | 36 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/pkg/nsx/services/common/store.go b/pkg/nsx/services/common/store.go index 6854bcb3e..4d5c7153a 100644 --- a/pkg/nsx/services/common/store.go +++ b/pkg/nsx/services/common/store.go @@ -51,6 +51,9 @@ func (resourceStore *ResourceStore) TransResourceToStore(entity *data.StructValu } } objAddr := nsxutil.CasttoPointer(obj) + if objAddr == nil { + return fmt.Errorf("failed to cast to pointer") + } err2 := resourceStore.Add(objAddr) if err2 != nil { return err2 diff --git a/pkg/nsx/util/utils.go b/pkg/nsx/util/utils.go index 2c26f18d4..d9d58745d 100644 --- a/pkg/nsx/util/utils.go +++ b/pkg/nsx/util/utils.go @@ -26,6 +26,7 @@ import ( apierrors "github.com/vmware/vsphere-automation-sdk-go/lib/vapi/std/errors" "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + mpmodel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -547,6 +548,8 @@ func FindTag(tags []model.Tag, tagScope string) string { func CasttoPointer(obj interface{}) interface{} { switch v := obj.(type) { + case mpmodel.PrincipalIdentity: + return &v case model.Rule: return &v case model.StaticRoutes: @@ -578,6 +581,8 @@ func CasttoPointer(obj interface{}) interface{} { case model.IpAddressBlock: return &v default: + objType := reflect.TypeOf(obj) + log.Info("Unsupported type", "objType", objType) return nil } } diff --git a/pkg/nsx/util/utils_test.go b/pkg/nsx/util/utils_test.go index 782b6c2f4..3428bc8c6 100644 --- a/pkg/nsx/util/utils_test.go +++ b/pkg/nsx/util/utils_test.go @@ -15,10 +15,13 @@ import ( "net/http" "net/http/httptest" "net/url" + "reflect" "strings" "testing" "github.com/stretchr/testify/assert" + mpmodel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" ) func TestHttpErrortoNSXError(t *testing.T) { @@ -510,3 +513,36 @@ Hce3uM6Xn8sAglod/r+0onZ09yoiH2Qj5EY50wUIOPtey2ilhuhwoo/M7Nt/yomF header = CertPemBytesToHeader("/tmp/test.pem") assert.Equal(t, "", header) } + +func TestCasttoPointer(t *testing.T) { + tests := []struct { + name string + obj interface{} + want interface{} + }{ + { + name: "PrincipalIdentity", + obj: mpmodel.PrincipalIdentity{}, + want: &mpmodel.PrincipalIdentity{}, + }, + { + name: "Rule", + obj: model.Rule{}, + want: &model.Rule{}, + }, + // Add more test cases for other types + { + name: "UnsupportedType", + obj: model.Tag{}, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := CasttoPointer(tt.obj); !reflect.DeepEqual(got, tt.want) { + t.Errorf("CasttoPointer() = %v, want %v", got, tt.want) + } + }) + } +} From c46325e6fe2ab77d2f60bd392f2fb8ae3d92b5dc Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Thu, 16 May 2024 11:09:22 +0800 Subject: [PATCH 16/23] Implement ipaddressallocation controller Signed-off-by: Xie Zheng --- .../nsx.vmware.com_ipaddressallocations.yaml | 4 +- .../nsx_v1alpha1_ipaddressallocation.yaml | 4 +- cmd/main.go | 22 ++ .../v1alpha1/ipaddressallocation_types.go | 4 +- .../v1alpha1/ipaddressallocation_types.go | 9 +- pkg/controllers/common/types.go | 29 +- .../ipaddressallocation_controller.go | 217 +++++++++++++ .../ipaddressallocation_controller_test.go | 301 ++++++++++++++++++ .../nsxserviceaccount_controller_test.go | 3 +- pkg/nsx/client.go | 41 +-- pkg/nsx/services/common/types.go | 50 +-- .../services/ipaddressallocation/builder.go | 49 +++ .../ipaddressallocation/builder_test.go | 115 +++++++ .../services/ipaddressallocation/compare.go | 32 ++ .../ipaddressallocation/compare_test.go | 52 +++ .../ipaddressallocation.go | 199 ++++++++++++ pkg/nsx/services/ipaddressallocation/store.go | 90 ++++++ .../ipaddressallocation/store_test.go | 98 ++++++ pkg/util/utils.go | 4 + 19 files changed, 1253 insertions(+), 70 deletions(-) create mode 100644 pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go create mode 100644 pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go create mode 100644 pkg/nsx/services/ipaddressallocation/builder.go create mode 100644 pkg/nsx/services/ipaddressallocation/builder_test.go create mode 100644 pkg/nsx/services/ipaddressallocation/compare.go create mode 100644 pkg/nsx/services/ipaddressallocation/compare_test.go create mode 100644 pkg/nsx/services/ipaddressallocation/ipaddressallocation.go create mode 100644 pkg/nsx/services/ipaddressallocation/store.go create mode 100644 pkg/nsx/services/ipaddressallocation/store_test.go diff --git a/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml b/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml index 476fa42d6..8b0bff706 100644 --- a/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml +++ b/build/yaml/crd/nsx.vmware.com_ipaddressallocations.yaml @@ -54,12 +54,10 @@ spec: ip_address_block_visibility: default: Private description: IPAddressBlockVisibility specifies the visibility of - the IPBlocks to allocate IP addresses. Can be External, Private - or Project. + the IPBlocks to allocate IP addresses. Can be External or Private. enum: - External - Private - - Project type: string type: object status: diff --git a/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml b/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml index c56cebd7f..a1b7bf29a 100644 --- a/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml +++ b/build/yaml/samples/nsx_v1alpha1_ipaddressallocation.yaml @@ -5,6 +5,4 @@ metadata: namespace: sc-a spec: ip_address_block_visibility: Private - allocation_size: 26 -status: - CIDR: 172.26.1.0/28 \ No newline at end of file + allocation_size: 32 \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 1abec4603..8be859b89 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -20,6 +20,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha2" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/ipaddressallocation" "github.com/vmware-tanzu/nsx-operator/pkg/config" ippool2 "github.com/vmware-tanzu/nsx-operator/pkg/controllers/ippool" @@ -39,6 +40,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/metrics" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + ipaddressallocationservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ippool" nodeservice "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/node" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/nsxserviceaccount" @@ -147,6 +149,21 @@ func StartNamespaceController(mgr ctrl.Manager, cf *config.NSXOperatorConfig, vp } } +func StartIPAddressAllocationController(mgr ctrl.Manager, ipAddressAllocationService *ipaddressallocationservice.IPAddressAllocationService, vpcService common.VPCServiceProvider) { + ipAddressAllocationReconciler := &ipaddressallocation.IPAddressAllocationReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Service: ipAddressAllocationService, + VPCService: vpcService, + Recorder: mgr.GetEventRecorderFor("ipaddressallocation-controller"), + } + + if err := ipAddressAllocationReconciler.SetupWithManager(mgr); err != nil { + log.Error(err, "failed to create ipaddressallocation controller") + os.Exit(1) + } +} + func main() { log.Info("starting NSX Operator") mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ @@ -202,6 +219,10 @@ func main() { if err != nil { log.Error(err, "failed to initialize ippool commonService", "controller", "IPPool") } + ipAddressAllocationService, err := ipaddressallocationservice.InitializeIPAddressAllocation(commonService, vpcService) + if err != nil { + log.Error(err, "failed to initialize ipaddressallocation commonService", "controller", "IPAddressAllocation") + } subnetPortService, err := subnetportservice.InitializeSubnetPort(commonService) if err != nil { log.Error(err, "failed to initialize subnetport commonService", "controller", "SubnetPort") @@ -238,6 +259,7 @@ func main() { subnetport.StartSubnetPortController(mgr, subnetPortService, subnetService, vpcService) pod.StartPodController(mgr, subnetPortService, subnetService, vpcService, nodeService) StartIPPoolController(mgr, ipPoolService, vpcService) + StartIPAddressAllocationController(mgr, ipAddressAllocationService, vpcService) networkpolicycontroller.StartNetworkPolicyController(mgr, commonService, vpcService) service.StartServiceLbController(mgr, commonService) } diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go index 6a50925c5..5e6ff5905 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/ipaddressallocation_types.go @@ -42,8 +42,8 @@ type IPAddressAllocationList struct { // IPAddressAllocationSpec defines the desired state of IPAddressAllocation. type IPAddressAllocationSpec struct { - // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External, Private or Project. - // +kubebuilder:validation:Enum=External;Private;Project + // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External or Private. + // +kubebuilder:validation:Enum=External;Private // +kubebuilder:default=Private // +optional IPAddressBlockVisibility IPAddressVisibility `json:"ip_address_block_visibility,omitempty"` diff --git a/pkg/apis/v1alpha1/ipaddressallocation_types.go b/pkg/apis/v1alpha1/ipaddressallocation_types.go index 6a50925c5..4c50d0e2d 100644 --- a/pkg/apis/v1alpha1/ipaddressallocation_types.go +++ b/pkg/apis/v1alpha1/ipaddressallocation_types.go @@ -10,9 +10,8 @@ import ( type IPAddressVisibility string const ( - IPAddressVisibilityExternal = "External" - IPAddressVisibilityPrivate = "Private" - IPAddressVisibilityProject = "Project" + IPAddressVisibilityExternal = "EXTERNAL" + IPAddressVisibilityPrivate = "PRIVATE" ) // +genclient @@ -42,8 +41,8 @@ type IPAddressAllocationList struct { // IPAddressAllocationSpec defines the desired state of IPAddressAllocation. type IPAddressAllocationSpec struct { - // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External, Private or Project. - // +kubebuilder:validation:Enum=External;Private;Project + // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External or Private. + // +kubebuilder:validation:Enum=External;Private // +kubebuilder:default=Private // +optional IPAddressBlockVisibility IPAddressVisibility `json:"ip_address_block_visibility,omitempty"` diff --git a/pkg/controllers/common/types.go b/pkg/controllers/common/types.go index e5c8a4392..f0a9c6158 100644 --- a/pkg/controllers/common/types.go +++ b/pkg/controllers/common/types.go @@ -8,20 +8,21 @@ import ( ) const ( - MetricResTypeSecurityPolicy = "securitypolicy" - MetricResTypeNetworkPolicy = "networkpolicy" - MetricResTypeIPPool = "ippool" - MetricResTypeNSXServiceAccount = "nsxserviceaccount" - MetricResTypeSubnetPort = "subnetport" - MetricResTypeStaticRoute = "staticroute" - MetricResTypeSubnet = "subnet" - MetricResTypeSubnetSet = "subnetset" - MetricResTypeNetworkInfo = "networkinfo" - MetricResTypeNamespace = "namespace" - MetricResTypePod = "pod" - MetricResTypeNode = "node" - MetricResTypeServiceLb = "servicelb" - MaxConcurrentReconciles = 8 + MetricResTypeSecurityPolicy = "securitypolicy" + MetricResTypeNetworkPolicy = "networkpolicy" + MetricResTypeIPPool = "ippool" + MetricResTypeIPAddressAllocation = "ipaddressallocation" + MetricResTypeNSXServiceAccount = "nsxserviceaccount" + MetricResTypeSubnetPort = "subnetport" + MetricResTypeStaticRoute = "staticroute" + MetricResTypeSubnet = "subnet" + MetricResTypeSubnetSet = "subnetset" + MetricResTypeNetworkInfo = "networkinfo" + MetricResTypeNamespace = "namespace" + MetricResTypePod = "pod" + MetricResTypeNode = "node" + MetricResTypeServiceLb = "servicelb" + MaxConcurrentReconciles = 8 LabelK8sMasterRole = "node-role.kubernetes.io/master" LabelK8sControlRole = "node-role.kubernetes.io/control-plane" diff --git a/pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go new file mode 100644 index 000000000..031765295 --- /dev/null +++ b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller.go @@ -0,0 +1,217 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package ipaddressallocation + +import ( + "context" + "fmt" + "sync" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apimachineryruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" + "github.com/vmware-tanzu/nsx-operator/pkg/logger" + "github.com/vmware-tanzu/nsx-operator/pkg/metrics" + servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" +) + +var ( + log = logger.Log + once sync.Once + resultNormal = common.ResultNormal + resultRequeue = common.ResultRequeue + MetricResType = common.MetricResTypeIPAddressAllocation +) + +// IPAddressAllocationReconciler reconciles a IPAddressAllocation object +type IPAddressAllocationReconciler struct { + client.Client + Scheme *apimachineryruntime.Scheme + Service *ipaddressallocation.IPAddressAllocationService + VPCService servicecommon.VPCServiceProvider + Recorder record.EventRecorder +} + +func deleteSuccess(r *IPAddressAllocationReconciler, _ *context.Context, o *v1alpha1.IPAddressAllocation) { + r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulDelete, "IPAddressAllocation CR has been successfully deleted") + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) +} + +func deleteFail(r *IPAddressAllocationReconciler, c *context.Context, o *v1alpha1.IPAddressAllocation, e *error) { + r.setReadyStatusFalse(c, o, metav1.Now(), e) + r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailDelete, fmt.Sprintf("%v", *e)) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) +} + +func updateSuccess(r *IPAddressAllocationReconciler, c *context.Context, o *v1alpha1.IPAddressAllocation) { + r.setReadyStatusTrue(c, o, metav1.Now()) + r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "IPAddressAllocation CR has been successfully updated") + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) +} + +func updateFail(r *IPAddressAllocationReconciler, c *context.Context, o *v1alpha1.IPAddressAllocation, e *error) { + r.setReadyStatusFalse(c, o, metav1.Now(), e) + r.Recorder.Event(o, v1.EventTypeWarning, common.ReasonFailUpdate, fmt.Sprintf("%v", *e)) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) +} + +func (r *IPAddressAllocationReconciler) setReadyStatusFalse(ctx *context.Context, ipaddressallocation *v1alpha1.IPAddressAllocation, transitionTime metav1.Time, err *error) { + conditions := []v1alpha1.Condition{ + { + Type: v1alpha1.Ready, + Status: v1.ConditionFalse, + Message: "NSX IPAddressAllocation could not be created or updated", + Reason: fmt.Sprintf( + "error occurred while processing the IPAddressAllocation CR. Error: %v", + *err, + ), + LastTransitionTime: transitionTime, + }, + } + ipaddressallocation.Status.Conditions = conditions + e := r.Client.Status().Update(*ctx, ipaddressallocation) + if e != nil { + log.Error(e, "unable to update IPAddressAllocation status", "IPAddressAllocation", ipaddressallocation) + } +} + +func (r *IPAddressAllocationReconciler) setReadyStatusTrue(ctx *context.Context, ipaddressallocation *v1alpha1.IPAddressAllocation, transitionTime metav1.Time) { + conditions := []v1alpha1.Condition{ + { + Type: v1alpha1.Ready, + Status: v1.ConditionTrue, + Message: "NSX IPAddressAllocation has been successfully created/updated", + Reason: "", + LastTransitionTime: transitionTime, + }, + } + ipaddressallocation.Status.Conditions = conditions + e := r.Client.Status().Update(*ctx, ipaddressallocation) + if e != nil { + log.Error(e, "unable to update IPAddressAllocation status", "IPAddressAllocation", ipaddressallocation) + } +} + +func (r *IPAddressAllocationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + once.Do(func() { go common.GenericGarbageCollector(make(chan bool), servicecommon.GCInterval, r.collectGarbage) }) + obj := &v1alpha1.IPAddressAllocation{} + log.Info("reconciling IPAddressAllocation CR", "IPAddressAllocation", req.NamespacedName) + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + log.Error(err, "unable to fetch IPAddressAllocation CR", "req", req.NamespacedName) + return resultNormal, client.IgnoreNotFound(err) + } + if obj.ObjectMeta.DeletionTimestamp.IsZero() { + return r.handleUpdate(ctx, req, obj) + } + return r.handleDeletion(ctx, req, obj) +} + +func (r *IPAddressAllocationReconciler) handleUpdate(ctx context.Context, req ctrl.Request, obj *v1alpha1.IPAddressAllocation) (ctrl.Result, error) { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType) + if !controllerutil.ContainsFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) { + controllerutil.AddFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) + if err := r.Client.Update(ctx, obj); err != nil { + log.Error(err, "add finalizer", "IPAddressAllocation", req.NamespacedName) + updateFail(r, &ctx, obj, &err) + return resultRequeue, err + } + log.V(1).Info("added finalizer on IPAddressAllocation CR", "IPAddressAllocation", req.NamespacedName) + } + + updated, err := r.Service.CreateOrUpdateIPAddressAllocation(obj) + if err != nil { + updateFail(r, &ctx, obj, &err) + return resultRequeue, err + } + if updated { + updateSuccess(r, &ctx, obj) + } + return resultNormal, nil +} + +func (r *IPAddressAllocationReconciler) handleDeletion(ctx context.Context, req ctrl.Request, obj *v1alpha1.IPAddressAllocation) (ctrl.Result, error) { + if controllerutil.ContainsFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) { + metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) + if err := r.Service.DeleteIPAddressAllocation(obj); err != nil { + log.Error(err, "deletion failed, would retry exponentially", "IPAddressAllocation", req.NamespacedName) + deleteFail(r, &ctx, obj, &err) + return resultRequeue, err + } + controllerutil.RemoveFinalizer(obj, servicecommon.IPAddressAllocationFinalizerName) + if err := r.Client.Update(ctx, obj); err != nil { + log.Error(err, "deletion failed, would retry exponentially", "IPAddressAllocation", req.NamespacedName) + deleteFail(r, &ctx, obj, &err) + return resultRequeue, err + } + log.V(1).Info("removed finalizer on IPAddressAllocation CR", "IPAddressAllocation", req.NamespacedName) + deleteSuccess(r, &ctx, obj) + log.Info("successfully deleted IPAddressAllocation CR and all subnets", "IPAddressAllocation", obj) + } else { + // only print a message because it's not a normal case + log.Info("IPAddressAllocation CR is being deleted but its finalizers cannot be recognized", "IPAddressAllocation", req.NamespacedName) + } + return resultNormal, nil +} + +func (r *IPAddressAllocationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.IPAddressAllocation{}). + WithEventFilter(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + // Ignore updates to CR status in which case metadata.Generation does not change + return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration() + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // Suppress Delete events to avoid filtering them out in the Reconcile function + return false + }, + }). + WithOptions( + controller.Options{ + MaxConcurrentReconciles: common.NumReconcile(), + }). + Complete(r) +} + +func (r *IPAddressAllocationReconciler) collectGarbage(ctx context.Context) { + log.Info("IPAddressAllocation garbage collector started") + ipAddressAllocationSet := r.Service.ListIPAddressAllocationID() + if len(ipAddressAllocationSet) == 0 { + return + } + + ipAddressAllocationList := &v1alpha1.IPAddressAllocationList{} + if err := r.Client.List(ctx, ipAddressAllocationList); err != nil { + log.Error(err, "failed to list IPAddressAllocation CR") + return + } + CRIPAddressAllocationSet := sets.New[string]() + for _, ipa := range ipAddressAllocationList.Items { + CRIPAddressAllocationSet.Insert(string(ipa.UID)) + } + + log.V(2).Info("IPAddressAllocation garbage collector", "nsxIPAddressAllocationSet", ipAddressAllocationSet, "CRIPAddressAllocationSet", CRIPAddressAllocationSet) + + diffSet := ipAddressAllocationSet.Difference(CRIPAddressAllocationSet) + for elem := range diffSet { + log.Info("GC collected nsx IPAddressAllocation", "UID", elem) + if err := r.Service.DeleteIPAddressAllocation(types.UID(elem)); err != nil { + log.Error(err, "failed to delete nsx IPAddressAllocation", "UID", elem) + } + } +} diff --git a/pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go new file mode 100644 index 000000000..6a724e2a7 --- /dev/null +++ b/pkg/controllers/ipaddressallocation/ipaddressallocation_controller_test.go @@ -0,0 +1,301 @@ +/* Copyright © 2021 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package ipaddressallocation + +import ( + "context" + "errors" + "reflect" + "sync" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/config" + mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx" + _ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/ipaddressallocation" +) + +func NewFakeIPAddressAllocationReconciler() *IPAddressAllocationReconciler { + return &IPAddressAllocationReconciler{ + Client: fake.NewClientBuilder().Build(), + Scheme: fake.NewClientBuilder().Build().Scheme(), + Service: nil, + } +} + +func TestIPAddressAllocationController_setReadyStatusTrue(t *testing.T) { + r := NewFakeIPAddressAllocationReconciler() + ctx := context.TODO() + dummyIPAddressAllocation := &v1alpha1.IPAddressAllocation{} + transitionTime := metav1.Now() + + // Case: Static Route CRD creation fails + newConditions := []v1alpha1.Condition{ + { + Type: v1alpha1.Ready, + Status: v1.ConditionTrue, + Message: "NSX IPAddressAllocation has been successfully created/updated", + Reason: "", + LastTransitionTime: transitionTime, + }, + } + r.setReadyStatusTrue(&ctx, dummyIPAddressAllocation, transitionTime) + + if !reflect.DeepEqual(dummyIPAddressAllocation.Status.Conditions, newConditions) { + t.Fatalf("Failed to correctly update Status Conditions when conditions haven't changed") + } +} + +type fakeStatusWriter struct { +} + +func (writer fakeStatusWriter) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error { + return nil +} +func (writer fakeStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { + return nil +} +func (writer fakeStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { + return nil +} + +type fakeRecorder struct { +} + +func (recorder fakeRecorder) Event(object runtime.Object, eventtype, reason, message string) { +} +func (recorder fakeRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) { +} +func (recorder fakeRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { +} + +func TestIPAddressAllocationReconciler_Reconcile(t *testing.T) { + + mockCtl := gomock.NewController(t) + k8sClient := mock_client.NewMockClient(mockCtl) + + service := &ipaddressallocation.IPAddressAllocationService{ + Service: common.Service{ + NSXClient: &nsx.Client{}, + + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + EnforcementPoint: "vmc-enforcementpoint", + }, + }, + }, + } + service.NSXConfig.CoeConfig = &config.CoeConfig{} + service.NSXConfig.Cluster = "k8s_cluster" + r := &IPAddressAllocationReconciler{ + Client: k8sClient, + Scheme: nil, + Service: service, + Recorder: fakeRecorder{}, + } + ctx := context.Background() + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "dummy", Name: "dummy"}} + + // common.GcOnce do nothing + var once sync.Once + pat := gomonkey.ApplyMethod(reflect.TypeOf(&once), "Do", func(_ *sync.Once, _ func()) {}) + defer pat.Reset() + + // not found + errNotFound := errors.New("not found") + k8sClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).Return(errNotFound) + _, err := r.Reconcile(ctx, req) + assert.Equal(t, err, errNotFound) + + // DeletionTimestamp.IsZero = ture, client update failed + sp := &v1alpha1.IPAddressAllocation{} + k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { + return nil + }) + err = errors.New("Update failed") + k8sClient.EXPECT().Update(ctx, gomock.Any(), gomock.Any()).Return(err) + fakewriter := fakeStatusWriter{} + k8sClient.EXPECT().Status().Return(fakewriter) + _, ret := r.Reconcile(ctx, req) + assert.Equal(t, err, ret) + + // DeletionTimestamp.IsZero = false, Finalizers doesn't include util.FinalizerName + k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { + v1sp := obj.(*v1alpha1.IPAddressAllocation) + time := metav1.Now() + v1sp.ObjectMeta.DeletionTimestamp = &time + return nil + }) + + patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + uid interface{}) error { + assert.FailNow(t, "should not be called") + return nil + }) + + k8sClient.EXPECT().Update(ctx, gomock.Any(), gomock.Any()).Return(nil) + _, ret = r.Reconcile(ctx, req) + assert.Equal(t, ret, nil) + patch.Reset() + + // DeletionTimestamp.IsZero = false, Finalizers include util.FinalizerName + k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { + v1sp := obj.(*v1alpha1.IPAddressAllocation) + time := metav1.Now() + v1sp.ObjectMeta.DeletionTimestamp = &time + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} + return nil + }) + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, uid interface{}) error { + return nil + }) + _, ret = r.Reconcile(ctx, req) + assert.Equal(t, ret, nil) + patch.Reset() + + // DeletionTimestamp.IsZero = false, Finalizers include util.FinalizerName, DeleteIPAddressAllocation fail + k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { + v1sp := obj.(*v1alpha1.IPAddressAllocation) + time := metav1.Now() + v1sp.ObjectMeta.DeletionTimestamp = &time + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} + return nil + }) + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + uid interface{}) error { + return errors.New("delete failed") + }) + + k8sClient.EXPECT().Status().Times(2).Return(fakewriter) + _, ret = r.Reconcile(ctx, req) + assert.NotEqual(t, ret, nil) + patch.Reset() + + // DeletionTimestamp.IsZero = true, Finalizers include util.FinalizerName, CreateorUpdateIPAddressAllocation fail + k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { + v1sp := obj.(*v1alpha1.IPAddressAllocation) + v1sp.ObjectMeta.DeletionTimestamp = nil + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} + return nil + }) + + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "CreateOrUpdateIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + obj *v1alpha1.IPAddressAllocation) (bool, error) { + return false, errors.New("create failed") + }) + res, ret := r.Reconcile(ctx, req) + assert.Equal(t, res, resultRequeue) + assert.NotEqual(t, ret, nil) + patch.Reset() + + // DeletionTimestamp.IsZero = true, Finalizers include util.FinalizerName, CreateorUpdateIPAddressAllocation succ + k8sClient.EXPECT().Get(ctx, gomock.Any(), sp).Return(nil).Do(func(_ context.Context, _ client.ObjectKey, obj client.Object, option ...client.GetOption) error { + v1sp := obj.(*v1alpha1.IPAddressAllocation) + v1sp.ObjectMeta.DeletionTimestamp = nil + v1sp.Finalizers = []string{common.IPAddressAllocationFinalizerName} + return nil + }) + + patch = gomonkey.ApplyMethod(reflect.TypeOf(service), "CreateOrUpdateIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, + obj *v1alpha1.IPAddressAllocation) (bool, error) { + return true, nil + }) + k8sClient.EXPECT().Status().Times(1).Return(fakewriter) + _, ret = r.Reconcile(ctx, req) + assert.Equal(t, ret, nil) + patch.Reset() +} + +func TestReconciler_GarbageCollector(t *testing.T) { + // gc collect item "2345", local store has more item than k8s cache + service := &ipaddressallocation.IPAddressAllocationService{ + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + EnforcementPoint: "vmc-enforcementpoint", + }, + }, + }, + } + patch := gomonkey.ApplyMethod(reflect.TypeOf(service), "ListIPAddressAllocationID", + func(_ *ipaddressallocation.IPAddressAllocationService) sets.Set[string] { + a := sets.New[string]() + a.Insert("1234") + a.Insert("2345") + return a + }) + patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, UID interface{}) error { + return nil + }) + mockCtl := gomock.NewController(t) + k8sClient := mock_client.NewMockClient(mockCtl) + + r := &IPAddressAllocationReconciler{ + Client: k8sClient, + Scheme: nil, + Service: service, + } + ctx := context.Background() + policyList := &v1alpha1.IPAddressAllocationList{} + k8sClient.EXPECT().List(gomock.Any(), policyList).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { + a := list.(*v1alpha1.IPAddressAllocationList) + a.Items = append(a.Items, v1alpha1.IPAddressAllocation{}) + a.Items[0].ObjectMeta = metav1.ObjectMeta{} + a.Items[0].UID = "1234" + return nil + }) + r.collectGarbage(context.Background()) + + // local store has same item as k8s cache + patch.Reset() + + patch.ApplyMethod(reflect.TypeOf(service), "ListIPAddressAllocationID", func(_ *ipaddressallocation.IPAddressAllocationService) sets.Set[string] { + a := sets.New[string]() + a.Insert("1234") + return a + }) + patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, UID interface{}) error { + assert.FailNow(t, "should not be called") + return nil + }) + k8sClient.EXPECT().List(ctx, policyList).Return(nil).Do(func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { + a := list.(*v1alpha1.IPAddressAllocationList) + a.Items = append(a.Items, v1alpha1.IPAddressAllocation{}) + a.Items[0].ObjectMeta = metav1.ObjectMeta{} + a.Items[0].UID = "1234" + return nil + }) + r.collectGarbage(context.Background()) + + // local store has no item + patch.Reset() + + patch.ApplyMethod(reflect.TypeOf(service), "ListIPAddressAllocationID", func(_ *ipaddressallocation.IPAddressAllocationService) sets.Set[string] { + a := sets.New[string]() + return a + }) + patch.ApplyMethod(reflect.TypeOf(service), "DeleteIPAddressAllocation", func(_ *ipaddressallocation.IPAddressAllocationService, UID interface{}) error { + assert.FailNow(t, "should not be called") + return nil + }) + k8sClient.EXPECT().List(ctx, policyList).Return(nil).Times(0) + r.collectGarbage(context.Background()) + + patch.Reset() +} diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go index 73c4c30a6..47170396d 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go @@ -875,7 +875,8 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { }) }, args: args{ - nsxServiceAccountUIDSet: sets.New[string]("00000000-0000-0000-0000-000000000002", "00000000-0000-0000-0000-000000000003", "00000000-0000-0000-0000-000000000004"), + nsxServiceAccountUIDSet: sets.New[string]("00000000-0000-0000-0000-000000000002", "00000000-0000-0000-0000-000000000003", + "00000000-0000-0000-0000-000000000004"), nsxServiceAccountList: &nsxvmwarecomv1alpha1.NSXServiceAccountList{Items: []nsxvmwarecomv1alpha1.NSXServiceAccount{{ ObjectMeta: metav1.ObjectMeta{ Namespace: "ns1", diff --git a/pkg/nsx/client.go b/pkg/nsx/client.go index 412b0bd1e..9bc961f36 100644 --- a/pkg/nsx/client.go +++ b/pkg/nsx/client.go @@ -71,19 +71,20 @@ type Client struct { VPCSecurityClient vpcs.SecurityPoliciesClient VPCRuleClient vpc_sp.RulesClient - OrgRootClient nsx_policy.OrgRootClient - ProjectInfraClient projects.InfraClient - VPCClient projects.VpcsClient - IPBlockClient infra.IpBlocksClient - StaticRouteClient vpcs.StaticRoutesClient - NATRuleClient nat.NatRulesClient - VpcGroupClient vpcs.GroupsClient - PortClient subnets.PortsClient - PortStateClient ports.StateClient - IPPoolClient subnets.IpPoolsClient - IPAllocationClient ip_pools.IpAllocationsClient - SubnetsClient vpcs.SubnetsClient - RealizedStateClient realized_state.RealizedEntitiesClient + OrgRootClient nsx_policy.OrgRootClient + ProjectInfraClient projects.InfraClient + VPCClient projects.VpcsClient + IPBlockClient infra.IpBlocksClient + StaticRouteClient vpcs.StaticRoutesClient + NATRuleClient nat.NatRulesClient + VpcGroupClient vpcs.GroupsClient + PortClient subnets.PortsClient + PortStateClient ports.StateClient + IPPoolClient subnets.IpPoolsClient + IPAllocationClient ip_pools.IpAllocationsClient + SubnetsClient vpcs.SubnetsClient + RealizedStateClient realized_state.RealizedEntitiesClient + IPAddressAllocationClient vpcs.IpAddressAllocationsClient NSXChecker NSXHealthChecker NSXVerChecker NSXVersionChecker @@ -163,6 +164,7 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { subnetsClient := vpcs.NewSubnetsClient(restConnector(cluster)) subnetStatusClient := subnets.NewStatusClient(restConnector(cluster)) realizedStateClient := realized_state.NewRealizedEntitiesClient(restConnector(cluster)) + ipAddressAllocationClient := vpcs.NewIpAddressAllocationsClient(restConnector(cluster)) vpcSecurityClient := vpcs.NewSecurityPoliciesClient(restConnector(cluster)) vpcRuleClient := vpc_sp.NewRulesClient(restConnector(cluster)) @@ -205,12 +207,13 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { VPCSecurityClient: vpcSecurityClient, VPCRuleClient: vpcRuleClient, - NSXChecker: *nsxChecker, - NSXVerChecker: *nsxVersionChecker, - IPPoolClient: ipPoolClient, - IPAllocationClient: ipAllocationClient, - SubnetsClient: subnetsClient, - RealizedStateClient: realizedStateClient, + NSXChecker: *nsxChecker, + NSXVerChecker: *nsxVersionChecker, + IPPoolClient: ipPoolClient, + IPAllocationClient: ipAllocationClient, + SubnetsClient: subnetsClient, + RealizedStateClient: realizedStateClient, + IPAddressAllocationClient: ipAddressAllocationClient, } // NSX version check will be restarted during SecurityPolicy reconcile // So, it's unnecessary to exit even if failed in the first time diff --git a/pkg/nsx/services/common/types.go b/pkg/nsx/services/common/types.go index 08d671dff..7a8ad278d 100644 --- a/pkg/nsx/services/common/types.go +++ b/pkg/nsx/services/common/types.go @@ -53,6 +53,8 @@ const ( TagScopeIPPoolCRName string = "nsx-op/ippool_name" TagScopeIPPoolCRUID string = "nsx-op/ippool_uid" TagScopeIPPoolCRType string = "nsx-op/ippool_type" + TagScopeIPAddressAllocationCRName string = "nsx-op/ipaddressallocation_name" + TagScopeIPAddressAllocationCRUID string = "nsx-op/ipaddressallocation_uid" TagScopeIPSubnetName string = "nsx-op/ipsubnet_name" TagScopeVMNamespaceUID string = "nsx-op/vm_namespace_uid" TagScopeVMNamespace string = "nsx-op/vm_namespace" @@ -84,24 +86,25 @@ const ( ValueMinorVersion string = "0" ValuePatchVersion string = "0" - GCInterval = 60 * time.Second - RealizeTimeout = 2 * time.Minute - RealizeMaxRetries = 3 - IPPoolFinalizerName = "ippool.nsx.vmware.com/finalizer" - DefaultSNATID = "DEFAULT" - AVISubnetLBID = "_AVI_SUBNET--LB" - IPPoolTypePublic = "Public" - IPPoolTypePrivate = "Private" - - SecurityPolicyFinalizerName = "securitypolicy.nsx.vmware.com/finalizer" - NetworkPolicyFinalizerName = "networkpolicy.nsx.vmware.com/finalizer" - StaticRouteFinalizerName = "staticroute.nsx.vmware.com/finalizer" - NSXServiceAccountFinalizerName = "nsxserviceaccount.nsx.vmware.com/finalizer" - SubnetFinalizerName = "subnet.nsx.vmware.com/finalizer" - SubnetSetFinalizerName = "subnetset.nsx.vmware.com/finalizer" - SubnetPortFinalizerName = "subnetport.nsx.vmware.com/finalizer" - NetworkInfoFinalizerName = "networkinfo.nsx.vmware.com/finalizer" - PodFinalizerName = "pod.nsx.vmware.com/finalizer" + GCInterval = 60 * time.Second + RealizeTimeout = 2 * time.Minute + RealizeMaxRetries = 3 + DefaultSNATID = "DEFAULT" + AVISubnetLBID = "_AVI_SUBNET--LB" + IPPoolTypePublic = "Public" + IPPoolTypePrivate = "Private" + + SecurityPolicyFinalizerName = "securitypolicy.nsx.vmware.com/finalizer" + NetworkPolicyFinalizerName = "networkpolicy.nsx.vmware.com/finalizer" + StaticRouteFinalizerName = "staticroute.nsx.vmware.com/finalizer" + NSXServiceAccountFinalizerName = "nsxserviceaccount.nsx.vmware.com/finalizer" + SubnetFinalizerName = "subnet.nsx.vmware.com/finalizer" + SubnetSetFinalizerName = "subnetset.nsx.vmware.com/finalizer" + SubnetPortFinalizerName = "subnetport.nsx.vmware.com/finalizer" + NetworkInfoFinalizerName = "networkinfo.nsx.vmware.com/finalizer" + PodFinalizerName = "pod.nsx.vmware.com/finalizer" + IPPoolFinalizerName = "ippool.nsx.vmware.com/finalizer" + IPAddressAllocationFinalizerName = "ipaddressallocation.nsx.vmware.com/finalizer" IndexKeySubnetID = "IndexKeySubnetID" IndexKeyPathPath = "Path" @@ -156,11 +159,12 @@ var ( // ResourceTypeClusterControlPlane is used by NSXServiceAccountController ResourceTypeClusterControlPlane = "clustercontrolplane" // ResourceTypePrincipalIdentity is used by NSXServiceAccountController, and it is MP resource type. - ResourceTypePrincipalIdentity = "principalidentity" - ResourceTypeSubnet = "VpcSubnet" - ResourceTypeIPPool = "IpAddressPool" - ResourceTypeIPPoolBlockSubnet = "IpAddressPoolBlockSubnet" - ResourceTypeNode = "HostTransportNode" + ResourceTypePrincipalIdentity = "principalidentity" + ResourceTypeSubnet = "VpcSubnet" + ResourceTypeIPPool = "IpAddressPool" + ResourceTypeIPAddressAllocation = "VpcIpAddressAllocation" + ResourceTypeIPPoolBlockSubnet = "IpAddressPoolBlockSubnet" + ResourceTypeNode = "HostTransportNode" ) type Service struct { diff --git a/pkg/nsx/services/ipaddressallocation/builder.go b/pkg/nsx/services/ipaddressallocation/builder.go new file mode 100644 index 000000000..742ef9e70 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/builder.go @@ -0,0 +1,49 @@ +package ipaddressallocation + +import ( + "fmt" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/util" +) + +var ( + Int64 = common.Int64 + String = common.String +) + +const ( + IPADDRESSALLOCATIONPREFIX = "ipa" +) + +func (service *IPAddressAllocationService) BuildIPAddressAllocation(IPAddressAllocation *v1alpha1.IPAddressAllocation) (*model.VpcIpAddressAllocation, error) { + VPCInfo := service.VPCService.ListVPCInfo(IPAddressAllocation.Namespace) + if len(VPCInfo) == 0 { + log.Error(nil, "failed to find VPCInfo for IPAddressAllocation CR", "IPAddressAllocation", IPAddressAllocation.Name, "namespace", IPAddressAllocation.Namespace) + return nil, fmt.Errorf("failed to find VPCInfo for IPAddressAllocation CR %s in namespace %s", IPAddressAllocation.Name, IPAddressAllocation.Namespace) + } + + ipAddressBlockVisibility := util.ToUpper(IPAddressAllocation.Spec.IPAddressBlockVisibility) + return &model.VpcIpAddressAllocation{ + Id: String(service.buildIPAddressAllocationID(IPAddressAllocation)), + DisplayName: String(service.buildIPAddressAllocationName(IPAddressAllocation)), + Tags: service.buildIPAddressAllocationTags(IPAddressAllocation), + IpAddressBlockVisibility: &ipAddressBlockVisibility, + AllocationSize: Int64(int64(IPAddressAllocation.Spec.AllocationSize)), + }, nil +} + +func (service *IPAddressAllocationService) buildIPAddressAllocationID(IPAddressAllocation *v1alpha1.IPAddressAllocation) string { + return util.GenerateID(string(IPAddressAllocation.UID), IPADDRESSALLOCATIONPREFIX, "", "") +} + +func (service *IPAddressAllocationService) buildIPAddressAllocationName(IPAddressAllocation *v1alpha1.IPAddressAllocation) string { + return util.GenerateDisplayName(IPAddressAllocation.ObjectMeta.Name, IPADDRESSALLOCATIONPREFIX, "", "", service.NSXConfig.Cluster) +} + +func (service *IPAddressAllocationService) buildIPAddressAllocationTags(IPAddressAllocation *v1alpha1.IPAddressAllocation) []model.Tag { + return util.BuildBasicTags(service.NSXConfig.Cluster, IPAddressAllocation, "") +} diff --git a/pkg/nsx/services/ipaddressallocation/builder_test.go b/pkg/nsx/services/ipaddressallocation/builder_test.go new file mode 100644 index 000000000..99b5922a4 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/builder_test.go @@ -0,0 +1,115 @@ +package ipaddressallocation + +import ( + "reflect" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/config" + mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" + mocks "github.com/vmware-tanzu/nsx-operator/pkg/mock/vpcclient" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +type fakeQueryClient struct { +} + +func (qIface *fakeQueryClient) List(_ string, _ *string, _ *string, _ *int64, _ *bool, _ *string) (model.SearchResponse, error) { + cursor := "2" + resultCount := int64(2) + return model.SearchResponse{ + Results: []*data.StructValue{{}}, + Cursor: &cursor, ResultCount: &resultCount, + }, nil +} + +func createService(t *testing.T) (*vpc.VPCService, *gomock.Controller, *mocks.MockVpcsClient) { + config2 := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) + + cluster, _ := nsx.NewCluster(config2) + rc, _ := cluster.NewRestConnector() + + mockCtrl := gomock.NewController(t) + mockVpcclient := mocks.NewMockVpcsClient(mockCtrl) + k8sClient := mock_client.NewMockClient(mockCtrl) + + vpcStore := &vpc.VPCStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeStaticRouteCRUID: indexFunc}), + BindingType: model.VpcBindingType(), + }} + + service := &vpc.VPCService{ + Service: common.Service{ + Client: k8sClient, + NSXClient: &nsx.Client{ + QueryClient: &fakeQueryClient{}, + VPCClient: mockVpcclient, + RestConnector: rc, + NsxConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "k8scl-one:test", + }, + }, + }, + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "k8scl-one:test", + }, + }, + }, + VpcStore: vpcStore, + VPCNetworkConfigStore: vpc.VPCNetworkInfoStore{ + VPCNetworkConfigMap: map[string]common.VPCNetworkConfigInfo{}, + }, + VPCNSNetworkConfigStore: vpc.VPCNsNetworkConfigStore{ + VPCNSNetworkConfigMap: map[string]string{}, + }, + } + return service, mockCtrl, mockVpcclient +} + +func TestBuildIPAddressAllocation(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + vpcService, _, _ := createService(t) + ipAllocService := &IPAddressAllocationService{ + VPCService: vpcService, + Service: common.Service{ + NSXConfig: &config.NSXOperatorConfig{ + NsxConfig: &config.NsxConfig{ + EnforcementPoint: "vmc-enforcementpoint", + }, + CoeConfig: &config.CoeConfig{ + Cluster: "default", + }, + }, + }, + } + + t.Run("VPCInfo is empty", func(t *testing.T) { + ipAlloc := &v1alpha1.IPAddressAllocation{} + ipAlloc.Namespace = "default" + ipAlloc.Name = "test-ip-alloc" + + patch := gomonkey.ApplyMethod(reflect.TypeOf(ipAllocService.VPCService), "ListVPCInfo", func(_ *vpc.VPCService, _ string) []common.VPCResourceInfo { + return []common.VPCResourceInfo{} + }) + defer patch.Reset() + + result, err := ipAllocService.BuildIPAddressAllocation(ipAlloc) + assert.Nil(t, result) + assert.EqualError(t, err, "failed to find VPCInfo for IPAddressAllocation CR test-ip-alloc in namespace default") + }) +} diff --git a/pkg/nsx/services/ipaddressallocation/compare.go b/pkg/nsx/services/ipaddressallocation/compare.go new file mode 100644 index 000000000..d490986d8 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/compare.go @@ -0,0 +1,32 @@ +package ipaddressallocation + +import ( + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +type ( + IpAddressAllocation model.VpcIpAddressAllocation +) + +type Comparable = common.Comparable + +func (iap *IpAddressAllocation) Key() string { + return *iap.Id +} + +func (iap *IpAddressAllocation) Value() data.DataValue { + s := &IpAddressAllocation{Id: iap.Id, DisplayName: iap.DisplayName, Tags: iap.Tags, AllocationSize: iap.AllocationSize, IpAddressBlockVisibility: iap.IpAddressBlockVisibility} + dataValue, _ := ComparableToIpAddressAllocation(s).GetDataValue__() + return dataValue +} + +func IpAddressAllocationToComparable(iap *model.VpcIpAddressAllocation) Comparable { + return (*IpAddressAllocation)(iap) +} + +func ComparableToIpAddressAllocation(iap Comparable) *model.VpcIpAddressAllocation { + return (*model.VpcIpAddressAllocation)(iap.(*IpAddressAllocation)) +} diff --git a/pkg/nsx/services/ipaddressallocation/compare_test.go b/pkg/nsx/services/ipaddressallocation/compare_test.go new file mode 100644 index 000000000..7e18ba86b --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/compare_test.go @@ -0,0 +1,52 @@ +package ipaddressallocation + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func TestKey(t *testing.T) { + id := "test-id" + iap := &IpAddressAllocation{Id: &id} + assert.Equal(t, "test-id", iap.Key()) + + iapNil := &IpAddressAllocation{Id: nil} + assert.Panics(t, func() { iapNil.Key() }) +} + +func TestValue(t *testing.T) { + id := "test-id" + displayName := "test-display-name" + tags := []model.Tag{{Scope: String("scope"), Tag: String("tag")}} + iap := &IpAddressAllocation{Id: &id, DisplayName: &displayName, Tags: tags} + + dataValue := iap.Value() + expectedDataValue, _ := ComparableToIpAddressAllocation(iap).GetDataValue__() + + assert.Equal(t, expectedDataValue, dataValue) +} + +func TestIpAddressAllocationToComparable(t *testing.T) { + id := "test-id" + displayName := "test-display-name" + tags := []model.Tag{{Scope: String("scope"), Tag: String("tag")}} + vpcIap := &model.VpcIpAddressAllocation{Id: &id, DisplayName: &displayName, Tags: tags} + + comparable := IpAddressAllocationToComparable(vpcIap) + assert.IsType(t, &IpAddressAllocation{}, comparable) +} + +func TestComparableToIpAddressAllocation(t *testing.T) { + id := "test-id" + displayName := "test-display-name" + tags := []model.Tag{{Scope: String("scope"), Tag: String("tag")}} + iap := &IpAddressAllocation{Id: &id, DisplayName: &displayName, Tags: tags} + + vpcIap := ComparableToIpAddressAllocation(iap) + assert.IsType(t, &model.VpcIpAddressAllocation{}, vpcIap) + assert.Equal(t, id, *vpcIap.Id) + assert.Equal(t, displayName, *vpcIap.DisplayName) + assert.Equal(t, tags, vpcIap.Tags) +} diff --git a/pkg/nsx/services/ipaddressallocation/ipaddressallocation.go b/pkg/nsx/services/ipaddressallocation/ipaddressallocation.go new file mode 100644 index 000000000..f013ec2a0 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/ipaddressallocation.go @@ -0,0 +1,199 @@ +package ipaddressallocation + +import ( + "context" + "fmt" + "sync" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/logger" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" +) + +var ( + log = logger.Log + MarkedForDelete = true + ResourceTypeIPAddressAllocation = common.ResourceTypeIPAddressAllocation +) + +type IPAddressAllocationService struct { + common.Service + ipAddressAllocationStore *IPAddressAllocationStore + VPCService common.VPCServiceProvider +} + +func InitializeIPAddressAllocation(service common.Service, vpcService common.VPCServiceProvider) (*IPAddressAllocationService, error) { + wg := sync.WaitGroup{} + wgDone := make(chan bool) + fatalErrors := make(chan error) + + wg.Add(1) + + ipAddressAllocationService := &IPAddressAllocationService{Service: service, VPCService: vpcService} + ipAddressAllocationService.ipAddressAllocationStore = &IPAddressAllocationStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPAddressAllocationCRUID: indexFunc}), + BindingType: model.VpcIpAddressAllocationBindingType(), + }} + + tags := []model.Tag{ + {Scope: String(common.TagScopeIPAddressAllocationCRUID)}, + } + go ipAddressAllocationService.InitializeResourceStore(&wg, fatalErrors, ResourceTypeIPAddressAllocation, tags, ipAddressAllocationService.ipAddressAllocationStore) + + go func() { + wg.Wait() + close(wgDone) + }() + select { + case <-wgDone: + break + case err := <-fatalErrors: + close(fatalErrors) + return ipAddressAllocationService, err + } + return ipAddressAllocationService, nil +} + +func (service *IPAddressAllocationService) CreateOrUpdateIPAddressAllocation(obj *v1alpha1.IPAddressAllocation) (bool, error) { + nsxIPAddressAllocation, err := service.BuildIPAddressAllocation(obj) + if err != nil { + return false, err + } + existingIPAddressAllocation, err := service.indexedIPAddressAllocation(obj.UID) + if err != nil { + log.Error(err, "failed to get ipaddressallocation", "UID", obj.UID) + return false, err + } + log.V(1).Info("existing ipaddressallocation", "ipaddressallocation", existingIPAddressAllocation) + ipAddressAllocationUpdated := common.CompareResource(IpAddressAllocationToComparable(existingIPAddressAllocation), + IpAddressAllocationToComparable(nsxIPAddressAllocation)) + + if !ipAddressAllocationUpdated { + log.Info("ipaddressallocation is not changed", "UID", obj.UID) + return false, nil + } + + if err := service.Apply(nsxIPAddressAllocation); err != nil { + return false, err + } + + createdIPAddressAllocation, err := service.indexedIPAddressAllocation(obj.UID) + if err != nil { + log.Error(err, "failed to get created ipaddressallocation", "UID", obj.UID) + return false, err + } + cidr := createdIPAddressAllocation.AllocationIps + if cidr == nil { + return false, fmt.Errorf("ipaddressallocation %s didn't realize available cidr", obj.UID) + } + obj.Status.CIDR = *cidr + return true, nil +} + +func (service *IPAddressAllocationService) Apply(nsxIPAddressAllocation *model.VpcIpAddressAllocation) error { + ns := service.GetIPAddressAllocationNamespace(nsxIPAddressAllocation) + var err error + VPCInfo := service.VPCService.ListVPCInfo(ns) + if len(VPCInfo) == 0 { + err = util.NoEffectiveOption{Desc: "no valid org and project for ipaddressallocation"} + return err + } + err = service.NSXClient.IPAddressAllocationClient.Patch(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, VPCInfo[0].ID, *nsxIPAddressAllocation.Id, *nsxIPAddressAllocation) + err = util.NSXApiError(err) + if err != nil { + // not return err, try to get it from nsx, in case if cidr not realized at the first time + // so it can be patched in the next time and reacquire cidr + log.Error(err, "patch failed, try to get it from nsx", "nsxIPAddressAllocation", nsxIPAddressAllocation) + } + // get back from nsx, it contains path which is used to parse vpc info when deleting + nsxIPAddressAllocationNew, err := service.NSXClient.IPAddressAllocationClient.Get(VPCInfo[0].OrgID, VPCInfo[0].ProjectID, VPCInfo[0].ID, *nsxIPAddressAllocation.Id) + err = util.NSXApiError(err) + if err != nil { + return err + } + if nsxIPAddressAllocation.AllocationIps == nil { + err := fmt.Errorf("cidr not realized yet") + return err + } + err = service.ipAddressAllocationStore.Apply(&nsxIPAddressAllocationNew) + if err != nil { + return err + } + log.V(1).Info("successfully created or updated ipaddressallocation", "nsxIPAddressAllocation", nsxIPAddressAllocation) + return nil +} + +func (service *IPAddressAllocationService) DeleteIPAddressAllocation(obj interface{}) error { + var err error + var nsxIPAddressAllocation *model.VpcIpAddressAllocation + switch o := obj.(type) { + case *v1alpha1.IPAddressAllocation: + nsxIPAddressAllocation, err = service.indexedIPAddressAllocation(o.UID) + if err != nil { + log.Error(err, "failed to get ipaddressallocation", "IPAddressAllocation", o) + return err + } + case types.UID: + nsxIPAddressAllocation, err = service.indexedIPAddressAllocation(o) + if err != nil { + log.Error(err, "failed to get ipaddressallocation by UID", "UID", o) + return err + } + } + if nsxIPAddressAllocation == nil { + log.Error(nil, "failed to get ipaddressallocation from store, skip") + return nil + } + vpcResourceInfo, err := common.ParseVPCResourcePath(*nsxIPAddressAllocation.Path) + if err != nil { + return err + } + err = service.NSXClient.IPAddressAllocationClient.Delete(vpcResourceInfo.OrgID, vpcResourceInfo.ProjectID, vpcResourceInfo.ID, *nsxIPAddressAllocation.Id) + if err != nil { + return err + } + nsxIPAddressAllocation.MarkedForDelete = &MarkedForDelete + err = service.ipAddressAllocationStore.Apply(nsxIPAddressAllocation) + if err != nil { + return err + } + log.V(1).Info("successfully deleted nsxIPAddressAllocation", "nsxIPAddressAllocation", nsxIPAddressAllocation) + return nil +} + +func (service *IPAddressAllocationService) ListIPAddressAllocationID() sets.Set[string] { + ipAddressAllocationSet := service.ipAddressAllocationStore.ListIndexFuncValues(common.TagScopeIPAddressAllocationCRUID) + return ipAddressAllocationSet +} + +func (service *IPAddressAllocationService) GetIPAddressAllocationNamespace(nsxIPAddressAllocation *model.VpcIpAddressAllocation) string { + for _, tag := range nsxIPAddressAllocation.Tags { + if *tag.Scope == common.TagScopeNamespace { + return *tag.Tag + } + } + return "" +} + +func (service *IPAddressAllocationService) Cleanup(ctx context.Context) error { + uids := service.ListIPAddressAllocationID() + log.Info("cleaning up ipaddressallocation", "count", len(uids)) + for uid := range uids { + select { + case <-ctx.Done(): + return util.TimeoutFailed + default: + err := service.DeleteIPAddressAllocation(types.UID(uid)) + if err != nil { + return err + } + } + } + return nil +} diff --git a/pkg/nsx/services/ipaddressallocation/store.go b/pkg/nsx/services/ipaddressallocation/store.go new file mode 100644 index 000000000..5b0047374 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/store.go @@ -0,0 +1,90 @@ +package ipaddressallocation + +import ( + "errors" + + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/apimachinery/pkg/types" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func keyFunc(obj interface{}) (string, error) { + switch v := obj.(type) { + case *model.VpcIpAddressAllocation: + return *v.Id, nil + case *model.GenericPolicyRealizedResource: + return *v.Id, nil + default: + return "", errors.New("keyFunc doesn't support unknown type") + } +} + +func indexFunc(obj interface{}) ([]string, error) { + res := make([]string, 0, 5) + switch v := obj.(type) { + case *model.VpcIpAddressAllocation: + return filterTag(v.Tags), nil + case *model.GenericPolicyRealizedResource: + return filterTag(v.Tags), nil + default: + return res, errors.New("indexFunc doesn't support unknown type") + } +} + +var filterTag = func(v []model.Tag) []string { + res := make([]string, 0, 5) + for _, tag := range v { + if *tag.Scope == common.TagScopeIPAddressAllocationCRUID { + res = append(res, *tag.Tag) + } + } + return res +} + +type IPAddressAllocationStore struct { + common.ResourceStore +} + +func (ipAddressAllocationStore *IPAddressAllocationStore) Apply(i interface{}) error { + ipAddressAllocation := i.(*model.VpcIpAddressAllocation) + if ipAddressAllocation.MarkedForDelete != nil && *ipAddressAllocation.MarkedForDelete { + err := ipAddressAllocationStore.Delete(ipAddressAllocation) + if err != nil { + return err + } + log.V(1).Info("delete ipAddressAllocation from store", "ipAddressAllocation", ipAddressAllocation) + } else { + err := ipAddressAllocationStore.Add(ipAddressAllocation) + if err != nil { + return err + } + log.V(1).Info("add ipAddressAllocation to store", "ipAddressAllocation", ipAddressAllocation) + } + return nil +} + +func (service *IPAddressAllocationService) indexedIPAddressAllocation(uid types.UID) (*model.VpcIpAddressAllocation, error) { + nsxIPAddressAllocation, err := service.ipAddressAllocationStore.GetByIndex(uid) + if err != nil { + return nil, err + } + return nsxIPAddressAllocation, nil +} + +func (ipAddressAllocationStore *IPAddressAllocationStore) GetByIndex(uid types.UID) (*model.VpcIpAddressAllocation, error) { + nsxIPAddressAllocation := &model.VpcIpAddressAllocation{} + indexResults, err := ipAddressAllocationStore.ResourceStore.ByIndex(common.TagScopeIPAddressAllocationCRUID, string(uid)) + if err != nil { + log.Error(err, "failed to get ipaddressallocation", "UID", string(uid)) + return nil, err + } + if len(indexResults) > 0 { + t := indexResults[0].(*model.VpcIpAddressAllocation) + nsxIPAddressAllocation = t + } else { + log.Info("did not get ipaddressallocation with index", "UID", string(uid)) + return nsxIPAddressAllocation, nil + } + return nsxIPAddressAllocation, nil +} diff --git a/pkg/nsx/services/ipaddressallocation/store_test.go b/pkg/nsx/services/ipaddressallocation/store_test.go new file mode 100644 index 000000000..002f6a429 --- /dev/null +++ b/pkg/nsx/services/ipaddressallocation/store_test.go @@ -0,0 +1,98 @@ +package ipaddressallocation + +import ( + "fmt" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/cache" + + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func TestIPAddressAllocationStore_CRUDResource(t *testing.T) { + ipAddressAllocationCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPAddressAllocationCRUID: indexFunc}) + resourceStore := common.ResourceStore{ + Indexer: ipAddressAllocationCacheIndexer, + BindingType: model.VpcIpAddressAllocationBindingType(), + } + ipAddressAllocationStore := &IPAddressAllocationStore{ResourceStore: resourceStore} + type args struct { + i interface{} + } + tests := []struct { + name string + args args + wantErr assert.ErrorAssertionFunc + }{ + {"1", args{i: &model.VpcIpAddressAllocation{Id: String("1")}}, assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.wantErr(t, ipAddressAllocationStore.Apply(tt.args.i), fmt.Sprintf("Apply(%v)", tt.args.i)) + }) + } +} + +func TestIPAddressAllocationStore_GetByIndex(t *testing.T) { + p := &model.VpcIpAddressAllocation{Id: String("1"), DisplayName: String("1"), + Tags: []model.Tag{{Scope: String(common.TagScopeIPAddressAllocationCRUID), + Tag: String("1")}}} + ipAddressAllocationStore := &IPAddressAllocationStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{common.TagScopeIPAddressAllocationCRUID: indexFunc}), + BindingType: model.VpcIpAddressBindingType(), + }} + _ = ipAddressAllocationStore.Apply(p) + type args struct { + uid types.UID + } + tests := []struct { + name string + args args + want *model.VpcIpAddressAllocation + wantErr bool + }{ + {"1", args{uid: "1"}, &model.VpcIpAddressAllocation{Id: String("1"), DisplayName: String("1"), + Tags: []model.Tag{{Scope: String(common.TagScopeIPAddressAllocationCRUID), Tag: String("1")}}}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ipAddressAllocationStore.GetByIndex(tt.args.uid) + if (err != nil) != tt.wantErr { + t.Errorf("indexedIPAddressAllocation() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("indexedIPAddressAllocation() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_indexFunc(t *testing.T) { + mId, mTag, mScope := "11111", "11111", common.TagScopeIPAddressAllocationCRUID + m := &model.VpcIpAddressAllocation{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + } + t.Run("1", func(t *testing.T) { + got, _ := indexFunc(m) + if !reflect.DeepEqual(got, []string{"11111"}) { + t.Errorf("indexFunc() = %v, want %v", got, model.Tag{Tag: &mTag, Scope: &mScope}) + } + }) +} + +func Test_keyFunc(t *testing.T) { + Id := "11111" + g := &model.VpcIpAddressAllocation{Id: &Id} + t.Run("2", func(t *testing.T) { + got, _ := keyFunc(g) + if got != "11111" { + t.Errorf("keyFunc() = %v, want %v", got, "11111") + } + }) +} diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 0b537b313..e6060c6fa 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -477,6 +477,10 @@ func BuildBasicTags(cluster string, obj interface{}, namespaceID types.UID) []mo tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) tags = append(tags, model.Tag{Scope: String(common.TagScopeIPPoolCRName), Tag: String(i.ObjectMeta.Name)}) tags = append(tags, model.Tag{Scope: String(common.TagScopeIPPoolCRUID), Tag: String(string(i.UID))}) + case *v1alpha1.IPAddressAllocation: + tags = append(tags, model.Tag{Scope: String(common.TagScopeNamespace), Tag: String(i.ObjectMeta.Namespace)}) + tags = append(tags, model.Tag{Scope: String(common.TagScopeIPAddressAllocationCRName), Tag: String(i.ObjectMeta.Name)}) + tags = append(tags, model.Tag{Scope: String(common.TagScopeIPAddressAllocationCRUID), Tag: String(string(i.UID))}) default: log.Info("unknown obj type", "obj", obj) } From b3932c52a8d95e20d0bbd6c7040c56ceabe9e4a3 Mon Sep 17 00:00:00 2001 From: Ran Gu Date: Mon, 22 Jul 2024 10:34:46 +0800 Subject: [PATCH 17/23] [NSXServiceAccount] Fix store issues (#642) [NSXServiceAccount] Fix store issues --- .../nsxserviceaccount_controller_test.go | 8 +-- pkg/nsx/services/common/store.go | 4 +- pkg/nsx/services/nsxserviceaccount/cluster.go | 22 ++++--- .../nsxserviceaccount/cluster_test.go | 26 ++++---- pkg/nsx/services/nsxserviceaccount/store.go | 61 ++++++++++--------- .../services/nsxserviceaccount/store_test.go | 11 ++-- 6 files changed, 71 insertions(+), 61 deletions(-) diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go index 73c4c30a6..65d29de9a 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go @@ -559,7 +559,7 @@ func TestNSXServiceAccountReconciler_GarbageCollector(t *testing.T) { name2 := "name2" clusterName2 := "cl1-ns2-name2" uid2 := "00000000-0000-0000-0000-000000000002" - assert.NoError(t, r.Service.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, r.Service.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Name: &clusterName2, Tags: []mpmodel.Tag{{ Scope: &tagScopeNamespace, @@ -813,7 +813,7 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { name2 := "name2" clusterName2 := "cl1-ns2-name2" uid2 := "00000000-0000-0000-0000-000000000002" - assert.NoError(t, r.Service.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, r.Service.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Name: &clusterName2, Tags: []mpmodel.Tag{{ Scope: &tagScopeNamespace, @@ -830,7 +830,7 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { name3 := "name3" clusterName3 := "cl1-ns3-name3" uid3 := "00000000-0000-0000-0000-000000000003" - assert.NoError(t, r.Service.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, r.Service.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Name: &clusterName3, Tags: []mpmodel.Tag{{ Scope: &tagScopeNamespace, @@ -847,7 +847,7 @@ func TestNSXServiceAccountReconciler_garbageCollector(t *testing.T) { name4 := "name4" clusterName4 := "cl1-ns4-name4" uid4 := "00000000-0000-0000-0000-000000000004" - assert.NoError(t, r.Service.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + assert.NoError(t, r.Service.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &clusterName4, Tags: []model.Tag{{ Scope: &tagScopeNamespace, diff --git a/pkg/nsx/services/common/store.go b/pkg/nsx/services/common/store.go index 4d5c7153a..2c01db15f 100644 --- a/pkg/nsx/services/common/store.go +++ b/pkg/nsx/services/common/store.go @@ -215,6 +215,8 @@ func (service *Service) InitializeCommonStore(wg *sync.WaitGroup, fatalErrors ch pathUnescape, _ := url.PathUnescape("path%3A") queryParam += " AND " + pathUnescape + path } - queryParam += " AND marked_for_delete:false" + if store.IsPolicyAPI() { + queryParam += " AND marked_for_delete:false" + } service.PopulateResourcetoStore(wg, fatalErrors, resourceTypeValue, queryParam, store, nil) } diff --git a/pkg/nsx/services/nsxserviceaccount/cluster.go b/pkg/nsx/services/nsxserviceaccount/cluster.go index d527d1006..6e79f8a08 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster.go @@ -246,7 +246,7 @@ func (s *NSXServiceAccountService) createPIAndCCP(normalizedClusterName string, if err != nil { return "", err } - s.PrincipalIdentityStore.Add(pi) + s.PrincipalIdentityStore.Add(&pi) } else if !hasPI != (piObj == nil) { return "", fmt.Errorf("old PI exists") } @@ -267,7 +267,7 @@ func (s *NSXServiceAccountService) createPIAndCCP(normalizedClusterName string, if err != nil { return "", err } - s.ClusterControlPlaneStore.Add(ccp) + s.ClusterControlPlaneStore.Add(&ccp) clusterId = *ccp.NodeId } else if !hasCCP != (ccpObj == nil) { return "", fmt.Errorf("old CCP exists") @@ -340,12 +340,12 @@ func (s *NSXServiceAccountService) DeleteNSXServiceAccount(ctx context.Context, log.Error(err, "failed to delete", "ClusterControlPlane", normalizedClusterName) return err } - s.ClusterControlPlaneStore.Delete(model.ClusterControlPlane{Id: &normalizedClusterName}) + s.ClusterControlPlaneStore.Delete(&model.ClusterControlPlane{Id: &normalizedClusterName}) } // delete PI if piobj := s.PrincipalIdentityStore.GetByKey(normalizedClusterName); isDeletePI && (piobj != nil) { - pi := piobj.(mpmodel.PrincipalIdentity) + pi := piobj.(*mpmodel.PrincipalIdentity) if err := s.NSXClient.PrincipalIdentitiesClient.Delete(*pi.Id); err != nil { err = nsxutil.NSXApiError(err) log.Error(err, "failed to delete", "PrincipalIdentity", *pi.Name) @@ -437,17 +437,18 @@ func (s *NSXServiceAccountService) updatePIAndCCPCert(normalizedClusterName, uid } // update ClusterControlPlane cert - ccp := ccpObj.(model.ClusterControlPlane) + ccp := ccpObj.(*model.ClusterControlPlane) ccp.Certificate = &cert - if ccp, err := s.NSXClient.ClusterControlPlanesClient.Update(siteId, enforcementpointId, normalizedClusterName, ccp); err != nil { + if ccp2, err := s.NSXClient.ClusterControlPlanesClient.Update(siteId, enforcementpointId, normalizedClusterName, *ccp); err != nil { err = nsxutil.NSXApiError(err) return err } else { + ccp = &ccp2 s.ClusterControlPlaneStore.Add(ccp) } // update PI cert - pi := piObj.(mpmodel.PrincipalIdentity) + pi := piObj.(*mpmodel.PrincipalIdentity) oldCertId := "" if pi.CertificateId != nil { oldCertId = *pi.CertificateId @@ -460,13 +461,14 @@ func (s *NSXServiceAccountService) updatePIAndCCPCert(normalizedClusterName, uid err = nsxutil.NSXApiError(err) return err } - if pi, err = s.NSXClient.PrincipalIdentitiesClient.Updatecertificate(mpmodel.UpdatePrincipalIdentityCertificateRequest{ + if pi2, err := s.NSXClient.PrincipalIdentitiesClient.Updatecertificate(mpmodel.UpdatePrincipalIdentityCertificateRequest{ CertificateId: certList.Results[0].Id, PrincipalIdentityId: pi.Id, }); err != nil { err = nsxutil.NSXApiError(err) return err } else { + pi = &pi2 s.PrincipalIdentityStore.Add(pi) } if oldCertId != "" { @@ -495,7 +497,7 @@ func (s *NSXServiceAccountService) GetNSXServiceAccountNameByUID(uid string) (na return } for _, obj := range objs { - pi := obj.(mpmodel.PrincipalIdentity) + pi := obj.(*mpmodel.PrincipalIdentity) for _, tag := range pi.Tags { switch *tag.Scope { case common.TagScopeNamespace: @@ -514,7 +516,7 @@ func (s *NSXServiceAccountService) GetNSXServiceAccountNameByUID(uid string) (na return } for _, obj := range objs { - ccp := obj.(model.ClusterControlPlane) + ccp := obj.(*model.ClusterControlPlane) for _, tag := range ccp.Tags { if tag.Scope != nil { switch *tag.Scope { diff --git a/pkg/nsx/services/nsxserviceaccount/cluster_test.go b/pkg/nsx/services/nsxserviceaccount/cluster_test.go index 985218534..24f8e5315 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster_test.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster_test.go @@ -551,7 +551,7 @@ func TestNSXServiceAccountService_RestoreRealizedNSXServiceAccount(t *testing.T) vpcPath := "/orgs/default/projects/k8scl-one:test/vpcs/vpc1" piId := "Id1" uid := "00000000-0000-0000-0000-000000000001" - s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ IsProtected: &isProtectedTrue, Name: &normalizedClusterName, NodeId: &normalizedClusterName, @@ -583,7 +583,7 @@ func TestNSXServiceAccountService_RestoreRealizedNSXServiceAccount(t *testing.T) }}, }) nodeId := "clusterId1" - s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &normalizedClusterName, NodeId: &nodeId, Revision: &revision1, @@ -637,7 +637,7 @@ func TestNSXServiceAccountService_RestoreRealizedNSXServiceAccount(t *testing.T) vpcPath := "/orgs/default/projects/k8scl-one:test/vpcs/vpc1" piId := "Id1" uid := "00000000-0000-0000-0000-000000000001" - s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ IsProtected: &isProtectedTrue, Name: &normalizedClusterName, NodeId: &normalizedClusterName, @@ -1130,8 +1130,8 @@ func TestNSXServiceAccountService_ValidateAndUpdateRealizedNSXServiceAccount(t * Scope: &uidScope, Tag: &uidTag, }}} - assert.NoError(t, s.ClusterControlPlaneStore.Add(ccp)) - assert.NoError(t, s.PrincipalIdentityStore.Add(pi)) + assert.NoError(t, s.ClusterControlPlaneStore.Add(&ccp)) + assert.NoError(t, s.PrincipalIdentityStore.Add(&pi)) patches := gomonkey.ApplyMethodSeq(s.NSXClient, "NSXCheckVersion", []gomonkey.OutputCell{{ Values: gomonkey.Params{true}, @@ -1245,8 +1245,8 @@ func TestNSXServiceAccountService_DeleteNSXServiceAccount(t *testing.T) { normalizedClusterName := "k8scl-one_test-ns1-name1" piId := "piId1" certId := "certId1" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{Id: &normalizedClusterName})) - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId})) + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{Id: &normalizedClusterName})) + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId})) assert.NoError(t, s.Client.Create(ctx, &v1alpha1.NSXServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "name1", @@ -1285,8 +1285,8 @@ func TestNSXServiceAccountService_DeleteNSXServiceAccount(t *testing.T) { normalizedClusterName := "k8scl-one_test-ns1-name1" piId := "piId1" certId := "certId1" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{Id: &normalizedClusterName})) - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId, Tags: []mpmodel.Tag{{ + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{Id: &normalizedClusterName})) + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{Name: &normalizedClusterName, Id: &piId, CertificateId: &certId, Tags: []mpmodel.Tag{{ Scope: &uidScope, Tag: &uidTag, }}})) @@ -1357,7 +1357,7 @@ func TestNSXServiceAccountService_ListNSXServiceAccountRealization(t *testing.T) piName := piKey piId := piKey + "-id" crUID := piKey + "-uid" - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Id: &piId, Name: &piName, Tags: []mpmodel.Tag{{ @@ -1369,7 +1369,7 @@ func TestNSXServiceAccountService_ListNSXServiceAccountRealization(t *testing.T) for _, ccpKey := range tt.ccpKeys { ccpId := ccpKey crUID := ccpKey + "-uid" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &ccpId, Tags: []model.Tag{{ Scope: &tagScopeNSXServiceAccountCRUID, @@ -1448,7 +1448,7 @@ func TestNSXServiceAccountService_GetNSXServiceAccountNameByUID(t *testing.T) { piName := piKey.Namespace + "-" + piKey.Name piId := piName + "-id" crUID := piName + "-uid" - assert.NoError(t, s.PrincipalIdentityStore.Add(mpmodel.PrincipalIdentity{ + assert.NoError(t, s.PrincipalIdentityStore.Add(&mpmodel.PrincipalIdentity{ Id: &piId, Name: &piName, Tags: []mpmodel.Tag{{ @@ -1466,7 +1466,7 @@ func TestNSXServiceAccountService_GetNSXServiceAccountNameByUID(t *testing.T) { for _, ccpKey := range tt.ccpKeys { ccpId := ccpKey.Namespace + "-" + ccpKey.Name crUID := ccpId + "-uid" - assert.NoError(t, s.ClusterControlPlaneStore.Add(model.ClusterControlPlane{ + assert.NoError(t, s.ClusterControlPlaneStore.Add(&model.ClusterControlPlane{ Id: &ccpId, Tags: []model.Tag{{ Scope: &tagScopeNamespace, diff --git a/pkg/nsx/services/nsxserviceaccount/store.go b/pkg/nsx/services/nsxserviceaccount/store.go index 66701f1c2..df9719619 100644 --- a/pkg/nsx/services/nsxserviceaccount/store.go +++ b/pkg/nsx/services/nsxserviceaccount/store.go @@ -4,7 +4,8 @@ package nsxserviceaccount import ( - "errors" + "fmt" + "reflect" mpmodel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" @@ -18,14 +19,15 @@ type PrincipalIdentityStore struct { } func (s *PrincipalIdentityStore) Apply(i interface{}) error { - pis := i.(*[]mpmodel.PrincipalIdentity) - for _, pi := range *pis { - // MP resource doesn't have MarkedForDelete tag. - err := s.Add(pi) - log.V(1).Info("add PI to store", "pi", pi) - if err != nil { - return err - } + if i == nil { + return nil + } + pi := i.(*mpmodel.PrincipalIdentity) + // MP resource doesn't have MarkedForDelete tag. + err := s.Add(pi) + log.V(1).Info("add PI to store", "pi", pi) + if err != nil { + return err } return nil } @@ -40,20 +42,21 @@ type ClusterControlPlaneStore struct { } func (s *ClusterControlPlaneStore) Apply(i interface{}) error { - pis := i.(*[]model.ClusterControlPlane) - for _, pi := range *pis { - if pi.MarkedForDelete != nil && *pi.MarkedForDelete { - err := s.Delete(pi) - log.V(1).Info("delete PI from store", "pi", pi) - if err != nil { - return err - } - } else { - err := s.Add(pi) - log.V(1).Info("add PI to store", "pi", pi) - if err != nil { - return err - } + if i == nil { + return nil + } + ccp := i.(*model.ClusterControlPlane) + if ccp.MarkedForDelete != nil && *ccp.MarkedForDelete { + err := s.Delete(ccp) + log.V(1).Info("delete ClusterCP from store", "ClusterCP", ccp) + if err != nil { + return err + } + } else { + err := s.Add(ccp) + log.V(1).Info("add ClusterCP to store", "ClusterCP", ccp) + if err != nil { + return err } } return nil @@ -62,12 +65,12 @@ func (s *ClusterControlPlaneStore) Apply(i interface{}) error { // keyFunc returns the key of the object. func keyFunc(obj interface{}) (string, error) { switch v := obj.(type) { - case model.ClusterControlPlane: + case *model.ClusterControlPlane: return *v.Id, nil - case mpmodel.PrincipalIdentity: + case *mpmodel.PrincipalIdentity: return *v.Name, nil default: - return "", errors.New("keyFunc doesn't support unknown type") + return "", fmt.Errorf("keyFunc doesn't support unknown type %v", reflect.TypeOf(obj)) } } @@ -76,12 +79,12 @@ func keyFunc(obj interface{}) (string, error) { func indexFunc(obj interface{}) ([]string, error) { res := make([]string, 0, 5) switch o := obj.(type) { - case model.ClusterControlPlane: + case *model.ClusterControlPlane: return filterTag(o.Tags), nil - case mpmodel.PrincipalIdentity: + case *mpmodel.PrincipalIdentity: return filterTag(common.ConvertMPTagsToTags(o.Tags)), nil default: - return res, errors.New("indexFunc doesn't support unknown type") + return res, fmt.Errorf("indexFunc doesn't support unknown type %v", reflect.TypeOf(obj)) } } diff --git a/pkg/nsx/services/nsxserviceaccount/store_test.go b/pkg/nsx/services/nsxserviceaccount/store_test.go index c79ab4573..fabe99174 100644 --- a/pkg/nsx/services/nsxserviceaccount/store_test.go +++ b/pkg/nsx/services/nsxserviceaccount/store_test.go @@ -27,8 +27,8 @@ func Test_indexFunc(t *testing.T) { want []string wantErr bool }{ - {"1", args{obj: ccp}, []string{"11111"}, false}, - {"2", args{obj: pi}, []string{"11111"}, false}, + {"1", args{obj: &ccp}, []string{"11111"}, false}, + {"2", args{obj: &pi}, []string{"11111"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -49,6 +49,7 @@ func Test_keyFunc(t *testing.T) { ccp := model.ClusterControlPlane{Id: &Id} pi := mpmodel.PrincipalIdentity{Name: &Id} o := model.UserInfo{} + var o2 *model.UserInfo type args struct { obj interface{} } @@ -58,9 +59,11 @@ func Test_keyFunc(t *testing.T) { want string wantErr bool }{ - {"1", args{obj: ccp}, Id, false}, - {"2", args{obj: pi}, Id, false}, + {"1", args{obj: &ccp}, Id, false}, + {"2", args{obj: &pi}, Id, false}, {"0", args{obj: o}, "", true}, + {"typednil", args{obj: o2}, "", true}, + {"nil", args{obj: nil}, "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From b0f98b74b85ccd4cda9253f78235a00127da19df Mon Sep 17 00:00:00 2001 From: Deng Yun Date: Tue, 23 Jul 2024 03:08:19 +0000 Subject: [PATCH 18/23] Chang LabelLbIngressIpMode label value This patch is to change LabelLbIngressIpMode label from tanzu.vmware.com/ingress-ip-mode to nsx.vmware.com/ingress-ip-mode --- pkg/controllers/service/service_lb_controller.go | 2 +- pkg/nsx/services/common/types.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controllers/service/service_lb_controller.go b/pkg/controllers/service/service_lb_controller.go index 48cc9838c..6280f3a58 100644 --- a/pkg/controllers/service/service_lb_controller.go +++ b/pkg/controllers/service/service_lb_controller.go @@ -69,7 +69,7 @@ func (r *ServiceLbReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( func (r *ServiceLbReconciler) setServiceLbStatus(ctx *context.Context, lbService *v1.Service) { ipMode := v1.LoadBalancerIPModeProxy statusUpdated := false - // If tanzu.vmware.com/ingress-ip-mode label with values proxy or vip, + // If nsx.vmware.com/ingress-ip-mode label with values proxy or vip, // the LoadBalancer serivice ipMode status would be set to whatever the label is set to, // Otherwise, it's set to Proxy by default when unset or other invalid values. if labelIpMode, ok := lbService.Labels[servicecommon.LabelLbIngressIpMode]; ok { diff --git a/pkg/nsx/services/common/types.go b/pkg/nsx/services/common/types.go index 08d671dff..75667160a 100644 --- a/pkg/nsx/services/common/types.go +++ b/pkg/nsx/services/common/types.go @@ -59,7 +59,7 @@ const ( LabelDefaultSubnetSet string = "nsxoperator.vmware.com/default-subnetset-for" LabelDefaultVMSubnetSet string = "VirtualMachine" LabelDefaultPodSubnetSet string = "Pod" - LabelLbIngressIpMode string = "tanzu.vmware.com/ingress-ip-mode" + LabelLbIngressIpMode string = "nsx.vmware.com/ingress-ip-mode" LabelLbIngressIpModeVipValue string = "vip" LabelLbIngressIpModeProxyValue string = "proxy" DefaultPodSubnetSet string = "pod-default" From 6b05d601ed1b038a19c1eada9a75fda4dd409b19 Mon Sep 17 00:00:00 2001 From: Ran Gu Date: Wed, 24 Jul 2024 10:36:56 +0800 Subject: [PATCH 19/23] [VPC][SubnetPort] Update attachment_ref annotation format (#635) Follow the change in https://github.com/vmware-tanzu/vm-operator/pull/624 Signed-off-by: gran --- pkg/controllers/common/utils.go | 2 +- pkg/controllers/common/utils_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/controllers/common/utils.go b/pkg/controllers/common/utils.go index 79a3898c6..846434f8e 100644 --- a/pkg/controllers/common/utils.go +++ b/pkg/controllers/common/utils.go @@ -131,7 +131,7 @@ func GetVirtualMachineNameForSubnetPort(subnetPort *v1alpha1.SubnetPort) (string return "", nil } array := strings.Split(attachmentRef, "/") - if len(array) != 2 || !strings.EqualFold(array[0], servicecommon.ResourceTypeVirtualMachine) { + if len(array) != 3 || !strings.EqualFold(array[0], servicecommon.ResourceTypeVirtualMachine) { err := fmt.Errorf("invalid annotation value of '%s': %s", servicecommon.AnnotationAttachmentRef, attachmentRef) return "", err } diff --git a/pkg/controllers/common/utils_test.go b/pkg/controllers/common/utils_test.go index a2b19fca0..516ecd20c 100644 --- a/pkg/controllers/common/utils_test.go +++ b/pkg/controllers/common/utils_test.go @@ -28,7 +28,7 @@ func TestGetVirtualMachineNameForSubnetPort(t *testing.T) { args{&v1alpha1.SubnetPort{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - "nsx.vmware.com/attachment_ref": "virtualmachine/abc", + "nsx.vmware.com/attachment_ref": "virtualmachine/abc/port1", }, }}}, want{vm: "abc", err: nil}, From 2c463966827abde009d155a99d0155e5d8895b99 Mon Sep 17 00:00:00 2001 From: Ran Gu Date: Thu, 25 Jul 2024 14:34:05 +0800 Subject: [PATCH 20/23] [VPC] Add NSX LBS path to VPCInfo and use LB options in NsxConfig (#606) Signed-off-by: gran --- ...x.vmware.com_vpcnetworkconfigurations.yaml | 9 +- .../v1alpha1/vpcnetworkconfiguration_types.go | 2 + .../v1alpha1/vpcnetworkconfiguration_types.go | 2 + pkg/config/config.go | 20 +++++ pkg/config/config_test.go | 84 +++++++++++++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml index 4911e9a63..9640e2666 100644 --- a/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml +++ b/build/yaml/crd/nsx.vmware.com_vpcnetworkconfigurations.yaml @@ -103,8 +103,9 @@ spec: maxLength: 8 type: string vpc: - description: NSX path of the VPC the Namespace associated with. If - vpc is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + description: |- + NSX path of the VPC the Namespace associated with. + If vpc is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode take effect, other fields are ignored. type: string type: object @@ -125,6 +126,10 @@ spec: name: description: VPC name. type: string + nsxLoadBalancerPath: + description: NSXLoadBalancerPath is the NSX Policy path for + the NSX Load Balancer. + type: string required: - name type: object diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go index 23355f5f9..08d5ee7fb 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go @@ -65,6 +65,8 @@ type VPCInfo struct { Name string `json:"name"` // AVISESubnetPath is the NSX Policy Path for the AVI SE Subnet. AVISESubnetPath string `json:"lbSubnetPath,omitempty"` + // NSXLoadBalancerPath is the NSX Policy path for the NSX Load Balancer. + NSXLoadBalancerPath string `json:"nsxLoadBalancerPath,omitempty"` } // +genclient diff --git a/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go index 23355f5f9..08d5ee7fb 100644 --- a/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go +++ b/pkg/apis/v1alpha1/vpcnetworkconfiguration_types.go @@ -65,6 +65,8 @@ type VPCInfo struct { Name string `json:"name"` // AVISESubnetPath is the NSX Policy Path for the AVI SE Subnet. AVISESubnetPath string `json:"lbSubnetPath,omitempty"` + // NSXLoadBalancerPath is the NSX Policy path for the NSX Load Balancer. + NSXLoadBalancerPath string `json:"nsxLoadBalancerPath,omitempty"` } // +genclient diff --git a/pkg/config/config.go b/pkg/config/config.go index 2710b69c9..29a3c60c5 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -11,6 +11,7 @@ import ( "fmt" "os" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "go.uber.org/zap" ini "gopkg.in/ini.v1" @@ -117,6 +118,10 @@ type NsxConfig struct { EnvoyHost string `ini:"envoy_host"` EnvoyPort int `ini:"envoy_port"` LicenseValidationInterval int `ini:"license_validation_interval"` + UseAVILoadBalancer bool `ini:"use_avi_lb"` + UseNSXLoadBalancer *bool `ini:"use_native_loadbalancer"` + RelaxNSXLBScaleValication bool `ini:"relax_scale_validation"` + NSXLBSize string `ini:"service_size"` } type K8sConfig struct { @@ -406,3 +411,18 @@ func (coeConfig *CoeConfig) validate() error { func (nsxConfig *NsxConfig) ValidateConfigFromCmd() error { return nsxConfig.validate(true) } + +func (nsxConfig *NsxConfig) NSXLBEnabled() bool { + if nsxConfig.UseAVILoadBalancer == false && (nsxConfig.UseNSXLoadBalancer == nil || *nsxConfig.UseNSXLoadBalancer == true) { + return true + } + return false +} + +func (nsxConfig *NsxConfig) GetNSXLBSize() string { + lbsSize := nsxConfig.NSXLBSize + if lbsSize == "" { + lbsSize = model.LBService_SIZE_SMALL + } + return lbsSize +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 6ca245042..afacbf018 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -9,7 +9,9 @@ import ( "os" "testing" + "github.com/openlyinc/pointy" "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" ) func TestConfig_VCConfig(t *testing.T) { @@ -176,3 +178,85 @@ func TestNSXOperatorConfig_GetCACert(t *testing.T) { }) } } + +func TestNsxConfig_NSXLBEnabled(t *testing.T) { + type fields struct { + UseAVILB bool + UseNativeLoadBalancer *bool + } + tests := []struct { + name string + fields fields + want bool + }{{ + name: "avilb", + fields: fields{ + UseAVILB: true, + UseNativeLoadBalancer: nil, + }, + want: false, + }, { + name: "nsxlbnil", + fields: fields{ + UseAVILB: false, + UseNativeLoadBalancer: nil, + }, + want: true, + }, { + name: "nsxlbtrue", + fields: fields{ + UseAVILB: false, + UseNativeLoadBalancer: pointy.Bool(true), + }, + want: true, + }, { + name: "nsxlbfalse", + fields: fields{ + UseAVILB: false, + UseNativeLoadBalancer: pointy.Bool(false), + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nsxConfig := &NsxConfig{ + UseAVILoadBalancer: tt.fields.UseAVILB, + UseNSXLoadBalancer: tt.fields.UseNativeLoadBalancer, + } + assert.Equalf(t, tt.want, nsxConfig.NSXLBEnabled(), "NSXLBEnabled()") + }) + } +} + +func TestNsxConfig_GetServiceSize(t *testing.T) { + type fields struct { + ServiceSize string + } + tests := []struct { + name string + fields fields + want string + }{{ + name: "default", + fields: fields{ + ServiceSize: "", + }, + want: model.LBService_SIZE_SMALL, + }, { + name: "large", + fields: fields{ + ServiceSize: model.LBService_SIZE_LARGE, + }, + want: model.LBService_SIZE_LARGE, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nsxConfig := &NsxConfig{ + NSXLBSize: tt.fields.ServiceSize, + } + assert.Equalf(t, tt.want, nsxConfig.GetNSXLBSize(), "GetNSXLBSize()") + }) + } +} From f008448ab50d769118d3310ddf47bf09bec35197 Mon Sep 17 00:00:00 2001 From: Ran Gu Date: Thu, 25 Jul 2024 15:09:55 +0800 Subject: [PATCH 21/23] [TenantManager][ExternalAddressBinding] Add CRD (#639) Signed-off-by: gran --- .../crd/nsx.vmware.com_addressbindings.yaml | 65 +++++++ .../v1alpha1/addressbinding_types.go | 41 ++++ .../v1alpha1/zz_generated.deepcopy.go | 89 +++++++++ pkg/apis/v1alpha1/addressbinding_types.go | 41 ++++ pkg/apis/v1alpha1/zz_generated.deepcopy.go | 89 +++++++++ .../nsx.vmware.com/v1alpha1/addressbinding.go | 182 ++++++++++++++++++ .../v1alpha1/fake/fake_addressbinding.go | 128 ++++++++++++ .../fake/fake_nsx.vmware.com_client.go | 4 + .../v1alpha1/generated_expansion.go | 2 + .../v1alpha1/nsx.vmware.com_client.go | 5 + .../informers/externalversions/generic.go | 2 + .../nsx.vmware.com/v1alpha1/addressbinding.go | 77 ++++++++ .../nsx.vmware.com/v1alpha1/interface.go | 7 + .../nsx.vmware.com/v1alpha1/addressbinding.go | 86 +++++++++ .../v1alpha1/expansion_generated.go | 8 + 15 files changed, 826 insertions(+) create mode 100644 build/yaml/crd/nsx.vmware.com_addressbindings.yaml create mode 100644 pkg/apis/nsx.vmware.com/v1alpha1/addressbinding_types.go create mode 100644 pkg/apis/v1alpha1/addressbinding_types.go create mode 100644 pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/addressbinding.go create mode 100644 pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_addressbinding.go create mode 100644 pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/addressbinding.go create mode 100644 pkg/client/listers/nsx.vmware.com/v1alpha1/addressbinding.go diff --git a/build/yaml/crd/nsx.vmware.com_addressbindings.yaml b/build/yaml/crd/nsx.vmware.com_addressbindings.yaml new file mode 100644 index 000000000..d406256e3 --- /dev/null +++ b/build/yaml/crd/nsx.vmware.com_addressbindings.yaml @@ -0,0 +1,65 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: addressbindings.nsx.vmware.com +spec: + group: nsx.vmware.com + names: + kind: AddressBinding + listKind: AddressBindingList + plural: addressbindings + singular: addressbinding + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AddressBinding is used to manage 1:1 NAT for a VM/NetworkInterface. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + interfaceName: + description: InterfaceName contains the interface name of the VM, + if not set, the first interface of the VM will be used + type: string + vmName: + description: VMName contains the VM's name + type: string + required: + - vmName + type: object + status: + properties: + ipAddress: + type: string + required: + - ipAddress + type: object + required: + - spec + - status + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/addressbinding_types.go b/pkg/apis/nsx.vmware.com/v1alpha1/addressbinding_types.go new file mode 100644 index 000000000..8faf6c44e --- /dev/null +++ b/pkg/apis/nsx.vmware.com/v1alpha1/addressbinding_types.go @@ -0,0 +1,41 @@ +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +type AddressBindingSpec struct { + // VMName contains the VM's name + VMName string `json:"vmName"` + // InterfaceName contains the interface name of the VM, if not set, the first interface of the VM will be used + InterfaceName string `json:"interfaceName,omitempty"` +} + +type AddressBindingStatus struct { + IPAddress string `json:"ipAddress"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// AddressBinding is used to manage 1:1 NAT for a VM/NetworkInterface. +type AddressBinding struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AddressBindingSpec `json:"spec"` + Status AddressBindingStatus `json:"status"` +} + +//+kubebuilder:object:root=true + +// AddressBindingList contains a list of AddressBinding. +type AddressBindingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AddressBinding `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AddressBinding{}, &AddressBindingList{}) +} diff --git a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go index 63704edcd..02a92beff 100644 --- a/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go @@ -12,6 +12,95 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBinding) DeepCopyInto(out *AddressBinding) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBinding. +func (in *AddressBinding) DeepCopy() *AddressBinding { + if in == nil { + return nil + } + out := new(AddressBinding) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressBinding) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBindingList) DeepCopyInto(out *AddressBindingList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AddressBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingList. +func (in *AddressBindingList) DeepCopy() *AddressBindingList { + if in == nil { + return nil + } + out := new(AddressBindingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressBindingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBindingSpec) DeepCopyInto(out *AddressBindingSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingSpec. +func (in *AddressBindingSpec) DeepCopy() *AddressBindingSpec { + if in == nil { + return nil + } + out := new(AddressBindingSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBindingStatus) DeepCopyInto(out *AddressBindingStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingStatus. +func (in *AddressBindingStatus) DeepCopy() *AddressBindingStatus { + if in == nil { + return nil + } + out := new(AddressBindingStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AdvancedConfig) DeepCopyInto(out *AdvancedConfig) { *out = *in diff --git a/pkg/apis/v1alpha1/addressbinding_types.go b/pkg/apis/v1alpha1/addressbinding_types.go new file mode 100644 index 000000000..8faf6c44e --- /dev/null +++ b/pkg/apis/v1alpha1/addressbinding_types.go @@ -0,0 +1,41 @@ +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +type AddressBindingSpec struct { + // VMName contains the VM's name + VMName string `json:"vmName"` + // InterfaceName contains the interface name of the VM, if not set, the first interface of the VM will be used + InterfaceName string `json:"interfaceName,omitempty"` +} + +type AddressBindingStatus struct { + IPAddress string `json:"ipAddress"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// AddressBinding is used to manage 1:1 NAT for a VM/NetworkInterface. +type AddressBinding struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AddressBindingSpec `json:"spec"` + Status AddressBindingStatus `json:"status"` +} + +//+kubebuilder:object:root=true + +// AddressBindingList contains a list of AddressBinding. +type AddressBindingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AddressBinding `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AddressBinding{}, &AddressBindingList{}) +} diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go index 63704edcd..02a92beff 100644 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go @@ -12,6 +12,95 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBinding) DeepCopyInto(out *AddressBinding) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBinding. +func (in *AddressBinding) DeepCopy() *AddressBinding { + if in == nil { + return nil + } + out := new(AddressBinding) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressBinding) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBindingList) DeepCopyInto(out *AddressBindingList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AddressBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingList. +func (in *AddressBindingList) DeepCopy() *AddressBindingList { + if in == nil { + return nil + } + out := new(AddressBindingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressBindingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBindingSpec) DeepCopyInto(out *AddressBindingSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingSpec. +func (in *AddressBindingSpec) DeepCopy() *AddressBindingSpec { + if in == nil { + return nil + } + out := new(AddressBindingSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressBindingStatus) DeepCopyInto(out *AddressBindingStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressBindingStatus. +func (in *AddressBindingStatus) DeepCopy() *AddressBindingStatus { + if in == nil { + return nil + } + out := new(AddressBindingStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AdvancedConfig) DeepCopyInto(out *AdvancedConfig) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/addressbinding.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/addressbinding.go new file mode 100644 index 000000000..bb89024ce --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/addressbinding.go @@ -0,0 +1,182 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + scheme "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// AddressBindingsGetter has a method to return a AddressBindingInterface. +// A group's client should implement this interface. +type AddressBindingsGetter interface { + AddressBindings(namespace string) AddressBindingInterface +} + +// AddressBindingInterface has methods to work with AddressBinding resources. +type AddressBindingInterface interface { + Create(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.CreateOptions) (*v1alpha1.AddressBinding, error) + Update(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (*v1alpha1.AddressBinding, error) + UpdateStatus(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (*v1alpha1.AddressBinding, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.AddressBinding, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.AddressBindingList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.AddressBinding, err error) + AddressBindingExpansion +} + +// addressBindings implements AddressBindingInterface +type addressBindings struct { + client rest.Interface + ns string +} + +// newAddressBindings returns a AddressBindings +func newAddressBindings(c *NsxV1alpha1Client, namespace string) *addressBindings { + return &addressBindings{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the addressBinding, and returns the corresponding addressBinding object, and an error if there is any. +func (c *addressBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Get(). + Namespace(c.ns). + Resource("addressbindings"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of AddressBindings that match those selectors. +func (c *addressBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.AddressBindingList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.AddressBindingList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested addressBindings. +func (c *addressBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a addressBinding and creates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *addressBindings) Create(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.CreateOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Post(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(addressBinding). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a addressBinding and updates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *addressBindings) Update(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Put(). + Namespace(c.ns). + Resource("addressbindings"). + Name(addressBinding.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(addressBinding). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *addressBindings) UpdateStatus(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Put(). + Namespace(c.ns). + Resource("addressbindings"). + Name(addressBinding.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(addressBinding). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the addressBinding and deletes it. Returns an error if one occurs. +func (c *addressBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("addressbindings"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *addressBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("addressbindings"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched addressBinding. +func (c *addressBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.AddressBinding, err error) { + result = &v1alpha1.AddressBinding{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("addressbindings"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_addressbinding.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_addressbinding.go new file mode 100644 index 000000000..dffcbdcdb --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_addressbinding.go @@ -0,0 +1,128 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeAddressBindings implements AddressBindingInterface +type FakeAddressBindings struct { + Fake *FakeNsxV1alpha1 + ns string +} + +var addressbindingsResource = v1alpha1.SchemeGroupVersion.WithResource("addressbindings") + +var addressbindingsKind = v1alpha1.SchemeGroupVersion.WithKind("AddressBinding") + +// Get takes name of the addressBinding, and returns the corresponding addressBinding object, and an error if there is any. +func (c *FakeAddressBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(addressbindingsResource, c.ns, name), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// List takes label and field selectors, and returns the list of AddressBindings that match those selectors. +func (c *FakeAddressBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.AddressBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(addressbindingsResource, addressbindingsKind, c.ns, opts), &v1alpha1.AddressBindingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.AddressBindingList{ListMeta: obj.(*v1alpha1.AddressBindingList).ListMeta} + for _, item := range obj.(*v1alpha1.AddressBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested addressBindings. +func (c *FakeAddressBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(addressbindingsResource, c.ns, opts)) + +} + +// Create takes the representation of a addressBinding and creates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *FakeAddressBindings) Create(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.CreateOptions) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(addressbindingsResource, c.ns, addressBinding), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// Update takes the representation of a addressBinding and updates it. Returns the server's representation of the addressBinding, and an error, if there is any. +func (c *FakeAddressBindings) Update(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(addressbindingsResource, c.ns, addressBinding), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeAddressBindings) UpdateStatus(ctx context.Context, addressBinding *v1alpha1.AddressBinding, opts v1.UpdateOptions) (*v1alpha1.AddressBinding, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(addressbindingsResource, "status", c.ns, addressBinding), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} + +// Delete takes name of the addressBinding and deletes it. Returns an error if one occurs. +func (c *FakeAddressBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(addressbindingsResource, c.ns, name, opts), &v1alpha1.AddressBinding{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeAddressBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(addressbindingsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.AddressBindingList{}) + return err +} + +// Patch applies the patch and returns the patched addressBinding. +func (c *FakeAddressBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.AddressBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(addressbindingsResource, c.ns, name, pt, data, subresources...), &v1alpha1.AddressBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AddressBinding), err +} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go index f073f5a3c..dcdcf5458 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/fake/fake_nsx.vmware.com_client.go @@ -15,6 +15,10 @@ type FakeNsxV1alpha1 struct { *testing.Fake } +func (c *FakeNsxV1alpha1) AddressBindings(namespace string) v1alpha1.AddressBindingInterface { + return &FakeAddressBindings{c, namespace} +} + func (c *FakeNsxV1alpha1) IPAddressAllocations(namespace string) v1alpha1.IPAddressAllocationInterface { return &FakeIPAddressAllocations{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go index cfc317984..2b2573df2 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/generated_expansion.go @@ -5,6 +5,8 @@ package v1alpha1 +type AddressBindingExpansion interface{} + type IPAddressAllocationExpansion interface{} type IPPoolExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go index 5c50677e3..ca34802f8 100644 --- a/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go +++ b/pkg/client/clientset/versioned/typed/nsx.vmware.com/v1alpha1/nsx.vmware.com_client.go @@ -15,6 +15,7 @@ import ( type NsxV1alpha1Interface interface { RESTClient() rest.Interface + AddressBindingsGetter IPAddressAllocationsGetter IPPoolsGetter NSXServiceAccountsGetter @@ -32,6 +33,10 @@ type NsxV1alpha1Client struct { restClient rest.Interface } +func (c *NsxV1alpha1Client) AddressBindings(namespace string) AddressBindingInterface { + return newAddressBindings(c, namespace) +} + func (c *NsxV1alpha1Client) IPAddressAllocations(namespace string) IPAddressAllocationInterface { return newIPAddressAllocations(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 7f49f905c..0a17d3814 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -41,6 +41,8 @@ func (f *genericInformer) Lister() cache.GenericLister { func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { // Group=nsx.vmware.com, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("addressbindings"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().AddressBindings().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("ipaddressallocations"): return &genericInformer{resource: resource.GroupResource(), informer: f.Nsx().V1alpha1().IPAddressAllocations().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("ippools"): diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/addressbinding.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/addressbinding.go new file mode 100644 index 000000000..17f3a2566 --- /dev/null +++ b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/addressbinding.go @@ -0,0 +1,77 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + versioned "github.com/vmware-tanzu/nsx-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/vmware-tanzu/nsx-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/client/listers/nsx.vmware.com/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// AddressBindingInformer provides access to a shared informer and lister for +// AddressBindings. +type AddressBindingInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.AddressBindingLister +} + +type addressBindingInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewAddressBindingInformer constructs a new informer for AddressBinding type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewAddressBindingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredAddressBindingInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredAddressBindingInformer constructs a new informer for AddressBinding type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredAddressBindingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NsxV1alpha1().AddressBindings(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NsxV1alpha1().AddressBindings(namespace).Watch(context.TODO(), options) + }, + }, + &nsxvmwarecomv1alpha1.AddressBinding{}, + resyncPeriod, + indexers, + ) +} + +func (f *addressBindingInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredAddressBindingInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *addressBindingInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&nsxvmwarecomv1alpha1.AddressBinding{}, f.defaultInformer) +} + +func (f *addressBindingInformer) Lister() v1alpha1.AddressBindingLister { + return v1alpha1.NewAddressBindingLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go index 835cd1514..62421cd81 100644 --- a/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/nsx.vmware.com/v1alpha1/interface.go @@ -11,6 +11,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // AddressBindings returns a AddressBindingInformer. + AddressBindings() AddressBindingInformer // IPAddressAllocations returns a IPAddressAllocationInformer. IPAddressAllocations() IPAddressAllocationInformer // IPPools returns a IPPoolInformer. @@ -44,6 +46,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// AddressBindings returns a AddressBindingInformer. +func (v *version) AddressBindings() AddressBindingInformer { + return &addressBindingInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // IPAddressAllocations returns a IPAddressAllocationInformer. func (v *version) IPAddressAllocations() IPAddressAllocationInformer { return &iPAddressAllocationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/addressbinding.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/addressbinding.go new file mode 100644 index 000000000..1668968ea --- /dev/null +++ b/pkg/client/listers/nsx.vmware.com/v1alpha1/addressbinding.go @@ -0,0 +1,86 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// AddressBindingLister helps list AddressBindings. +// All objects returned here must be treated as read-only. +type AddressBindingLister interface { + // List lists all AddressBindings in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) + // AddressBindings returns an object that can list and get AddressBindings. + AddressBindings(namespace string) AddressBindingNamespaceLister + AddressBindingListerExpansion +} + +// addressBindingLister implements the AddressBindingLister interface. +type addressBindingLister struct { + indexer cache.Indexer +} + +// NewAddressBindingLister returns a new AddressBindingLister. +func NewAddressBindingLister(indexer cache.Indexer) AddressBindingLister { + return &addressBindingLister{indexer: indexer} +} + +// List lists all AddressBindings in the indexer. +func (s *addressBindingLister) List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.AddressBinding)) + }) + return ret, err +} + +// AddressBindings returns an object that can list and get AddressBindings. +func (s *addressBindingLister) AddressBindings(namespace string) AddressBindingNamespaceLister { + return addressBindingNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// AddressBindingNamespaceLister helps list and get AddressBindings. +// All objects returned here must be treated as read-only. +type AddressBindingNamespaceLister interface { + // List lists all AddressBindings in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) + // Get retrieves the AddressBinding from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.AddressBinding, error) + AddressBindingNamespaceListerExpansion +} + +// addressBindingNamespaceLister implements the AddressBindingNamespaceLister +// interface. +type addressBindingNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all AddressBindings in the indexer for a given namespace. +func (s addressBindingNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.AddressBinding, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.AddressBinding)) + }) + return ret, err +} + +// Get retrieves the AddressBinding from the indexer for a given namespace and name. +func (s addressBindingNamespaceLister) Get(name string) (*v1alpha1.AddressBinding, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("addressbinding"), name) + } + return obj.(*v1alpha1.AddressBinding), nil +} diff --git a/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go b/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go index f9e197206..d34972490 100644 --- a/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/nsx.vmware.com/v1alpha1/expansion_generated.go @@ -5,6 +5,14 @@ package v1alpha1 +// AddressBindingListerExpansion allows custom methods to be added to +// AddressBindingLister. +type AddressBindingListerExpansion interface{} + +// AddressBindingNamespaceListerExpansion allows custom methods to be added to +// AddressBindingNamespaceLister. +type AddressBindingNamespaceListerExpansion interface{} + // IPAddressAllocationListerExpansion allows custom methods to be added to // IPAddressAllocationLister. type IPAddressAllocationListerExpansion interface{} From a9899a0cc979ca67f5a54447917123708a6ddce2 Mon Sep 17 00:00:00 2001 From: Xie Zheng Date: Thu, 25 Jul 2024 10:50:25 +0800 Subject: [PATCH 22/23] Add crd.nsx.vmware.com apiVersion for vpc controllers Signed-off-by: Xie Zheng --- .../t1/nsx.vmware.com_nsxserviceaccounts.yaml | 179 ++ .../t1/nsx.vmware.com_securitypolicies.yaml | 651 +++++++ ...d.nsx.vmware.com_ipaddressallocations.yaml | 105 ++ .../crd/vpc/crd.nsx.vmware.com_ippools.yaml | 251 +++ .../vpc/crd.nsx.vmware.com_networkinfos.yaml | 71 + .../crd.nsx.vmware.com_securitypolicies.yaml | 660 ++++++++ .../vpc/crd.nsx.vmware.com_staticroutes.yaml | 114 ++ .../vpc/crd.nsx.vmware.com_subnetports.yaml | 122 ++ .../crd/vpc/crd.nsx.vmware.com_subnets.yaml | 146 ++ .../vpc/crd.nsx.vmware.com_subnetsets.yaml | 146 ++ ...x.vmware.com_vpcnetworkconfigurations.yaml | 142 ++ .../v1alpha1/condition_types.go | 29 + pkg/apis/crd.nsx.vmware.com/v1alpha1/doc.go | 4 + .../v1alpha1/groupversion_info.go | 22 + .../v1alpha1/ipaddressallocation_types.go | 63 + .../v1alpha1/ippool_types.go | 73 + .../v1alpha1/networkinfo_types.go | 48 + .../v1alpha1/nsxserviceaccount_types.go | 0 .../crd.nsx.vmware.com/v1alpha1/register.go | 12 + .../v1alpha1/securitypolicy_types.go | 141 ++ .../v1alpha1/staticroute_types.go | 65 + .../v1alpha1/subnet_types.go | 92 + .../v1alpha1/subnetport_types.go | 72 + .../v1alpha1/subnetset_types.go | 67 + .../v1alpha1/vpcnetworkconfiguration_types.go | 95 ++ .../v1alpha1/zz_generated.deepcopy.go | 1492 +++++++++++++++++ pkg/apis/crd.nsx.vmware.com/v1alpha2/doc.go | 4 + .../v1alpha2/groupversion_info.go | 23 + .../v1alpha2/ippool_types.go | 82 + .../crd.nsx.vmware.com/v1alpha2/register.go | 12 + .../v1alpha2/zz_generated.deepcopy.go | 149 ++ pkg/apis/v1alpha1/zz_generated.deepcopy.go | 177 -- .../nsxserviceaccount_controller.go | 2 +- .../nsxserviceaccount_controller_test.go | 2 +- pkg/nsx/services/nsxserviceaccount/builder.go | 2 +- pkg/nsx/services/nsxserviceaccount/cluster.go | 2 +- .../nsxserviceaccount/cluster_test.go | 2 +- test/e2e/nsx_ippool_test.go | 2 +- test/e2e/nsx_networkinfo_test.go | 2 +- test/e2e/nsx_security_policy_test.go | 2 +- test/e2e/nsx_subnet_test.go | 8 +- 41 files changed, 5144 insertions(+), 189 deletions(-) create mode 100644 build/yaml/crd/t1/nsx.vmware.com_nsxserviceaccounts.yaml create mode 100644 build/yaml/crd/t1/nsx.vmware.com_securitypolicies.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_ippools.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml create mode 100644 build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/condition_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/doc.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/groupversion_info.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/ipaddressallocation_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/ippool_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/networkinfo_types.go rename pkg/apis/{ => crd.nsx.vmware.com}/v1alpha1/nsxserviceaccount_types.go (100%) create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/register.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/securitypolicy_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/staticroute_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/subnet_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetport_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetset_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha2/doc.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha2/groupversion_info.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha2/ippool_types.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha2/register.go create mode 100644 pkg/apis/crd.nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go diff --git a/build/yaml/crd/t1/nsx.vmware.com_nsxserviceaccounts.yaml b/build/yaml/crd/t1/nsx.vmware.com_nsxserviceaccounts.yaml new file mode 100644 index 000000000..b29d33835 --- /dev/null +++ b/build/yaml/crd/t1/nsx.vmware.com_nsxserviceaccounts.yaml @@ -0,0 +1,179 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: nsxserviceaccounts.nsx.vmware.com +spec: + group: nsx.vmware.com + names: + kind: NSXServiceAccount + listKind: NSXServiceAccountList + plural: nsxserviceaccounts + singular: nsxserviceaccount + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NSXServiceAccount is the Schema for the nsxserviceaccounts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NSXServiceAccountSpec defines the desired state of NSXServiceAccount + properties: + enableCertRotation: + description: EnableCertRotation enables cert rotation feature in this + cluster when NSXT >=4.1.3 + type: boolean + vpcName: + type: string + type: object + status: + description: NSXServiceAccountStatus defines the observed state of NSXServiceAccount + properties: + clusterID: + type: string + clusterName: + type: string + conditions: + description: |- + Represents the realization status of a NSXServiceAccount's current state. + Known .status.conditions.type is: "Realized" + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + nsxManagers: + items: + type: string + type: array + phase: + type: string + proxyEndpoints: + properties: + addresses: + items: + properties: + hostname: + type: string + ip: + format: ip + type: string + type: object + type: array + ports: + items: + properties: + name: + type: string + port: + type: integer + protocol: + type: string + type: object + type: array + type: object + reason: + type: string + secrets: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + vpcPath: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/t1/nsx.vmware.com_securitypolicies.yaml b/build/yaml/crd/t1/nsx.vmware.com_securitypolicies.yaml new file mode 100644 index 000000000..d93dc4c2a --- /dev/null +++ b/build/yaml/crd/t1/nsx.vmware.com_securitypolicies.yaml @@ -0,0 +1,651 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: securitypolicies.nsx.vmware.com +spec: + group: nsx.vmware.com + names: + kind: SecurityPolicy + listKind: SecurityPolicyList + plural: securitypolicies + singular: securitypolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: SecurityPolicy is the Schema for the securitypolicies API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SecurityPolicySpec defines the desired state of SecurityPolicy. + properties: + appliedTo: + description: |- + AppliedTo is a list of policy targets to apply rules. + Policy level 'Applied To' will take precedence over rule level. + items: + description: SecurityPolicyTarget defines the target endpoints to + apply SecurityPolicy. + properties: + podSelector: + description: PodSelector uses label selector to select Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + priority: + description: Priority defines the order of policy enforcement. + maximum: 1000 + minimum: 0 + type: integer + rules: + description: Rules is a list of policy rules. + items: + description: SecurityPolicyRule defines a rule of SecurityPolicy. + properties: + action: + description: Action specifies the action to be applied on the + rule. + type: string + appliedTo: + description: |- + AppliedTo is a list of rule targets. + Policy level 'Applied To' will take precedence over rule level. + items: + description: SecurityPolicyTarget defines the target endpoints + to apply SecurityPolicy. + properties: + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + destinations: + description: Destinations defines the endpoints where the traffic + is to. For egress rule only. + items: + description: SecurityPolicyPeer defines the source or destination + of traffic. + properties: + ipBlocks: + description: IPBlocks is a list of IP CIDRs. + items: + description: IPBlock describes a particular CIDR that + is allowed or denied to/from the workloads matched + by an AppliedTo. + properties: + cidr: + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". + type: string + required: + - cidr + type: object + type: array + namespaceSelector: + description: NamespaceSelector uses label selector to + select Namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + direction: + description: Direction is the direction of the rule, including + 'In' or 'Ingress', 'Out' or 'Egress'. + type: string + name: + description: Name is the display name of this rule. + type: string + ports: + description: Ports is a list of ports to be matched. + items: + description: SecurityPolicyPort describes protocol and ports + for traffic. + properties: + endPort: + description: EndPort defines the end of port range. + type: integer + port: + anyOf: + - type: integer + - type: string + description: Port is the name or port number. + x-kubernetes-int-or-string: true + protocol: + default: TCP + description: |- + Protocol(TCP, UDP) is the protocol to match traffic. + It is TCP by default. + type: string + type: object + type: array + sources: + description: Sources defines the endpoints where the traffic + is from. For ingress rule only. + items: + description: SecurityPolicyPeer defines the source or destination + of traffic. + properties: + ipBlocks: + description: IPBlocks is a list of IP CIDRs. + items: + description: IPBlock describes a particular CIDR that + is allowed or denied to/from the workloads matched + by an AppliedTo. + properties: + cidr: + description: |- + CIDR is a string representing the IP Block. + A valid example is "192.168.1.1/24". + type: string + required: + - cidr + type: object + type: array + namespaceSelector: + description: NamespaceSelector uses label selector to + select Namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + required: + - action + - direction + type: object + type: array + type: object + status: + description: SecurityPolicyStatus defines the observed state of SecurityPolicy. + properties: + conditions: + description: Conditions describes current state of security policy. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml new file mode 100644 index 000000000..88e4417da --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_ipaddressallocations.yaml @@ -0,0 +1,105 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.0 + creationTimestamp: null + name: ipaddressallocations.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: IPAddressAllocation + listKind: IPAddressAllocationList + plural: ipaddressallocations + singular: ipaddressallocation + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: IPAddressBlockVisibility of IPAddressAllocation + jsonPath: .spec.ip_address_block_visibility + name: IPAddressBlockVisibility + type: string + - description: CIDRs for the IPAddressAllocation + jsonPath: .status.cidr + name: CIDR + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: IPAddressAllocation is the Schema for the IP allocation API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IPAddressAllocationSpec defines the desired state of IPAddressAllocation. + properties: + allocation_size: + description: AllocationSize specifies the size of IP CIDR to be allocated. + type: integer + ip_address_block_visibility: + default: Private + description: IPAddressBlockVisibility specifies the visibility of + the IPBlocks to allocate IP addresses. Can be External, Private + or Project. + enum: + - External + - Private + - Project + type: string + type: object + status: + description: IPAddressAllocationStatus defines the observed state of IPAddressAllocation. + properties: + CIDR: + description: CIDR is the allocated CIDR + type: string + conditions: + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. This should be when the underlying condition changed. + If that is not known, then using the time when the API field + changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + required: + - CIDR + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_ippools.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_ippools.yaml new file mode 100644 index 000000000..ccad6744d --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_ippools.yaml @@ -0,0 +1,251 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ippools.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: IPPool + listKind: IPPoolList + plural: ippools + singular: ippool + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IPPool is the Schema for the ippools API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IPPoolSpec defines the desired state of IPPool. + properties: + subnets: + description: Subnets defines set of subnets need to be allocated. + items: + description: SubnetRequest defines the subnet allocation request. + properties: + ipFamily: + default: IPv4 + description: |- + IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. + This is optional, the default is IPv4. + enum: + - IPv4 + - IPv6 + type: string + name: + description: Name defines the name of this subnet. + type: string + prefixLength: + description: PrefixLength defines prefix length for this subnet. + type: integer + required: + - name + type: object + type: array + type: object + status: + description: IPPoolStatus defines the observed state of IPPool. + properties: + conditions: + description: Conditions defines current state of the IPPool. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + subnets: + description: Subnets defines subnets allocation result. + items: + description: SubnetResult defines the subnet allocation result. + properties: + cidr: + description: CIDR defines the allocated CIDR. + type: string + name: + description: Name defines the name of this subnet. + type: string + required: + - cidr + - name + type: object + type: array + required: + - conditions + - subnets + type: object + required: + - metadata + - spec + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: Type of IPPool + jsonPath: .spec.type + name: Type + type: string + - description: CIDRs for the Subnet + jsonPath: .status.subnets[*].cidr + name: Subnets + type: string + name: v1alpha2 + schema: + openAPIV3Schema: + description: IPPool is the Schema for the ippools API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IPPoolSpec defines the desired state of IPPool. + properties: + subnets: + description: Subnets defines set of subnets need to be allocated. + items: + description: SubnetRequest defines the subnet allocation request. + properties: + ipFamily: + default: IPv4 + description: |- + IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. + This is optional, the default is IPv4. + enum: + - IPv4 + - IPv6 + type: string + name: + description: Name defines the name of this subnet. + type: string + prefixLength: + description: PrefixLength defines prefix length for this subnet. + type: integer + required: + - name + type: object + type: array + type: + description: Type defines the type of this IPPool, Public or Private. + enum: + - Public + - Private + type: string + type: object + status: + description: IPPoolStatus defines the observed state of IPPool. + properties: + conditions: + description: Conditions defines current state of the IPPool. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + subnets: + description: Subnets defines subnets allocation result. + items: + description: SubnetResult defines the subnet allocation result. + properties: + cidr: + description: CIDR defines the allocated CIDR. + type: string + name: + description: Name defines the name of this subnet. + type: string + required: + - cidr + - name + type: object + type: array + required: + - conditions + - subnets + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml new file mode 100644 index 000000000..85fcb94f7 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_networkinfos.yaml @@ -0,0 +1,71 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: networkinfos.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: NetworkInfo + listKind: NetworkInfoList + plural: networkinfos + singular: networkinfo + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NetworkInfo is used to report the network information for a namespace. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + vpcs: + items: + description: VPCState defines information for VPC. + properties: + defaultSNATIP: + description: Default SNAT IP for Private Subnets. + type: string + loadBalancerIPAddresses: + description: LoadBalancerIPAddresses (AVI SE Subnet CIDR or NSX + LB SNAT IPs). + type: string + name: + description: VPC name. + type: string + privateIPv4CIDRs: + description: Private CIDRs used for the VPC. + items: + type: string + type: array + vpcPath: + description: NSX Policy path for VPC. + type: string + required: + - defaultSNATIP + - name + - vpcPath + type: object + type: array + required: + - vpcs + type: object + served: true + storage: true diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml new file mode 100644 index 000000000..756e079cb --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_securitypolicies.yaml @@ -0,0 +1,660 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.0 + creationTimestamp: null + name: securitypolicies.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: SecurityPolicy + listKind: SecurityPolicyList + plural: securitypolicies + singular: securitypolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: SecurityPolicy is the Schema for the securitypolicies API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SecurityPolicySpec defines the desired state of SecurityPolicy. + properties: + appliedTo: + description: AppliedTo is a list of policy targets to apply rules. + Policy level 'Applied To' will take precedence over rule level. + items: + description: SecurityPolicyTarget defines the target endpoints to + apply SecurityPolicy. + properties: + podSelector: + description: PodSelector uses label selector to select Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + priority: + description: Priority defines the order of policy enforcement. + maximum: 1000 + minimum: 0 + type: integer + rules: + description: Rules is a list of policy rules. + items: + description: SecurityPolicyRule defines a rule of SecurityPolicy. + properties: + action: + description: Action specifies the action to be applied on the + rule. + type: string + appliedTo: + description: AppliedTo is a list of rule targets. Policy level + 'Applied To' will take precedence over rule level. + items: + description: SecurityPolicyTarget defines the target endpoints + to apply SecurityPolicy. + properties: + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + destinations: + description: Destinations defines the endpoints where the traffic + is to. For egress rule only. + items: + description: SecurityPolicyPeer defines the source or destination + of traffic. + properties: + ipBlocks: + description: IPBlocks is a list of IP CIDRs. + items: + description: IPBlock describes a particular CIDR that + is allowed or denied to/from the workloads matched + by an AppliedTo. + properties: + cidr: + description: CIDR is a string representing the IP + Block. A valid example is "192.168.1.1/24". + type: string + required: + - cidr + type: object + type: array + namespaceSelector: + description: NamespaceSelector uses label selector to + select Namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + direction: + description: Direction is the direction of the rule, including + 'In' or 'Ingress', 'Out' or 'Egress'. + type: string + name: + description: Name is the display name of this rule. + type: string + ports: + description: Ports is a list of ports to be matched. + items: + description: SecurityPolicyPort describes protocol and ports + for traffic. + properties: + endPort: + description: EndPort defines the end of port range. + type: integer + port: + anyOf: + - type: integer + - type: string + description: Port is the name or port number. + x-kubernetes-int-or-string: true + protocol: + default: TCP + description: Protocol(TCP, UDP) is the protocol to match + traffic. It is TCP by default. + type: string + type: object + type: array + sources: + description: Sources defines the endpoints where the traffic + is from. For ingress rule only. + items: + description: SecurityPolicyPeer defines the source or destination + of traffic. + properties: + ipBlocks: + description: IPBlocks is a list of IP CIDRs. + items: + description: IPBlock describes a particular CIDR that + is allowed or denied to/from the workloads matched + by an AppliedTo. + properties: + cidr: + description: CIDR is a string representing the IP + Block. A valid example is "192.168.1.1/24". + type: string + required: + - cidr + type: object + type: array + namespaceSelector: + description: NamespaceSelector uses label selector to + select Namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + podSelector: + description: PodSelector uses label selector to select + Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + vmSelector: + description: VMSelector uses label selector to select + VMs. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + required: + - action + - direction + type: object + type: array + type: object + status: + description: SecurityPolicyStatus defines the observed state of SecurityPolicy. + properties: + conditions: + description: Conditions describes current state of security policy. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. This should be when the underlying condition changed. + If that is not known, then using the time when the API field + changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + required: + - conditions + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml new file mode 100644 index 000000000..166c61a89 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_staticroutes.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: staticroutes.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: StaticRoute + listKind: StaticRouteList + plural: staticroutes + singular: staticroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Network in CIDR format + jsonPath: .spec.network + name: Network + type: string + - description: Next Hops + jsonPath: .spec.nextHops[*].ipAddress + name: NextHops + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: StaticRoute is the Schema for the staticroutes API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: StaticRouteSpec defines static routes configuration on VPC. + properties: + network: + description: Specify network address in CIDR format. + format: cidr + type: string + nextHops: + description: Next hop gateway + items: + description: NextHop defines next hop configuration for network. + properties: + ipAddress: + description: Next hop gateway IP address. + format: ip + type: string + required: + - ipAddress + type: object + minItems: 1 + type: array + required: + - network + - nextHops + type: object + status: + description: StaticRouteStatus defines the observed state of StaticRoute. + properties: + conditions: + items: + description: StaticRouteCondition defines condition of StaticRoute. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + nsxResourcePath: + type: string + required: + - conditions + - nsxResourcePath + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml new file mode 100644 index 000000000..3737aa586 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetports.yaml @@ -0,0 +1,122 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: subnetports.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: SubnetPort + listKind: SubnetPortList + plural: subnetports + singular: subnetport + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Attachment VIF ID owned by the SubnetPort. + jsonPath: .status.attachment.id + name: VIFID + type: string + - description: IP address string with the prefix. + jsonPath: .status.networkInterfaceConfig.ipAddresses[0].ipAddress + name: IPAddress + type: string + - description: MAC Address of the SubnetPort. + jsonPath: .status.networkInterfaceConfig.macAddress + name: MACAddress + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: SubnetPort is the Schema for the subnetports API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SubnetPortSpec defines the desired state of SubnetPort. + properties: + subnet: + description: Subnet defines the parent Subnet name of the SubnetPort. + type: string + subnetSet: + description: SubnetSet defines the parent SubnetSet name of the SubnetPort. + type: string + type: object + status: + description: SubnetPortStatus defines the observed state of SubnetPort. + properties: + attachment: + description: Subnet port attachment state. + properties: + id: + type: string + type: object + conditions: + description: Conditions describes current state of SubnetPort. + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + networkInterfaceConfig: + properties: + ipAddresses: + items: + properties: + gateway: + type: string + ipAddress: + description: IP address string with the prefix. + type: string + type: object + type: array + logicalSwitchUUID: + type: string + macAddress: + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml new file mode 100644 index 000000000..299fdd984 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnets.yaml @@ -0,0 +1,146 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: subnets.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: Subnet + listKind: SubnetList + plural: subnets + singular: subnet + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Access mode of Subnet + jsonPath: .spec.accessMode + name: AccessMode + type: string + - description: Size of Subnet + jsonPath: .spec.ipv4SubnetSize + name: IPv4SubnetSize + type: string + - description: CIDRs for the Subnet + jsonPath: .status.ipAddresses[*] + name: IPAddresses + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Subnet is the Schema for the subnets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SubnetSpec defines the desired state of Subnet. + properties: + DHCPConfig: + description: DHCPConfig DHCP configuration. + properties: + enableDHCP: + default: false + type: boolean + type: object + accessMode: + description: Access mode of Subnet, accessible only from within VPC + or from outside VPC. + enum: + - Private + - Public + type: string + advancedConfig: + description: Subnet advanced configuration. + properties: + staticIPAllocation: + description: StaticIPAllocation configuration for subnet ports + with VIF attachment. + properties: + enable: + default: false + description: Enable or disable static IP allocation for subnet + ports with VIF attachment. + type: boolean + type: object + type: object + ipAddresses: + description: Subnet CIDRS. + items: + type: string + maxItems: 2 + minItems: 0 + type: array + ipv4SubnetSize: + description: Size of Subnet based upon estimated workload count. + maximum: 65536 + minimum: 16 + type: integer + type: object + status: + description: SubnetStatus defines the observed state of Subnet. + properties: + DHCPServerAddresses: + items: + type: string + type: array + conditions: + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + gatewayAddresses: + items: + type: string + type: array + networkAddresses: + items: + type: string + type: array + nsxResourcePath: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml new file mode 100644 index 000000000..6d0b23fae --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_subnetsets.yaml @@ -0,0 +1,146 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: subnetsets.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: SubnetSet + listKind: SubnetSetList + plural: subnetsets + singular: subnetset + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Access mode of Subnet + jsonPath: .spec.accessMode + name: AccessMode + type: string + - description: Size of Subnet + jsonPath: .spec.ipv4SubnetSize + name: IPv4SubnetSize + type: string + - description: CIDRs for the Subnet + jsonPath: .status.subnets[*].ipAddresses[*] + name: IPAddresses + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: SubnetSet is the Schema for the subnetsets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SubnetSetSpec defines the desired state of SubnetSet. + properties: + DHCPConfig: + description: DHCPConfig DHCP configuration. + properties: + enableDHCP: + default: false + type: boolean + type: object + accessMode: + description: Access mode of Subnet, accessible only from within VPC + or from outside VPC. + enum: + - Private + - Public + type: string + advancedConfig: + description: Subnet advanced configuration. + properties: + staticIPAllocation: + description: StaticIPAllocation configuration for subnet ports + with VIF attachment. + properties: + enable: + default: false + description: Enable or disable static IP allocation for subnet + ports with VIF attachment. + type: boolean + type: object + type: object + ipv4SubnetSize: + description: Size of Subnet based upon estimated workload count. + maximum: 65536 + minimum: 16 + type: integer + type: object + status: + description: SubnetSetStatus defines the observed state of SubnetSet. + properties: + conditions: + items: + description: Condition defines condition of custom resource. + properties: + lastTransitionTime: + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: Message shows a human-readable message about condition. + type: string + reason: + description: Reason shows a brief reason of condition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type defines condition type. + type: string + required: + - status + - type + type: object + type: array + subnets: + items: + description: SubnetInfo defines the observed state of a single Subnet + of a SubnetSet. + properties: + DHCPServerAddresses: + items: + type: string + type: array + gatewayAddresses: + items: + type: string + type: array + networkAddresses: + items: + type: string + type: array + nsxResourcePath: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml b/build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml new file mode 100644 index 000000000..dbce17082 --- /dev/null +++ b/build/yaml/crd/vpc/crd.nsx.vmware.com_vpcnetworkconfigurations.yaml @@ -0,0 +1,142 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: vpcnetworkconfigurations.crd.nsx.vmware.com +spec: + group: crd.nsx.vmware.com + names: + kind: VPCNetworkConfiguration + listKind: VPCNetworkConfigurationList + plural: vpcnetworkconfigurations + singular: vpcnetworkconfiguration + scope: Cluster + versions: + - additionalPrinterColumns: + - description: NSXTProject the Namespace associated with + jsonPath: .spec.nsxtProject + name: NSXTProject + type: string + - description: ExternalIPv4Blocks assigned to the Namespace + jsonPath: .spec.externalIPv4Blocks + name: ExternalIPv4Blocks + type: string + - description: PrivateIPv4CIDRs assigned to the Namespace + jsonPath: .spec.privateIPv4CIDRs + name: PrivateIPv4CIDRs + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. + There is a default VPCNetworkConfiguration that applies to Namespaces + do not have a VPCNetworkConfiguration assigned. When a field is not set + in a Namespace's VPCNetworkConfiguration, the Namespace will use the value + in the default VPCNetworkConfiguration. + properties: + defaultGatewayPath: + description: PolicyPath of Tier0 or Tier0 VRF gateway. + type: string + defaultIPv4SubnetSize: + default: 26 + description: |- + Default size of Subnet based upon estimated workload count. + Defaults to 26. + type: integer + defaultSubnetAccessMode: + description: |- + DefaultSubnetAccessMode defines the access mode of the default SubnetSet for PodVM and VM. + Must be Public or Private. + enum: + - Public + - Private + type: string + edgeClusterPath: + description: Edge cluster path on which the networking elements will + be created. + type: string + externalIPv4Blocks: + description: NSX-T IPv4 Block paths used to allocate external Subnets. + items: + type: string + maxItems: 5 + minItems: 0 + type: array + nsxtProject: + description: NSX-T Project the Namespace associated with. + type: string + privateIPv4CIDRs: + description: Private IPv4 CIDRs used to allocate Private Subnets. + items: + type: string + maxItems: 5 + minItems: 0 + type: array + shortID: + description: |- + ShortID specifies Identifier to use when displaying VPC context in logs. + Less than or equal to 8 characters. + maxLength: 8 + type: string + vpc: + description: |- + NSX path of the VPC the Namespace associated with. + If vpc is set, only defaultIPv4SubnetSize and defaultSubnetAccessMode + take effect, other fields are ignored. + type: string + type: object + status: + description: VPCNetworkConfigurationStatus defines the observed state + of VPCNetworkConfiguration + properties: + vpcs: + description: VPCs describes VPC info, now it includes lb Subnet info + which are needed for AKO. + items: + description: VPCInfo defines VPC info needed by tenant admin. + properties: + lbSubnetPath: + description: AVISESubnetPath is the NSX Policy Path for the + AVI SE Subnet. + type: string + name: + description: VPC name. + type: string + nsxLoadBalancerPath: + description: NSXLoadBalancerPath is the NSX Policy path for + the NSX Load Balancer. + type: string + required: + - name + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/condition_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/condition_types.go new file mode 100644 index 000000000..5d708b849 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/condition_types.go @@ -0,0 +1,29 @@ +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ConditionType string + +const ( + Ready ConditionType = "Ready" +) + +// Condition defines condition of custom resource. +type Condition struct { + // Type defines condition type. + Type ConditionType `json:"type"` + // Status of the condition, one of True, False, Unknown. + Status corev1.ConditionStatus `json:"status"` + // Last time the condition transitioned from one status to another. + // This should be when the underlying condition changed. If that is not known, then using the time when + // the API field changed is acceptable. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + // Reason shows a brief reason of condition. + Reason string `json:"reason,omitempty"` + // Message shows a human-readable message about condition. + Message string `json:"message,omitempty"` +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/doc.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/doc.go new file mode 100644 index 000000000..f452fd25d --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/doc.go @@ -0,0 +1,4 @@ +// +k8s:deepcopy-gen=package +// +groupName=crd.nsx.vmware.com + +package v1alpha1 diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/groupversion_info.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/groupversion_info.go new file mode 100644 index 000000000..c4d8528f4 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/groupversion_info.go @@ -0,0 +1,22 @@ +/* Copyright © 2021 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// +kubebuilder:object:generate=true +// +groupName=crd.nsx.vmware.com +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "crd.nsx.vmware.com", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/ipaddressallocation_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/ipaddressallocation_types.go new file mode 100644 index 000000000..6a50925c5 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/ipaddressallocation_types.go @@ -0,0 +1,63 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type IPAddressVisibility string + +const ( + IPAddressVisibilityExternal = "External" + IPAddressVisibilityPrivate = "Private" + IPAddressVisibilityProject = "Project" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// IPAddressAllocation is the Schema for the IP allocation API. +// +kubebuilder:printcolumn:name="IPAddressBlockVisibility",type=string,JSONPath=`.spec.ip_address_block_visibility`,description="IPAddressBlockVisibility of IPAddressAllocation" +// +kubebuilder:printcolumn:name="CIDR",type=string,JSONPath=`.status.cidr`,description="CIDRs for the IPAddressAllocation" +type IPAddressAllocation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec IPAddressAllocationSpec `json:"spec"` + Status IPAddressAllocationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPAddressAllocationList contains a list of IPAddressAllocation. +type IPAddressAllocationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPAddressAllocation `json:"items"` +} + +// IPAddressAllocationSpec defines the desired state of IPAddressAllocation. +type IPAddressAllocationSpec struct { + // IPAddressBlockVisibility specifies the visibility of the IPBlocks to allocate IP addresses. Can be External, Private or Project. + // +kubebuilder:validation:Enum=External;Private;Project + // +kubebuilder:default=Private + // +optional + IPAddressBlockVisibility IPAddressVisibility `json:"ip_address_block_visibility,omitempty"` + // AllocationSize specifies the size of IP CIDR to be allocated. + AllocationSize int `json:"allocation_size,omitempty"` +} + +// IPAddressAllocationStatus defines the observed state of IPAddressAllocation. +type IPAddressAllocationStatus struct { + // CIDR is the allocated CIDR + CIDR string `json:"CIDR"` + Conditions []Condition `json:"conditions,omitempty"` +} + +func init() { + SchemeBuilder.Register(&IPAddressAllocation{}, &IPAddressAllocationList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/ippool_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/ippool_types.go new file mode 100644 index 000000000..6620529b0 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/ippool_types.go @@ -0,0 +1,73 @@ +/* Copyright © 2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// IPPool is the Schema for the ippools API. +type IPPool struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec IPPoolSpec `json:"spec"` + Status IPPoolStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPPoolList contains a list of IPPool. +type IPPoolList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPPool `json:"items"` +} + +// IPPoolSpec defines the desired state of IPPool. +type IPPoolSpec struct { + // Subnets defines set of subnets need to be allocated. + // +optional + Subnets []SubnetRequest `json:"subnets"` +} + +// IPPoolStatus defines the observed state of IPPool. +type IPPoolStatus struct { + // Subnets defines subnets allocation result. + Subnets []SubnetResult `json:"subnets"` + // Conditions defines current state of the IPPool. + Conditions []Condition `json:"conditions"` +} + +// SubnetRequest defines the subnet allocation request. +type SubnetRequest struct { + // PrefixLength defines prefix length for this subnet. + PrefixLength int `json:"prefixLength,omitempty"` + + // IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. + // This is optional, the default is IPv4. + // +kubebuilder:validation:Enum=IPv4;IPv6 + // +kubebuilder:default=IPv4 + IPFamily string `json:"ipFamily,omitempty"` + + // Name defines the name of this subnet. + Name string `json:"name"` +} + +// SubnetResult defines the subnet allocation result. +type SubnetResult struct { + // CIDR defines the allocated CIDR. + CIDR string `json:"cidr"` + + // Name defines the name of this subnet. + Name string `json:"name"` +} + +func init() { + SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/networkinfo_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/networkinfo_types.go new file mode 100644 index 000000000..4785fa7ec --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/networkinfo_types.go @@ -0,0 +1,48 @@ +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:storageversion + +// NetworkInfo is used to report the network information for a namespace. +// +kubebuilder:resource:path=networkinfos +type NetworkInfo struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + VPCs []VPCState `json:"vpcs"` +} + +//+kubebuilder:object:root=true + +// NetworkInfoList contains a list of NetworkInfo. +type NetworkInfoList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []NetworkInfo `json:"items"` +} + +// VPCState defines information for VPC. +type VPCState struct { + // VPC name. + Name string `json:"name"` + // NSX Policy path for VPC. + VPCPath string `json:"vpcPath"` + // Default SNAT IP for Private Subnets. + DefaultSNATIP string `json:"defaultSNATIP"` + // LoadBalancerIPAddresses (AVI SE Subnet CIDR or NSX LB SNAT IPs). + LoadBalancerIPAddresses string `json:"loadBalancerIPAddresses,omitempty"` + // Private CIDRs used for the VPC. + PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs,omitempty"` +} + +func init() { + SchemeBuilder.Register(&NetworkInfo{}, &NetworkInfoList{}) +} diff --git a/pkg/apis/v1alpha1/nsxserviceaccount_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/nsxserviceaccount_types.go similarity index 100% rename from pkg/apis/v1alpha1/nsxserviceaccount_types.go rename to pkg/apis/crd.nsx.vmware.com/v1alpha1/nsxserviceaccount_types.go diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/register.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/register.go new file mode 100644 index 000000000..2dfd631eb --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/register.go @@ -0,0 +1,12 @@ +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects. +var SchemeGroupVersion = GroupVersion + +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/securitypolicy_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/securitypolicy_types.go new file mode 100644 index 000000000..246965a80 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/securitypolicy_types.go @@ -0,0 +1,141 @@ +/* Copyright © 2021 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// +kubebuilder:object:generate=true +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// RuleAction describes the action to be applied on traffic matching a rule. +type RuleAction string + +const ( + // RuleActionAllow describes that the traffic matching the rule must be allowed. + RuleActionAllow RuleAction = "Allow" + // RuleActionDrop describes that the traffic matching the rule must be dropped. + RuleActionDrop RuleAction = "Drop" + // RuleActionReject indicates that the traffic matching the rule must be rejected and the + // client will receive a response. + RuleActionReject RuleAction = "Reject" +) + +// RuleDirection specifies the direction of traffic. +type RuleDirection string + +const ( + // RuleDirectionIn specifies that the direction of traffic must be ingress, equivalent to "Ingress". + RuleDirectionIn RuleDirection = "In" + // RuleDirectionIngress specifies that the direction of traffic must be ingress, equivalent to "In". + RuleDirectionIngress RuleDirection = "Ingress" + // RuleDirectionOut specifies that the direction of traffic must be egress, equivalent to "Egress". + RuleDirectionOut RuleDirection = "Out" + // RuleDirectionEgress specifies that the direction of traffic must be egress, equivalent to "Out". + RuleDirectionEgress RuleDirection = "Egress" +) + +// SecurityPolicySpec defines the desired state of SecurityPolicy. +type SecurityPolicySpec struct { + // Priority defines the order of policy enforcement. + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=1000 + Priority int `json:"priority,omitempty"` + // AppliedTo is a list of policy targets to apply rules. + // Policy level 'Applied To' will take precedence over rule level. + AppliedTo []SecurityPolicyTarget `json:"appliedTo,omitempty"` + // Rules is a list of policy rules. + Rules []SecurityPolicyRule `json:"rules,omitempty"` +} + +// SecurityPolicyRule defines a rule of SecurityPolicy. +type SecurityPolicyRule struct { + // Action specifies the action to be applied on the rule. + Action *RuleAction `json:"action"` + // AppliedTo is a list of rule targets. + // Policy level 'Applied To' will take precedence over rule level. + AppliedTo []SecurityPolicyTarget `json:"appliedTo,omitempty"` + // Direction is the direction of the rule, including 'In' or 'Ingress', 'Out' or 'Egress'. + Direction *RuleDirection `json:"direction"` + // Sources defines the endpoints where the traffic is from. For ingress rule only. + Sources []SecurityPolicyPeer `json:"sources,omitempty"` + // Destinations defines the endpoints where the traffic is to. For egress rule only. + Destinations []SecurityPolicyPeer `json:"destinations,omitempty"` + // Ports is a list of ports to be matched. + Ports []SecurityPolicyPort `json:"ports,omitempty"` + // Name is the display name of this rule. + Name string `json:"name,omitempty"` +} + +// SecurityPolicyTarget defines the target endpoints to apply SecurityPolicy. +type SecurityPolicyTarget struct { + // VMSelector uses label selector to select VMs. + VMSelector *metav1.LabelSelector `json:"vmSelector,omitempty"` + // PodSelector uses label selector to select Pods. + PodSelector *metav1.LabelSelector `json:"podSelector,omitempty"` +} + +// SecurityPolicyPeer defines the source or destination of traffic. +type SecurityPolicyPeer struct { + // VMSelector uses label selector to select VMs. + VMSelector *metav1.LabelSelector `json:"vmSelector,omitempty"` + // PodSelector uses label selector to select Pods. + PodSelector *metav1.LabelSelector `json:"podSelector,omitempty"` + // NamespaceSelector uses label selector to select Namespaces. + NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"` + // IPBlocks is a list of IP CIDRs. + IPBlocks []IPBlock `json:"ipBlocks,omitempty"` +} + +// IPBlock describes a particular CIDR that is allowed or denied to/from the workloads matched by an AppliedTo. +type IPBlock struct { + // CIDR is a string representing the IP Block. + // A valid example is "192.168.1.1/24". + CIDR string `json:"cidr"` +} + +// SecurityPolicyPort describes protocol and ports for traffic. +type SecurityPolicyPort struct { + // Protocol(TCP, UDP) is the protocol to match traffic. + // It is TCP by default. + Protocol corev1.Protocol `json:"protocol,omitempty"` + // Port is the name or port number. + Port intstr.IntOrString `json:"port,omitempty"` + // EndPort defines the end of port range. + EndPort int `json:"endPort,omitempty"` +} + +// SecurityPolicyStatus defines the observed state of SecurityPolicy. +type SecurityPolicyStatus struct { + // Conditions describes current state of security policy. + Conditions []Condition `json:"conditions"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// SecurityPolicy is the Schema for the securitypolicies API. +type SecurityPolicy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SecurityPolicySpec `json:"spec"` + Status SecurityPolicyStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// SecurityPolicyList contains a list of SecurityPolicy. +type SecurityPolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SecurityPolicy `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SecurityPolicy{}, &SecurityPolicyList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/staticroute_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/staticroute_types.go new file mode 100644 index 000000000..87d6b7b80 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/staticroute_types.go @@ -0,0 +1,65 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type StaticRouteStatusCondition string + +// StaticRouteCondition defines condition of StaticRoute. +type StaticRouteCondition Condition + +// StaticRouteSpec defines static routes configuration on VPC. +type StaticRouteSpec struct { + // Specify network address in CIDR format. + // +kubebuilder:validation:Format=cidr + Network string `json:"network"` + // Next hop gateway + // +kubebuilder:validation:MinItems=1 + NextHops []NextHop `json:"nextHops"` +} + +// NextHop defines next hop configuration for network. +type NextHop struct { + // Next hop gateway IP address. + // +kubebuilder:validation:Format=ip + IPAddress string `json:"ipAddress"` +} + +// StaticRouteStatus defines the observed state of StaticRoute. +type StaticRouteStatus struct { + Conditions []StaticRouteCondition `json:"conditions"` + NSXResourcePath string `json:"nsxResourcePath"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// StaticRoute is the Schema for the staticroutes API. +// +kubebuilder:printcolumn:name="Network",type=string,JSONPath=`.spec.network`,description="Network in CIDR format" +// +kubebuilder:printcolumn:name="NextHops",type=string,JSONPath=`.spec.nextHops[*].ipAddress`,description="Next Hops" +type StaticRoute struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec StaticRouteSpec `json:"spec,omitempty"` + Status StaticRouteStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// StaticRouteList contains a list of StaticRoute. +type StaticRouteList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []StaticRoute `json:"items"` +} + +func init() { + SchemeBuilder.Register(&StaticRoute{}, &StaticRouteList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnet_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnet_types.go new file mode 100644 index 000000000..47553cd10 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnet_types.go @@ -0,0 +1,92 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type AccessMode string + +// SubnetSpec defines the desired state of Subnet. +type SubnetSpec struct { + // Size of Subnet based upon estimated workload count. + // +kubebuilder:validation:Maximum:=65536 + // +kubebuilder:validation:Minimum:=16 + IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` + // Access mode of Subnet, accessible only from within VPC or from outside VPC. + // +kubebuilder:validation:Enum=Private;Public + AccessMode AccessMode `json:"accessMode,omitempty"` + // Subnet CIDRS. + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=2 + IPAddresses []string `json:"ipAddresses,omitempty"` + // Subnet advanced configuration. + AdvancedConfig AdvancedConfig `json:"advancedConfig,omitempty"` + // DHCPConfig DHCP configuration. + DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` +} + +// SubnetStatus defines the observed state of Subnet. +type SubnetStatus struct { + NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` + Conditions []Condition `json:"conditions,omitempty"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// Subnet is the Schema for the subnets API. +// +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" +// +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" +// +kubebuilder:printcolumn:name="IPAddresses",type=string,JSONPath=`.status.ipAddresses[*]`,description="CIDRs for the Subnet" +type Subnet struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SubnetSpec `json:"spec,omitempty"` + Status SubnetStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// SubnetList contains a list of Subnet. +type SubnetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Subnet `json:"items"` +} + +// AdvancedConfig is Subnet advanced configuration. +type AdvancedConfig struct { + // StaticIPAllocation configuration for subnet ports with VIF attachment. + StaticIPAllocation StaticIPAllocation `json:"staticIPAllocation,omitempty"` +} + +// StaticIPAllocation is static IP allocation for subnet ports with VIF attachment. +type StaticIPAllocation struct { + // Enable or disable static IP allocation for subnet ports with VIF attachment. + // +kubebuilder:default:=false + Enable bool `json:"enable,omitempty"` +} + +// DHCPConfig is DHCP configuration. +type DHCPConfig struct { + // +kubebuilder:default:=false + EnableDHCP bool `json:"enableDHCP,omitempty"` +} + +// DNSClientConfig holds DNS configurations. +type DNSClientConfig struct { + DNSServersIPs []string `json:"dnsServersIPs,omitempty"` +} + +func init() { + SchemeBuilder.Register(&Subnet{}, &SubnetList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetport_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetport_types.go new file mode 100644 index 000000000..8c128a6e7 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetport_types.go @@ -0,0 +1,72 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// SubnetPortSpec defines the desired state of SubnetPort. +type SubnetPortSpec struct { + // Subnet defines the parent Subnet name of the SubnetPort. + Subnet string `json:"subnet,omitempty"` + // SubnetSet defines the parent SubnetSet name of the SubnetPort. + SubnetSet string `json:"subnetSet,omitempty"` +} + +// SubnetPortStatus defines the observed state of SubnetPort. +type SubnetPortStatus struct { + // Conditions describes current state of SubnetPort. + Conditions []Condition `json:"conditions,omitempty"` + // Subnet port attachment state. + Attachment SegmentPortAttachmentState `json:"attachment,omitempty"` + NetworkInterfaceConfig NetworkInterfaceConfig `json:"networkInterfaceConfig,omitempty"` +} + +// VIF attachment state of a subnet port. +type SegmentPortAttachmentState struct { + ID string `json:"id,omitempty"` +} + +type NetworkInterfaceConfig struct { + LogicalSwitchUUID string `json:"logicalSwitchUUID,omitempty"` + IPAddresses []NetworkInterfaceIPAddress `json:"ipAddresses,omitempty"` + MACAddress string `json:"macAddress,omitempty"` +} + +type NetworkInterfaceIPAddress struct { + // IP address string with the prefix. + IPAddress string `json:"ipAddress,omitempty"` + Gateway string `json:"gateway,omitempty"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// SubnetPort is the Schema for the subnetports API. +// +kubebuilder:printcolumn:name="VIFID",type=string,JSONPath=`.status.attachment.id`,description="Attachment VIF ID owned by the SubnetPort." +// +kubebuilder:printcolumn:name="IPAddress",type=string,JSONPath=`.status.networkInterfaceConfig.ipAddresses[0].ipAddress`,description="IP address string with the prefix." +// +kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.status.networkInterfaceConfig.macAddress`,description="MAC Address of the SubnetPort." +type SubnetPort struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SubnetPortSpec `json:"spec,omitempty"` + Status SubnetPortStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// SubnetPortList contains a list of SubnetPort. +type SubnetPortList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SubnetPort `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SubnetPort{}, &SubnetPortList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetset_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetset_types.go new file mode 100644 index 000000000..3d8883355 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/subnetset_types.go @@ -0,0 +1,67 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// SubnetSetSpec defines the desired state of SubnetSet. +type SubnetSetSpec struct { + // Size of Subnet based upon estimated workload count. + // +kubebuilder:validation:Maximum:=65536 + // +kubebuilder:validation:Minimum:=16 + IPv4SubnetSize int `json:"ipv4SubnetSize,omitempty"` + // Access mode of Subnet, accessible only from within VPC or from outside VPC. + // +kubebuilder:validation:Enum=Private;Public + AccessMode AccessMode `json:"accessMode,omitempty"` + // Subnet advanced configuration. + AdvancedConfig AdvancedConfig `json:"advancedConfig,omitempty"` + // DHCPConfig DHCP configuration. + DHCPConfig DHCPConfig `json:"DHCPConfig,omitempty"` +} + +// SubnetInfo defines the observed state of a single Subnet of a SubnetSet. +type SubnetInfo struct { + NSXResourcePath string `json:"nsxResourcePath,omitempty"` + NetworkAddresses []string `json:"networkAddresses,omitempty"` + GatewayAddresses []string `json:"gatewayAddresses,omitempty"` + DHCPServerAddresses []string `json:"DHCPServerAddresses,omitempty"` +} + +// SubnetSetStatus defines the observed state of SubnetSet. +type SubnetSetStatus struct { + Conditions []Condition `json:"conditions,omitempty"` + Subnets []SubnetInfo `json:"subnets,omitempty"` +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// SubnetSet is the Schema for the subnetsets API. +// +kubebuilder:printcolumn:name="AccessMode",type=string,JSONPath=`.spec.accessMode`,description="Access mode of Subnet" +// +kubebuilder:printcolumn:name="IPv4SubnetSize",type=string,JSONPath=`.spec.ipv4SubnetSize`,description="Size of Subnet" +// +kubebuilder:printcolumn:name="IPAddresses",type=string,JSONPath=`.status.subnets[*].ipAddresses[*]`,description="CIDRs for the Subnet" +type SubnetSet struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SubnetSetSpec `json:"spec,omitempty"` + Status SubnetSetStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// SubnetSetList contains a list of SubnetSet. +type SubnetSetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SubnetSet `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SubnetSet{}, &SubnetSetList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go new file mode 100644 index 000000000..9ba4babbc --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/vpcnetworkconfiguration_types.go @@ -0,0 +1,95 @@ +/* Copyright © 2022-2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// +kubebuilder:object:generate=true +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + AccessModePublic string = "Public" + AccessModePrivate string = "Private" +) + +// VPCNetworkConfigurationSpec defines the desired state of VPCNetworkConfiguration. +// There is a default VPCNetworkConfiguration that applies to Namespaces +// do not have a VPCNetworkConfiguration assigned. When a field is not set +// in a Namespace's VPCNetworkConfiguration, the Namespace will use the value +// in the default VPCNetworkConfiguration. +type VPCNetworkConfigurationSpec struct { + // PolicyPath of Tier0 or Tier0 VRF gateway. + DefaultGatewayPath string `json:"defaultGatewayPath,omitempty"` + // Edge cluster path on which the networking elements will be created. + EdgeClusterPath string `json:"edgeClusterPath,omitempty"` + // NSX-T Project the Namespace associated with. + NSXTProject string `json:"nsxtProject,omitempty"` + // NSX-T IPv4 Block paths used to allocate external Subnets. + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=5 + ExternalIPv4Blocks []string `json:"externalIPv4Blocks,omitempty"` + // Private IPv4 CIDRs used to allocate Private Subnets. + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=5 + PrivateIPv4CIDRs []string `json:"privateIPv4CIDRs,omitempty"` + // Default size of Subnet based upon estimated workload count. + // Defaults to 26. + // +kubebuilder:default=26 + DefaultIPv4SubnetSize int `json:"defaultIPv4SubnetSize,omitempty"` + // DefaultSubnetAccessMode defines the access mode of the default SubnetSet for PodVM and VM. + // Must be Public or Private. + // +kubebuilder:validation:Enum=Public;Private + DefaultSubnetAccessMode string `json:"defaultSubnetAccessMode,omitempty"` + // ShortID specifies Identifier to use when displaying VPC context in logs. + // Less than or equal to 8 characters. + // +kubebuilder:validation:MaxLength=8 + // +optional + ShortID string `json:"shortID,omitempty"` +} + +// VPCNetworkConfigurationStatus defines the observed state of VPCNetworkConfiguration +type VPCNetworkConfigurationStatus struct { + // VPCs describes VPC info, now it includes lb Subnet info which are needed for AKO. + VPCs []VPCInfo `json:"vpcs,omitempty"` +} + +// VPCInfo defines VPC info needed by tenant admin. +type VPCInfo struct { + // VPC name. + Name string `json:"name"` + // AVISESubnetPath is the NSX Policy Path for the AVI SE Subnet. + AVISESubnetPath string `json:"lbSubnetPath,omitempty"` +} + +// +genclient +// +genclient:nonNamespaced +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// VPCNetworkConfiguration is the Schema for the vpcnetworkconfigurations API. +// +kubebuilder:resource:scope="Cluster" +// +kubebuilder:printcolumn:name="NSXTProject",type=string,JSONPath=`.spec.nsxtProject`,description="NSXTProject the Namespace associated with" +// +kubebuilder:printcolumn:name="ExternalIPv4Blocks",type=string,JSONPath=`.spec.externalIPv4Blocks`,description="ExternalIPv4Blocks assigned to the Namespace" +// +kubebuilder:printcolumn:name="PrivateIPv4CIDRs",type=string,JSONPath=`.spec.privateIPv4CIDRs`,description="PrivateIPv4CIDRs assigned to the Namespace" +type VPCNetworkConfiguration struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VPCNetworkConfigurationSpec `json:"spec,omitempty"` + Status VPCNetworkConfigurationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VPCNetworkConfigurationList contains a list of VPCNetworkConfiguration. +type VPCNetworkConfigurationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VPCNetworkConfiguration `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VPCNetworkConfiguration{}, &VPCNetworkConfigurationList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/crd.nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..63704edcd --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,1492 @@ +//go:build !ignore_autogenerated + +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdvancedConfig) DeepCopyInto(out *AdvancedConfig) { + *out = *in + out.StaticIPAllocation = in.StaticIPAllocation +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdvancedConfig. +func (in *AdvancedConfig) DeepCopy() *AdvancedConfig { + if in == nil { + return nil + } + out := new(AdvancedConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Condition) DeepCopyInto(out *Condition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. +func (in *Condition) DeepCopy() *Condition { + if in == nil { + return nil + } + out := new(Condition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DHCPConfig) DeepCopyInto(out *DHCPConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPConfig. +func (in *DHCPConfig) DeepCopy() *DHCPConfig { + if in == nil { + return nil + } + out := new(DHCPConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DNSClientConfig) DeepCopyInto(out *DNSClientConfig) { + *out = *in + if in.DNSServersIPs != nil { + in, out := &in.DNSServersIPs, &out.DNSServersIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSClientConfig. +func (in *DNSClientConfig) DeepCopy() *DNSClientConfig { + if in == nil { + return nil + } + out := new(DNSClientConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocation) DeepCopyInto(out *IPAddressAllocation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocation. +func (in *IPAddressAllocation) DeepCopy() *IPAddressAllocation { + if in == nil { + return nil + } + out := new(IPAddressAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationList) DeepCopyInto(out *IPAddressAllocationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPAddressAllocation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationList. +func (in *IPAddressAllocationList) DeepCopy() *IPAddressAllocationList { + if in == nil { + return nil + } + out := new(IPAddressAllocationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPAddressAllocationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationSpec) DeepCopyInto(out *IPAddressAllocationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationSpec. +func (in *IPAddressAllocationSpec) DeepCopy() *IPAddressAllocationSpec { + if in == nil { + return nil + } + out := new(IPAddressAllocationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPAddressAllocationStatus) DeepCopyInto(out *IPAddressAllocationStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAddressAllocationStatus. +func (in *IPAddressAllocationStatus) DeepCopy() *IPAddressAllocationStatus { + if in == nil { + return nil + } + out := new(IPAddressAllocationStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPBlock) DeepCopyInto(out *IPBlock) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPBlock. +func (in *IPBlock) DeepCopy() *IPBlock { + if in == nil { + return nil + } + out := new(IPBlock) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPool) DeepCopyInto(out *IPPool) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. +func (in *IPPool) DeepCopy() *IPPool { + if in == nil { + return nil + } + out := new(IPPool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPPool) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPPool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. +func (in *IPPoolList) DeepCopy() *IPPoolList { + if in == nil { + return nil + } + out := new(IPPoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPPoolList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { + *out = *in + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]SubnetRequest, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. +func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { + if in == nil { + return nil + } + out := new(IPPoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { + *out = *in + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]SubnetResult, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. +func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { + if in == nil { + return nil + } + out := new(IPPoolStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXProxyEndpoint) DeepCopyInto(out *NSXProxyEndpoint) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]NSXProxyEndpointAddress, len(*in)) + copy(*out, *in) + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]NSXProxyEndpointPort, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpoint. +func (in *NSXProxyEndpoint) DeepCopy() *NSXProxyEndpoint { + if in == nil { + return nil + } + out := new(NSXProxyEndpoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXProxyEndpointAddress) DeepCopyInto(out *NSXProxyEndpointAddress) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointAddress. +func (in *NSXProxyEndpointAddress) DeepCopy() *NSXProxyEndpointAddress { + if in == nil { + return nil + } + out := new(NSXProxyEndpointAddress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXProxyEndpointPort) DeepCopyInto(out *NSXProxyEndpointPort) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointPort. +func (in *NSXProxyEndpointPort) DeepCopy() *NSXProxyEndpointPort { + if in == nil { + return nil + } + out := new(NSXProxyEndpointPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXSecret) DeepCopyInto(out *NSXSecret) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXSecret. +func (in *NSXSecret) DeepCopy() *NSXSecret { + if in == nil { + return nil + } + out := new(NSXSecret) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccount) DeepCopyInto(out *NSXServiceAccount) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccount. +func (in *NSXServiceAccount) DeepCopy() *NSXServiceAccount { + if in == nil { + return nil + } + out := new(NSXServiceAccount) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NSXServiceAccount) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccountList) DeepCopyInto(out *NSXServiceAccountList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NSXServiceAccount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountList. +func (in *NSXServiceAccountList) DeepCopy() *NSXServiceAccountList { + if in == nil { + return nil + } + out := new(NSXServiceAccountList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NSXServiceAccountList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccountSpec) DeepCopyInto(out *NSXServiceAccountSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountSpec. +func (in *NSXServiceAccountSpec) DeepCopy() *NSXServiceAccountSpec { + if in == nil { + return nil + } + out := new(NSXServiceAccountSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NSXServiceAccountStatus) DeepCopyInto(out *NSXServiceAccountStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NSXManagers != nil { + in, out := &in.NSXManagers, &out.NSXManagers + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.ProxyEndpoints.DeepCopyInto(&out.ProxyEndpoints) + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make([]NSXSecret, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountStatus. +func (in *NSXServiceAccountStatus) DeepCopy() *NSXServiceAccountStatus { + if in == nil { + return nil + } + out := new(NSXServiceAccountStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkInfo) DeepCopyInto(out *NetworkInfo) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.VPCs != nil { + in, out := &in.VPCs, &out.VPCs + *out = make([]VPCState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInfo. +func (in *NetworkInfo) DeepCopy() *NetworkInfo { + if in == nil { + return nil + } + out := new(NetworkInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkInfo) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkInfoList) DeepCopyInto(out *NetworkInfoList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NetworkInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInfoList. +func (in *NetworkInfoList) DeepCopy() *NetworkInfoList { + if in == nil { + return nil + } + out := new(NetworkInfoList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkInfoList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkInterfaceConfig) DeepCopyInto(out *NetworkInterfaceConfig) { + *out = *in + if in.IPAddresses != nil { + in, out := &in.IPAddresses, &out.IPAddresses + *out = make([]NetworkInterfaceIPAddress, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInterfaceConfig. +func (in *NetworkInterfaceConfig) DeepCopy() *NetworkInterfaceConfig { + if in == nil { + return nil + } + out := new(NetworkInterfaceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkInterfaceIPAddress) DeepCopyInto(out *NetworkInterfaceIPAddress) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkInterfaceIPAddress. +func (in *NetworkInterfaceIPAddress) DeepCopy() *NetworkInterfaceIPAddress { + if in == nil { + return nil + } + out := new(NetworkInterfaceIPAddress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NextHop) DeepCopyInto(out *NextHop) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NextHop. +func (in *NextHop) DeepCopy() *NextHop { + if in == nil { + return nil + } + out := new(NextHop) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicy) DeepCopyInto(out *SecurityPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicy. +func (in *SecurityPolicy) DeepCopy() *SecurityPolicy { + if in == nil { + return nil + } + out := new(SecurityPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SecurityPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyList) DeepCopyInto(out *SecurityPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SecurityPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyList. +func (in *SecurityPolicyList) DeepCopy() *SecurityPolicyList { + if in == nil { + return nil + } + out := new(SecurityPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SecurityPolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyPeer) DeepCopyInto(out *SecurityPolicyPeer) { + *out = *in + if in.VMSelector != nil { + in, out := &in.VMSelector, &out.VMSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.PodSelector != nil { + in, out := &in.PodSelector, &out.PodSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.IPBlocks != nil { + in, out := &in.IPBlocks, &out.IPBlocks + *out = make([]IPBlock, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyPeer. +func (in *SecurityPolicyPeer) DeepCopy() *SecurityPolicyPeer { + if in == nil { + return nil + } + out := new(SecurityPolicyPeer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyPort) DeepCopyInto(out *SecurityPolicyPort) { + *out = *in + out.Port = in.Port +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyPort. +func (in *SecurityPolicyPort) DeepCopy() *SecurityPolicyPort { + if in == nil { + return nil + } + out := new(SecurityPolicyPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyRule) DeepCopyInto(out *SecurityPolicyRule) { + *out = *in + if in.Action != nil { + in, out := &in.Action, &out.Action + *out = new(RuleAction) + **out = **in + } + if in.AppliedTo != nil { + in, out := &in.AppliedTo, &out.AppliedTo + *out = make([]SecurityPolicyTarget, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Direction != nil { + in, out := &in.Direction, &out.Direction + *out = new(RuleDirection) + **out = **in + } + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]SecurityPolicyPeer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Destinations != nil { + in, out := &in.Destinations, &out.Destinations + *out = make([]SecurityPolicyPeer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]SecurityPolicyPort, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyRule. +func (in *SecurityPolicyRule) DeepCopy() *SecurityPolicyRule { + if in == nil { + return nil + } + out := new(SecurityPolicyRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicySpec) DeepCopyInto(out *SecurityPolicySpec) { + *out = *in + if in.AppliedTo != nil { + in, out := &in.AppliedTo, &out.AppliedTo + *out = make([]SecurityPolicyTarget, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]SecurityPolicyRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicySpec. +func (in *SecurityPolicySpec) DeepCopy() *SecurityPolicySpec { + if in == nil { + return nil + } + out := new(SecurityPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyStatus) DeepCopyInto(out *SecurityPolicyStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyStatus. +func (in *SecurityPolicyStatus) DeepCopy() *SecurityPolicyStatus { + if in == nil { + return nil + } + out := new(SecurityPolicyStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityPolicyTarget) DeepCopyInto(out *SecurityPolicyTarget) { + *out = *in + if in.VMSelector != nil { + in, out := &in.VMSelector, &out.VMSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.PodSelector != nil { + in, out := &in.PodSelector, &out.PodSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityPolicyTarget. +func (in *SecurityPolicyTarget) DeepCopy() *SecurityPolicyTarget { + if in == nil { + return nil + } + out := new(SecurityPolicyTarget) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SegmentPortAttachmentState) DeepCopyInto(out *SegmentPortAttachmentState) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SegmentPortAttachmentState. +func (in *SegmentPortAttachmentState) DeepCopy() *SegmentPortAttachmentState { + if in == nil { + return nil + } + out := new(SegmentPortAttachmentState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StaticIPAllocation) DeepCopyInto(out *StaticIPAllocation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticIPAllocation. +func (in *StaticIPAllocation) DeepCopy() *StaticIPAllocation { + if in == nil { + return nil + } + out := new(StaticIPAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StaticRoute) DeepCopyInto(out *StaticRoute) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRoute. +func (in *StaticRoute) DeepCopy() *StaticRoute { + if in == nil { + return nil + } + out := new(StaticRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *StaticRoute) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StaticRouteCondition) DeepCopyInto(out *StaticRouteCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteCondition. +func (in *StaticRouteCondition) DeepCopy() *StaticRouteCondition { + if in == nil { + return nil + } + out := new(StaticRouteCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StaticRouteList) DeepCopyInto(out *StaticRouteList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]StaticRoute, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteList. +func (in *StaticRouteList) DeepCopy() *StaticRouteList { + if in == nil { + return nil + } + out := new(StaticRouteList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *StaticRouteList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StaticRouteSpec) DeepCopyInto(out *StaticRouteSpec) { + *out = *in + if in.NextHops != nil { + in, out := &in.NextHops, &out.NextHops + *out = make([]NextHop, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteSpec. +func (in *StaticRouteSpec) DeepCopy() *StaticRouteSpec { + if in == nil { + return nil + } + out := new(StaticRouteSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StaticRouteStatus) DeepCopyInto(out *StaticRouteStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]StaticRouteCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRouteStatus. +func (in *StaticRouteStatus) DeepCopy() *StaticRouteStatus { + if in == nil { + return nil + } + out := new(StaticRouteStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Subnet) DeepCopyInto(out *Subnet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subnet. +func (in *Subnet) DeepCopy() *Subnet { + if in == nil { + return nil + } + out := new(Subnet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Subnet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetInfo) DeepCopyInto(out *SubnetInfo) { + *out = *in + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetInfo. +func (in *SubnetInfo) DeepCopy() *SubnetInfo { + if in == nil { + return nil + } + out := new(SubnetInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetList) DeepCopyInto(out *SubnetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Subnet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetList. +func (in *SubnetList) DeepCopy() *SubnetList { + if in == nil { + return nil + } + out := new(SubnetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubnetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetPort) DeepCopyInto(out *SubnetPort) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPort. +func (in *SubnetPort) DeepCopy() *SubnetPort { + if in == nil { + return nil + } + out := new(SubnetPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubnetPort) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetPortList) DeepCopyInto(out *SubnetPortList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SubnetPort, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPortList. +func (in *SubnetPortList) DeepCopy() *SubnetPortList { + if in == nil { + return nil + } + out := new(SubnetPortList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubnetPortList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetPortSpec) DeepCopyInto(out *SubnetPortSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPortSpec. +func (in *SubnetPortSpec) DeepCopy() *SubnetPortSpec { + if in == nil { + return nil + } + out := new(SubnetPortSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetPortStatus) DeepCopyInto(out *SubnetPortStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.Attachment = in.Attachment + in.NetworkInterfaceConfig.DeepCopyInto(&out.NetworkInterfaceConfig) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPortStatus. +func (in *SubnetPortStatus) DeepCopy() *SubnetPortStatus { + if in == nil { + return nil + } + out := new(SubnetPortStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetRequest) DeepCopyInto(out *SubnetRequest) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetRequest. +func (in *SubnetRequest) DeepCopy() *SubnetRequest { + if in == nil { + return nil + } + out := new(SubnetRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetResult) DeepCopyInto(out *SubnetResult) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResult. +func (in *SubnetResult) DeepCopy() *SubnetResult { + if in == nil { + return nil + } + out := new(SubnetResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetSet) DeepCopyInto(out *SubnetSet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSet. +func (in *SubnetSet) DeepCopy() *SubnetSet { + if in == nil { + return nil + } + out := new(SubnetSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubnetSet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetSetList) DeepCopyInto(out *SubnetSetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SubnetSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetList. +func (in *SubnetSetList) DeepCopy() *SubnetSetList { + if in == nil { + return nil + } + out := new(SubnetSetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubnetSetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetSetSpec) DeepCopyInto(out *SubnetSetSpec) { + *out = *in + out.AdvancedConfig = in.AdvancedConfig + out.DHCPConfig = in.DHCPConfig +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetSpec. +func (in *SubnetSetSpec) DeepCopy() *SubnetSetSpec { + if in == nil { + return nil + } + out := new(SubnetSetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetSetStatus) DeepCopyInto(out *SubnetSetStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]SubnetInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSetStatus. +func (in *SubnetSetStatus) DeepCopy() *SubnetSetStatus { + if in == nil { + return nil + } + out := new(SubnetSetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { + *out = *in + if in.IPAddresses != nil { + in, out := &in.IPAddresses, &out.IPAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.AdvancedConfig = in.AdvancedConfig + out.DHCPConfig = in.DHCPConfig +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. +func (in *SubnetSpec) DeepCopy() *SubnetSpec { + if in == nil { + return nil + } + out := new(SubnetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { + *out = *in + if in.NetworkAddresses != nil { + in, out := &in.NetworkAddresses, &out.NetworkAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.GatewayAddresses != nil { + in, out := &in.GatewayAddresses, &out.GatewayAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DHCPServerAddresses != nil { + in, out := &in.DHCPServerAddresses, &out.DHCPServerAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetStatus. +func (in *SubnetStatus) DeepCopy() *SubnetStatus { + if in == nil { + return nil + } + out := new(SubnetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCInfo) DeepCopyInto(out *VPCInfo) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCInfo. +func (in *VPCInfo) DeepCopy() *VPCInfo { + if in == nil { + return nil + } + out := new(VPCInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCNetworkConfiguration) DeepCopyInto(out *VPCNetworkConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfiguration. +func (in *VPCNetworkConfiguration) DeepCopy() *VPCNetworkConfiguration { + if in == nil { + return nil + } + out := new(VPCNetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VPCNetworkConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCNetworkConfigurationList) DeepCopyInto(out *VPCNetworkConfigurationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VPCNetworkConfiguration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationList. +func (in *VPCNetworkConfigurationList) DeepCopy() *VPCNetworkConfigurationList { + if in == nil { + return nil + } + out := new(VPCNetworkConfigurationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VPCNetworkConfigurationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCNetworkConfigurationSpec) DeepCopyInto(out *VPCNetworkConfigurationSpec) { + *out = *in + if in.ExternalIPv4Blocks != nil { + in, out := &in.ExternalIPv4Blocks, &out.ExternalIPv4Blocks + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PrivateIPv4CIDRs != nil { + in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationSpec. +func (in *VPCNetworkConfigurationSpec) DeepCopy() *VPCNetworkConfigurationSpec { + if in == nil { + return nil + } + out := new(VPCNetworkConfigurationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCNetworkConfigurationStatus) DeepCopyInto(out *VPCNetworkConfigurationStatus) { + *out = *in + if in.VPCs != nil { + in, out := &in.VPCs, &out.VPCs + *out = make([]VPCInfo, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCNetworkConfigurationStatus. +func (in *VPCNetworkConfigurationStatus) DeepCopy() *VPCNetworkConfigurationStatus { + if in == nil { + return nil + } + out := new(VPCNetworkConfigurationStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VPCState) DeepCopyInto(out *VPCState) { + *out = *in + if in.PrivateIPv4CIDRs != nil { + in, out := &in.PrivateIPv4CIDRs, &out.PrivateIPv4CIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCState. +func (in *VPCState) DeepCopy() *VPCState { + if in == nil { + return nil + } + out := new(VPCState) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha2/doc.go b/pkg/apis/crd.nsx.vmware.com/v1alpha2/doc.go new file mode 100644 index 000000000..cbf1b02cf --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha2/doc.go @@ -0,0 +1,4 @@ +// +k8s:deepcopy-gen=package +// +groupName=crd.nsx.vmware.com + +package v1alpha2 diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha2/groupversion_info.go b/pkg/apis/crd.nsx.vmware.com/v1alpha2/groupversion_info.go new file mode 100644 index 000000000..e4bfce60e --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha2/groupversion_info.go @@ -0,0 +1,23 @@ +/* Copyright © 2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Package v1alpha2 contains API Schema definitions for the v1alpha2 API group +// +kubebuilder:object:generate=true +// +groupName=crd.nsx.vmware.com +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "crd.nsx.vmware.com", Version: "v1alpha2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha2/ippool_types.go b/pkg/apis/crd.nsx.vmware.com/v1alpha2/ippool_types.go new file mode 100644 index 000000000..56dac408a --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha2/ippool_types.go @@ -0,0 +1,82 @@ +/* Copyright © 2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/crd.nsx.vmware.com/v1alpha1" +) + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// IPPool is the Schema for the ippools API. +// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type`,description="Type of IPPool" +// +kubebuilder:printcolumn:name="Subnets",type=string,JSONPath=`.status.subnets[*].cidr`,description="CIDRs for the Subnet" +type IPPool struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec IPPoolSpec `json:"spec"` + Status IPPoolStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IPPoolList contains a list of IPPool. +type IPPoolList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPPool `json:"items"` +} + +// IPPoolSpec defines the desired state of IPPool. +type IPPoolSpec struct { + // Type defines the type of this IPPool, Public or Private. + // +kubebuilder:validation:Enum=Public;Private + // +optional + Type string `json:"type,omitempty"` + // Subnets defines set of subnets need to be allocated. + // +optional + Subnets []SubnetRequest `json:"subnets"` +} + +// IPPoolStatus defines the observed state of IPPool. +type IPPoolStatus struct { + // Subnets defines subnets allocation result. + Subnets []SubnetResult `json:"subnets"` + // Conditions defines current state of the IPPool. + Conditions []v1alpha1.Condition `json:"conditions"` +} + +// SubnetRequest defines the subnet allocation request. +type SubnetRequest struct { + // PrefixLength defines prefix length for this subnet. + PrefixLength int `json:"prefixLength,omitempty"` + + // IPFamily defines the IP family type for this subnet, could be IPv4 or IPv6. + // This is optional, the default is IPv4. + // +kubebuilder:validation:Enum=IPv4;IPv6 + // +kubebuilder:default=IPv4 + IPFamily string `json:"ipFamily,omitempty"` + + // Name defines the name of this subnet. + Name string `json:"name"` +} + +// SubnetResult defines the subnet allocation result. +type SubnetResult struct { + // CIDR defines the allocated CIDR. + CIDR string `json:"cidr"` + + // Name defines the name of this subnet. + Name string `json:"name"` +} + +func init() { + SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha2/register.go b/pkg/apis/crd.nsx.vmware.com/v1alpha2/register.go new file mode 100644 index 000000000..26d0e5656 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha2/register.go @@ -0,0 +1,12 @@ +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects. +var SchemeGroupVersion = GroupVersion + +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/pkg/apis/crd.nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/crd.nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 000000000..dbd5ee6b7 --- /dev/null +++ b/pkg/apis/crd.nsx.vmware.com/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,149 @@ +//go:build !ignore_autogenerated + +/* Copyright © 2024 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 */ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "github.com/vmware-tanzu/nsx-operator/pkg/apis/crd.nsx.vmware.com/v1alpha1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPool) DeepCopyInto(out *IPPool) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. +func (in *IPPool) DeepCopy() *IPPool { + if in == nil { + return nil + } + out := new(IPPool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPPool) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPPool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. +func (in *IPPoolList) DeepCopy() *IPPoolList { + if in == nil { + return nil + } + out := new(IPPoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPPoolList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { + *out = *in + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]SubnetRequest, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. +func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { + if in == nil { + return nil + } + out := new(IPPoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { + *out = *in + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]SubnetResult, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1alpha1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. +func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { + if in == nil { + return nil + } + out := new(IPPoolStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetRequest) DeepCopyInto(out *SubnetRequest) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetRequest. +func (in *SubnetRequest) DeepCopy() *SubnetRequest { + if in == nil { + return nil + } + out := new(SubnetRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetResult) DeepCopyInto(out *SubnetResult) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResult. +func (in *SubnetResult) DeepCopy() *SubnetResult { + if in == nil { + return nil + } + out := new(SubnetResult) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go index 63704edcd..3d230a661 100644 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go @@ -296,183 +296,6 @@ func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpoint) DeepCopyInto(out *NSXProxyEndpoint) { - *out = *in - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]NSXProxyEndpointAddress, len(*in)) - copy(*out, *in) - } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = make([]NSXProxyEndpointPort, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpoint. -func (in *NSXProxyEndpoint) DeepCopy() *NSXProxyEndpoint { - if in == nil { - return nil - } - out := new(NSXProxyEndpoint) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpointAddress) DeepCopyInto(out *NSXProxyEndpointAddress) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointAddress. -func (in *NSXProxyEndpointAddress) DeepCopy() *NSXProxyEndpointAddress { - if in == nil { - return nil - } - out := new(NSXProxyEndpointAddress) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXProxyEndpointPort) DeepCopyInto(out *NSXProxyEndpointPort) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXProxyEndpointPort. -func (in *NSXProxyEndpointPort) DeepCopy() *NSXProxyEndpointPort { - if in == nil { - return nil - } - out := new(NSXProxyEndpointPort) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXSecret) DeepCopyInto(out *NSXSecret) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXSecret. -func (in *NSXSecret) DeepCopy() *NSXSecret { - if in == nil { - return nil - } - out := new(NSXSecret) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccount) DeepCopyInto(out *NSXServiceAccount) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccount. -func (in *NSXServiceAccount) DeepCopy() *NSXServiceAccount { - if in == nil { - return nil - } - out := new(NSXServiceAccount) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NSXServiceAccount) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountList) DeepCopyInto(out *NSXServiceAccountList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]NSXServiceAccount, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountList. -func (in *NSXServiceAccountList) DeepCopy() *NSXServiceAccountList { - if in == nil { - return nil - } - out := new(NSXServiceAccountList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NSXServiceAccountList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountSpec) DeepCopyInto(out *NSXServiceAccountSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountSpec. -func (in *NSXServiceAccountSpec) DeepCopy() *NSXServiceAccountSpec { - if in == nil { - return nil - } - out := new(NSXServiceAccountSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NSXServiceAccountStatus) DeepCopyInto(out *NSXServiceAccountStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.NSXManagers != nil { - in, out := &in.NSXManagers, &out.NSXManagers - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.ProxyEndpoints.DeepCopyInto(&out.ProxyEndpoints) - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]NSXSecret, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NSXServiceAccountStatus. -func (in *NSXServiceAccountStatus) DeepCopy() *NSXServiceAccountStatus { - if in == nil { - return nil - } - out := new(NSXServiceAccountStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkInfo) DeepCopyInto(out *NetworkInfo) { *out = *in diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go index ca14aa1e5..8c6ae4457 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" "github.com/vmware-tanzu/nsx-operator/pkg/logger" diff --git a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go index d131a6352..49b35e589 100644 --- a/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go +++ b/pkg/controllers/nsxserviceaccount/nsxserviceaccount_controller_test.go @@ -25,7 +25,7 @@ import ( controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" - nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + nsxvmwarecomv1alpha1 "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" diff --git a/pkg/nsx/services/nsxserviceaccount/builder.go b/pkg/nsx/services/nsxserviceaccount/builder.go index 0f66a4a0b..5fb79af7e 100644 --- a/pkg/nsx/services/nsxserviceaccount/builder.go +++ b/pkg/nsx/services/nsxserviceaccount/builder.go @@ -6,7 +6,7 @@ package nsxserviceaccount import ( "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" ) diff --git a/pkg/nsx/services/nsxserviceaccount/cluster.go b/pkg/nsx/services/nsxserviceaccount/cluster.go index 6e79f8a08..a43538f51 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster.go @@ -22,7 +22,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" diff --git a/pkg/nsx/services/nsxserviceaccount/cluster_test.go b/pkg/nsx/services/nsxserviceaccount/cluster_test.go index 24f8e5315..955eaa478 100644 --- a/pkg/nsx/services/nsxserviceaccount/cluster_test.go +++ b/pkg/nsx/services/nsxserviceaccount/cluster_test.go @@ -26,7 +26,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/apis/nsx.vmware.com/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/config" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" diff --git a/test/e2e/nsx_ippool_test.go b/test/e2e/nsx_ippool_test.go index cc5f837bc..6ca2a426c 100644 --- a/test/e2e/nsx_ippool_test.go +++ b/test/e2e/nsx_ippool_test.go @@ -10,7 +10,7 @@ import ( ) const ( - IPPool = "ippool" + IPPool = "ippools.nsx.vmware.com" ) // TestIPPoolBasic verifies that it could successfully realize ippool subnet from ipblock. diff --git a/test/e2e/nsx_networkinfo_test.go b/test/e2e/nsx_networkinfo_test.go index de628682e..15c911fdb 100644 --- a/test/e2e/nsx_networkinfo_test.go +++ b/test/e2e/nsx_networkinfo_test.go @@ -8,7 +8,7 @@ import ( ) const ( - NetworkInfoCRType = "networkinfos" + NetworkInfoCRType = "networkinfos.nsx.vmware.com" NSCRType = "namespaces" PrivateIPBlockNSXType = "IpAddressBlock" diff --git a/test/e2e/nsx_security_policy_test.go b/test/e2e/nsx_security_policy_test.go index 5bef4affc..5c9cedb6e 100644 --- a/test/e2e/nsx_security_policy_test.go +++ b/test/e2e/nsx_security_policy_test.go @@ -23,7 +23,7 @@ import ( ) const ( - SP = "securitypolicy" + SP = "securitypolicies.nsx.vmware.com" ) // TestSecurityPolicyBasicTraffic verifies that the basic traffic of security policy. diff --git a/test/e2e/nsx_subnet_test.go b/test/e2e/nsx_subnet_test.go index f89b56408..03c5e0a36 100644 --- a/test/e2e/nsx_subnet_test.go +++ b/test/e2e/nsx_subnet_test.go @@ -19,8 +19,8 @@ import ( ) const ( - SubnetSetCRType = "subnetsets" - SubnetPortCRType = "subnetport" + SubnetSetCRType = "subnetsets.nsx.vmware.com" + SubnetPortCRType = "subnetports.nsx.vmware.com" E2ENamespace = "subnet-e2e" E2ENamespaceShared = "subnet-e2e-shared" E2ENamespaceTarget = "target-ns" @@ -266,7 +266,7 @@ func SubnetCIDR(t *testing.T) { err = nil } assertNil(t, err) - err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets", E2ENamespace, subnet.Name, Ready) + err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets.nsx.vmware.com", E2ENamespace, subnet.Name, Ready) assertNil(t, err) allocatedSubnet, err := testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) assertNil(t, err) @@ -289,7 +289,7 @@ func SubnetCIDR(t *testing.T) { err = nil } assertNil(t, err) - err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets", E2ENamespace, subnet.Name, Ready) + err = testData.waitForCRReadyOrDeleted(defaultTimeout, "subnets.nsx.vmware.com", E2ENamespace, subnet.Name, Ready) assertNil(t, err) allocatedSubnet, err = testData.crdClientset.NsxV1alpha1().Subnets(E2ENamespace).Get(context.TODO(), subnet.Name, v1.GetOptions{}) assertNil(t, err) From 0784c07910815d1bf2464b62b36a6db23f07b1d9 Mon Sep 17 00:00:00 2001 From: Ran Gu Date: Tue, 30 Jul 2024 10:30:32 +0800 Subject: [PATCH 23/23] [VPC] Support NSXLB for VPC (#618) Signed-off-by: gran --- .golangci.yml | 8 +- .../networkinfo/networkinfo_controller.go | 6 +- .../networkinfo/networkinfo_utils.go | 11 +- pkg/nsx/client.go | 3 + pkg/nsx/services/common/types.go | 3 + pkg/nsx/services/common/wrap.go | 84 ++++++++++ .../services/realizestate/realize_state.go | 2 +- pkg/nsx/services/vpc/builder.go | 27 +++- pkg/nsx/services/vpc/builder_test.go | 79 +++++++++ pkg/nsx/services/vpc/store.go | 39 +++++ pkg/nsx/services/vpc/store_test.go | 152 +++++++++++++++--- pkg/nsx/services/vpc/vpc.go | 82 +++++++++- pkg/nsx/services/vpc/wrap.go | 41 +++++ pkg/nsx/services/vpc/wrap_test.go | 51 ++++++ pkg/nsx/util/utils.go | 2 + pkg/util/retry.go | 21 +++ 16 files changed, 565 insertions(+), 46 deletions(-) create mode 100644 pkg/nsx/services/common/wrap.go create mode 100644 pkg/nsx/services/vpc/builder_test.go create mode 100644 pkg/nsx/services/vpc/wrap.go create mode 100644 pkg/nsx/services/vpc/wrap_test.go create mode 100644 pkg/util/retry.go diff --git a/.golangci.yml b/.golangci.yml index eec0fea19..c8d26644d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -32,4 +32,10 @@ linters: - gosec - goimports - vet - - revive \ No newline at end of file + - revive + +issues: + exclude-rules: + - linters: + - staticcheck + text: "SA1019: lbs.RelaxScaleValidation" \ No newline at end of file diff --git a/pkg/controllers/networkinfo/networkinfo_controller.go b/pkg/controllers/networkinfo/networkinfo_controller.go index 06e62de74..5669a2563 100644 --- a/pkg/controllers/networkinfo/networkinfo_controller.go +++ b/pkg/controllers/networkinfo/networkinfo_controller.go @@ -78,7 +78,7 @@ func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request) log.Error(err, "failed to check if namespace is shared", "Namespace", obj.GetNamespace()) return common.ResultRequeue, err } - if !isShared { + if r.Service.NSXConfig.NsxConfig.UseAVILoadBalancer && !isShared { err = r.Service.CreateOrUpdateAVIRule(createdVpc, obj.Namespace) if err != nil { state := &v1alpha1.VPCState{ @@ -116,7 +116,7 @@ func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request) // if lb vpc enabled, read avi subnet path and cidr // nsx bug, if set LoadBalancerVpcEndpoint.Enabled to false, when read this vpc back, // LoadBalancerVpcEndpoint.Enabled will become a nil pointer. - if createdVpc.LoadBalancerVpcEndpoint.Enabled != nil && *createdVpc.LoadBalancerVpcEndpoint.Enabled { + if r.Service.NSXConfig.NsxConfig.UseAVILoadBalancer && createdVpc.LoadBalancerVpcEndpoint.Enabled != nil && *createdVpc.LoadBalancerVpcEndpoint.Enabled { path, cidr, err = r.Service.GetAVISubnetInfo(*createdVpc) if err != nil { log.Error(err, "failed to read lb subnet path and cidr", "VPC", createdVpc.Id) @@ -139,7 +139,7 @@ func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request) LoadBalancerIPAddresses: cidr, PrivateIPv4CIDRs: nc.PrivateIPv4CIDRs, } - updateSuccess(r, &ctx, obj, r.Client, state, nc.Name, path) + updateSuccess(r, &ctx, obj, r.Client, state, nc.Name, path, r.Service.GetNSXLBSPath(*createdVpc.Id)) } else { if controllerutil.ContainsFinalizer(obj, commonservice.NetworkInfoFinalizerName) { metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, common.MetricResTypeNetworkInfo) diff --git a/pkg/controllers/networkinfo/networkinfo_utils.go b/pkg/controllers/networkinfo/networkinfo_utils.go index 076301185..e34164509 100644 --- a/pkg/controllers/networkinfo/networkinfo_utils.go +++ b/pkg/controllers/networkinfo/networkinfo_utils.go @@ -29,10 +29,10 @@ func updateFail(r *NetworkInfoReconciler, c *context.Context, o *v1alpha1.Networ } func updateSuccess(r *NetworkInfoReconciler, c *context.Context, o *v1alpha1.NetworkInfo, client client.Client, - vpcState *v1alpha1.VPCState, ncName string, subnetPath string) { + vpcState *v1alpha1.VPCState, ncName string, subnetPath string, nsxLBSPath string) { setNetworkInfoVPCStatus(c, o, client, vpcState) // ako needs to know the avi subnet path created by nsx - setVPCNetworkConfigurationStatus(c, client, ncName, vpcState.Name, subnetPath) + setVPCNetworkConfigurationStatus(c, client, ncName, vpcState.Name, subnetPath, nsxLBSPath) r.Recorder.Event(o, v1.EventTypeNormal, common.ReasonSuccessfulUpdate, "NetworkInfo CR has been successfully updated") metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, common.MetricResTypeNetworkInfo) } @@ -59,7 +59,7 @@ func setNetworkInfoVPCStatus(ctx *context.Context, networkInfo *v1alpha1.Network } } -func setVPCNetworkConfigurationStatus(ctx *context.Context, client client.Client, ncName string, vpcName string, aviSubnetPath string) { +func setVPCNetworkConfigurationStatus(ctx *context.Context, client client.Client, ncName string, vpcName string, aviSubnetPath string, nsxLBSPath string) { // read v1alpha1.VPCNetworkConfiguration by ncName nc := &v1alpha1.VPCNetworkConfiguration{} err := client.Get(*ctx, apitypes.NamespacedName{Name: ncName}, nc) @@ -67,8 +67,9 @@ func setVPCNetworkConfigurationStatus(ctx *context.Context, client client.Client log.Error(err, "failed to get VPCNetworkConfiguration", "Name", ncName) } createdVPCInfo := &v1alpha1.VPCInfo{ - Name: vpcName, - AVISESubnetPath: aviSubnetPath, + Name: vpcName, + AVISESubnetPath: aviSubnetPath, + NSXLoadBalancerPath: nsxLBSPath, } // iterate through VPCNetworkConfiguration.Status.VPCs, if vpcName already exists, update it for i, vpc := range nc.Status.VPCs { diff --git a/pkg/nsx/client.go b/pkg/nsx/client.go index 9bc961f36..ea1e845ed 100644 --- a/pkg/nsx/client.go +++ b/pkg/nsx/client.go @@ -85,6 +85,7 @@ type Client struct { SubnetsClient vpcs.SubnetsClient RealizedStateClient realized_state.RealizedEntitiesClient IPAddressAllocationClient vpcs.IpAddressAllocationsClient + VPCLBSClient vpcs.VpcLbsClient NSXChecker NSXHealthChecker NSXVerChecker NSXVersionChecker @@ -165,6 +166,7 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { subnetStatusClient := subnets.NewStatusClient(restConnector(cluster)) realizedStateClient := realized_state.NewRealizedEntitiesClient(restConnector(cluster)) ipAddressAllocationClient := vpcs.NewIpAddressAllocationsClient(restConnector(cluster)) + vpcLBSClient := vpcs.NewVpcLbsClient(restConnector(cluster)) vpcSecurityClient := vpcs.NewSecurityPoliciesClient(restConnector(cluster)) vpcRuleClient := vpc_sp.NewRulesClient(restConnector(cluster)) @@ -206,6 +208,7 @@ func GetClient(cf *config.NSXOperatorConfig) *Client { SubnetStatusClient: subnetStatusClient, VPCSecurityClient: vpcSecurityClient, VPCRuleClient: vpcRuleClient, + VPCLBSClient: vpcLBSClient, NSXChecker: *nsxChecker, NSXVerChecker: *nsxVersionChecker, diff --git a/pkg/nsx/services/common/types.go b/pkg/nsx/services/common/types.go index c12d3d04c..81bae7e20 100644 --- a/pkg/nsx/services/common/types.go +++ b/pkg/nsx/services/common/types.go @@ -28,6 +28,7 @@ const ( TagScopeNCPVIFProjectUID string = "ncp/vif_project_uid" TagScopeNCPPod string = "ncp/pod" TagScopeNCPVNETInterface string = "ncp/vnet_interface" + TagScopeCreatedFor string = "nsx-op/created_for" TagScopeVersion string = "nsx-op/version" TagScopeCluster string = "nsx-op/cluster" TagScopeNamespace string = "nsx-op/namespace" @@ -74,6 +75,7 @@ const ( TagValueGroupSource string = "source" TagValueGroupDestination string = "destination" TagValueGroupAvi string = "avi" + TagValueSLB string = "SLB" AnnotationVPCNetworkConfig string = "nsx.vmware.com/vpc_network_config" AnnotationSharedVPCNamespace string = "nsx.vmware.com/shared_vpc_namespace" AnnotationDefaultNetworkConfig string = "nsx.vmware.com/default" @@ -147,6 +149,7 @@ var ( ResourceTypeVpc = "Vpc" ResourceTypeSubnetPort = "VpcSubnetPort" ResourceTypeVirtualMachine = "VirtualMachine" + ResourceTypeLBService = "LBService" ResourceTypeShare = "Share" ResourceTypeSharedResource = "SharedResource" ResourceTypeChildSharedResource = "ChildSharedResource" diff --git a/pkg/nsx/services/common/wrap.go b/pkg/nsx/services/common/wrap.go new file mode 100644 index 000000000..a2c96d3a0 --- /dev/null +++ b/pkg/nsx/services/common/wrap.go @@ -0,0 +1,84 @@ +package common + +import ( + "github.com/openlyinc/pointy" + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +// WrapInfra TODO(gran) refactor existing code in other package +func (service *Service) WrapInfra(children []*data.StructValue) (*model.Infra, error) { + // This is the outermost layer of the hierarchy infra client. + // It doesn't need ID field. + resourceType := ResourceTypeInfra + infraObj := model.Infra{ + Children: children, + ResourceType: &resourceType, + } + return &infraObj, nil +} + +func (service *Service) WrapOrgRoot(children []*data.StructValue) (*model.OrgRoot, error) { + resourceType := ResourceTypeOrgRoot + orgRootObj := model.OrgRoot{ + Children: children, + ResourceType: &resourceType, + } + return &orgRootObj, nil +} + +func (service *Service) WrapOrg(org string, children []*data.StructValue) ([]*data.StructValue, error) { + targetType := ResourceTypeOrg + return wrapChildResourceReference(targetType, org, children) +} + +func (service *Service) WrapProject(nsxtProject string, children []*data.StructValue) ([]*data.StructValue, error) { + targetType := ResourceTypeProject + return wrapChildResourceReference(targetType, nsxtProject, children) +} + +func wrapChildResourceReference(targetType, id string, children []*data.StructValue) ([]*data.StructValue, error) { + resourceType := ResourceTypeChildResourceReference + childProject := model.ChildResourceReference{ + Id: &id, + ResourceType: resourceType, + TargetType: &targetType, + Children: children, + } + dataValue, errors := NewConverter().ConvertToVapi(childProject, childProject.GetType__()) + if len(errors) > 0 { + return nil, errors[0] + } + return []*data.StructValue{dataValue.(*data.StructValue)}, nil + +} + +func (service *Service) WrapVPC(vpc *model.Vpc) ([]*data.StructValue, error) { + vpc.ResourceType = pointy.String(ResourceTypeVpc) + childVpc := model.ChildVpc{ + Id: vpc.Id, + MarkedForDelete: vpc.MarkedForDelete, + ResourceType: "ChildVpc", + Vpc: vpc, + } + dataValue, errs := NewConverter().ConvertToVapi(childVpc, childVpc.GetType__()) + if len(errs) > 0 { + return nil, errs[0] + } + return []*data.StructValue{dataValue.(*data.StructValue)}, nil +} + +func (service *Service) WrapLBS(lbs *model.LBService) ([]*data.StructValue, error) { + lbs.ResourceType = pointy.String(ResourceTypeLBService) + childLBService := model.ChildLBService{ + Id: lbs.Id, + MarkedForDelete: lbs.MarkedForDelete, + ResourceType: "ChildLBService", + LbService: lbs, + } + dataValue, errs := NewConverter().ConvertToVapi(childLBService, childLBService.GetType__()) + if len(errs) > 0 { + return nil, errs[0] + } + return []*data.StructValue{dataValue.(*data.StructValue)}, nil +} diff --git a/pkg/nsx/services/realizestate/realize_state.go b/pkg/nsx/services/realizestate/realize_state.go index 8fef3bf8a..3fbc1ea35 100644 --- a/pkg/nsx/services/realizestate/realize_state.go +++ b/pkg/nsx/services/realizestate/realize_state.go @@ -49,7 +49,7 @@ func (service *RealizeStateService) CheckRealizeState(backoff wait.Backoff, inte return err } for _, result := range results.Results { - if *result.EntityType != entityType { + if entityType != "" && result.EntityType != nil && *result.EntityType != entityType { continue } if *result.State == model.GenericPolicyRealizedResource_STATE_REALIZED { diff --git a/pkg/nsx/services/vpc/builder.go b/pkg/nsx/services/vpc/builder.go index 5189ac73e..04d3c4227 100644 --- a/pkg/nsx/services/vpc/builder.go +++ b/pkg/nsx/services/vpc/builder.go @@ -51,7 +51,7 @@ func buildPrivateIpBlock(networkInfo *v1alpha1.NetworkInfo, nsObj *v1.Namespace, } func buildNSXVPC(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, nc common.VPCNetworkConfigInfo, cluster string, pathMap map[string]string, - nsxVPC *model.Vpc) (*model.Vpc, + nsxVPC *model.Vpc, useAVILB bool) (*model.Vpc, error) { vpc := &model.Vpc{} if nsxVPC != nil { @@ -61,7 +61,7 @@ func buildNSXVPC(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, nc common.VPCNe return nil, nil } // for updating vpc case, use current vpc id, name - vpc = nsxVPC + *vpc = *nsxVPC } else { // for creating vpc case, fill in vpc properties based on networkconfig vpcName := util.GenerateDisplayName("", "vpc", obj.GetNamespace(), "", cluster) @@ -76,7 +76,10 @@ func buildNSXVPC(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, nc common.VPCNe }, } vpc.SiteInfos = siteInfos - vpc.LoadBalancerVpcEndpoint = &model.LoadBalancerVPCEndpoint{Enabled: &DefaultLoadBalancerVPCEndpointEnabled} + if useAVILB { + loadBalancerVPCEndpointEnabled := true + vpc.LoadBalancerVpcEndpoint = &model.LoadBalancerVPCEndpoint{Enabled: &loadBalancerVPCEndpointEnabled} + } vpc.Tags = util.BuildBasicTags(cluster, obj, nsObj.UID) } @@ -89,3 +92,21 @@ func buildNSXVPC(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, nc common.VPCNe return vpc, nil } + +func buildNSXLBS(obj *v1alpha1.NetworkInfo, nsObj *v1.Namespace, cluster, lbsSize, vpcPath string, relaxScaleValidation *bool) (*model.LBService, error) { + lbs := &model.LBService{} + lbsName := util.GenerateDisplayName("", "vpc", nsObj.GetName(), "", cluster) + // Use VPC id for auto-created LBS id + lbs.Id = common.String(string(nsObj.GetUID())) + lbs.DisplayName = &lbsName + lbs.Tags = util.BuildBasicTags(cluster, obj, nsObj.GetUID()) + // "created_for" is required by NCP, and "lb_t1_link_ip" is not needed for VPC + lbs.Tags = append(lbs.Tags, model.Tag{ + Scope: common.String(common.TagScopeCreatedFor), + Tag: common.String(common.TagValueSLB), + }) + lbs.Size = &lbsSize + lbs.ConnectivityPath = &vpcPath + lbs.RelaxScaleValidation = relaxScaleValidation + return lbs, nil +} diff --git a/pkg/nsx/services/vpc/builder_test.go b/pkg/nsx/services/vpc/builder_test.go new file mode 100644 index 000000000..06d93f34b --- /dev/null +++ b/pkg/nsx/services/vpc/builder_test.go @@ -0,0 +1,79 @@ +package vpc + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" + "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" +) + +func Test_buildNSXLBS(t *testing.T) { + type args struct { + obj *v1alpha1.NetworkInfo + nsObj *v1.Namespace + cluster string + lbsSize string + vpcPath string + relaxScaleValidation *bool + } + tests := []struct { + name string + args args + want *model.LBService + wantErr assert.ErrorAssertionFunc + }{ + { + name: "1", + args: args{ + obj: &v1alpha1.NetworkInfo{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns1"}, + VPCs: nil, + }, + nsObj: &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "ns1", UID: "nsuid1"}, + }, + cluster: "cluster1", + lbsSize: model.LBService_SIZE_SMALL, + vpcPath: "/vpc1", + relaxScaleValidation: nil, + }, + want: &model.LBService{ + Id: common.String("nsuid1"), + DisplayName: common.String("vpc-cluster1--ns1"), + Tags: []model.Tag{ + { + Scope: common.String(common.TagScopeCluster), + Tag: common.String("cluster1"), + }, + { + Scope: common.String(common.TagScopeVersion), + Tag: common.String(strings.Join(common.TagValueVersion, ".")), + }, + {Scope: common.String(common.TagScopeNamespace), Tag: common.String("ns1")}, + {Scope: common.String(common.TagScopeNamespaceUID), Tag: common.String("nsuid1")}, + {Scope: common.String(common.TagScopeCreatedFor), Tag: common.String(common.TagValueSLB)}, + }, + Size: common.String(model.LBService_SIZE_SMALL), + ConnectivityPath: common.String("/vpc1"), + RelaxScaleValidation: nil, + }, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := buildNSXLBS(tt.args.obj, tt.args.nsObj, tt.args.cluster, tt.args.lbsSize, tt.args.vpcPath, tt.args.relaxScaleValidation) + if !tt.wantErr(t, err, fmt.Sprintf("buildNSXLBS(%v, %v, %v, %v, %v, %v)", tt.args.obj, tt.args.nsObj, tt.args.cluster, tt.args.lbsSize, tt.args.vpcPath, tt.args.relaxScaleValidation)) { + return + } + assert.Equalf(t, tt.want, got, "buildNSXLBS(%v, %v, %v, %v, %v, %v)", tt.args.obj, tt.args.nsObj, tt.args.cluster, tt.args.lbsSize, tt.args.vpcPath, tt.args.relaxScaleValidation) + }) + } +} diff --git a/pkg/nsx/services/vpc/store.go b/pkg/nsx/services/vpc/store.go index 6c5d90610..4b3ca419d 100644 --- a/pkg/nsx/services/vpc/store.go +++ b/pkg/nsx/services/vpc/store.go @@ -13,6 +13,8 @@ func keyFunc(obj interface{}) (string, error) { switch v := obj.(type) { case *model.Vpc: return *v.Id, nil + case *model.LBService: + return *v.Id, nil case *model.IpAddressBlock: return generateIPBlockKey(*v), nil default: @@ -27,6 +29,8 @@ func indexFunc(obj interface{}) ([]string, error) { switch o := obj.(type) { case *model.Vpc: return filterTag(o.Tags), nil + case *model.LBService: + return filterTag(o.Tags), nil case *model.IpAddressBlock: return filterTag(o.Tags), nil default: @@ -148,6 +152,41 @@ func (is *IPBlockStore) GetByIndex(index string, value string) *model.IpAddressB return block } +// LBSStore is a store for LBS +type LBSStore struct { + common.ResourceStore +} + +func (ls *LBSStore) Apply(i interface{}) error { + if i == nil { + return nil + } + lbs := i.(*model.LBService) + if lbs.MarkedForDelete != nil && *lbs.MarkedForDelete { + err := ls.Delete(lbs) + log.V(1).Info("delete LBS from store", "LBS", lbs) + if err != nil { + return err + } + } else { + err := ls.Add(lbs) + log.V(1).Info("add LBS to store", "LBS", lbs) + if err != nil { + return err + } + } + return nil +} + +func (ls *LBSStore) GetByKey(key string) *model.LBService { + obj := ls.ResourceStore.GetByKey(key) + if obj != nil { + lbs := obj.(*model.LBService) + return lbs + } + return nil +} + // keyFuncAVI is used to get the key of a AVI rule related resource func keyFuncAVI(obj interface{}) (string, error) { switch v := obj.(type) { diff --git a/pkg/nsx/services/vpc/store_test.go b/pkg/nsx/services/vpc/store_test.go index 2e6601615..8e0ab0734 100644 --- a/pkg/nsx/services/vpc/store_test.go +++ b/pkg/nsx/services/vpc/store_test.go @@ -8,6 +8,7 @@ import ( "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" "github.com/vmware/vsphere-automation-sdk-go/runtime/data" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" @@ -32,20 +33,6 @@ func (qIface *fakeQueryClient) List(_ string, _ *string, _ *string, _ *int64, _ }, nil } -func Test_IndexFunc(t *testing.T) { - mId, mTag, mScope := "test_id", "test_tag", "nsx-op/namespace_uid" - v := &model.Vpc{ - Id: &mId, - Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, - } - t.Run("1", func(t *testing.T) { - got, _ := indexFunc(v) - if !reflect.DeepEqual(got, []string{"test_tag"}) { - t.Errorf("NSCRUIDScopeIndexFunc() = %v, want %v", got, model.Tag{Tag: &mTag, Scope: &mScope}) - } - }) -} - func Test_filterTag(t *testing.T) { mTag, mScope := "test_tag", "nsx-op/namespace_uid" mTag2, mScope2 := "test_tag", "nsx" @@ -74,17 +61,6 @@ func Test_filterTag(t *testing.T) { } } -func Test_KeyFunc(t *testing.T) { - Id := "test_id" - v := &model.Vpc{Id: &Id} - t.Run("1", func(t *testing.T) { - got, _ := keyFunc(v) - if got != "test_id" { - t.Errorf("keyFunc() = %v, want %v", got, "test_id") - } - }) -} - func Test_InitializeVPCStore(t *testing.T) { config2 := nsx.NewConfig("localhost", "1", "1", []string{}, 10, 3, 20, 20, true, true, true, ratelimiter.AIMD, nil, nil, []string{}) cluster, _ := nsx.NewCluster(config2) @@ -337,3 +313,129 @@ func TestSecurityPolicyStore_GetByKey(t *testing.T) { sp = spStore.GetByKey(path2) assert.Equal(t, sp.Path, sp2.Path) } + +func Test_keyFunc(t *testing.T) { + id := "test_id" + type args struct { + obj interface{} + } + tests := []struct { + name string + args args + want string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "vpc", + args: args{obj: &model.Vpc{Id: &id}}, + want: id, + wantErr: assert.NoError, + }, + { + name: "lbs", + args: args{obj: &model.LBService{Id: &id}}, + want: id, + wantErr: assert.NoError, + }, + { + name: "invalid", + args: args{obj: &model.AntreaTraceflowConfig{Id: &id}}, + want: "", + wantErr: assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := keyFunc(tt.args.obj) + if !tt.wantErr(t, err, fmt.Sprintf("keyFunc(%v)", tt.args.obj)) { + return + } + assert.Equalf(t, tt.want, got, "keyFunc(%v)", tt.args.obj) + }) + } +} + +func Test_indexFunc(t *testing.T) { + mId, mTag, mScope := "test_id", "test_tag", "nsx-op/namespace_uid" + type args struct { + obj interface{} + } + tests := []struct { + name string + args args + want []string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "vpc", + args: args{obj: &model.Vpc{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + }}, + want: []string{"test_tag"}, + wantErr: assert.NoError, + }, + { + name: "lbs", + args: args{obj: &model.LBService{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + }}, + want: []string{"test_tag"}, + wantErr: assert.NoError, + }, + { + name: "lbsnotag", + args: args{obj: &model.LBService{ + Id: &mId, + Tags: []model.Tag{}, + }}, + want: []string{}, + wantErr: assert.NoError, + }, + { + name: "invalid", + args: args{obj: &model.AntreaTraceflowConfig{ + Id: &mId, + Tags: []model.Tag{{Tag: &mTag, Scope: &mScope}}, + }}, + want: []string{}, + wantErr: assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := indexFunc(tt.args.obj) + if !tt.wantErr(t, err, fmt.Sprintf("indexFunc(%v)", tt.args.obj)) { + return + } + assert.Equalf(t, tt.want, got, "indexFunc(%v)", tt.args.obj) + }) + } +} + +func TestLBSStore_CRUD(t *testing.T) { + vpcCacheIndexer := cache.NewIndexer(keyFunc, cache.Indexers{}) + resourceStore := common.ResourceStore{ + Indexer: vpcCacheIndexer, + BindingType: model.LBServiceBindingType(), + } + ls := &LBSStore{ + ResourceStore: resourceStore, + } + lbs1 := &model.LBService{Id: common.String("1")} + lbs2 := &model.LBService{Id: common.String("2")} + require.NoError(t, ls.Apply(lbs1)) + require.Equal(t, 1, len(ls.List())) + require.True(t, reflect.DeepEqual(lbs1, ls.GetByKey("1"))) + require.NoError(t, ls.Apply(lbs2)) + require.Equal(t, 2, len(ls.List())) + lbs2.MarkedForDelete = common.Bool(true) + require.NoError(t, ls.Apply(lbs2)) + require.Equal(t, 1, len(ls.List())) + require.Nil(t, ls.GetByKey("2")) + defer func() { + require.NotNil(t, recover()) + }() + ls.Apply(&model.AntreaTraceflowConfig{Id: common.String("invalid")}) +} diff --git a/pkg/nsx/services/vpc/vpc.go b/pkg/nsx/services/vpc/vpc.go index 415b92773..577f7a612 100644 --- a/pkg/nsx/services/vpc/vpc.go +++ b/pkg/nsx/services/vpc/vpc.go @@ -15,7 +15,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/retry" "github.com/vmware-tanzu/nsx-operator/pkg/apis/v1alpha1" "github.com/vmware-tanzu/nsx-operator/pkg/logger" @@ -30,6 +29,7 @@ const ( AviSEIngressAllowRuleId = "avi-se-ingress-allow-rule" VPCAviSEGroupId = "avi-se-vms" VpcDefaultSecurityPolicyId = "default-layer3-section" + VPCKey = "/orgs/%s/projects/%s/vpcs/%s" GroupKey = "/orgs/%s/projects/%s/vpcs/%s/groups/%s" SecurityPolicyKey = "/orgs/%s/projects/%s/vpcs/%s/security-policies/%s" RuleKey = "/orgs/%s/projects/%s/vpcs/%s/security-policies/%s/rules/%s" @@ -41,8 +41,9 @@ var ( ResourceTypeVPC = common.ResourceTypeVpc NewConverter = common.NewConverter - MarkedForDelete = true - enableAviAllowRule = false + MarkedForDelete = true + enableAviAllowRule = false + EnforceRevisionCheckParam = false ) type VPCNetworkInfoStore struct { @@ -58,6 +59,7 @@ type VPCNsNetworkConfigStore struct { type VPCService struct { common.Service VpcStore *VPCStore + LbsStore *LBSStore IpblockStore *IPBlockStore VPCNetworkConfigStore VPCNetworkInfoStore VPCNSNetworkConfigStore VPCNsNetworkConfigStore @@ -161,6 +163,10 @@ func InitializeVPC(service common.Service) (*VPCService, error) { Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), BindingType: model.VpcBindingType(), }} + VPCService.LbsStore = &LBSStore{ResourceStore: common.ResourceStore{ + Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}), + BindingType: model.LBServiceBindingType(), + }} VPCService.IpblockStore = &IPBlockStore{ResourceStore: common.ResourceStore{ Indexer: cache.NewIndexer(keyFunc, cache.Indexers{ @@ -173,8 +179,10 @@ func InitializeVPC(service common.Service) (*VPCService, error) { VPCService.VPCNSNetworkConfigStore = VPCNsNetworkConfigStore{ VPCNSNetworkConfigMap: make(map[string]string), } - //initialize vpc store and ip blocks store + //initialize vpc store, lbs store and ip blocks store go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeVpc, nil, VPCService.VpcStore) + wg.Add(1) + go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeLBService, nil, VPCService.LbsStore) go VPCService.InitializeResourceStore(&wg, fatalErrors, common.ResourceTypeIPBlock, nil, VPCService.IpblockStore) //initalize avi rule related store @@ -251,6 +259,10 @@ func (s *VPCService) DeleteVPC(path string) error { err = nsxutil.NSXApiError(err) return err } + lbs := s.LbsStore.GetByKey(pathInfo.VPCID) + if lbs != nil { + s.LbsStore.Delete(lbs) + } vpc.MarkedForDelete = &MarkedForDelete if err := s.VpcStore.Apply(vpc); err != nil { return err @@ -556,7 +568,7 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * nsxVPC = nil } - createdVpc, err := buildNSXVPC(obj, nsObj, nc, s.NSXConfig.Cluster, paths, nsxVPC) + createdVpc, err := buildNSXVPC(obj, nsObj, nc, s.NSXConfig.Cluster, paths, nsxVPC, s.NSXConfig.NsxConfig.UseAVILoadBalancer) if err != nil { log.Error(err, "failed to build NSX VPC object") return nil, nil, err @@ -568,8 +580,26 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * return existingVPC[0], &nc, nil } + // build NSX LBS + var createdLBS *model.LBService + if s.NSXConfig.NsxConfig.NSXLBEnabled() { + lbsSize := s.NSXConfig.NsxConfig.GetNSXLBSize() + vpcPath := fmt.Sprintf(VPCKey, nc.Org, nc.NsxtProject, nc.Name) + var relaxScaleValidation *bool + if s.NSXConfig.NsxConfig.RelaxNSXLBScaleValication { + relaxScaleValidation = common.Bool(true) + } + createdLBS, _ = buildNSXLBS(obj, nsObj, s.NSXConfig.Cluster, lbsSize, vpcPath, relaxScaleValidation) + } + // build HAPI request + orgRoot, err := s.WrapHierarchyVPC(nc.Org, nc.NsxtProject, createdVpc, createdLBS) + if err != nil { + log.Error(err, "failed to build HAPI request") + return nil, nil, err + } + log.Info("creating NSX VPC", "VPC", *createdVpc.Id) - err = s.NSXClient.VPCClient.Patch(nc.Org, nc.NsxtProject, *createdVpc.Id, *createdVpc) + err = s.NSXClient.OrgRootClient.Patch(*orgRoot, &EnforceRevisionCheckParam) err = nsxutil.NSXApiError(err) if err != nil { log.Error(err, "failed to create VPC", "Project", nc.NsxtProject, "Namespace", obj.Namespace) @@ -596,12 +626,14 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * return nil, nil, err } + log.V(2).Info("check VPC realization state", "VPC", *createdVpc.Id) realizeService := realizestate.InitializeRealizeState(s.Service) - if err = realizeService.CheckRealizeState(retry.DefaultRetry, *newVpc.Path, "RealizedLogicalRouter"); err != nil { + if err = realizeService.CheckRealizeState(util.NSXTDefaultRetry, *newVpc.Path, "RealizedLogicalRouter"); err != nil { log.Error(err, "failed to check VPC realization state", "VPC", *createdVpc.Id) if realizestate.IsRealizeStateError(err) { log.Error(err, "the created VPC is in error realization state, cleaning the resource", "VPC", *createdVpc.Id) - // delete the nsx vpc object and re-created in next loop + // delete the nsx vpc object and re-create it in the next loop + // TODO(gran) DeleteVPC will check VpcStore but new Vpc is not in store at this moment. Is it correct? if err := s.DeleteVPC(*newVpc.Path); err != nil { log.Error(err, "cleanup VPC failed", "VPC", *createdVpc.Id) return nil, nil, err @@ -611,6 +643,32 @@ func (s *VPCService) CreateOrUpdateVPC(obj *v1alpha1.NetworkInfo) (*model.Vpc, * } s.VpcStore.Add(&newVpc) + + // Check LBS realization + if createdLBS != nil { + newLBS, err := s.NSXClient.VPCLBSClient.Get(nc.Org, nc.NsxtProject, *createdVpc.Id, *createdLBS.Id) + if err != nil { + log.Error(err, "failed to read LBS object after creating or updating", "LBS", createdLBS.Id) + return nil, nil, err + } + s.LbsStore.Add(&newLBS) + + log.V(2).Info("check LBS realization state", "LBS", *createdLBS.Id) + realizeService := realizestate.InitializeRealizeState(s.Service) + if err = realizeService.CheckRealizeState(util.NSXTLBVSDefaultRetry, *newLBS.Path, ""); err != nil { + log.Error(err, "failed to check LBS realization state", "LBS", *createdLBS.Id) + if realizestate.IsRealizeStateError(err) { + log.Error(err, "the created LBS is in error realization state, cleaning the resource", "LBS", *createdLBS.Id) + // delete the nsx vpc object and re-create it in the next loop + if err := s.DeleteVPC(*newVpc.Path); err != nil { + log.Error(err, "cleanup VPC failed", "VPC", *createdVpc.Id) + return nil, nil, err + } + } + return nil, nil, err + } + } + return &newVpc, &nc, nil } @@ -902,3 +960,11 @@ func (service *VPCService) ListVPCInfo(ns string) []common.VPCResourceInfo { } return VPCInfoList } + +func (s *VPCService) GetNSXLBSPath(lbsId string) string { + vpcLBS := s.LbsStore.GetByKey(lbsId) + if vpcLBS == nil { + return "" + } + return *vpcLBS.Path +} diff --git a/pkg/nsx/services/vpc/wrap.go b/pkg/nsx/services/vpc/wrap.go new file mode 100644 index 000000000..8b16e771b --- /dev/null +++ b/pkg/nsx/services/vpc/wrap.go @@ -0,0 +1,41 @@ +package vpc + +import ( + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func (s *VPCService) WrapHierarchyVPC(org, nsxtProject string, vpc *model.Vpc, lbs *model.LBService) (*model.OrgRoot, error) { + if lbs != nil { + var vpcChildren []*data.StructValue + childrenLBS, err := s.WrapLBS(lbs) + if err != nil { + return nil, err + } + vpcChildren = append(vpcChildren, childrenLBS...) + vpc.Children = vpcChildren + } + var projectChildren []*data.StructValue + childrenVPC, err := s.WrapVPC(vpc) + if err != nil { + return nil, err + } + projectChildren = append(projectChildren, childrenVPC...) + + var orgChildren []*data.StructValue + childrenProject, err := s.WrapProject(nsxtProject, projectChildren) + if err != nil { + return nil, err + } + orgChildren = append(orgChildren, childrenProject...) + + var orgRootChildren []*data.StructValue + childrenOrg, err := s.WrapOrg(org, orgChildren) + if err != nil { + return nil, err + } + orgRootChildren = append(orgRootChildren, childrenOrg...) + + orgRoot, _ := s.WrapOrgRoot(orgRootChildren) + return orgRoot, nil +} diff --git a/pkg/nsx/services/vpc/wrap_test.go b/pkg/nsx/services/vpc/wrap_test.go new file mode 100644 index 000000000..b51338705 --- /dev/null +++ b/pkg/nsx/services/vpc/wrap_test.go @@ -0,0 +1,51 @@ +package vpc + +import ( + "fmt" + "testing" + + "github.com/openlyinc/pointy" + "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func TestVPCService_WrapHierarchyVPC(t *testing.T) { + type args struct { + org string + nsxtProject string + vpc *model.Vpc + lbs *model.LBService + } + tests := []struct { + name string + args args + want *model.OrgRoot + wantChildren int + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test", + args: args{ + org: "testorg", + nsxtProject: "testproject", + vpc: &model.Vpc{}, + lbs: &model.LBService{}, + }, + want: &model.OrgRoot{ResourceType: pointy.String("OrgRoot")}, + wantChildren: 1, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &VPCService{} + got, err := s.WrapHierarchyVPC(tt.args.org, tt.args.nsxtProject, tt.args.vpc, tt.args.lbs) + if !tt.wantErr(t, err, fmt.Sprintf("WrapHierarchyVPC(%v, %v, %v, %v)", tt.args.org, tt.args.nsxtProject, tt.args.vpc, tt.args.lbs)) { + return + } + assert.Equalf(t, tt.wantChildren, len(got.Children), "WrapHierarchyVPC children count") + got.Children = nil + assert.Equalf(t, tt.want, got, "WrapHierarchyVPC(%v, %v, %v, %v)", tt.args.org, tt.args.nsxtProject, tt.args.vpc, tt.args.lbs) + }) + } +} diff --git a/pkg/nsx/util/utils.go b/pkg/nsx/util/utils.go index d9d58745d..6fee23f9c 100644 --- a/pkg/nsx/util/utils.go +++ b/pkg/nsx/util/utils.go @@ -564,6 +564,8 @@ func CasttoPointer(obj interface{}) interface{} { return &v case model.Vpc: return &v + case model.LBService: + return &v case model.IpAddressPoolBlockSubnet: return &v case model.Group: diff --git a/pkg/util/retry.go b/pkg/util/retry.go new file mode 100644 index 000000000..131529a0e --- /dev/null +++ b/pkg/util/retry.go @@ -0,0 +1,21 @@ +package util + +import ( + "time" + + "k8s.io/apimachinery/pkg/util/wait" +) + +var NSXTDefaultRetry = wait.Backoff{ + Steps: 10, + Duration: 500 * time.Millisecond, + Factor: 1.0, + Jitter: 0.1, +} + +var NSXTLBVSDefaultRetry = wait.Backoff{ + Steps: 60, + Duration: 500 * time.Millisecond, + Factor: 1.0, + Jitter: 0.1, +}