Skip to content

Commit 3499a03

Browse files
authored
Support ExternalIPBlocksConfigured check for IPv6 (#1440)
ExternalIPBlocksConfigured should be checked based on Supervisor IPFamily. - For IPv4, checks ExternalIpBlocks - For IPv6, checks Ipv6Blocks - For dualstack, checks both ExternalIpBlocks and Ipv6Blocks Signed-off-by: Yanjun Zhou <yanjun.zhou@broadcom.com>
1 parent e07ae39 commit 3499a03

2 files changed

Lines changed: 120 additions & 86 deletions

File tree

pkg/controllers/networkinfo/networkinfo_controller.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,14 @@ func (r *NetworkInfoReconciler) Reconcile(ctx context.Context, req ctrl.Request)
358358

359359
// Check external IP blocks on system VPC network config.
360360
if ncName == commonservice.SystemVPCNetworkConfigurationName {
361-
hasExternalIPs := len(vpcConnectivityProfile.ExternalIpBlocks) > 0
361+
ipFamily := r.Service.NSXConfig.K8sConfig.GetIPAddressType()
362+
hasExternalIPs := true
363+
if util.IPAddressTypeIncludesIPv4(ipFamily) {
364+
hasExternalIPs = len(vpcConnectivityProfile.ExternalIpBlocks) > 0
365+
}
366+
if util.IPAddressTypeIncludesIPv6(ipFamily) {
367+
hasExternalIPs = hasExternalIPs && len(vpcConnectivityProfile.Ipv6Blocks) > 0
368+
}
362369
setVPCNetworkConfigurationStatusWithNoExternalIPBlock(ctx, r.Client, systemVpcNetCfg, hasExternalIPs)
363370
if !hasExternalIPs && !retryWithSystemVPC {
364371
log.Error(err, "There is no ExternalIPBlock in VPC ConnectivityProfile", "NetworkInfo", req.NamespacedName)

pkg/controllers/networkinfo/networkinfo_controller_test.go

Lines changed: 112 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -781,91 +781,6 @@ func TestNetworkInfoReconciler_Reconcile(t *testing.T) {
781781
want: common.ResultNormal,
782782
wantErr: false,
783783
},
784-
{
785-
name: "VPCNetworkConfigurationStatusWithNoExternalIPBlockInSystemVPC",
786-
prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) {
787-
assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{
788-
ObjectMeta: metav1.ObjectMeta{
789-
Namespace: requestArgs.req.Namespace,
790-
Name: requestArgs.req.Name,
791-
},
792-
}))
793-
assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{
794-
ObjectMeta: metav1.ObjectMeta{
795-
Name: "system",
796-
},
797-
}))
798-
patches = gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, ctx context.Context, _ string) (string, error) {
799-
return servicecommon.SystemVPCNetworkConfigurationName, nil
800-
})
801-
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (*v1alpha1.VPCNetworkConfiguration, bool, error) {
802-
return &v1alpha1.VPCNetworkConfiguration{
803-
ObjectMeta: metav1.ObjectMeta{Name: servicecommon.SystemVPCNetworkConfigurationName},
804-
Spec: v1alpha1.VPCNetworkConfigurationSpec{
805-
VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default",
806-
NSXProject: "/orgs/default/projects/project-quality",
807-
},
808-
}, true, nil
809-
})
810-
patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateConnectionStatus", func(_ *vpc.VPCService, _ *v1alpha1.VPCNetworkConfiguration, _ string) (*servicecommon.VPCConnectionStatus, error) {
811-
return &servicecommon.VPCConnectionStatus{
812-
GatewayConnectionReady: true,
813-
ServiceClusterReady: false,
814-
ServiceClusterReason: servicecommon.ReasonServiceClusterNotSet,
815-
}, nil
816-
})
817-
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetLBProvider", func(_ *vpc.VPCService) (vpc.LBProvider, error) {
818-
return vpc.NSXLB, nil
819-
})
820-
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSNATIP", func(_ *vpc.VPCService, _ model.Vpc, _ string) ([]string, error) {
821-
return []string{"100.64.0.3"}, nil
822-
})
823-
patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, ctx context.Context, _ *v1alpha1.NetworkInfo, _ *v1alpha1.VPCNetworkConfiguration, _ vpc.LBProvider) (*model.Vpc, error) {
824-
return &model.Vpc{
825-
DisplayName: servicecommon.String("vpc-name"),
826-
Path: servicecommon.String("/orgs/default/projects/project-quality/vpcs/fake-vpc"),
827-
Id: servicecommon.String("vpc-id"),
828-
}, nil
829-
})
830-
patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, ctx context.Context, _ string) (bool, error) {
831-
return false, nil
832-
})
833-
patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{
834-
Values: gomonkey.Params{model.VpcConnectivityProfile{
835-
ServiceGateway: nil,
836-
}, nil},
837-
Times: 1,
838-
}})
839-
patches.ApplyFunc(setVPCNetworkConfigurationStatusWithNoExternalIPBlock,
840-
func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, _ bool) {
841-
t.Log("setVPCNetworkConfigurationStatusWithNoExternalIPBlock")
842-
})
843-
844-
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultNSXLBSPathByVPC", func(_ *vpc.VPCService, _ string) string {
845-
return "lbs-path"
846-
})
847-
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultSNATIP", func(_ *vpc.VPCService, _ model.Vpc) (string, error) {
848-
return "snat-ip", nil
849-
})
850-
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkStackFromNC", func(_ *vpc.VPCService, _ *v1alpha1.VPCNetworkConfiguration) (v1alpha1.NetworkStackType, error) {
851-
return v1alpha1.FullStackVPC, nil
852-
})
853-
patches.ApplyFunc(setVPCNetworkConfigurationStatusWithSnatEnabled,
854-
func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) {
855-
if autoSnatEnabled {
856-
assert.FailNow(t, "should set VPCNetworkConfiguration status with AutoSnatEnabled=false")
857-
}
858-
})
859-
patches.ApplyFunc(setNSNetworkReadyCondition,
860-
func(ctx context.Context, client client.Client, nsName string, condition *corev1.NamespaceCondition) {
861-
require.True(t, nsConditionEquals(*condition, *nsMsgVPCNoExternalIPBlock.getNSNetworkCondition()))
862-
})
863-
return patches
864-
},
865-
args: requestArgs,
866-
want: common.ResultRequeueAfter60sec,
867-
wantErr: false,
868-
},
869784
{
870785
name: "Pre-create VPC success case with AVILB",
871786
prepareFunc: func(t *testing.T, r *NetworkInfoReconciler, ctx context.Context) (patches *gomonkey.Patches) {
@@ -1317,6 +1232,118 @@ func TestNetworkInfoReconciler_Reconcile(t *testing.T) {
13171232
})
13181233
}
13191234
}
1235+
func TestNetworkInfoReconciler_Reconcile_ExternalIPBlockInSystemVPC(t *testing.T) {
1236+
req := controllerruntime.Request{
1237+
NamespacedName: types.NamespacedName{Namespace: "ns1", Name: "name"},
1238+
}
1239+
1240+
tests := []struct {
1241+
nameSuffix string
1242+
ipType v1alpha1.IPAddressType
1243+
}{
1244+
{nameSuffix: "IPv4", ipType: v1alpha1.IPAddressTypeIPv4},
1245+
{nameSuffix: "IPv6", ipType: v1alpha1.IPAddressTypeIPv6},
1246+
{nameSuffix: "IPv4IPv6", ipType: v1alpha1.IPAddressTypeIPv4IPv6},
1247+
}
1248+
1249+
for _, tt := range tests {
1250+
t.Run("VPCNetworkConfigurationStatusWithNoExternalIPBlockInSystemVPC_"+tt.nameSuffix, func(t *testing.T) {
1251+
ns1 := &corev1.Namespace{
1252+
ObjectMeta: metav1.ObjectMeta{Name: "ns1"},
1253+
}
1254+
r := createNetworkInfoReconciler([]client.Object{ns1})
1255+
v1alpha1.AddToScheme(r.Scheme)
1256+
ctx := context.TODO()
1257+
1258+
assert.NoError(t, r.Client.Create(ctx, &v1alpha1.NetworkInfo{
1259+
ObjectMeta: metav1.ObjectMeta{Namespace: req.Namespace, Name: req.Name},
1260+
}))
1261+
assert.NoError(t, r.Client.Create(ctx, &v1alpha1.VPCNetworkConfiguration{
1262+
ObjectMeta: metav1.ObjectMeta{Name: "system"},
1263+
}))
1264+
1265+
patches := gomonkey.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkconfigNameFromNS", func(_ *vpc.VPCService, _ context.Context, _ string) (string, error) {
1266+
return servicecommon.SystemVPCNetworkConfigurationName, nil
1267+
})
1268+
defer patches.Reset()
1269+
1270+
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetVPCNetworkConfig", func(_ *vpc.VPCService, _ string) (*v1alpha1.VPCNetworkConfiguration, bool, error) {
1271+
return &v1alpha1.VPCNetworkConfiguration{
1272+
ObjectMeta: metav1.ObjectMeta{Name: servicecommon.SystemVPCNetworkConfigurationName},
1273+
Spec: v1alpha1.VPCNetworkConfigurationSpec{
1274+
VPCConnectivityProfile: "/orgs/default/projects/nsx_operator_e2e_test/vpc-connectivity-profiles/default",
1275+
NSXProject: "/orgs/default/projects/project-quality",
1276+
},
1277+
}, true, nil
1278+
})
1279+
1280+
patches.ApplyMethod(reflect.TypeOf(r.Service), "ValidateConnectionStatus", func(_ *vpc.VPCService, _ *v1alpha1.VPCNetworkConfiguration, _ string) (*servicecommon.VPCConnectionStatus, error) {
1281+
return &servicecommon.VPCConnectionStatus{GatewayConnectionReady: true}, nil
1282+
})
1283+
1284+
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetLBProvider", func(_ *vpc.VPCService) (vpc.LBProvider, error) {
1285+
return vpc.NSXLB, nil
1286+
})
1287+
1288+
// Dynamically mock the SNAT IP based on the IP format variation
1289+
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNSXLBSNATIP", func(_ *vpc.VPCService, _ model.Vpc, _ string) ([]string, error) {
1290+
if tt.ipType == v1alpha1.IPAddressTypeIPv6 {
1291+
return []string{"2001::1"}, nil
1292+
}
1293+
return []string{"100.64.0.3"}, nil
1294+
})
1295+
1296+
patches.ApplyMethod(reflect.TypeOf(r.Service), "CreateOrUpdateVPC", func(_ *vpc.VPCService, _ context.Context, _ *v1alpha1.NetworkInfo, _ *v1alpha1.VPCNetworkConfiguration, _ vpc.LBProvider) (*model.Vpc, error) {
1297+
return &model.Vpc{DisplayName: servicecommon.String("vpc-name"), Path: servicecommon.String("path"), Id: servicecommon.String("vpc-id")}, nil
1298+
})
1299+
1300+
patches.ApplyMethod(reflect.TypeOf(r.Service), "IsSharedVPCNamespaceByNS", func(_ *vpc.VPCService, _ context.Context, _ string) (bool, error) {
1301+
return false, nil
1302+
})
1303+
1304+
// Dynamically mock the cluster IP address layout structure configuration block
1305+
patches.ApplyMethod(reflect.TypeOf(&config.K8sConfig{}), "GetIPAddressType", func(_ *config.K8sConfig) v1alpha1.IPAddressType {
1306+
return tt.ipType
1307+
})
1308+
1309+
patches.ApplyMethodSeq(reflect.TypeOf(r.Service.Service.NSXClient.VPCConnectivityProfilesClient), "Get", []gomonkey.OutputCell{{
1310+
Values: gomonkey.Params{model.VpcConnectivityProfile{ServiceGateway: nil}, nil},
1311+
Times: 1,
1312+
}})
1313+
1314+
patches.ApplyFunc(setVPCNetworkConfigurationStatusWithNoExternalIPBlock, func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, _ bool) {
1315+
t.Log("setVPCNetworkConfigurationStatusWithNoExternalIPBlock called")
1316+
})
1317+
1318+
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetDefaultNSXLBSPathByVPC", func(_ *vpc.VPCService, _ string) string {
1319+
return "lbs-path"
1320+
})
1321+
1322+
patches.ApplyMethod(reflect.TypeOf(r.Service), "GetNetworkStackFromNC", func(_ *vpc.VPCService, _ *v1alpha1.VPCNetworkConfiguration) (v1alpha1.NetworkStackType, error) {
1323+
return v1alpha1.FullStackVPC, nil
1324+
})
1325+
1326+
patches.ApplyFunc(setVPCNetworkConfigurationStatusWithSnatEnabled, func(_ context.Context, _ client.Client, _ *v1alpha1.VPCNetworkConfiguration, autoSnatEnabled bool) {
1327+
if autoSnatEnabled {
1328+
assert.FailNow(t, "should set VPCNetworkConfiguration status with AutoSnatEnabled=false")
1329+
}
1330+
})
1331+
1332+
patches.ApplyFunc(setNSNetworkReadyCondition, func(_ context.Context, _ client.Client, _ string, condition *corev1.NamespaceCondition) {
1333+
require.True(t, nsConditionEquals(*condition, *nsMsgVPCNoExternalIPBlock.getNSNetworkCondition()))
1334+
})
1335+
1336+
got, err := r.Reconcile(ctx, req)
1337+
if err != nil {
1338+
t.Errorf("Reconcile() error = %v, wantErr false", err)
1339+
return
1340+
}
1341+
if !reflect.DeepEqual(got, common.ResultRequeueAfter60sec) {
1342+
t.Errorf("Reconcile() got = %v, want %v", got, common.ResultRequeueAfter60sec)
1343+
}
1344+
})
1345+
}
1346+
}
13201347

13211348
func TestNetworkInfoReconciler_deleteStaleVPCs(t *testing.T) {
13221349
testCases := []struct {

0 commit comments

Comments
 (0)