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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ require (
github.com/vmware/govmomi v0.53.1
github.com/vmware/vsphere-automation-sdk-go/lib v0.8.0
github.com/vmware/vsphere-automation-sdk-go/runtime v0.8.0
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260310075027-d32fca6a7b22
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260310075027-d32fca6a7b22
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260506074423-13747423203f
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260506074423-13747423203f
go.uber.org/automaxprocs v1.6.0
go.uber.org/zap v1.27.1
golang.org/x/crypto v0.50.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,10 @@ github.com/vmware/vsphere-automation-sdk-go/lib v0.8.0 h1:u1SXOTM6D4Ygb3jeidj2Rd
github.com/vmware/vsphere-automation-sdk-go/lib v0.8.0/go.mod h1:8d5JTwjpM/Z03n/IZb0fwmXkJNWvWwuLXBqoakqYio4=
github.com/vmware/vsphere-automation-sdk-go/runtime v0.8.0 h1:KnDIX9LY0nru7iMQTg0sy9vChhyorPo5OdASM2MaAcI=
github.com/vmware/vsphere-automation-sdk-go/runtime v0.8.0/go.mod h1:DzLetYAmw1+vj7bqElRWEpuy40WYE/woL3alsymYa/c=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260310075027-d32fca6a7b22 h1:yDMJj+UG0u9aDdC0Q1byw8QEjfPd8gm7QKB2mo2oU1I=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260310075027-d32fca6a7b22/go.mod h1:C3JVOHRVLrGBQ8kTWAiGYlRz5UQC5qAcTdt3tvA+5P0=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260310075027-d32fca6a7b22 h1:SKbUc9p+LFUwtPvjk9WCwrjstN6NpewgPx4eWSIZq+k=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260310075027-d32fca6a7b22/go.mod h1:ugk9I4YM62SSAox57l5NAVBCRIkPQ1RNLb3URxyTADc=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260506074423-13747423203f h1:HvbZGTOUm9rJDG7ngNQSd5UC5ikiZI/M3cUai8u5+Jg=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260506074423-13747423203f/go.mod h1:C3JVOHRVLrGBQ8kTWAiGYlRz5UQC5qAcTdt3tvA+5P0=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260506074423-13747423203f h1:dzC9XLdl0fdqZB/K97m/NMY9o/voA2Qa4shHRnK900Q=
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260506074423-13747423203f/go.mod h1:fDH7JI080OD5t6TGwjJx3mMX/g6W7t6Radlome6hze8=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down
46 changes: 34 additions & 12 deletions pkg/nsx/services/ipblocksinfo/ipblocksinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,11 @@ func (s *IPBlocksInfoService) ResetPeriodicSync() {
}

// mergeIPCidrs merges target CIDRs into source CIDRs if not already covered by source.
// Only considers IPv4, assumes no overlaps and all CIDRs are valid.
// Assume there were no duplicate cidr in target,
// None of the elements in target will be a subset of another element
// consider using radix tree or sort + binary search for large scale
// Supports both IPv4 and IPv6 CIDRs. IPv4 and IPv6 CIDRs are treated as disjoint address
// spaces and will never be considered to cover each other.
// Assumes no overlaps within source and all CIDRs are valid.
// Assumes there are no duplicate CIDRs in target, and no element in target is a subset of another.
// Consider using a radix tree or sort + binary search for large-scale inputs.
func (s *IPBlocksInfoService) mergeIPCidrs(source []string, target []string) []string {
if len(source) == 0 {
return target
Expand Down Expand Up @@ -258,14 +259,30 @@ func (s *IPBlocksInfoService) getSharedSubnetsCIDRs(vpcConfigList []v1alpha1.VPC
continue
}

switch *subnet.AccessMode {
case model.VpcSubnet_ACCESS_MODE_PUBLIC:
externalIPCIDRs = append(externalIPCIDRs, subnet.IpAddresses...)

case model.VpcSubnet_ACCESS_MODE_PRIVATE_TGW:
project := fmt.Sprintf("/orgs/%s/projects/%s", vpcInfo.OrgID, vpcInfo.ProjectID)
if project == s.defaultProject {
privateTGWIPCIDRs = append(privateTGWIPCIDRs, subnet.IpAddresses...)
for _, cidr := range subnet.IpAddresses {
ip, _, parseErr := net.ParseCIDR(cidr)
if parseErr != nil {
log.Warn("failed to parse subnet CIDR", "cidr", cidr, "err", parseErr)
continue
}
if ip.To4() == nil {
// IPv6 CIDRs are always public with no access mode
externalIPCIDRs = append(externalIPCIDRs, cidr)
continue
}
// IPv4: apply access mode check
Comment thread
wenqiq marked this conversation as resolved.
accessMode := model.VpcSubnet_ACCESS_MODE_PUBLIC
if subnet.AccessMode != nil {
accessMode = *subnet.AccessMode
}
switch accessMode {
case model.VpcSubnet_ACCESS_MODE_PUBLIC:
externalIPCIDRs = append(externalIPCIDRs, cidr)
case model.VpcSubnet_ACCESS_MODE_PRIVATE_TGW:
project := fmt.Sprintf("/orgs/%s/projects/%s", vpcInfo.OrgID, vpcInfo.ProjectID)
if project == s.defaultProject {
privateTGWIPCIDRs = append(privateTGWIPCIDRs, cidr)
}
}
}
}
Expand Down Expand Up @@ -370,6 +387,11 @@ func (s *IPBlocksInfoService) getIPBlockCIDRsByVPCConfig(vpcConfigList []v1alpha
for _, externalIPBlock := range vpcConnectivityProfile.ExternalIpBlocks {
externalIPBlockPaths.Insert(externalIPBlock)
}
// Ipv6Blocks are external-visibility IPv6 blocks; merge them into the external set so their
// CIDRs/ranges appear in ExternalIPCIDRs/ExternalIPRanges without any CRD schema change.
for _, ipv6Block := range vpcConnectivityProfile.Ipv6Blocks {
externalIPBlockPaths.Insert(ipv6Block)
}
// save private_tgw_ip_blocks path in set for profile associated with default project
if isDefault {
for _, privateTgwIpBlocks := range vpcConnectivityProfile.PrivateTgwIpBlocks {
Expand Down
247 changes: 246 additions & 1 deletion pkg/nsx/services/ipblocksinfo/ipblocksinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ var (
ipBlocksPath2 = "/infra/ip-blocks/ipblock2"
ipBlocksPath3 = "/infra/ip-blocks/ipblock3"
ipBlocksPath4 = "/infra/ip-blocks/ipblock4"
ipBlocksPath5 = "/infra/ip-blocks/ipblock5"

ipBlocksMap = map[string]string{
ipBlocksPath1: "192.168.0.0/16",
ipBlocksPath2: "10.172.0.0/16",
ipBlocksPath3: "10.173.0.0/16",
ipBlocksPath4: "2002::1234:abcd:ffff:c0a8:101/64",
ipBlocksPath5: "2001:db8::/32",
}
vpcConnectivityProfilePath1 = "/orgs/default/projects/default/vpc-connectivity-profiles/vpc-connectivity-profile-1"
vpcConnectivityProfilePath2 = "/orgs/default/projects/default/vpc-connectivity-profiles/vpc-connectivity-profile-2"
Expand Down Expand Up @@ -79,6 +81,7 @@ func fakeSearchResource(_ *common.Service, resourceTypeValue string, _ string, s
Path: &vpcConnectivityProfilePath1,
ExternalIpBlocks: []string{ipBlocksPath1},
PrivateTgwIpBlocks: []string{ipBlocksPath2},
Ipv6Blocks: []string{ipBlocksPath5},
}
vpcConnectivityProfile2 := &model.VpcConnectivityProfile{
Path: &vpcConnectivityProfilePath2,
Expand Down Expand Up @@ -121,7 +124,8 @@ func TestIPBlocksInfoService_UpdateIPBlocksInfo(t *testing.T) {
mockK8sClient.EXPECT().Update(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
actualUpdated, ok := obj.(*v1alpha1.IPBlocksInfo)
assert.True(t, ok, "expected *v1alpha1.IPBlocksInfo when updating CR, got %T")
assert.True(t, util.CompareArraysWithoutOrder(actualUpdated.ExternalIPCIDRs, []string{ipBlocksMap[ipBlocksPath4], ipBlocksMap[ipBlocksPath1]}))
// IPv6 CIDRs from Ipv6Blocks (ipBlocksPath5) are merged into ExternalIPCIDRs alongside IPv4 externals
assert.True(t, util.CompareArraysWithoutOrder(actualUpdated.ExternalIPCIDRs, []string{ipBlocksMap[ipBlocksPath4], ipBlocksMap[ipBlocksPath1], ipBlocksMap[ipBlocksPath5]}))
assert.Equal(t, actualUpdated.PrivateTGWIPCIDRs, []string{ipBlocksMap[ipBlocksPath2]})
return nil
})
Expand Down Expand Up @@ -295,6 +299,54 @@ func TestIPBlocksInfoService_mergeIPCidrs(t *testing.T) {
target: []string{"10.0.0.1", "192.168.1.0/-1"},
expected: []string{"10.0.0.0/8"},
},
// IPv6 cases
{
name: "IPv6: target is subnet of source, should not add",
source: []string{"2001:db8::/32"},
target: []string{"2001:db8:1::/48"},
expected: []string{"2001:db8::/32"},
},
{
name: "IPv6: target is not covered by source, should add",
source: []string{"2001:db8::/32"},
target: []string{"2001:db9::/32"},
expected: []string{"2001:db8::/32", "2001:db9::/32"},
},
{
name: "IPv6: identical CIDRs in source and target, no duplicates",
source: []string{"2001:db8::/32"},
target: []string{"2001:db8::/32"},
expected: []string{"2001:db8::/32"},
},
{
name: "IPv6: empty source, all targets added",
source: []string{},
target: []string{"2001:db8::/32", "2001:db9::/32"},
expected: []string{"2001:db8::/32", "2001:db9::/32"},
},
{
name: "mixed IPv4 and IPv6: IPv6 source does not block IPv4 target",
source: []string{"2001:db8::/32"},
target: []string{"192.168.0.0/16"},
expected: []string{"2001:db8::/32", "192.168.0.0/16"},
},
{
name: "mixed IPv4 and IPv6: IPv4 source does not block IPv6 target",
source: []string{"192.168.0.0/16"},
target: []string{"2001:db8::/32"},
expected: []string{"192.168.0.0/16", "2001:db8::/32"},
},
{
name: "mixed IPv4 and IPv6: source has both families, correctly covers subnets",
source: []string{"192.168.0.0/16", "2001:db8::/32"},
target: []string{
"192.168.1.0/24", // subset of IPv4 source
"2001:db8:1::/48", // subset of IPv6 source
"10.0.0.0/8", // new IPv4
"2001:db9::/32", // new IPv6
},
expected: []string{"192.168.0.0/16", "2001:db8::/32", "10.0.0.0/8", "2001:db9::/32"},
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -496,6 +548,76 @@ func TestIPBlocksInfoService_getCIDRsRangesFromStore(t *testing.T) {
ipBlockStore.Delete("block2")
ipBlockStore.Delete("block3")
ipBlockStore.Delete("block4")

// Case: IPv6 CIDR in external IPBlock
addBlock("ipv6-ext", nil, []string{"2001:db8::/32"}, nil)
pathSet = sets.New[string]()
pathSet.Insert("ipv6-ext")
extCIDRs, privCIDRs, extRanges, privRanges, err = service.getCIDRsRangesFromStore(pathSet, sets.New[string](), ipBlockStore)
assert.NoError(t, err)
assert.Equal(t, []string{"2001:db8::/32"}, extCIDRs)
assert.Empty(t, privCIDRs)
assert.Empty(t, extRanges)
assert.Empty(t, privRanges)
ipBlockStore.Delete("ipv6-ext")

// Case: IPv6 range in external IPBlock
addBlock("ipv6-range-ext", nil, nil, []model.IpPoolRange{
{Start: stringPtr("2001:db8::1"), End: stringPtr("2001:db8::ff")},
})
pathSet = sets.New[string]()
pathSet.Insert("ipv6-range-ext")
extCIDRs, privCIDRs, extRanges, privRanges, err = service.getCIDRsRangesFromStore(pathSet, sets.New[string](), ipBlockStore)
assert.NoError(t, err)
assert.Empty(t, extCIDRs)
assert.Empty(t, privCIDRs)
assert.Equal(t, []v1alpha1.IPPoolRange{{Start: "2001:db8::1", End: "2001:db8::ff"}}, extRanges)
assert.Empty(t, privRanges)
ipBlockStore.Delete("ipv6-range-ext")

// Case: IPv6 CIDR in privateTGW IPBlock
addBlock("ipv6-priv", nil, []string{"fd00::/48"}, nil)
privSet = sets.New[string]()
privSet.Insert("ipv6-priv")
extCIDRs, privCIDRs, extRanges, privRanges, err = service.getCIDRsRangesFromStore(sets.New[string](), privSet, ipBlockStore)
assert.NoError(t, err)
assert.Empty(t, extCIDRs)
assert.Equal(t, []string{"fd00::/48"}, privCIDRs)
assert.Empty(t, extRanges)
assert.Empty(t, privRanges)
ipBlockStore.Delete("ipv6-priv")

// Case: mixed IPv4 and IPv6 CIDRs in the same IPBlock
addBlock("mixed", nil, []string{"192.168.0.0/16", "2001:db8::/32"}, []model.IpPoolRange{
{Start: stringPtr("10.0.0.1"), End: stringPtr("10.0.0.10")},
{Start: stringPtr("2001:db8::1"), End: stringPtr("2001:db8::ff")},
})
pathSet = sets.New[string]()
pathSet.Insert("mixed")
extCIDRs, privCIDRs, extRanges, privRanges, err = service.getCIDRsRangesFromStore(pathSet, sets.New[string](), ipBlockStore)
assert.NoError(t, err)
assert.True(t, util.CompareArraysWithoutOrder([]string{"192.168.0.0/16", "2001:db8::/32"}, extCIDRs))
assert.Empty(t, privCIDRs)
assert.True(t, util.CompareArraysWithoutOrder([]v1alpha1.IPPoolRange{
{Start: "10.0.0.1", End: "10.0.0.10"},
{Start: "2001:db8::1", End: "2001:db8::ff"},
}, extRanges))
assert.Empty(t, privRanges)
ipBlockStore.Delete("mixed")

// Case: Ipv6Blocks paths in externalIPBlockPaths (IPv6 from VpcConnectivityProfile.Ipv6Blocks)
addBlock("ipv6-block", nil, []string{"2001:db8::/32"}, []model.IpPoolRange{
{Start: stringPtr("2001:db8::1"), End: stringPtr("2001:db8::ff")},
})
ipv6AsExtSet := sets.New[string]()
ipv6AsExtSet.Insert("ipv6-block")
extCIDRs, privCIDRs, extRanges, privRanges, err = service.getCIDRsRangesFromStore(ipv6AsExtSet, sets.New[string](), ipBlockStore)
assert.NoError(t, err)
assert.Equal(t, []string{"2001:db8::/32"}, extCIDRs)
assert.Empty(t, privCIDRs)
assert.Equal(t, []v1alpha1.IPPoolRange{{Start: "2001:db8::1", End: "2001:db8::ff"}}, extRanges)
assert.Empty(t, privRanges)
ipBlockStore.Delete("ipv6-block")
}

func TestIPBlocksInfoService_getSharedSubnetsCIDRs(t *testing.T) {
Expand Down Expand Up @@ -580,6 +702,129 @@ func TestIPBlocksInfoService_getSharedSubnetsCIDRs(t *testing.T) {
assert.Empty(t, external)
assert.Empty(t, private)

// Test: dual-stack subnet with both IPv4 and IPv6 addresses (Public access mode)
dualStackSubnetPath := "/orgs/default/projects/default/vpcs/vpc1/vpc-subnets/dualstack-subnet"
getSubnetPatch.Reset()
getSubnetPatch = gomonkey.ApplyMethod(reflect.TypeOf(service.subnetService), "GetNSXSubnetFromCacheOrAPI", func(_ *subnet.SubnetService, associate string, forceAPI bool) (*model.VpcSubnet, error) {
public := "Public"
return &model.VpcSubnet{
Path: &dualStackSubnetPath,
AccessMode: &public,
IpAddresses: []string{"192.168.20.0/24", "2001:db8::/48"},
}, nil
})
vpcConfigList = []v1alpha1.VPCNetworkConfiguration{
{
Spec: v1alpha1.VPCNetworkConfigurationSpec{
Subnets: []v1alpha1.SharedSubnet{{
Path: dualStackSubnetPath,
}},
},
},
}
external, private, err = service.getSharedSubnetsCIDRs(vpcConfigList)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"192.168.20.0/24", "2001:db8::/48"}, external)
assert.Empty(t, private)

// Test: dual-stack Private_TGW subnet – IPv6 always goes to external, only IPv4 respects access mode
dualStackPrivateTgwPath := "/orgs/default/projects/default/vpcs/vpc1/vpc-subnets/dualstack-private-tgw"
getSubnetPatch.Reset()
getSubnetPatch = gomonkey.ApplyMethod(reflect.TypeOf(service.subnetService), "GetNSXSubnetFromCacheOrAPI", func(_ *subnet.SubnetService, associate string, forceAPI bool) (*model.VpcSubnet, error) {
privateTgw := "Private_TGW"
return &model.VpcSubnet{
Path: &dualStackPrivateTgwPath,
AccessMode: &privateTgw,
IpAddresses: []string{"10.20.0.0/16", "fd00::/48"},
}, nil
})
vpcConfigList = []v1alpha1.VPCNetworkConfiguration{
{
Spec: v1alpha1.VPCNetworkConfigurationSpec{
Subnets: []v1alpha1.SharedSubnet{{
Path: dualStackPrivateTgwPath,
}},
},
},
}
external, private, err = service.getSharedSubnetsCIDRs(vpcConfigList)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"fd00::/48"}, external)
assert.ElementsMatch(t, []string{"10.20.0.0/16"}, private)

// Test: IPv6-only Private_TGW subnet – all CIDRs go to external (no access mode applied to IPv6)
ipv6OnlyPrivateTgwPath := "/orgs/default/projects/default/vpcs/vpc1/vpc-subnets/ipv6-only-private-tgw"
getSubnetPatch.Reset()
getSubnetPatch = gomonkey.ApplyMethod(reflect.TypeOf(service.subnetService), "GetNSXSubnetFromCacheOrAPI", func(_ *subnet.SubnetService, associate string, forceAPI bool) (*model.VpcSubnet, error) {
privateTgw := "Private_TGW"
return &model.VpcSubnet{
Path: &ipv6OnlyPrivateTgwPath,
AccessMode: &privateTgw,
IpAddresses: []string{"2001:db8::/32", "fd00::/48"},
}, nil
})
vpcConfigList = []v1alpha1.VPCNetworkConfiguration{
{
Spec: v1alpha1.VPCNetworkConfigurationSpec{
Subnets: []v1alpha1.SharedSubnet{{
Path: ipv6OnlyPrivateTgwPath,
}},
},
},
}
external, private, err = service.getSharedSubnetsCIDRs(vpcConfigList)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"2001:db8::/32", "fd00::/48"}, external)
assert.Empty(t, private)

// Test: subnet with an invalid CIDR entry – invalid entries are skipped, valid ones processed
invalidCIDRSubnetPath := "/orgs/default/projects/default/vpcs/vpc1/vpc-subnets/invalid-cidr-subnet"
getSubnetPatch.Reset()
getSubnetPatch = gomonkey.ApplyMethod(reflect.TypeOf(service.subnetService), "GetNSXSubnetFromCacheOrAPI", func(_ *subnet.SubnetService, associate string, forceAPI bool) (*model.VpcSubnet, error) {
public := "Public"
return &model.VpcSubnet{
Path: &invalidCIDRSubnetPath,
AccessMode: &public,
IpAddresses: []string{"not-a-cidr", "10.30.0.0/24", "2001:db8:1::/48"},
}, nil
})
vpcConfigList = []v1alpha1.VPCNetworkConfiguration{
{
Spec: v1alpha1.VPCNetworkConfigurationSpec{
Subnets: []v1alpha1.SharedSubnet{{
Path: invalidCIDRSubnetPath,
}},
},
},
}
external, private, err = service.getSharedSubnetsCIDRs(vpcConfigList)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"10.30.0.0/24", "2001:db8:1::/48"}, external)
assert.Empty(t, private)

// Test: nil AccessMode defaults to Public for IPv4 (consistent with MapNSXSubnetToSubnetCR)
nilAccessModeSubnetPath := "/orgs/default/projects/default/vpcs/vpc1/vpc-subnets/nil-access-mode"
getSubnetPatch.Reset()
getSubnetPatch = gomonkey.ApplyMethod(reflect.TypeOf(service.subnetService), "GetNSXSubnetFromCacheOrAPI", func(_ *subnet.SubnetService, associate string, forceAPI bool) (*model.VpcSubnet, error) {
return &model.VpcSubnet{
Path: &nilAccessModeSubnetPath,
IpAddresses: []string{"172.16.0.0/16"},
}, nil
})
vpcConfigList = []v1alpha1.VPCNetworkConfiguration{
{
Spec: v1alpha1.VPCNetworkConfigurationSpec{
Subnets: []v1alpha1.SharedSubnet{{
Path: nilAccessModeSubnetPath,
}},
},
},
}
external, private, err = service.getSharedSubnetsCIDRs(vpcConfigList)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"172.16.0.0/16"}, external)
assert.Empty(t, private)

// Test: SearchResource returns error
getSubnetPatch.Reset()
getSubnetPatch = gomonkey.ApplyMethod(reflect.TypeOf(service.subnetService), "GetNSXSubnetFromCacheOrAPI", func(_ *subnet.SubnetService, associate string, forceAPI bool) (*model.VpcSubnet, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/nsx/services/nsxserviceaccount/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (s *NSXServiceAccountService) RestoreRealizedNSXServiceAccount(ctx context.
detail := true
if piObj != nil {
pi = piObj.(*mpmodel.PrincipalIdentity)
certificate, _ = s.NSXClient.CertificatesClient.Get(*(pi.CertificateId), &detail)
certificate, _ = s.NSXClient.CertificatesClient.Get(*(pi.CertificateId), &detail, nil)
}
// read Secret
secretName := obj.Status.Secrets[0].Name
Expand Down
Loading
Loading