Skip to content

Commit b888c22

Browse files
authored
For RWX block volumes, for VMFS datastores, policy must be EZT (#3471)
1 parent 8a604b5 commit b888c22

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

pkg/csi/service/wcp/controller.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,17 @@ func (c *controller) createBlockVolume(ctx context.Context, req *csi.CreateVolum
505505
return nil, csifault.CSIInternalFault, logger.LogNewErrorCodef(log, codes.Internal,
506506
"failed to get vCenter from Manager. Error: %v", err)
507507
}
508+
509+
if commonco.ContainerOrchestratorUtility.IsFSSEnabled(ctx,
510+
common.SharedDiskFss) && isSharedRawBlockRequest(ctx, req.VolumeCapabilities) {
511+
log.Infof("Volume request is for shared RWX volume. Validatig if policy is compatible for VMFS datastores.")
512+
err := validateStoragePolicyForVmfs(ctx, vc, storagePolicyID)
513+
if err != nil {
514+
log.Errorf("failed validation for policy %s", storagePolicyID)
515+
return nil, csifault.CSIInternalFault, err
516+
}
517+
}
518+
508519
// Fetch the accessibility requirements from the request.
509520
topologyRequirement = req.GetAccessibilityRequirements()
510521
filterSuspendedDatastores := commonco.ContainerOrchestratorUtility.IsFSSEnabled(ctx, common.CnsMgrSuspendCreateVolume)

pkg/csi/service/wcp/controller_helper.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ import (
5050
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer/k8scloudoperator"
5151
)
5252

53+
var (
54+
vmfsNamespace = "com.vmware.storage.volumeallocation"
55+
vmfsNamespaceEztValue = "Fully initialized"
56+
)
57+
5358
// validateCreateBlockReqParam is a helper function used to validate the parameter
5459
// name received in the CreateVolume request for block volumes on WCP CSI driver.
5560
// Returns true if the parameter name is valid, false otherwise.
@@ -86,6 +91,51 @@ func validateCreateFileReqParam(paramName, value string) bool {
8691
paramName == common.AttributeIsLinkedCloneKey
8792
}
8893

94+
// verifyStoragePolicyForVmfsWithEageredZeroThick goes through each rule in the policy to
95+
// find out if it is fully intialized for VMFS datastores.
96+
// This check is required for RWX shared block volumes as for VMFS, the policy must be EZT.
97+
func verifyStoragePolicyForVmfsWithEageredZeroThick(ctx context.Context,
98+
spbmPolicyContentList []vsphere.SpbmPolicyContent,
99+
storagePolicyId string) error {
100+
log := logger.GetLogger(ctx)
101+
102+
for _, polictContent := range spbmPolicyContentList {
103+
for _, profile := range polictContent.Profiles {
104+
for _, rule := range profile.Rules {
105+
if rule.Ns == vmfsNamespace {
106+
if rule.Value != vmfsNamespaceEztValue {
107+
msg := fmt.Sprintf("Policy %s is for VMFS datastores. It must be fully initialized for "+
108+
"RWX block volumes", storagePolicyId)
109+
err := errors.New(msg)
110+
log.Errorf(msg)
111+
return err
112+
}
113+
log.Infof("Policy %s is for VMFS and is fully initialized", storagePolicyId)
114+
return nil
115+
}
116+
}
117+
}
118+
}
119+
120+
log.Debugf("Policy %s validated correctly", storagePolicyId)
121+
return nil
122+
}
123+
124+
// validateStoragePolicyForVmfs checks whether the policy is compatible for VMFS datastores.
125+
// This function is only called for RWX shared block volumes.
126+
func validateStoragePolicyForVmfs(ctx context.Context,
127+
vc *vsphere.VirtualCenter, storagePolicyId string) error {
128+
log := logger.GetLogger(ctx)
129+
130+
spbmPolicyContentList, err := vc.PbmRetrieveContent(ctx, []string{storagePolicyId})
131+
if err != nil {
132+
log.Errorf("failed to retrieve policy %s", storagePolicyId)
133+
return err
134+
}
135+
136+
return verifyStoragePolicyForVmfsWithEageredZeroThick(ctx, spbmPolicyContentList, storagePolicyId)
137+
}
138+
89139
// validateWCPCreateVolumeRequest is the helper function to validate
90140
// CreateVolumeRequest for WCP CSI driver.
91141
// Function returns error if validation fails otherwise returns nil.

pkg/csi/service/wcp/controller_helper_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"k8s.io/client-go/kubernetes"
1212
"k8s.io/client-go/kubernetes/fake"
1313
k8stesting "k8s.io/client-go/testing"
14+
cnsvsphere "sigs.k8s.io/vsphere-csi-driver/v3/pkg/common/cns-lib/vsphere"
1415
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/common/unittestcommon"
1516
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/csi/service/common/commonco"
1617
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/csi/service/logger"
@@ -132,6 +133,68 @@ func TestGetPodVMUUID(t *testing.T) {
132133
})
133134
}
134135

136+
func TestVerifyStoragePolicyForVmfsWithEageredZeroThick(t *testing.T) {
137+
ctx := context.TODO()
138+
139+
t.Run("Valid VMFS EZT policy", func(t *testing.T) {
140+
policyList := []cnsvsphere.SpbmPolicyContent{
141+
{
142+
Profiles: []cnsvsphere.SpbmPolicySubProfile{
143+
{
144+
Rules: []cnsvsphere.SpbmPolicyRule{
145+
{Ns: vmfsNamespace, Value: vmfsNamespaceEztValue},
146+
},
147+
},
148+
},
149+
},
150+
}
151+
152+
err := verifyStoragePolicyForVmfsWithEageredZeroThick(ctx, policyList, "valid-policy-id")
153+
assert.NoError(t, err)
154+
})
155+
156+
t.Run("Invalid VMFS policy - not EZT", func(t *testing.T) {
157+
policyList := []cnsvsphere.SpbmPolicyContent{
158+
{
159+
Profiles: []cnsvsphere.SpbmPolicySubProfile{
160+
{
161+
Rules: []cnsvsphere.SpbmPolicyRule{
162+
{Ns: vmfsNamespace, Value: "Thin"},
163+
},
164+
},
165+
},
166+
},
167+
}
168+
169+
err := verifyStoragePolicyForVmfsWithEageredZeroThick(ctx, policyList, "invalid-policy-id")
170+
assert.Error(t, err)
171+
assert.Contains(t, err.Error(), "must be fully initialized")
172+
})
173+
174+
t.Run("Policy with no VMFS rule", func(t *testing.T) {
175+
policyList := []cnsvsphere.SpbmPolicyContent{
176+
{
177+
Profiles: []cnsvsphere.SpbmPolicySubProfile{
178+
{
179+
Rules: []cnsvsphere.SpbmPolicyRule{
180+
{Ns: "VSAN", Value: "Whatever"},
181+
},
182+
},
183+
},
184+
},
185+
}
186+
187+
err := verifyStoragePolicyForVmfsWithEageredZeroThick(ctx, policyList, "no-vmfs-rule-policy")
188+
assert.NoError(t, err)
189+
})
190+
191+
t.Run("Empty policy list", func(t *testing.T) {
192+
var policyList []cnsvsphere.SpbmPolicyContent
193+
err := verifyStoragePolicyForVmfsWithEageredZeroThick(ctx, policyList, "empty-policy")
194+
assert.NoError(t, err)
195+
})
196+
}
197+
135198
func newMockPod(name, namespace, nodeName string, volumes []string,
136199
annotations map[string]string, phase v1.PodPhase) *v1.Pod {
137200
vols := make([]v1.Volume, len(volumes))

0 commit comments

Comments
 (0)