Merge pull request #5863 from prksu/nfs-provisioner

nfs: nfs provisioner controlled by operator
This commit is contained in:
Jared Watts authored and GitHub committed 2020-08-24 16:26:23 -07:00
commit 06ab07be8b
10 files changed
+510 -255

No files matched your search

+48
View File
@@ -9,6 +9,54 @@ metadata:
name: rook-nfs-server
namespace: rook-nfs
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rook-nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups:
- nfs.rook.io
resources:
- "*"
verbs:
- "*"
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rook-nfs-provisioner-runner
subjects:
- kind: ServiceAccount
name: rook-nfs-server
# replace with namespace where provisioner is deployed
namespace: rook-nfs
roleRef:
kind: ClusterRole
name: rook-nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
# A default storageclass must be present
apiVersion: v1
kind: PersistentVolumeClaim
@@ -1,86 +0,0 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rook-nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups:
- nfs.rook.io
resources:
- "*"
verbs:
- "*"
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: rook-nfs-provisioner
# replace with namespace where provisioner is deployed
namespace: rook-nfs-system
roleRef:
kind: ClusterRole
name: rook-nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: rook-nfs-provisioner
namespace: rook-nfs-system
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: rook-nfs-provisioner
namespace: rook-nfs-system
spec:
selector:
matchLabels:
app: rook-nfs-provisioner
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: rook-nfs-provisioner
spec:
serviceAccount: rook-nfs-provisioner
containers:
- name: rook-nfs-provisioner
image: rook/nfs:master
imagePullPolicy: IfNotPresent
args: ["nfs", "provisioner","--provisioner=rook.io/nfs-provisioner"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
+1 -1
View File
@@ -8,6 +8,6 @@ parameters:
exportName: share1
nfsServerName: rook-nfs
nfsServerNamespace: rook-nfs
provisioner: rook.io/nfs-provisioner
provisioner: nfs.rook.io/rook-nfs-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
+9 -4
View File
@@ -19,6 +19,7 @@ package nfs
import (
"context"
"fmt"
"path"
"strings"
"time"
@@ -158,8 +159,8 @@ func (r *NFSServerReconciler) reconcileNFSServerConfig(ctx context.Context, cr *
nfsGaneshaConfig := `
EXPORT {
Export_Id = ` + fmt.Sprintf("%v", id) + `;
Path = /` + claimName + `;
Pseudo = /` + claimName + `;
Path = ` + path.Join("/", claimName) + `;
Pseudo = ` + path.Join("/", claimName) + `;
Protocols = 4;
Transports = TCP;
Sectype = sys;
@@ -287,12 +288,16 @@ func (r *NFSServerReconciler) reconcileNFSServer(ctx context.Context, cr *nfsv1a
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: shareName,
MountPath: "/" + claimName,
MountPath: path.Join("/", claimName),
})
}
sts.Spec.Template.Spec.Volumes = volumes
sts.Spec.Template.Spec.Containers[0].VolumeMounts = volumeMounts
for i, container := range sts.Spec.Template.Spec.Containers {
if container.Name == "nfs-server" || container.Name == "nfs-provisioner" {
sts.Spec.Template.Spec.Containers[i].VolumeMounts = volumeMounts
}
}
return nil
})
+41 -4
View File
@@ -17,6 +17,8 @@ limitations under the License.
package nfs
import (
"context"
"path"
"reflect"
"testing"
@@ -92,7 +94,7 @@ func (r *resource) Generate() *nfsv1alpha1.NFSServer {
}
func TestNFSServerReconciler_Reconcile(t *testing.T) {
expectedStatefulSet := func(scheme *runtime.Scheme, cr *nfsv1alpha1.NFSServer) *appsv1.StatefulSet {
expectedServerFunc := func(scheme *runtime.Scheme, cr *nfsv1alpha1.NFSServer) *appsv1.StatefulSet {
sts := newStatefulSetForNFSServer(cr)
sts.Spec.Selector = &metav1.LabelSelector{
MatchLabels: newLabels(cr),
@@ -137,16 +139,26 @@ func TestNFSServerReconciler_Reconcile(t *testing.T) {
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: shareName,
MountPath: "/" + claimName,
MountPath: path.Join("/", claimName),
})
}
sts.Status.ReadyReplicas = int32(cr.Spec.Replicas)
sts.Spec.Template.Spec.Volumes = volumes
sts.Spec.Template.Spec.Containers[0].VolumeMounts = volumeMounts
for i, container := range sts.Spec.Template.Spec.Containers {
if container.Name == "nfs-server" || container.Name == "nfs-provisioner" {
sts.Spec.Template.Spec.Containers[i].VolumeMounts = volumeMounts
}
}
return sts
}
expectedServerServiceFunc := func(scheme *runtime.Scheme, cr *nfsv1alpha1.NFSServer) *corev1.Service {
svc := newServiceForNFSServer(cr)
_ = controllerutil.SetControllerReference(cr, svc, scheme)
return svc
}
rr := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "nfs-server",
@@ -208,11 +220,18 @@ func TestNFSServerReconciler_Reconcile(t *testing.T) {
scheme := clientgoscheme.Scheme
scheme.AddKnownTypes(nfsv1alpha1.SchemeGroupVersion, tt.cr)
expectedServer := expectedServerFunc(scheme, tt.cr)
expectedServerService := expectedServerServiceFunc(scheme, tt.cr)
objs := []runtime.Object{
tt.cr,
expectedStatefulSet(scheme, tt.cr),
expectedServer,
expectedServerService,
}
expectedServer.GetObjectKind().SetGroupVersionKind(appsv1.SchemeGroupVersion.WithKind("StatefulSet"))
expectedServerService.GetObjectKind().SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Service"))
fc := fake.NewFakeClient(objs...)
fr := record.NewFakeRecorder(2)
@@ -230,6 +249,24 @@ func TestNFSServerReconciler_Reconcile(t *testing.T) {
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NFSServerReconciler.Reconcile() = %v, want %v", got, tt.want)
}
gotServer := &appsv1.StatefulSet{}
if err := fc.Get(context.Background(), tt.args.req.NamespacedName, gotServer); err != nil {
t.Errorf("NFSServerReconciler.Reconcile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotServer, expectedServer) {
t.Errorf("NFSServerReconciler.Reconcile() = %v, want %v", gotServer, expectedServer)
}
gotServerService := &corev1.Service{}
if err := fc.Get(context.Background(), tt.args.req.NamespacedName, gotServerService); err != nil {
t.Errorf("NFSServerReconciler.Reconcile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotServerService, expectedServerService) {
t.Errorf("NFSServerReconciler.Reconcile() = %v, want %v", gotServerService, expectedServerService)
}
})
}
}
+126 -66
View File
@@ -18,11 +18,14 @@ package nfs
import (
"fmt"
"os"
"path"
"strings"
"github.com/pkg/errors"
rookclient "github.com/rook/rook/pkg/client/clientset/versioned"
v1 "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
"sigs.k8s.io/sig-storage-lib-external-provisioner/controller"
@@ -30,50 +33,87 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type nfsProvisioner struct {
const (
nfsServerNameSCParam = "nfsServerName"
nfsServerNamespaceSCParam = "nfsServerNamespace"
exportNameSCParam = "exportName"
)
var (
mountPath = "/"
)
type Provisioner struct {
client kubernetes.Interface
rookClient rookclient.Interface
}
var _ controller.Provisioner = &nfsProvisioner{}
var _ controller.Provisioner = &Provisioner{}
// NewNFSProvisioner returns an instance of nfsProvisioner
func NewNFSProvisioner(clientset kubernetes.Interface, rookClientset rookclient.Interface) *nfsProvisioner {
return &nfsProvisioner{clientset, rookClientset}
func NewNFSProvisioner(clientset kubernetes.Interface, rookClientset rookclient.Interface) *Provisioner {
return &Provisioner{clientset, rookClientset}
}
func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.PersistentVolume, error) {
func (p *Provisioner) Provision(options controller.ProvisionOptions) (*v1.PersistentVolume, error) {
logger.Infof("nfs provisioner: ProvisionOptions %v", options)
// Get the storage class for this volume.
storageClass, err := p.getClassForPVC(options.PVC)
if err != nil {
return nil, err
}
if options.PVC.Spec.Selector != nil {
return nil, fmt.Errorf("claim Selector is not supported")
}
nfsServerName, present := storageClass.Parameters["nfsServerName"]
if !present {
return nil, errors.Errorf("NFS share Path not found in the storageclass: %v", storageClass.GetName())
}
nfsNamespace, present := storageClass.Parameters["nfsServerNamespace"]
if !present {
return nil, errors.Errorf("NFS share Path not found in the storageclass: %v", storageClass.GetName())
}
exportName, present := storageClass.Parameters["exportName"]
if !present {
return nil, errors.Errorf("NFS share Path not found in the storageclass: %v", storageClass.GetName())
}
nfsVolumeSource, err := p.getNFSVolumeSource(nfsServerName, nfsNamespace, exportName)
sc, err := p.storageClassForPVC(options.PVC)
if err != nil {
return nil, err
}
serverName, present := sc.Parameters[nfsServerNameSCParam]
if !present {
return nil, errors.Errorf("NFS share Path not found in the storageclass: %v", sc.GetName())
}
serverNamespace, present := sc.Parameters[nfsServerNamespaceSCParam]
if !present {
return nil, errors.Errorf("NFS share Path not found in the storageclass: %v", sc.GetName())
}
exportName, present := sc.Parameters[exportNameSCParam]
if !present {
return nil, errors.Errorf("NFS share Path not found in the storageclass: %v", sc.GetName())
}
nfsserver, err := p.rookClient.NfsV1alpha1().NFSServers(serverNamespace).Get(serverName, metav1.GetOptions{})
if err != nil {
return nil, err
}
nfsserversvc, err := p.client.CoreV1().Services(serverNamespace).Get(serverName, metav1.GetOptions{})
if err != nil {
return nil, err
}
var (
exportPath string
found bool
)
for _, export := range nfsserver.Spec.Exports {
if export.Name == exportName {
exportPath = path.Join(mountPath, export.PersistentVolumeClaim.ClaimName)
found = true
}
}
if !found {
return nil, fmt.Errorf("No export name from storageclass is match with NFSServer %s in namespace %s", nfsserver.Name, nfsserver.Namespace)
}
pvName := strings.Join([]string{options.PVC.Namespace, options.PVC.Name, options.PVName}, "-")
fullPath := path.Join(exportPath, pvName)
if err := os.MkdirAll(fullPath, 0700); err != nil {
return nil, errors.New("unable to create directory to provision new pv: " + err.Error())
}
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: options.PVName,
@@ -86,19 +126,68 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per
v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)],
},
PersistentVolumeSource: v1.PersistentVolumeSource{
NFS: nfsVolumeSource,
NFS: &v1.NFSVolumeSource{
Server: nfsserversvc.Spec.ClusterIP,
Path: fullPath,
ReadOnly: false,
},
},
},
}
return pv, nil
}
func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error {
return nil
func (p *Provisioner) Delete(volume *v1.PersistentVolume) error {
nfsPath := volume.Spec.PersistentVolumeSource.NFS.Path
pvName := path.Base(nfsPath)
sc, err := p.storageClassForPV(volume)
if err != nil {
return err
}
serverName, present := sc.Parameters[nfsServerNameSCParam]
if !present {
return errors.Errorf("NFS share Path not found in the storageclass: %v", sc.GetName())
}
serverNamespace, present := sc.Parameters[nfsServerNamespaceSCParam]
if !present {
return errors.Errorf("NFS share Path not found in the storageclass: %v", sc.GetName())
}
exportName, present := sc.Parameters[exportNameSCParam]
if !present {
return errors.Errorf("NFS share Path not found in the storageclass: %v", sc.GetName())
}
nfsserver, err := p.rookClient.NfsV1alpha1().NFSServers(serverNamespace).Get(serverName, metav1.GetOptions{})
if err != nil {
return err
}
var (
exportPath string
found bool
)
for _, export := range nfsserver.Spec.Exports {
if export.Name == exportName {
exportPath = path.Join(mountPath, export.PersistentVolumeClaim.ClaimName)
found = true
}
}
if !found {
return fmt.Errorf("No export name from storageclass is match with NFSServer %s in namespace %s", nfsserver.Name, nfsserver.Namespace)
}
fullPath := path.Join(exportPath, pvName)
return os.RemoveAll(fullPath)
}
// getClassForPV returns StorageClass
func (p *nfsProvisioner) getClassForPV(pv *v1.PersistentVolume) (*storage.StorageClass, error) {
func (p *Provisioner) storageClassForPV(pv *v1.PersistentVolume) (*storagev1.StorageClass, error) {
if p.client == nil {
return nil, fmt.Errorf("Cannot get kube client")
}
@@ -106,15 +195,11 @@ func (p *nfsProvisioner) getClassForPV(pv *v1.PersistentVolume) (*storage.Storag
if className == "" {
return nil, fmt.Errorf("Volume has no storage class")
}
class, err := p.client.StorageV1().StorageClasses().Get(className, metav1.GetOptions{})
if err != nil {
return nil, err
}
return class, nil
return p.client.StorageV1().StorageClasses().Get(className, metav1.GetOptions{})
}
// getClassForPVC returns StorageClass
func (p *nfsProvisioner) getClassForPVC(pvc *v1.PersistentVolumeClaim) (*storage.StorageClass, error) {
func (p *Provisioner) storageClassForPVC(pvc *v1.PersistentVolumeClaim) (*storagev1.StorageClass, error) {
if p.client == nil {
return nil, fmt.Errorf("Cannot get kube client")
}
@@ -122,31 +207,6 @@ func (p *nfsProvisioner) getClassForPVC(pvc *v1.PersistentVolumeClaim) (*storage
if className == "" {
return nil, fmt.Errorf("Volume has no storage class")
}
class, err := p.client.StorageV1().StorageClasses().Get(className, metav1.GetOptions{})
if err != nil {
return nil, err
}
return class, nil
}
// getNFSVolumeSource returns the nfs source configuration for the pv
func (p *nfsProvisioner) getNFSVolumeSource(nfsServerName, namespace, exportName string) (*v1.NFSVolumeSource, error) {
nfsServer, err := p.rookClient.NfsV1alpha1().NFSServers(namespace).Get(nfsServerName, metav1.GetOptions{})
if err != nil {
return nil, err
}
nfsService, err := p.client.CoreV1().Services(namespace).Get(nfsServerName, metav1.GetOptions{})
if err != nil {
return nil, err
}
for _, export := range nfsServer.Spec.Exports {
if export.Name == exportName {
return &v1.NFSVolumeSource{
ReadOnly: false,
Server: nfsService.Spec.ClusterIP,
Path: "/" + export.PersistentVolumeClaim.ClaimName,
}, nil
}
}
return nil, errors.Errorf("exportName not Found")
return p.client.StorageV1().StorageClasses().Get(className, metav1.GetOptions{})
}
+221
View File
@@ -0,0 +1,221 @@
/*
Copyright 2019 The Rook Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nfs
import (
"os"
"reflect"
"testing"
rookclient "github.com/rook/rook/pkg/client/clientset/versioned"
rookclientfake "github.com/rook/rook/pkg/client/clientset/versioned/fake"
corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
apiresource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
k8sclientfake "k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/sig-storage-lib-external-provisioner/controller"
)
func init() {
mountPath = "/tmp/test-rook-nfs"
}
func newDummyStorageClass(name string, nfsServerNamespacedName types.NamespacedName, reclaimPolicy corev1.PersistentVolumeReclaimPolicy) *storagev1.StorageClass {
return &storagev1.StorageClass{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Parameters: map[string]string{
nfsServerNameSCParam: nfsServerNamespacedName.Name,
nfsServerNamespaceSCParam: nfsServerNamespacedName.Namespace,
exportNameSCParam: name,
},
ReclaimPolicy: &reclaimPolicy,
}
}
func newDummyPVC(name, namespace string, capacity apiresource.Quantity, storageClassName string) *corev1.PersistentVolumeClaim {
return &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceStorage): capacity,
},
},
StorageClassName: &storageClassName,
},
}
}
func newDummyPV(name, scName, expectedPath string, expectedCapacity apiresource.Quantity, expectedReclaimPolicy corev1.PersistentVolumeReclaimPolicy) *corev1.PersistentVolume {
return &corev1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: corev1.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: expectedReclaimPolicy,
Capacity: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceStorage): expectedCapacity,
},
PersistentVolumeSource: corev1.PersistentVolumeSource{
NFS: &corev1.NFSVolumeSource{
Path: expectedPath,
},
},
StorageClassName: scName,
},
}
}
func TestProvisioner_Provision(t *testing.T) {
if err := os.MkdirAll(mountPath, 0755); err != nil {
t.Error("error creating test provisioner directory")
}
defer os.RemoveAll(mountPath)
nfsserver := newCustomResource(types.NamespacedName{Name: "test-nfsserver", Namespace: "test-nfsserver"}).WithExports("share-1", "ReadWrite", "none", "test-claim").Generate()
type fields struct {
client kubernetes.Interface
rookClient rookclient.Interface
}
type args struct {
options controller.ProvisionOptions
}
tests := []struct {
name string
fields fields
args args
want *corev1.PersistentVolume
wantErr bool
}{
{
name: "success create volume",
fields: fields{
client: k8sclientfake.NewSimpleClientset(
newServiceForNFSServer(nfsserver),
newDummyStorageClass("share-1", types.NamespacedName{Name: nfsserver.Name, Namespace: nfsserver.Namespace}, corev1.PersistentVolumeReclaimDelete),
),
rookClient: rookclientfake.NewSimpleClientset(
nfsserver,
),
},
args: args{
options: controller.ProvisionOptions{
StorageClass: newDummyStorageClass("share-1", types.NamespacedName{Name: nfsserver.Name, Namespace: nfsserver.Namespace}, corev1.PersistentVolumeReclaimDelete),
PVName: "share-1-pvc",
PVC: newDummyPVC("share-1-pvc", "default", apiresource.MustParse("1Mi"), "share-1"),
},
},
want: newDummyPV("share-1-pvc", "", "/tmp/test-rook-nfs/test-claim/default-share-1-pvc-share-1-pvc", apiresource.MustParse("1Mi"), corev1.PersistentVolumeReclaimDelete),
},
{
name: "no matching export",
fields: fields{
client: k8sclientfake.NewSimpleClientset(
newServiceForNFSServer(nfsserver),
newDummyStorageClass("foo", types.NamespacedName{Name: nfsserver.Name, Namespace: nfsserver.Namespace}, corev1.PersistentVolumeReclaimDelete),
),
rookClient: rookclientfake.NewSimpleClientset(
nfsserver,
),
},
args: args{
options: controller.ProvisionOptions{
StorageClass: newDummyStorageClass("foo", types.NamespacedName{Name: nfsserver.Name, Namespace: nfsserver.Namespace}, corev1.PersistentVolumeReclaimDelete),
PVName: "share-1-pvc",
PVC: newDummyPVC("share-1-pvc", "default", apiresource.MustParse("1Mi"), "foo"),
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Provisioner{
client: tt.fields.client,
rookClient: tt.fields.rookClient,
}
got, err := p.Provision(tt.args.options)
if (err != nil) != tt.wantErr {
t.Errorf("Provisioner.Provision() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Provisioner.Provision() = %v, want %v", got, tt.want)
}
})
}
}
func TestProvisioner_Delete(t *testing.T) {
if err := os.MkdirAll(mountPath, 0755); err != nil {
t.Error("error creating test provisioner directory")
}
defer os.RemoveAll(mountPath)
nfsserver := newCustomResource(types.NamespacedName{Name: "test-nfsserver", Namespace: "test-nfsserver"}).WithExports("share-1", "ReadWrite", "none", "test-claim").Generate()
type fields struct {
client kubernetes.Interface
rookClient rookclient.Interface
}
type args struct {
volume *corev1.PersistentVolume
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "success delete volume",
fields: fields{
client: k8sclientfake.NewSimpleClientset(
newServiceForNFSServer(nfsserver),
newDummyStorageClass("share-1", types.NamespacedName{Name: nfsserver.Name, Namespace: nfsserver.Namespace}, corev1.PersistentVolumeReclaimDelete),
),
rookClient: rookclientfake.NewSimpleClientset(
nfsserver,
),
},
args: args{
volume: newDummyPV("share-1-pvc", "share-1", "/tmp/test-rook-nfs/test-claim/default-share-1-pvc-share-1-pvc", apiresource.MustParse("1Mi"), corev1.PersistentVolumeReclaimDelete),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Provisioner{
client: tt.fields.client,
rookClient: tt.fields.rookClient,
}
if err := p.Delete(tt.args.volume); (err != nil) != tt.wantErr {
t.Errorf("Provisioner.Delete() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
+14 -4
View File
@@ -67,6 +67,7 @@ func newServiceForNFSServer(cr *nfsv1alpha1.NFSServer) *corev1.Service {
}
func newStatefulSetForNFSServer(cr *nfsv1alpha1.NFSServer) *appsv1.StatefulSet {
privilaged := true
replicas := int32(cr.Spec.Replicas)
return &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
@@ -87,10 +88,9 @@ func newStatefulSetForNFSServer(cr *nfsv1alpha1.NFSServer) *appsv1.StatefulSet {
ServiceAccountName: "rook-nfs-server",
Containers: []corev1.Container{
{
ImagePullPolicy: "IfNotPresent",
Name: cr.Name,
Image: "rook/nfs:master",
Args: []string{"nfs", "server", "--ganeshaConfigPath=" + nfsConfigMapPath + "/" + cr.Name},
Name: "nfs-server",
Image: "rook/nfs:master",
Args: []string{"nfs", "server", "--ganeshaConfigPath=" + nfsConfigMapPath + "/" + cr.Name},
Ports: []corev1.ContainerPort{
{
Name: "nfs-port",
@@ -110,6 +110,16 @@ func newStatefulSetForNFSServer(cr *nfsv1alpha1.NFSServer) *appsv1.StatefulSet {
},
},
},
{
Name: "nfs-provisioner",
Image: "rook/nfs:master",
Args: []string{"nfs", "provisioner", "--provisioner=" + "nfs.rook.io/" + cr.Name + "-provisioner"},
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
SecurityContext: &corev1.SecurityContext{
Privileged: &privilaged,
},
},
},
},
},
+49 -89
View File
@@ -320,93 +320,6 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rook-nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups:
- nfs.rook.io
resources:
- "*"
verbs:
- "*"
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: rook-nfs-provisioner
# replace with namespace where provisioner is deployed
namespace: ` + namespace + `
roleRef:
kind: ClusterRole
name: rook-nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: rook-nfs-provisioner
namespace: ` + namespace + `
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: rook-nfs-provisioner
namespace: ` + namespace + `
spec:
selector:
matchLabels:
app: rook-nfs-provisioner
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: rook-nfs-provisioner
spec:
serviceAccount: rook-nfs-provisioner
containers:
- name: rook-nfs-provisioner
image: rook/nfs:master
imagePullPolicy: IfNotPresent
args: ["nfs", "provisioner","--provisioner=rook.io/nfs-provisioner"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
`
}
@@ -462,7 +375,7 @@ parameters:
exportName: nfs-share
nfsServerName: ` + namespace + `
nfsServerNamespace: ` + namespace + `
provisioner: rook.io/nfs-provisioner
provisioner: nfs.rook.io/` + namespace + `-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
---
@@ -476,7 +389,7 @@ parameters:
exportName: nfs-share1
nfsServerName: ` + namespace + `
nfsServerNamespace: ` + namespace + `
provisioner: rook.io/nfs-provisioner
provisioner: nfs.rook.io/` + namespace + `-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
---
@@ -515,6 +428,53 @@ metadata:
name: rook-nfs-server
namespace: ` + namespace + `
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rook-nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups:
- nfs.rook.io
resources:
- "*"
verbs:
- "*"
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: rook-nfs-server
namespace: ` + namespace + `
roleRef:
kind: ClusterRole
name: rook-nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
+1 -1
View File
@@ -68,7 +68,7 @@ func (suite *NfsSuite) TearDownSuite() {
}
func (suite *NfsSuite) Setup() {
suite.namespace = "nfs-ns"
suite.namespace = "rook-nfs"
suite.systemNamespace = installer.SystemNamespace(suite.namespace)
suite.instanceCount = 1