From f70aef31d7351d272698d022210639a50d2215e1 Mon Sep 17 00:00:00 2001 From: "cheolho.kang" Date: Wed, 19 Mar 2025 14:53:05 +0900 Subject: [PATCH] feat: add `CreateVolume()` and `DeleteVolume()` skeletons with RBAC permissions Signed-off-by: cheolho.kang --- deploy/kubernetes/csi-nvmf-rbac.yaml | 81 +++++++++++++++++++++++++++- pkg/nvmf/controllerserver.go | 64 ++++++++++++++++++++-- pkg/nvmf/driver.go | 4 +- 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/deploy/kubernetes/csi-nvmf-rbac.yaml b/deploy/kubernetes/csi-nvmf-rbac.yaml index 6335742..7aa3600 100644 --- a/deploy/kubernetes/csi-nvmf-rbac.yaml +++ b/deploy/kubernetes/csi-nvmf-rbac.yaml @@ -42,6 +42,17 @@ rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list"] + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: nvmf-external-provisioner-role +rules: + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "update", "patch"] + --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -64,7 +75,10 @@ metadata: rules: - apiGroups: [""] resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "update", "patch"] + verbs: ["get", "list", "watch", "create", "delete", "update", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "create", "delete", "update", "patch"] - apiGroups: ["storage.k8s.io"] resources: ["csinodes"] verbs: ["get", "list", "watch"] @@ -74,6 +88,9 @@ rules: - apiGroups: ["storage.k8s.io"] resources: ["volumeattachments/status"] verbs: ["patch"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] --- kind: ClusterRoleBinding @@ -87,4 +104,64 @@ subjects: roleRef: kind: ClusterRole name: nvmf-external-attacher-role - apiGroup: rbac.authorization.k8s.io \ No newline at end of file + apiGroup: rbac.authorization.k8s.io + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: nvmf-csi-node-role +rules: + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["storage.k8s.io"] + resources: ["volumeattachments"] + verbs: ["get", "list", "watch"] + - apiGroups: ["storage.k8s.io"] + resources: ["csinodes"] + verbs: ["get", "list", "watch", "update"] + - apiGroups: ["storage.k8s.io"] + resources: ["csinodeinfos"] + verbs: ["get", "list", "watch"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-nvmf-node-binding +subjects: + - kind: ServiceAccount + name: csi-nvmf-node-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: nvmf-csi-node-role + apiGroup: rbac.authorization.k8s.io + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-nvmf-node-volumeattachment-binding +subjects: + - kind: Group + name: system:nodes + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: nvmf-csi-node-volumeattachment-role + apiGroup: rbac.authorization.k8s.io + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: nvmf-csi-node-volumeattachment-role +rules: + - apiGroups: ["storage.k8s.io"] + resources: ["volumeattachments"] + verbs: ["get", "list", "watch"] \ No newline at end of file diff --git a/pkg/nvmf/controllerserver.go b/pkg/nvmf/controllerserver.go index 13bdc1d..2c45ec4 100644 --- a/pkg/nvmf/controllerserver.go +++ b/pkg/nvmf/controllerserver.go @@ -17,8 +17,9 @@ limitations under the License. package nvmf import ( + "context" + "github.com/container-storage-interface/spec/lib/go/csi" - "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "k8s.io/klog/v2" @@ -35,13 +36,32 @@ func NewControllerServer(d *driver) *ControllerServer { } } -// You should realize your volume provider here, such as requesting the Cloud to create an NVMf block and -// returning specific information to you +// CreateVolume provisions a new volume func (c *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { + volumeName := req.GetName() + if !isValidVolumeName(volumeName) { + return nil, status.Error(codes.InvalidArgument, "volume Name must be provided") + } + + cap := req.GetVolumeCapabilities() + if !isValidVolumeCapabilities(cap) { + return nil, status.Error(codes.InvalidArgument, "volume Capabilities are invalid") + } + + klog.V(4).Infof("CreateVolume called with name: %s", volumeName) + return nil, status.Errorf(codes.Unimplemented, "CreateVolume should implement by yourself. ") } +// DeleteVolume deletes a volume func (c *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { + volumeID := req.GetVolumeId() + if !isValidVolumeID(volumeID) { + return nil, status.Error(codes.InvalidArgument, "volume ID must be provided") + } + + klog.V(4).Infof("DeleteVolume called for volume ID %s", volumeID) + return nil, status.Errorf(codes.Unimplemented, "DeleteVolume should implement by yourself. ") } @@ -92,3 +112,41 @@ func (c *ControllerServer) DeleteSnapshot(ctx context.Context, request *csi.Dele func (c *ControllerServer) ListSnapshots(ctx context.Context, request *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "ListSnapshots not implement") } + +func isValidVolumeName(volumeName string) bool { + if volumeName == "" { + klog.Error("Volume Name cannot be empty") + return false + } + + return true +} + +func isValidVolumeID(volumeID string) bool { + if volumeID == "" { + klog.Error("Volume ID cannot be empty") + return false + } + + return true +} + +func isValidVolumeCapabilities(volCaps []*csi.VolumeCapability) bool { + if len(volCaps) == 0 { + klog.Error("Volume Capabilities not provided") + return false + } + + for _, cap := range volCaps { + if cap.GetBlock() != nil && cap.GetMount() != nil { + klog.Error("Cannot specify both block and mount access types") + return false + } + if cap.GetBlock() == nil && cap.GetMount() == nil { + klog.Error("Must specify either block or mount access type") + return false + } + } + + return true +} diff --git a/pkg/nvmf/driver.go b/pkg/nvmf/driver.go index c3b157a..6a1ccd2 100644 --- a/pkg/nvmf/driver.go +++ b/pkg/nvmf/driver.go @@ -57,7 +57,9 @@ func NewDriver(conf *GlobalConfig) *driver { } func (d *driver) Run(conf *GlobalConfig) { - d.AddControllerServiceCapabilities([]csi.ControllerServiceCapability_RPC_Type{}) + d.AddControllerServiceCapabilities([]csi.ControllerServiceCapability_RPC_Type{ + csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, + }) d.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{ csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, })