Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support showing NSX LB SNAT IP in networkinfo CR #1018

Merged
merged 1 commit into from
Feb 24, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions pkg/controllers/networkinfo/networkinfo_controller.go
Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@ var (
nsMsgVPCCreateUpdateError = newNsUnreadyMessage("Error happened to create or update VPC: %v", NSReasonVPCNotReady)
nsMsgVPCNsxLBSNotReady = newNsUnreadyMessage("Error happened to get NSX LBS path in VPC: %v", NSReasonVPCNotReady)
nsMsgVPCAviSubnetError = newNsUnreadyMessage("Error happened to get Avi Load balancer Subnet info: %v", NSReasonVPCNotReady)
nsMsgVPCNSXLBSNATIPError = newNsUnreadyMessage("Error happened to get NSX Load balancer SNAT IP info: %v", NSReasonVPCNotReady)
nsMsgVPCGetExtIPBlockError = newNsUnreadyMessage("Error happened to get external IP blocks: %v", NSReasonVPCNotReady)
nsMsgVPCNoExternalIPBlock = newNsUnreadyMessage("System VPC has no external IP blocks", NSReasonVPCNotReady)
nsMsgVPCAutoSNATDisabled = newNsUnreadyMessage("SNAT is not enabled in System VPC", NSReasonVPCSnatNotReady)
@@ -125,6 +126,7 @@ func (r *NetworkInfoReconciler) GetVpcConnectivityProfilePathByVpcPath(vpcPath s
return "", err
}
}

func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
startTime := time.Now()
defer func() {
@@ -252,7 +254,7 @@ func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request)
nsxLBSPath = r.Service.GetDefaultNSXLBSPathByVPC(*createdVpc.Id)
}

snatIP, path, cidr := "", "", ""
snatIP, aviSubnetPath, aviSECIDR, nsxLBSNATIP, lbIP := "", "", "", "", ""

vpcConnectivityProfile, err := r.Service.GetVpcConnectivityProfile(&nc, vpcConnectivityProfilePath)
if err != nil {
@@ -302,30 +304,46 @@ func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request)
// nsx bug, if set LoadBalancerVpcEndpoint.Enabled to false, when read this VPC back,
// LoadBalancerVpcEndpoint.Enabled will become a nil pointer.
if lbProvider == vpc.AVILB && createdVpc.LoadBalancerVpcEndpoint != nil && createdVpc.LoadBalancerVpcEndpoint.Enabled != nil && *createdVpc.LoadBalancerVpcEndpoint.Enabled {
path, cidr, err = r.Service.GetAVISubnetInfo(*createdVpc)
aviSubnetPath, aviSECIDR, err = r.Service.GetAVISubnetInfo(*createdVpc)
if err != nil {
log.Error(err, "Failed to read LB Subnet path and CIDR", "VPC", createdVpc.Id)
log.Error(err, "Failed to read AVI LB Subnet path and CIDR", "VPC", createdVpc.Id)
state := &v1alpha1.VPCState{
Name: *createdVpc.DisplayName,
DefaultSNATIP: snatIP,
LoadBalancerIPAddresses: "",
PrivateIPs: privateIPs,
}
r.StatusUpdater.UpdateFail(ctx, networkInfoCR, err, fmt.Sprintf("Failed to read LB Subnet path and CIDR, VPC: %s", *createdVpc.Id), setNetworkInfoVPCStatusWithError, state)
r.StatusUpdater.UpdateFail(ctx, networkInfoCR, err, fmt.Sprintf("Failed to read AVI LB Subnet path and CIDR, VPC: %s", *createdVpc.Id), setNetworkInfoVPCStatusWithError, state)
setNSNetworkReadyCondition(ctx, r.Client, req.Namespace, nsMsgVPCAviSubnetError.getNSNetworkCondition(err))
return common.ResultRequeueAfter10sec, err
}
lbIP = aviSECIDR
} else if lbProvider == vpc.NSXLB {
nsxLBSNATIP, err = r.Service.GetNSXLBSNATIP(*createdVpc)
if err != nil {
log.Error(err, "Failed to read NSX LB SNAT IP", "VPC", createdVpc.Id)
state := &v1alpha1.VPCState{
Name: *createdVpc.DisplayName,
DefaultSNATIP: snatIP,
LoadBalancerIPAddresses: "",
PrivateIPs: privateIPs,
}
r.StatusUpdater.UpdateFail(ctx, networkInfoCR, err, fmt.Sprintf("Failed to read NSX LB Subnet path and CIDR, VPC: %s", *createdVpc.Id), setNetworkInfoVPCStatusWithError, state)
setNSNetworkReadyCondition(ctx, r.Client, req.Namespace, nsMsgVPCNSXLBSNATIPError.getNSNetworkCondition(err))
return common.ResultRequeueAfter10sec, err
}
lbIP = nsxLBSNATIP
}

state := &v1alpha1.VPCState{
Name: *createdVpc.DisplayName,
DefaultSNATIP: snatIP,
LoadBalancerIPAddresses: cidr,
LoadBalancerIPAddresses: lbIP,
PrivateIPs: privateIPs,
}

// AKO needs to know the AVI subnet path created by NSX
setVPCNetworkConfigurationStatusWithLBS(ctx, r.Client, ncName, state.Name, path, nsxLBSPath, *createdVpc.Path)
setVPCNetworkConfigurationStatusWithLBS(ctx, r.Client, ncName, state.Name, aviSubnetPath, nsxLBSPath, *createdVpc.Path)
r.StatusUpdater.UpdateSuccess(ctx, networkInfoCR, setNetworkInfoVPCStatus, state)

if retryWithSystemVPC {
189 changes: 138 additions & 51 deletions pkg/controllers/networkinfo/networkinfo_controller_test.go

Large diffs are not rendered by default.

33 changes: 30 additions & 3 deletions pkg/nsx/services/realizestate/realize_state.go
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ package realizestate

import (
"fmt"
"strings"

"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
"k8s.io/apimachinery/pkg/util/wait"
@@ -15,9 +16,7 @@ import (
nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util"
)

var (
log = &logger.Log
)
var log = &logger.Log

type RealizeStateService struct {
common.Service
@@ -76,3 +75,31 @@ func (service *RealizeStateService) CheckRealizeState(backoff wait.Backoff, inte
return fmt.Errorf("%s not realized", intentPath)
})
}

func (service *RealizeStateService) GetPolicyTier1UplinkPortIP(intentPath string) (string, error) {
results, err := service.NSXClient.RealizedEntitiesClient.List(intentPath, nil)
err = nsxutil.TransNSXApiError(err)
if err != nil {
return "", err
}

for _, result := range results.Results {
extendAttributes := result.ExtendedAttributes
if len(extendAttributes) == 0 || len(result.IntentPaths) != 1 || (result.EntityType != nil && *result.EntityType != "RealizedLogicalRouterPort") {
continue
}
for i := range extendAttributes {
if extendAttributes[i].Key != nil && *extendAttributes[i].Key == "IpAddresses" {
for _, ip := range extendAttributes[i].Values {
parts := strings.Split(ip, "/")
if len(parts) != 2 {
continue
}
return parts[0], nil
}
}
}
}

return "", fmt.Errorf("%s tier1 uplink port IP not found", intentPath)
}
150 changes: 150 additions & 0 deletions pkg/nsx/services/realizestate/realize_state_test.go
Original file line number Diff line number Diff line change
@@ -6,7 +6,10 @@ import (

"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
apierrors "github.com/vmware/vsphere-automation-sdk-go/lib/vapi/std/errors"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"

"k8s.io/apimachinery/pkg/util/wait"

"github.com/vmware-tanzu/nsx-operator/pkg/config"
@@ -229,5 +232,152 @@ func TestRealizeStateService_CheckRealizeState(t *testing.T) {
_, ok = err.(*nsxutil.RealizeStateError)
assert.Equal(t, ok, false)
patches.Reset()
}

func TestRealizeStateService_GetPolicyTier1UplinkPortIP(t *testing.T) {
commonService := common.Service{
NSXClient: &nsx.Client{
RealizedEntitiesClient: &fakeRealizedEntitiesClient{},
NsxConfig: &config.NSXOperatorConfig{
CoeConfig: &config.CoeConfig{
Cluster: "k8scl-one:test",
},
},
},
NSXConfig: &config.NSXOperatorConfig{
CoeConfig: &config.CoeConfig{
Cluster: "k8scl-one:test",
},
},
}
s := &RealizeStateService{
Service: commonService,
}

testCases := []struct {
name string
intentPath string
prepareFuncs func() *gomonkey.Patches
wantObj string
wantErr string
}{
{
name: "Test normal case",
intentPath: "/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
wantObj: "100.64.0.3",
prepareFuncs: func() *gomonkey.Patches {
patches := gomonkey.ApplyFunc((*fakeRealizedEntitiesClient).List, func(c *fakeRealizedEntitiesClient, intentPathParam string, sitePathParam *string) (model.GenericPolicyRealizedResourceListResult, error) {
return model.GenericPolicyRealizedResourceListResult{
Results: []model.GenericPolicyRealizedResource{
{
State: common.String(model.GenericPolicyRealizedResource_STATE_REALIZED),
EntityType: common.String("RealizedLogicalRouterPort"),
IntentPaths: []string{
"/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
},
},
{
State: common.String(model.GenericPolicyRealizedResource_STATE_REALIZED),
ExtendedAttributes: []model.AttributeVal{
{
DataType: common.String("STRING"),
Key: common.String("IpAddresses"),
Values: []string{"100.64.0.3/31"},
},
{
DataType: common.String("STRING"),
Key: common.String("MacAddress"),
Values: []string{"02:50:56:56:44:52"},
},
},
EntityType: common.String("RealizedLogicalRouterPort"),
IntentPaths: []string{
"/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
},
},
},
}, nil
})
return patches
},
},
{
name: "Empty list result",
intentPath: "/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
wantErr: "tier1 uplink port IP not found",
prepareFuncs: func() *gomonkey.Patches {
patches := gomonkey.ApplyFunc((*fakeRealizedEntitiesClient).List, func(c *fakeRealizedEntitiesClient, intentPathParam string, sitePathParam *string) (model.GenericPolicyRealizedResourceListResult, error) {
return model.GenericPolicyRealizedResourceListResult{
Results: []model.GenericPolicyRealizedResource{
{},
},
}, nil
})
return patches
},
},
{
name: "Invalid tier1 uplink port IP",
intentPath: "/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
wantErr: "tier1 uplink port IP not found",
prepareFuncs: func() *gomonkey.Patches {
patches := gomonkey.ApplyFunc((*fakeRealizedEntitiesClient).List, func(c *fakeRealizedEntitiesClient, intentPathParam string, sitePathParam *string) (model.GenericPolicyRealizedResourceListResult, error) {
return model.GenericPolicyRealizedResourceListResult{
Results: []model.GenericPolicyRealizedResource{
{
State: common.String(model.GenericPolicyRealizedResource_STATE_REALIZED),
ExtendedAttributes: []model.AttributeVal{
{
DataType: common.String("STRING"),
Key: common.String("IpAddresses"),
Values: []string{"100.64.0.3/31/33"},
},
},
EntityType: common.String("RealizedLogicalRouterPort"),
IntentPaths: []string{
"/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
},
},
},
}, nil
})
return patches
},
},
{
name: "Realized error",
intentPath: "/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1",
wantErr: "com.vmware.vapi.std.errors.service_unavailable",
prepareFuncs: func() *gomonkey.Patches {
patches := gomonkey.ApplyFunc((*fakeRealizedEntitiesClient).List, func(c *fakeRealizedEntitiesClient, intentPathParam string, sitePathParam *string) (model.GenericPolicyRealizedResourceListResult, error) {
return model.GenericPolicyRealizedResourceListResult{
Results: []model.GenericPolicyRealizedResource{
{
State: common.String(model.GenericPolicyRealizedResource_STATE_ERROR),
EntityType: common.String("RealizedLogicalRouterPort"),
},
},
}, apierrors.NewServiceUnavailable()
})
return patches
},
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
if testCase.prepareFuncs != nil {
patches := testCase.prepareFuncs()
defer patches.Reset()
}

got, err := s.GetPolicyTier1UplinkPortIP(testCase.intentPath)
if testCase.wantErr != "" {
assert.ErrorContains(t, err, testCase.wantErr)
} else {
require.NoError(t, err)
assert.Equal(t, testCase.wantObj, got)
}
})
}
}
18 changes: 16 additions & 2 deletions pkg/nsx/services/vpc/vpc.go
Original file line number Diff line number Diff line change
@@ -643,7 +643,6 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) {
subnetsClient := s.NSXClient.SubnetsClient
statusClient := s.NSXClient.SubnetStatusClient
info, err := common.ParseVPCResourcePath(*vpc.Path)

if err != nil {
return "", "", err
}
@@ -679,6 +678,22 @@ func (s *VPCService) GetAVISubnetInfo(vpc model.Vpc) (string, string, error) {
return path, cidr, nil
}

func (s *VPCService) GetNSXLBSNATIP(vpc model.Vpc) (string, error) {
log.V(2).Info("Getting VPC NSX LB SNAT IP", "VPC", *vpc.Id)
_, err := common.ParseVPCResourcePath(*vpc.Path)
if err != nil {
return "", err
}

realizeService := realizestate.InitializeRealizeState(s.Service)
tier1UpLinkIP, err := realizeService.GetPolicyTier1UplinkPortIP(*vpc.Path)
if err != nil {
log.Error(err, "Failed to get VPC NSX LB SNAT IP", "VPC", *vpc.Id)
return "", err
}
return tier1UpLinkIP, nil
}

func (s *VPCService) GetVpcConnectivityProfile(nc *common.VPCNetworkConfigInfo, vpcConnectivityProfilePath string) (*model.VpcConnectivityProfile, error) {
parts := strings.Split(vpcConnectivityProfilePath, "/")
if len(parts) < 1 {
@@ -953,7 +968,6 @@ func (s *VPCService) ValidateGatewayConnectionStatus(nc *common.VPCNetworkConfig
transitGatewayId := parts[len(parts)-1]
res, err := s.NSXClient.TransitGatewayAttachmentClient.List(nc.Org, nc.NSXProject, transitGatewayId, nil, &markedForDelete, nil, nil, nil, nil)
err = nsxutil.TransNSXApiError(err)

if err != nil {
return false, "", err
}
119 changes: 98 additions & 21 deletions pkg/nsx/services/vpc/vpc_test.go
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client/fake"

"github.com/agiledragon/gomonkey/v2"
@@ -35,6 +36,7 @@ import (
"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/realizestate"
nsxUtil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util"
)

@@ -270,15 +272,19 @@ func TestGetSharedVPCNamespaceFromNS(t *testing.T) {
existingNames: []*v1.Namespace{
{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{Name: "test-ns-1",
Annotations: map[string]string{"nsx.vmware.com/vpc_network_config": "default", "nsx.vmware.com/shared_vpc_namespace": "test-ns-2"}},
ObjectMeta: metav1.ObjectMeta{
Name: "test-ns-1",
Annotations: map[string]string{"nsx.vmware.com/vpc_network_config": "default", "nsx.vmware.com/shared_vpc_namespace": "test-ns-2"},
},
Spec: v1.NamespaceSpec{},
Status: v1.NamespaceStatus{},
},
{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{Name: "test-ns-2",
Annotations: map[string]string{"nsx.vmware.com/vpc_network_config": "default"}},
ObjectMeta: metav1.ObjectMeta{
Name: "test-ns-2",
Annotations: map[string]string{"nsx.vmware.com/vpc_network_config": "default"},
},
Spec: v1.NamespaceSpec{},
Status: v1.NamespaceStatus{},
},
@@ -677,9 +683,11 @@ func TestEdgeClusterEnabled(t *testing.T) {
}

vpcConnPrfile := model.VpcConnectivityProfile{
ServiceGateway: &model.VpcServiceGatewayConfig{Enable: common.Bool(false),
ServiceGateway: &model.VpcServiceGatewayConfig{
Enable: common.Bool(false),
NatConfig: &model.VpcNatConfig{EnableDefaultSnat: common.Bool(true)},
}}
},
}

patch := gomonkey.ApplyMethod(reflect.TypeOf(vpcService), "GetVpcConnectivityProfile", func(_ *VPCService, _ *common.VPCNetworkConfigInfo, _ string) (*model.VpcConnectivityProfile, error) {
return &vpcConnPrfile, nil
@@ -1208,7 +1216,6 @@ func TestVPCService_RegisterVPCNetworkConfig(t *testing.T) {
got, exist := service.GetVPCNetworkConfig("fake-name")
assert.True(t, exist)
reflect.DeepEqual(got, info)

}

func TestVPCService_UnRegisterVPCNetworkConfig(t *testing.T) {
@@ -1237,11 +1244,9 @@ func TestVPCService_UnRegisterVPCNetworkConfig(t *testing.T) {
got, exist = service.GetVPCNetworkConfig("fake-name")
assert.False(t, exist)
assert.Equal(t, common.VPCNetworkConfigInfo{}, got)

}

func TestVPCService_RegisterNamespaceNetworkconfigBinding(t *testing.T) {

service, _, _ := createService(t)

info := common.VPCNetworkConfigInfo{
@@ -1261,11 +1266,9 @@ func TestVPCService_RegisterNamespaceNetworkconfigBinding(t *testing.T) {
reflect.DeepEqual(info, got)
got = service.GetVPCNetworkConfigByNamespace("non-exist")
assert.Nil(t, got)

}

func TestVPCService_UnRegisterNamespaceNetworkconfigBinding(t *testing.T) {

service, _, _ := createService(t)

info := common.VPCNetworkConfigInfo{
@@ -1288,7 +1291,6 @@ func TestVPCService_UnRegisterNamespaceNetworkconfigBinding(t *testing.T) {
service.UnRegisterNamespaceNetworkconfigBinding("fake-ns")
got = service.GetVPCNetworkConfigByNamespace("fake-ns")
assert.Nil(t, got)

}

func TestVPCService_GetNamespacesByNetworkconfigName(t *testing.T) {
@@ -1417,7 +1419,8 @@ func TestVPCService_DeleteVPC(t *testing.T) {
checkLBStore: false,
checkVPCStore: false,
},
{name: "lb in store but vpc not",
{
name: "lb in store but vpc not",
prepareFunc: func(_ *testing.T, service *VPCService) (patches *gomonkey.Patches) {
patches = gomonkey.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCClient), "Delete", []gomonkey.OutputCell{{
Values: gomonkey.Params{
@@ -1438,7 +1441,8 @@ func TestVPCService_DeleteVPC(t *testing.T) {
checkLBStore: true,
checkVPCStore: false,
},
{name: "delete vpc store fail",
{
name: "delete vpc store fail",
prepareFunc: func(_ *testing.T, service *VPCService) (patches *gomonkey.Patches) {
patches = gomonkey.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCClient), "Delete", []gomonkey.OutputCell{{
Values: gomonkey.Params{
@@ -1467,7 +1471,8 @@ func TestVPCService_DeleteVPC(t *testing.T) {
checkLBStore: true,
checkVPCStore: false,
},
{name: "happy pass",
{
name: "happy pass",
prepareFunc: func(_ *testing.T, service *VPCService) (patches *gomonkey.Patches) {
patches = gomonkey.ApplyMethodSeq(reflect.TypeOf(service.NSXClient.VPCClient), "Delete", []gomonkey.OutputCell{{
Values: gomonkey.Params{
@@ -1501,7 +1506,6 @@ func TestVPCService_DeleteVPC(t *testing.T) {
// nolint: copylocks
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

if tt.prepareFunc != nil {
patches := tt.prepareFunc(t, service)
defer patches.Reset()
@@ -1535,7 +1539,6 @@ func TestVPCService_DeleteVPC(t *testing.T) {
lb := service.LbsStore.GetByKey(mockLBKey)
assert.Nil(t, lb)
}

})
}
}
@@ -2046,8 +2049,7 @@ func TestVPCService_CreateOrUpdateVPC(t *testing.T) {
}
}

type fakeOrgRootClient struct {
}
type fakeOrgRootClient struct{}

func (f fakeOrgRootClient) Get(basePathParam *string, filterParam *string, typeFilterParam *string) (model.OrgRoot, error) {
return model.OrgRoot{}, nil
@@ -2057,8 +2059,7 @@ func (f fakeOrgRootClient) Patch(orgRootParam model.OrgRoot, enforceRevisionChec
return nil
}

type fakeRealizedEntitiesClient struct {
}
type fakeRealizedEntitiesClient struct{}

func (f fakeRealizedEntitiesClient) List(intentPathParam string, sitePathParam *string) (model.GenericPolicyRealizedResourceListResult, error) {
state := model.GenericPolicyRealizedResource_STATE_REALIZED
@@ -2133,3 +2134,79 @@ func TestInitializeVPC(t *testing.T) {
assert.Equal(t, tc.expectAllVPCNum, len(allVPCs))
}
}

func TestGetNSXLBSNATIP(t *testing.T) {
vpcService := &VPCService{
Service: common.Service{
NSXConfig: &config.NSXOperatorConfig{
NsxConfig: &config.NsxConfig{
UseAVILoadBalancer: false,
UseNSXLoadBalancer: ptr.To(true),
},
},
NSXClient: &nsx.Client{
Cluster: &nsx.Cluster{},
},
},
LbsStore: &LBSStore{ResourceStore: common.ResourceStore{
Indexer: cache.NewIndexer(keyFunc, cache.Indexers{}),
BindingType: model.LBServiceBindingType(),
}},
}

vpc1 := model.Vpc{
DisplayName: &vpcName1,
Id: &vpcID1,
Path: ptr.To("/orgs/default/projects/project-quality/vpcs/ns-vpc-uid-1"),
}

testCases := []struct {
name string
vpc model.Vpc
prepareFuncs func() *gomonkey.Patches
wantObj string
wantErr string
}{
{
name: "Test normal case",
vpc: vpc1,
wantObj: "100.64.0.3",
prepareFuncs: func() *gomonkey.Patches {
patches := gomonkey.ApplyFunc((*realizestate.RealizeStateService).GetPolicyTier1UplinkPortIP,
func(_ *realizestate.RealizeStateService, _ string) (string, error) {
return "100.64.0.3", nil
})
return patches
},
},
{
name: "nsx lb uplink port IP not found error",
vpc: vpc1,
prepareFuncs: func() *gomonkey.Patches {
patches := gomonkey.ApplyFunc((*realizestate.RealizeStateService).GetPolicyTier1UplinkPortIP,
func(_ *realizestate.RealizeStateService, _ string) (string, error) {
return "", fmt.Errorf("fake-vpc tier1 uplink port IP not found")
})
return patches
},
wantErr: "tier1 uplink port IP not found",
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
if testCase.prepareFuncs != nil {
patches := testCase.prepareFuncs()
defer patches.Reset()
}

got, err := vpcService.GetNSXLBSNATIP(testCase.vpc)
if testCase.wantErr != "" {
assert.ErrorContains(t, err, testCase.wantErr)
} else {
require.NoError(t, err)
assert.Equal(t, testCase.wantObj, got)
}
})
}
}