Skip to content

Commit c7f4b82

Browse files
zhengxiexieoz-agent
andcommitted
Fix IsDefaultNSXProject always returning false after SDK field rename
Use Cluster.HttpGet to read the "default" field directly from the NSX REST API JSON response, bypassing the SDK struct deserialization which cannot populate the unexported model.Project._Default field. Co-Authored-By: Oz <oz-agent@warp.dev> Change-Id: I79cfd117c95abe17ef7032525e69cd1695e8822e
1 parent 4ba0355 commit c7f4b82

File tree

2 files changed

+54
-80
lines changed

2 files changed

+54
-80
lines changed

pkg/nsx/services/vpc/vpc.go

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"reflect"
87
"strings"
98
"sync"
10-
"unsafe"
119

1210
stderrors "github.com/vmware/vsphere-automation-sdk-go/lib/vapi/std/errors"
1311
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
@@ -54,8 +52,9 @@ var (
5452

5553
type VPCService struct {
5654
common.Service
57-
VpcStore *VPCStore
58-
LbsStore *LBSStore
55+
VpcStore *VPCStore
56+
LbsStore *LBSStore
57+
defaultProjectCache sync.Map // cache for IsDefaultNSXProject results, key: "orgID/projectID", value: bool
5958
}
6059

6160
func (s *VPCService) GetDefaultNetworkConfig() (*v1alpha1.VPCNetworkConfiguration, error) {
@@ -1168,27 +1167,29 @@ func IsPreCreatedVPC(nc *v1alpha1.VPCNetworkConfiguration) bool {
11681167
return nc.Spec.VPC != ""
11691168
}
11701169

1171-
func getProjectDefault(p *model.Project) *bool {
1172-
v := reflect.ValueOf(p).Elem()
1173-
f := v.FieldByName("_Default")
1174-
if !f.IsValid() {
1175-
return nil
1170+
// IsDefaultNSXProject checks if the given project is an NSX default project.
1171+
// It queries the NSX Policy API directly and reads the "default" field from the
1172+
// JSON response, bypassing the Go SDK struct deserialization which cannot populate
1173+
// the unexported model.Project._Default field (CanSet=false for unexported fields).
1174+
// Results are cached since a project's default status does not change at runtime.
1175+
func (s *VPCService) IsDefaultNSXProject(orgID, projectID string) (bool, error) {
1176+
cacheKey := orgID + "/" + projectID
1177+
if val, ok := s.defaultProjectCache.Load(cacheKey); ok {
1178+
return val.(bool), nil
11761179
}
11771180

1178-
ptr := unsafe.Pointer(f.UnsafeAddr())
1179-
return *(**bool)(ptr) // read *bool safely
1180-
}
1181-
1182-
// IsDefaultNSXProject checks if the given project is a default project
1183-
func (s *VPCService) IsDefaultNSXProject(orgID, projectID string) (bool, error) {
1184-
proj, err := s.NSXClient.ProjectClient.Get(orgID, projectID, nil)
1181+
url := fmt.Sprintf("policy/api/v1/orgs/%s/projects/%s", orgID, projectID)
1182+
resp, err := s.NSXClient.Cluster.HttpGet(url)
11851183
if err != nil {
1186-
log.Error(err, "Failed to get project", "ProjectID", projectID)
1184+
log.Error(err, "Failed to get project from NSX", "OrgID", orgID, "ProjectID", projectID)
11871185
return false, err
11881186
}
1189-
defaultVal := getProjectDefault(&proj)
1190-
if defaultVal != nil && *defaultVal {
1191-
return true, nil
1187+
isDefault := false
1188+
if defaultVal, ok := resp["default"]; ok {
1189+
if boolVal, ok := defaultVal.(bool); ok {
1190+
isDefault = boolVal
1191+
}
11921192
}
1193-
return false, nil
1193+
s.defaultProjectCache.Store(cacheKey, isDefault)
1194+
return isDefault, nil
11941195
}

pkg/nsx/services/vpc/vpc_test.go

Lines changed: 32 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,13 @@ import (
77
"reflect"
88
"strings"
99
"testing"
10-
"unsafe"
1110

1211
"github.com/agiledragon/gomonkey/v2"
1312
"github.com/golang/mock/gomock"
1413
"github.com/stretchr/testify/assert"
1514
"github.com/stretchr/testify/require"
1615
"github.com/vmware/vsphere-automation-sdk-go/runtime/data"
17-
nsx_client "github.com/vmware/vsphere-automation-sdk-go/runtime/protocol/client"
1816
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
19-
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs"
2017
v1 "k8s.io/api/core/v1"
2118
k8sapierrors "k8s.io/apimachinery/pkg/api/errors"
2219
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -2921,83 +2918,59 @@ func Test_isNamespaceReady(t *testing.T) {
29212918
assert.False(t, isNamespaceReady(nsUnready))
29222919
}
29232920

2924-
func SetProjectDefault(p *model.Project, b bool) {
2925-
v := reflect.ValueOf(p).Elem()
2926-
f := v.FieldByName("_Default")
2927-
if !f.IsValid() {
2928-
return
2929-
}
2930-
2931-
val := b // bool value
2932-
ptr := unsafe.Pointer(f.UnsafeAddr())
2933-
realPtr := (*unsafe.Pointer)(ptr)
2934-
*realPtr = unsafe.Pointer(&val)
2935-
}
2936-
29372921
func TestIsDefaultNSXProject(t *testing.T) {
2938-
connector := nsx_client.NewConnector("localhost")
2939-
projectClient := orgs.NewProjectsClient(connector)
29402922
tests := []struct {
29412923
name string
29422924
orgID string
29432925
projectID string
2944-
prepareFunc func(*VPCService) *gomonkey.Patches
2926+
httpGetResp map[string]interface{}
2927+
httpGetErr error
29452928
expectedResult bool
2946-
expectedErrStr string
2929+
expectedErr bool
29472930
}{
29482931
{
2949-
name: "Project is default",
2950-
orgID: "default",
2951-
projectID: "project-1",
2952-
prepareFunc: func(service *VPCService) *gomonkey.Patches {
2953-
patches := gomonkey.ApplyMethod(reflect.TypeOf(projectClient), "Get", func(_ orgs.ProjectsClient, _ string, _ string, _ *bool) (model.Project, error) {
2954-
pro := model.Project{}
2955-
SetProjectDefault(&pro, true)
2956-
return pro, nil
2957-
})
2958-
return patches
2959-
},
2932+
name: "project is default",
2933+
orgID: "default",
2934+
projectID: "default",
2935+
httpGetResp: map[string]interface{}{"default": true, "id": "default"},
29602936
expectedResult: true,
29612937
},
29622938
{
2963-
name: "Project is not default",
2964-
orgID: "default",
2965-
projectID: "project-2",
2966-
prepareFunc: func(service *VPCService) *gomonkey.Patches {
2967-
patches := gomonkey.ApplyMethod(reflect.TypeOf(projectClient), "Get", func(_ orgs.ProjectsClient, _ string, _ string, _ *bool) (model.Project, error) {
2968-
pro := model.Project{}
2969-
return pro, nil
2970-
})
2971-
return patches
2972-
},
2939+
name: "project is not default",
2940+
orgID: "default",
2941+
projectID: "customer-project",
2942+
httpGetResp: map[string]interface{}{"default": false, "id": "customer-project"},
29732943
expectedResult: false,
29742944
},
29752945
{
2976-
name: "Get project error",
2977-
orgID: "default",
2978-
projectID: "project-3",
2979-
prepareFunc: func(service *VPCService) *gomonkey.Patches {
2980-
patches := gomonkey.ApplyMethod(reflect.TypeOf(projectClient), "Get", func(_ orgs.ProjectsClient, _ string, _ string, _ *bool) (model.Project, error) {
2981-
return model.Project{}, fmt.Errorf("failed to get project")
2982-
})
2983-
return patches
2984-
},
2985-
expectedErrStr: "failed to get project",
2946+
name: "response missing default field",
2947+
orgID: "default",
2948+
projectID: "some-project",
2949+
httpGetResp: map[string]interface{}{"id": "some-project"},
2950+
expectedResult: false,
2951+
},
2952+
{
2953+
name: "HTTP error",
2954+
orgID: "default",
2955+
projectID: "default",
2956+
httpGetErr: fmt.Errorf("connection refused"),
2957+
expectedErr: true,
29862958
},
29872959
}
29882960

29892961
for _, tt := range tests {
29902962
t.Run(tt.name, func(t *testing.T) {
29912963
service, _, _, _, _ := createService(t)
2992-
if tt.prepareFunc != nil {
2993-
patches := tt.prepareFunc(service)
2994-
defer patches.Reset()
2995-
}
2996-
service.NSXClient.ProjectClient = projectClient
2997-
result, err := service.IsDefaultNSXProject(tt.orgID, tt.projectID)
2964+
service.NSXClient.Cluster = &nsx.Cluster{}
2965+
patches := gomonkey.ApplyMethod(reflect.TypeOf(service.NSXClient.Cluster), "HttpGet",
2966+
func(_ *nsx.Cluster, _ string) (map[string]interface{}, error) {
2967+
return tt.httpGetResp, tt.httpGetErr
2968+
})
2969+
defer patches.Reset()
29982970

2999-
if tt.expectedErrStr != "" {
3000-
assert.ErrorContains(t, err, tt.expectedErrStr)
2971+
result, err := service.IsDefaultNSXProject(tt.orgID, tt.projectID)
2972+
if tt.expectedErr {
2973+
assert.Error(t, err)
30012974
} else {
30022975
assert.NoError(t, err)
30032976
assert.Equal(t, tt.expectedResult, result)

0 commit comments

Comments
 (0)