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

NFSv4 ACL support in CSI PowerStore #55

Merged
merged 11 commits into from
Feb 21, 2022
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
2 changes: 1 addition & 1 deletion docker-files/Dockerfile.centos
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ LABEL vendor="Dell Inc." \
COPY licenses /licenses

# dependencies, following by cleaning the cache
RUN echo "%_netsharedpath /sys:/proc" >> /etc/rpm/macros.dist && yum update -y && yum install -y e2fsprogs xfsprogs nfs-utils which device-mapper-multipath \
RUN echo "%_netsharedpath /sys:/proc" >> /etc/rpm/macros.dist && yum update -y && yum install -y e2fsprogs xfsprogs nfs-utils nfs4-acl-tools acl which device-mapper-multipath \
&& \
yum clean all \
&& \
Expand Down
2 changes: 1 addition & 1 deletion docker-files/Dockerfile.ubi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ COPY licenses /licenses
# dependencies, following by cleaning the cache
RUN yum update -y \
&& \
yum install -y e2fsprogs xfsprogs nfs-utils which device-mapper-multipath \
yum install -y e2fsprogs xfsprogs nfs-utils nfs4-acl-tools acl which device-mapper-multipath \
&& \
yum clean all \
&& \
Expand Down
2 changes: 2 additions & 0 deletions docker-files/Dockerfile.ubi.alt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ RUN yum -y update && \
e2fsprogs.x86_64 \
xfsprogs.x86_64 \
nfs-utils.x86_64 \
nfs4-acl-tools \
acl \
which \
device-mapper-multipath \
&& \
Expand Down
2 changes: 2 additions & 0 deletions docker-files/Dockerfile.ubi.min
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ RUN microdnf update -y \
e2fsprogs \
xfsprogs \
nfs-utils \
nfs4-acl-tools \
acl \
which \
device-mapper-multipath \
&& \
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/dell/gocsi v1.5.0
github.com/dell/gofsutil v1.7.1-0.20220204052137-9928a2dc48d8
github.com/dell/goiscsi v1.2.0
github.com/dell/gopowerstore v1.6.1-0.20211223095101-c47391fc979f
github.com/dell/gopowerstore v1.6.1-0.20220214164327-12bc4206c198
github.com/fsnotify/fsnotify v1.4.9
github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.5.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ github.com/dell/gofsutil v1.7.1-0.20220204052137-9928a2dc48d8/go.mod h1:0tAefmK/
github.com/dell/goiscsi v1.1.0/go.mod h1:MfuMjbKWsh/MOb0VDW20C+LFYRIOfWKGiAxWkeM5TKo=
github.com/dell/goiscsi v1.2.0 h1:ocQs4pz2Fw2vr73RVAQBKwpN468SK4TZHPLhU7/FB9A=
github.com/dell/goiscsi v1.2.0/go.mod h1:MfuMjbKWsh/MOb0VDW20C+LFYRIOfWKGiAxWkeM5TKo=
github.com/dell/gopowerstore v1.6.1-0.20211223095101-c47391fc979f h1:F+aAuMlcTUV/F6eWYoM94+I6MR94gVE3g8ZY65DGzbE=
github.com/dell/gopowerstore v1.6.1-0.20211223095101-c47391fc979f/go.mod h1:0ziQJ1iuZYDV+P53ua+VeH+rIylYT9WNjGSI/7aPly0=
github.com/dell/gopowerstore v1.6.1-0.20220214164327-12bc4206c198 h1:yOIMDcJ9fjuBHytDf32rjowoL8WM1VPuB7Yh8TYG1eU=
github.com/dell/gopowerstore v1.6.1-0.20220214164327-12bc4206c198/go.mod h1:0ziQJ1iuZYDV+P53ua+VeH+rIylYT9WNjGSI/7aPly0=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
Expand Down
2 changes: 2 additions & 0 deletions helm/csi-powerstore/templates/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ spec:
value: {{ .Values.driverName }}
- name: X_CSI_POWERSTORE_EXTERNAL_ACCESS
value: {{ .Values.externalAccess }}
- name: X_CSI_NFS_ACLS
value: "{{ .Values.nfsAcls }}"
- name: X_CSI_POWERSTORE_CONFIG_PATH
value: /powerstore-config/config
- name: X_CSI_POWERSTORE_CONFIG_PARAMS_PATH
Expand Down
15 changes: 15 additions & 0 deletions helm/csi-powerstore/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ externalAccess:
# Default value: None
imagePullPolicy: IfNotPresent

# nfsAcls: enables setting permissions on NFS mount directory
# This value acts as default value for NFS ACL (nfsAcls), if not specified for an array config in secret
# Permissions can be specified in two formats:
# 1) Unix mode (NFSv3)
# 2) NFSv4 ACLs (NFSv4)
# NFSv4 ACLs are supported on NFSv4 share only.
# Allowed values:
# 1) Unix mode: valid octal mode number
# Examples: "0777", "777", "0755"
# 2) NFSv4 acls: valid NFSv4 acls, seperated by comma
# Examples: "A::OWNER@:RWX,A::GROUP@:RWX", "A::OWNER@:rxtncy"
# Optional: true
# Default value: "0777"
nfsAcls: "0777"

# controller: configure controller specific parameters
controller:
# controllerCount: defines the number of csi-powerscale controller pods to deploy to
Expand Down
24 changes: 24 additions & 0 deletions mocks/NFSv4ACLsInterface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/array/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ type PowerStoreArray struct {
BlockProtocol common.TransportType `yaml:"blockProtocol"`
Insecure bool `yaml:"skipCertificateValidation"`
IsDefault bool `yaml:"isDefault"`
NfsAcls string `yaml:"nfsAcls"`

Client gopowerstore.Client
IP string
Expand Down
4 changes: 4 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ const (
KeyArrayVolumeName = "Name"
// KeyProtocol key value to check in request parameters for volume name
KeyProtocol = "Protocol"
// KeyNfsACL key value to specify NFS ACLs for NFS volume
KeyNfsACL = "nfsAcls"
// KeyNasName key value to specify NAS server name
KeyNasName = "nasName"
// VerboseName longer description of the driver
VerboseName = "CSI Driver for Dell EMC PowerStore"
// FcTransport indicates that FC is chosen as a SCSI transport protocol
Expand Down
3 changes: 3 additions & 0 deletions pkg/common/envvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,7 @@ const (

// EnvIsHealthMonitorEnabled specifies if health monitor is enabled.
EnvIsHealthMonitorEnabled = "X_CSI_HEALTH_MONITOR_ENABLED"

// EnvNfsAcls specifies acls to be set on NFS mount directory
EnvNfsAcls = "X_CSI_NFS_ACLS"
)
21 changes: 21 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type Service struct {
Fs fs.Interface

externalAccess string
nfsAcls string

array.Locker

Expand Down Expand Up @@ -85,6 +86,13 @@ func (s *Service) Init() error {
s.isHealthMonitorEnabled, _ = strconv.ParseBool(isHealthMonitorEnabled)
}

s.nfsAcls = ""
if nfsAcls, ok := csictx.LookupEnv(ctx, common.EnvNfsAcls); ok {
if nfsAcls != "" {
s.nfsAcls = nfsAcls
}
}

return nil
}

Expand Down Expand Up @@ -132,6 +140,7 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest
var creator VolumeCreator
var protocol string

nfsAcls := s.nfsAcls
if useNFS {
protocol = "nfs"
nasParamsName, ok := params[KeyNasName]
Expand All @@ -144,6 +153,12 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest
nasName: arr.GetNasName(),
}
}

if params[common.KeyNfsACL] != "" {
nfsAcls = params[common.KeyNfsACL] // Storage class takes precedence
} else if arr.NfsAcls != "" {
nfsAcls = arr.NfsAcls // Secrets next
}
} else {
protocol = "scsi"
creator = &SCSICreator{}
Expand Down Expand Up @@ -308,6 +323,12 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest
volumeResponse.VolumeContext[common.KeyArrayID] = arr.GetGlobalID()
volumeResponse.VolumeContext[common.KeyArrayVolumeName] = req.Name
volumeResponse.VolumeContext[common.KeyProtocol] = protocol

if useNFS {
volumeResponse.VolumeContext[common.KeyNfsACL] = nfsAcls
volumeResponse.VolumeContext[common.KeyNasName] = arr.GetNasName()
}

volumeResponse.VolumeId = volumeResponse.VolumeId + "/" + arr.GetGlobalID() + "/" + protocol
volumeResponse.AccessibleTopology = topology
return &csi.CreateVolumeResponse{
Expand Down
127 changes: 127 additions & 0 deletions pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ const (
validReplicationPrefix = "/" + controller.KeyReplicationEnabled
validVolumeGroupName = "VGName"
validRemoteSystemGlobalID = "PS111111111111"
validNfsAcls = "A::OWNER@:RWX"
validNfsServerID = "24aefac2-a796-47dc-886a-c73ff8c1a671"
)

var (
Expand Down Expand Up @@ -119,6 +121,7 @@ func setVariables() {
arrays[secondValidID] = second

csictx.Setenv(context.Background(), common.EnvReplicationPrefix, "replication.storage.dell.com")
csictx.Setenv(context.Background(), common.EnvNfsAcls, "A::OWNER@:RWX")

ctrlSvc = &controller.Service{Fs: fsMock}
ctrlSvc.SetArrays(arrays)
Expand Down Expand Up @@ -388,6 +391,126 @@ var _ = Describe("CSIControllerService", func() {
common.KeyArrayVolumeName: "my-vol",
common.KeyProtocol: "nfs",
common.KeyArrayID: secondValidID,
common.KeyNfsACL: "A::OWNER@:RWX",
common.KeyNasName: validNasName,
},
},
}))
})
})

When("creating nfs volume with NFS acls in array config and storage class", func() {
It("should successfully create nfs volume with storage class NFS acls in volume response", func() {
clientMock.On("GetNASByName", mock.Anything, validNasName).Return(gopowerstore.NAS{ID: validNasID}, nil)
clientMock.On("CreateFS", mock.Anything, mock.Anything).Return(gopowerstore.CreateResponse{ID: validBaseVolID}, nil)
clientMock.On("GetNfsServer", mock.Anything, mock.Anything).Return(gopowerstore.NFSServerInstance{Id: validNfsServerID, IsNFSv4Enabled: true}, nil)

ctrlSvc.Arrays()[secondValidID].NfsAcls = "A::GROUP@:RWX"

req := getTypicalCreateVolumeNFSRequest("my-vol", validVolSize)
req.Parameters[common.KeyNfsACL] = "0777"
req.Parameters[common.KeyArrayID] = secondValidID

res, err := ctrlSvc.CreateVolume(context.Background(), req)
Expect(err).To(BeNil())
Expect(res).To(Equal(&csi.CreateVolumeResponse{
Volume: &csi.Volume{
CapacityBytes: validVolSize,
VolumeId: filepath.Join(validBaseVolID, secondValidID, "nfs"),
VolumeContext: map[string]string{
common.KeyArrayVolumeName: "my-vol",
common.KeyProtocol: "nfs",
common.KeyArrayID: secondValidID,
common.KeyNfsACL: "0777",
common.KeyNasName: validNasName,
},
},
}))
})
})

When("creating nfs volume with NFS acls in array config and not in storage class", func() {
It("should successfully create nfs volume with array config NFS acls in volume response", func() {
clientMock.On("GetNASByName", mock.Anything, validNasName).Return(gopowerstore.NAS{ID: validNasID}, nil)
clientMock.On("CreateFS", mock.Anything, mock.Anything).Return(gopowerstore.CreateResponse{ID: validBaseVolID}, nil)
clientMock.On("GetNfsServer", mock.Anything, mock.Anything).Return(gopowerstore.NFSServerInstance{Id: validNfsServerID, IsNFSv4Enabled: true}, nil)

ctrlSvc.Arrays()[secondValidID].NfsAcls = "A::GROUP@:RWX"

req := getTypicalCreateVolumeNFSRequest("my-vol", validVolSize)
req.Parameters[common.KeyArrayID] = secondValidID

res, err := ctrlSvc.CreateVolume(context.Background(), req)
Expect(err).To(BeNil())
Expect(res).To(Equal(&csi.CreateVolumeResponse{
Volume: &csi.Volume{
CapacityBytes: validVolSize,
VolumeId: filepath.Join(validBaseVolID, secondValidID, "nfs"),
VolumeContext: map[string]string{
common.KeyArrayVolumeName: "my-vol",
common.KeyProtocol: "nfs",
common.KeyArrayID: secondValidID,
common.KeyNfsACL: "A::GROUP@:RWX",
common.KeyNasName: validNasName,
},
},
}))
})
})

When("creating nfs volume with NFS acls not in array config and not in storage class", func() {
It("should successfully create nfs volume with default NFS acls in volume response", func() {
clientMock.On("GetNASByName", mock.Anything, validNasName).Return(gopowerstore.NAS{ID: validNasID}, nil)
clientMock.On("CreateFS", mock.Anything, mock.Anything).Return(gopowerstore.CreateResponse{ID: validBaseVolID}, nil)
clientMock.On("GetNfsServer", mock.Anything, mock.Anything).Return(gopowerstore.NFSServerInstance{Id: validNfsServerID, IsNFSv4Enabled: true}, nil)

req := getTypicalCreateVolumeNFSRequest("my-vol", validVolSize)
req.Parameters[common.KeyArrayID] = secondValidID

res, err := ctrlSvc.CreateVolume(context.Background(), req)
Expect(err).To(BeNil())
Expect(res).To(Equal(&csi.CreateVolumeResponse{
Volume: &csi.Volume{
CapacityBytes: validVolSize,
VolumeId: filepath.Join(validBaseVolID, secondValidID, "nfs"),
VolumeContext: map[string]string{
common.KeyArrayVolumeName: "my-vol",
common.KeyProtocol: "nfs",
common.KeyArrayID: secondValidID,
common.KeyNfsACL: "A::OWNER@:RWX",
common.KeyNasName: validNasName,
},
},
}))
})
})

When("creating nfs volume with NFS acls in not in secrets & default", func() {
It("should successfully create nfs volume with empty NFS acls in volume response", func() {
clientMock.On("GetNASByName", mock.Anything, validNasName).Return(gopowerstore.NAS{ID: validNasID}, nil)
clientMock.On("CreateFS", mock.Anything, mock.Anything).Return(gopowerstore.CreateResponse{ID: validBaseVolID}, nil)
clientMock.On("GetNfsServer", mock.Anything, mock.Anything).Return(gopowerstore.NFSServerInstance{Id: validNfsServerID, IsNFSv4Enabled: true}, nil)

req := getTypicalCreateVolumeNFSRequest("my-vol", validVolSize)
req.Parameters[common.KeyArrayID] = secondValidID

ctrlSvc.Arrays()[secondValidID].NfsAcls = ""
csictx.Setenv(context.Background(), common.EnvNfsAcls, "")

_ = ctrlSvc.Init()

res, err := ctrlSvc.CreateVolume(context.Background(), req)
Expect(err).To(BeNil())
Expect(res).To(Equal(&csi.CreateVolumeResponse{
Volume: &csi.Volume{
CapacityBytes: validVolSize,
VolumeId: filepath.Join(validBaseVolID, secondValidID, "nfs"),
VolumeContext: map[string]string{
common.KeyArrayVolumeName: "my-vol",
common.KeyProtocol: "nfs",
common.KeyArrayID: secondValidID,
common.KeyNfsACL: "",
common.KeyNasName: validNasName,
},
},
}))
Expand Down Expand Up @@ -457,6 +580,8 @@ var _ = Describe("CSIControllerService", func() {
common.KeyArrayVolumeName: "my-vol",
common.KeyProtocol: "nfs",
common.KeyArrayID: secondValidID,
common.KeyNfsACL: "A::OWNER@:RWX",
common.KeyNasName: validNasName,
},
},
}))
Expand Down Expand Up @@ -1533,6 +1658,7 @@ var _ = Describe("CSIControllerService", func() {
"ExportID": nfsID,
"allowRoot": "",
"HostIP": "127.0.0.1",
"nfsAcls": "",
},
}))
})
Expand Down Expand Up @@ -1654,6 +1780,7 @@ var _ = Describe("CSIControllerService", func() {
"allowRoot": "",
"HostIP": "127.0.0.1",
"NatIP": "10.0.0.1",
"nfsAcls": "",
},
}))
})
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ func (n *NfsPublisher) Publish(ctx context.Context, req *csi.ControllerPublishVo
}
publishContext[common.KeyExportID] = export.ID
publishContext[common.KeyAllowRoot] = req.VolumeContext[common.KeyAllowRoot]
publishContext[common.KeyNfsACL] = req.VolumeContext[common.KeyNfsACL]
return &csi.ControllerPublishVolumeResponse{PublishContext: publishContext}, nil
}

Expand Down
Loading