...

Source file src/k8s.io/kubernetes/pkg/volume/rbd/rbd_test.go

Documentation: k8s.io/kubernetes/pkg/volume/rbd

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rbd
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"reflect"
    24  	"runtime"
    25  	"strings"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  
    30  	"k8s.io/mount-utils"
    31  
    32  	v1 "k8s.io/api/core/v1"
    33  	"k8s.io/apimachinery/pkg/api/resource"
    34  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    35  	"k8s.io/apimachinery/pkg/types"
    36  	"k8s.io/apimachinery/pkg/util/uuid"
    37  	"k8s.io/client-go/kubernetes/fake"
    38  	utiltesting "k8s.io/client-go/util/testing"
    39  	"k8s.io/kubernetes/pkg/volume"
    40  	volumetest "k8s.io/kubernetes/pkg/volume/testing"
    41  )
    42  
    43  const (
    44  	testVolName    = "vol-1234"
    45  	testRBDImage   = "volume-a4b47414-a675-47dc-a9cc-c223f13439b0"
    46  	testRBDPool    = "volumes"
    47  	testGlobalPath = "plugins/kubernetes.io/rbd/volumeDevices/volumes-image-volume-a4b47414-a675-47dc-a9cc-c223f13439b0"
    48  )
    49  
    50  func TestGetVolumeSpecFromGlobalMapPath(t *testing.T) {
    51  	// make our test path for fake GlobalMapPath
    52  	// /tmp symbolized our pluginDir
    53  	// /tmp/testGlobalPathXXXXX/plugins/kubernetes.io/rbd/volumeDevices/pdVol1
    54  	tmpVDir, err := utiltesting.MkTmpdir("rbdBlockTest")
    55  	if err != nil {
    56  		t.Fatalf("can't make a temp dir: %v", err)
    57  	}
    58  	//deferred clean up
    59  	defer os.RemoveAll(tmpVDir)
    60  
    61  	expectedGlobalPath := filepath.Join(tmpVDir, testGlobalPath)
    62  
    63  	//Bad Path
    64  	badspec, err := getVolumeSpecFromGlobalMapPath("", testVolName)
    65  	if badspec != nil || err == nil {
    66  		t.Fatalf("Expected not to get spec from GlobalMapPath but did")
    67  	}
    68  
    69  	// Good Path
    70  	spec, err := getVolumeSpecFromGlobalMapPath(expectedGlobalPath, testVolName)
    71  	if spec == nil || err != nil {
    72  		t.Fatalf("Failed to get spec from GlobalMapPath: %v", err)
    73  	}
    74  
    75  	if spec.PersistentVolume.Name != testVolName {
    76  		t.Errorf("Invalid spec name for GlobalMapPath spec: %s", spec.PersistentVolume.Name)
    77  	}
    78  
    79  	if spec.PersistentVolume.Spec.RBD.RBDPool != testRBDPool {
    80  		t.Errorf("Invalid RBDPool from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.RBD.RBDPool)
    81  	}
    82  
    83  	if spec.PersistentVolume.Spec.RBD.RBDImage != testRBDImage {
    84  		t.Errorf("Invalid RBDImage from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.RBD.RBDImage)
    85  	}
    86  
    87  	block := v1.PersistentVolumeBlock
    88  	specMode := spec.PersistentVolume.Spec.VolumeMode
    89  	if specMode == nil {
    90  		t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v - %v", specMode, block)
    91  	}
    92  	if *specMode != block {
    93  		t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v - %v", *specMode, block)
    94  	}
    95  }
    96  
    97  func TestCanSupport(t *testing.T) {
    98  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
    99  	if err != nil {
   100  		t.Fatalf("error creating temp dir: %v", err)
   101  	}
   102  	defer os.RemoveAll(tmpDir)
   103  
   104  	plugMgr := volume.VolumePluginMgr{}
   105  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
   106  
   107  	plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
   108  	if err != nil {
   109  		t.Fatal("Can't find the plugin by name")
   110  	}
   111  	if plug.GetPluginName() != "kubernetes.io/rbd" {
   112  		t.Errorf("Wrong name: %s", plug.GetPluginName())
   113  	}
   114  	if plug.CanSupport(&volume.Spec{}) {
   115  		t.Errorf("Expected false")
   116  	}
   117  	if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
   118  		t.Errorf("Expected false")
   119  	}
   120  	if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{RBD: &v1.RBDVolumeSource{}}}}) {
   121  		t.Errorf("Expected true")
   122  	}
   123  	if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{}}}) {
   124  		t.Errorf("Expected false")
   125  	}
   126  	if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{}}}}) {
   127  		t.Errorf("Expected false")
   128  	}
   129  	if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{RBD: &v1.RBDPersistentVolumeSource{}}}}}) {
   130  		t.Errorf("Expected true")
   131  	}
   132  }
   133  
   134  type fakeDiskManager struct {
   135  	// Make sure we can run tests in parallel.
   136  	mutex sync.RWMutex
   137  	// Key format: "<pool>/<image>"
   138  	rbdImageLocks map[string]bool
   139  	rbdMapIndex   int
   140  	rbdDevices    map[string]bool
   141  }
   142  
   143  func newFakeDiskManager() *fakeDiskManager {
   144  	return &fakeDiskManager{
   145  		rbdImageLocks: make(map[string]bool),
   146  		rbdMapIndex:   0,
   147  		rbdDevices:    make(map[string]bool),
   148  	}
   149  }
   150  
   151  func (fake *fakeDiskManager) MakeGlobalPDName(rbd rbd) string {
   152  	return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
   153  }
   154  
   155  func (fake *fakeDiskManager) MakeGlobalVDPDName(rbd rbd) string {
   156  	return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
   157  }
   158  
   159  func (fake *fakeDiskManager) DetachDisk(r *rbdPlugin, deviceMountPath string, device string) error {
   160  	fake.mutex.Lock()
   161  	defer fake.mutex.Unlock()
   162  	ok := fake.rbdDevices[device]
   163  	if !ok {
   164  		return fmt.Errorf("rbd: failed to detach device %s, it does not exist", device)
   165  	}
   166  	delete(fake.rbdDevices, device)
   167  	return nil
   168  }
   169  
   170  func (fake *fakeDiskManager) DetachBlockDisk(r rbdDiskUnmapper, device string) error {
   171  	fake.mutex.Lock()
   172  	defer fake.mutex.Unlock()
   173  	ok := fake.rbdDevices[device]
   174  	if !ok {
   175  		return fmt.Errorf("rbd: failed to detach device %s, it does not exist", device)
   176  	}
   177  	delete(fake.rbdDevices, device)
   178  	return nil
   179  }
   180  
   181  func (fake *fakeDiskManager) CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, volumeSizeGB int, err error) {
   182  	return nil, 0, fmt.Errorf("not implemented")
   183  }
   184  
   185  func (fake *fakeDiskManager) DeleteImage(deleter *rbdVolumeDeleter) error {
   186  	return fmt.Errorf("not implemented")
   187  }
   188  
   189  func (fake *fakeDiskManager) Fencing(r rbdMounter, nodeName string) error {
   190  	fake.mutex.Lock()
   191  	defer fake.mutex.Unlock()
   192  	key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
   193  	isLocked, ok := fake.rbdImageLocks[key]
   194  	if ok && isLocked {
   195  		// not expected in testing
   196  		return fmt.Errorf("%s is already locked", key)
   197  	}
   198  	fake.rbdImageLocks[key] = true
   199  	return nil
   200  }
   201  
   202  func (fake *fakeDiskManager) Defencing(r rbdMounter, nodeName string) error {
   203  	fake.mutex.Lock()
   204  	defer fake.mutex.Unlock()
   205  	key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
   206  	isLocked, ok := fake.rbdImageLocks[key]
   207  	if !ok || !isLocked {
   208  		// not expected in testing
   209  		return fmt.Errorf("%s is not locked", key)
   210  	}
   211  	delete(fake.rbdImageLocks, key)
   212  	return nil
   213  }
   214  
   215  func (fake *fakeDiskManager) IsLocked(r rbdMounter, nodeName string) (bool, error) {
   216  	fake.mutex.RLock()
   217  	defer fake.mutex.RUnlock()
   218  	key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
   219  	isLocked, ok := fake.rbdImageLocks[key]
   220  	return ok && isLocked, nil
   221  }
   222  
   223  func (fake *fakeDiskManager) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
   224  	return resource.Quantity{}, fmt.Errorf("not implemented")
   225  }
   226  
   227  // checkMounterLog checks fakeMounter must have expected logs, and the last action msut equal to expectedAction.
   228  func checkMounterLog(t *testing.T, fakeMounter *mount.FakeMounter, expected int, expectedAction mount.FakeAction) {
   229  	log := fakeMounter.GetLog()
   230  	if len(log) != expected {
   231  		t.Fatalf("fakeMounter should have %d logs, actual: %d", expected, len(log))
   232  	}
   233  	lastIndex := len(log) - 1
   234  	lastAction := log[lastIndex]
   235  	if !reflect.DeepEqual(expectedAction, lastAction) {
   236  		t.Fatalf("fakeMounter.Log[%d] should be %#v, not: %#v", lastIndex, expectedAction, lastAction)
   237  	}
   238  }
   239  
   240  func doTestPlugin(t *testing.T, c *testcase) {
   241  	fakeVolumeHost := volumetest.NewFakeKubeletVolumeHost(t, c.root, nil, nil)
   242  	plugMgr := volume.VolumePluginMgr{}
   243  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, fakeVolumeHost)
   244  	plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
   245  	if err != nil {
   246  		t.Fatal("Can't find the plugin by name")
   247  	}
   248  	fakeMounter := fakeVolumeHost.GetMounter(plug.GetPluginName()).(*mount.FakeMounter)
   249  	fakeNodeName := types.NodeName("localhost")
   250  	fdm := newFakeDiskManager()
   251  
   252  	// attacher
   253  	attacher, err := plug.(*rbdPlugin).newAttacherInternal(fdm)
   254  	if err != nil {
   255  		t.Errorf("Failed to make a new Attacher: %v", err)
   256  	}
   257  	deviceAttachPath, err := attacher.Attach(c.spec, fakeNodeName)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  	devicePath, err := attacher.WaitForAttach(c.spec, deviceAttachPath, c.pod, time.Second*10)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	if devicePath != c.expectedDevicePath {
   266  		t.Errorf("Unexpected path, expected %q, not: %q", c.expectedDevicePath, devicePath)
   267  	}
   268  	deviceMountPath, err := attacher.GetDeviceMountPath(c.spec)
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if deviceMountPath != c.expectedDeviceMountPath {
   273  		t.Errorf("Unexpected mount path, expected %q, not: %q", c.expectedDeviceMountPath, deviceMountPath)
   274  	}
   275  	err = attacher.MountDevice(c.spec, devicePath, deviceMountPath, volume.DeviceMounterArgs{})
   276  	if err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	if _, err := os.Stat(deviceMountPath); err != nil {
   280  		if os.IsNotExist(err) {
   281  			t.Errorf("Attacher.MountDevice() failed, device mount path not created: %s", deviceMountPath)
   282  		} else {
   283  			t.Errorf("Attacher.MountDevice() failed: %v", err)
   284  		}
   285  	}
   286  	loggedSource, err := getLoggedSource(devicePath)
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	checkMounterLog(t, fakeMounter, 1, mount.FakeAction{Action: "mount", Target: c.expectedDeviceMountPath, Source: loggedSource, FSType: "ext4"})
   291  
   292  	// mounter
   293  	mounter, err := plug.(*rbdPlugin).newMounterInternal(c.spec, c.pod.UID, fdm, "secrets")
   294  	if err != nil {
   295  		t.Errorf("Failed to make a new Mounter: %v", err)
   296  	}
   297  	if mounter == nil {
   298  		t.Error("Got a nil Mounter")
   299  	}
   300  	path := mounter.GetPath()
   301  	if path != c.expectedPodMountPath {
   302  		t.Errorf("Unexpected path, expected %q, got: %q", c.expectedPodMountPath, path)
   303  	}
   304  
   305  	if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
   306  		t.Errorf("Expected success, got: %v", err)
   307  	}
   308  	if _, err := os.Stat(path); err != nil {
   309  		if os.IsNotExist(err) {
   310  			t.Errorf("SetUp() failed, volume path not created: %s", path)
   311  		} else {
   312  			t.Errorf("SetUp() failed: %v", err)
   313  		}
   314  	}
   315  	checkMounterLog(t, fakeMounter, 2, mount.FakeAction{Action: "mount", Target: c.expectedPodMountPath, Source: loggedSource, FSType: ""})
   316  
   317  	// unmounter
   318  	unmounter, err := plug.(*rbdPlugin).newUnmounterInternal(c.spec.Name(), c.pod.UID, fdm)
   319  	if err != nil {
   320  		t.Errorf("Failed to make a new Unmounter: %v", err)
   321  	}
   322  	if unmounter == nil {
   323  		t.Error("Got a nil Unmounter")
   324  	}
   325  
   326  	if err := unmounter.TearDown(); err != nil {
   327  		t.Errorf("Expected success, got: %v", err)
   328  	}
   329  	if _, err := os.Stat(path); err == nil {
   330  		t.Errorf("TearDown() failed, volume path still exists: %s", path)
   331  	} else if !os.IsNotExist(err) {
   332  		t.Errorf("TearDown() failed: %v", err)
   333  	}
   334  	checkMounterLog(t, fakeMounter, 3, mount.FakeAction{Action: "unmount", Target: c.expectedPodMountPath, Source: "", FSType: ""})
   335  
   336  	// detacher
   337  	detacher, err := plug.(*rbdPlugin).newDetacherInternal(fdm)
   338  	if err != nil {
   339  		t.Errorf("Failed to make a new Attacher: %v", err)
   340  	}
   341  	err = detacher.UnmountDevice(deviceMountPath)
   342  	if err != nil {
   343  		t.Fatalf("Detacher.UnmountDevice failed to unmount %s", deviceMountPath)
   344  	}
   345  	checkMounterLog(t, fakeMounter, 4, mount.FakeAction{Action: "unmount", Target: c.expectedDeviceMountPath, Source: "", FSType: ""})
   346  	err = detacher.Detach(deviceMountPath, fakeNodeName)
   347  	if err != nil {
   348  		t.Fatalf("Detacher.Detach failed to detach %s from %s", deviceMountPath, fakeNodeName)
   349  	}
   350  }
   351  
   352  type testcase struct {
   353  	spec                    *volume.Spec
   354  	root                    string
   355  	pod                     *v1.Pod
   356  	expectedDevicePath      string
   357  	expectedDeviceMountPath string
   358  	expectedPodMountPath    string
   359  }
   360  
   361  func TestPlugin(t *testing.T) {
   362  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   363  	if err != nil {
   364  		t.Fatalf("error creating temp dir: %v", err)
   365  	}
   366  	defer os.RemoveAll(tmpDir)
   367  	tmpDir, err = filepath.EvalSymlinks(tmpDir)
   368  	if err != nil {
   369  		t.Fatal(err)
   370  	}
   371  
   372  	expectedDevicePath := "/dev/rbd0"
   373  	if runtime.GOOS == "windows" {
   374  		// Windows expects Disk Numbers.
   375  		expectedDevicePath = "0"
   376  	}
   377  
   378  	podUID := uuid.NewUUID()
   379  	var cases []*testcase
   380  	cases = append(cases, &testcase{
   381  		spec: volume.NewSpecFromVolume(&v1.Volume{
   382  			Name: "vol1",
   383  			VolumeSource: v1.VolumeSource{
   384  				RBD: &v1.RBDVolumeSource{
   385  					CephMonitors: []string{"a", "b"},
   386  					RBDPool:      "pool1",
   387  					RBDImage:     "image1",
   388  					FSType:       "ext4",
   389  				},
   390  			},
   391  		}),
   392  		root: tmpDir,
   393  		pod: &v1.Pod{
   394  			ObjectMeta: metav1.ObjectMeta{
   395  				Name:      "testpod",
   396  				Namespace: "testns",
   397  				UID:       podUID,
   398  			},
   399  		},
   400  		expectedDevicePath:      expectedDevicePath,
   401  		expectedDeviceMountPath: filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts/pool1-image-image1"),
   402  		expectedPodMountPath:    filepath.Join(tmpDir, "pods", string(podUID), "volumes/kubernetes.io~rbd/vol1"),
   403  	})
   404  	cases = append(cases, &testcase{
   405  		spec: volume.NewSpecFromPersistentVolume(&v1.PersistentVolume{
   406  			ObjectMeta: metav1.ObjectMeta{
   407  				Name: "vol2",
   408  			},
   409  			Spec: v1.PersistentVolumeSpec{
   410  				PersistentVolumeSource: v1.PersistentVolumeSource{
   411  					RBD: &v1.RBDPersistentVolumeSource{
   412  						CephMonitors: []string{"a", "b"},
   413  						RBDPool:      "pool2",
   414  						RBDImage:     "image2",
   415  						FSType:       "ext4",
   416  					},
   417  				},
   418  				AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany},
   419  			},
   420  		}, false),
   421  		root: tmpDir,
   422  		pod: &v1.Pod{
   423  			ObjectMeta: metav1.ObjectMeta{
   424  				Name:      "testpod",
   425  				Namespace: "testns",
   426  				UID:       podUID,
   427  			},
   428  		},
   429  		expectedDevicePath:      expectedDevicePath,
   430  		expectedDeviceMountPath: filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts/pool2-image-image2"),
   431  		expectedPodMountPath:    filepath.Join(tmpDir, "pods", string(podUID), "volumes/kubernetes.io~rbd/vol2"),
   432  	})
   433  
   434  	for i := 0; i < len(cases); i++ {
   435  		doTestPlugin(t, cases[i])
   436  	}
   437  }
   438  
   439  func TestPersistentClaimReadOnlyFlag(t *testing.T) {
   440  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   441  	if err != nil {
   442  		t.Fatalf("error creating temp dir: %v", err)
   443  	}
   444  	defer os.RemoveAll(tmpDir)
   445  
   446  	pv := &v1.PersistentVolume{
   447  		ObjectMeta: metav1.ObjectMeta{
   448  			Name: "pvA",
   449  		},
   450  		Spec: v1.PersistentVolumeSpec{
   451  			PersistentVolumeSource: v1.PersistentVolumeSource{
   452  				RBD: &v1.RBDPersistentVolumeSource{
   453  					CephMonitors: []string{"a", "b"},
   454  					RBDImage:     "bar",
   455  					FSType:       "ext4",
   456  				},
   457  			},
   458  			ClaimRef: &v1.ObjectReference{
   459  				Name: "claimA",
   460  			},
   461  		},
   462  	}
   463  
   464  	claim := &v1.PersistentVolumeClaim{
   465  		ObjectMeta: metav1.ObjectMeta{
   466  			Name:      "claimA",
   467  			Namespace: "nsA",
   468  		},
   469  		Spec: v1.PersistentVolumeClaimSpec{
   470  			VolumeName: "pvA",
   471  		},
   472  		Status: v1.PersistentVolumeClaimStatus{
   473  			Phase: v1.ClaimBound,
   474  		},
   475  	}
   476  
   477  	client := fake.NewSimpleClientset(pv, claim)
   478  
   479  	plugMgr := volume.VolumePluginMgr{}
   480  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeKubeletVolumeHost(t, tmpDir, client, nil))
   481  	plug, _ := plugMgr.FindPluginByName(rbdPluginName)
   482  
   483  	// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
   484  	spec := volume.NewSpecFromPersistentVolume(pv, true)
   485  	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
   486  	mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
   487  	if mounter == nil {
   488  		t.Fatalf("Got a nil Mounter")
   489  	}
   490  
   491  	if !mounter.GetAttributes().ReadOnly {
   492  		t.Errorf("Expected true for mounter.IsReadOnly")
   493  	}
   494  }
   495  
   496  func TestGetSecretNameAndNamespace(t *testing.T) {
   497  	secretName := "test-secret-name"
   498  	secretNamespace := "test-secret-namespace"
   499  
   500  	volSpec := &volume.Spec{
   501  		PersistentVolume: &v1.PersistentVolume{
   502  			Spec: v1.PersistentVolumeSpec{
   503  				PersistentVolumeSource: v1.PersistentVolumeSource{
   504  					RBD: &v1.RBDPersistentVolumeSource{
   505  						CephMonitors: []string{"a", "b"},
   506  						RBDImage:     "bar",
   507  						FSType:       "ext4",
   508  					},
   509  				},
   510  			},
   511  		},
   512  	}
   513  
   514  	secretRef := new(v1.SecretReference)
   515  	secretRef.Name = secretName
   516  	secretRef.Namespace = secretNamespace
   517  	volSpec.PersistentVolume.Spec.PersistentVolumeSource.RBD.SecretRef = secretRef
   518  
   519  	foundSecretName, foundSecretNamespace, err := getSecretNameAndNamespace(volSpec, "default")
   520  	if err != nil {
   521  		t.Errorf("getSecretNameAndNamespace failed to get Secret's name and namespace: %v", err)
   522  	}
   523  	if strings.Compare(secretName, foundSecretName) != 0 || strings.Compare(secretNamespace, foundSecretNamespace) != 0 {
   524  		t.Errorf("getSecretNameAndNamespace returned incorrect values, expected %s and %s but got %s and %s", secretName, secretNamespace, foundSecretName, foundSecretNamespace)
   525  	}
   526  }
   527  
   528  // https://github.com/kubernetes/kubernetes/issues/57744
   529  func TestGetDeviceMountPath(t *testing.T) {
   530  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   531  	if err != nil {
   532  		t.Fatalf("error creating temp dir: %v", err)
   533  	}
   534  	defer os.RemoveAll(tmpDir)
   535  
   536  	fakeVolumeHost := volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)
   537  	plugMgr := volume.VolumePluginMgr{}
   538  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, fakeVolumeHost)
   539  	plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
   540  	if err != nil {
   541  		t.Errorf("Can't find the plugin by name")
   542  	}
   543  	fdm := newFakeDiskManager()
   544  
   545  	// attacher
   546  	attacher, err := plug.(*rbdPlugin).newAttacherInternal(fdm)
   547  	if err != nil {
   548  		t.Errorf("Failed to make a new Attacher: %v", err)
   549  	}
   550  
   551  	pool, image := "pool", "image"
   552  	spec := volume.NewSpecFromVolume(&v1.Volume{
   553  		Name: "vol",
   554  		VolumeSource: v1.VolumeSource{
   555  			RBD: &v1.RBDVolumeSource{
   556  				CephMonitors: []string{"a", "b"},
   557  				RBDPool:      pool,
   558  				RBDImage:     image,
   559  				FSType:       "ext4",
   560  			},
   561  		},
   562  	})
   563  
   564  	deprecatedDir := filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/rbd/rbd/%s-image-%s", pool, image))
   565  	canonicalDir := filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/rbd/mounts/%s-image-%s", pool, image))
   566  
   567  	type testCase struct {
   568  		deprecated bool
   569  		targetPath string
   570  	}
   571  	for _, c := range []testCase{
   572  		{false, canonicalDir},
   573  		{true, deprecatedDir},
   574  	} {
   575  		if c.deprecated {
   576  			// This is a deprecated device mount path, we create it,
   577  			// and hope attacher.GetDeviceMountPath return c.targetPath.
   578  			if err := os.MkdirAll(c.targetPath, 0700); err != nil {
   579  				t.Fatalf("Create deprecated mount path failed: %v", err)
   580  			}
   581  		}
   582  		mountPath, err := attacher.GetDeviceMountPath(spec)
   583  		if err != nil {
   584  			t.Fatalf("GetDeviceMountPath failed: %v", err)
   585  		}
   586  		if mountPath != c.targetPath {
   587  			t.Errorf("Mismatch device mount path: wanted %s, got %s", c.targetPath, mountPath)
   588  		}
   589  	}
   590  }
   591  
   592  // https://github.com/kubernetes/kubernetes/issues/57744
   593  func TestConstructVolumeSpec(t *testing.T) {
   594  	if runtime.GOOS == "darwin" {
   595  		t.Skipf("TestConstructVolumeSpec is not supported on GOOS=%s", runtime.GOOS)
   596  	}
   597  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   598  	if err != nil {
   599  		t.Fatalf("error creating temp dir: %v", err)
   600  	}
   601  	defer os.RemoveAll(tmpDir)
   602  
   603  	fakeVolumeHost := volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)
   604  	plugMgr := volume.VolumePluginMgr{}
   605  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, fakeVolumeHost)
   606  	plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
   607  	if err != nil {
   608  		t.Fatal("Can't find the plugin by name")
   609  	}
   610  	fakeMounter := fakeVolumeHost.GetMounter(plug.GetPluginName()).(*mount.FakeMounter)
   611  
   612  	pool, image, volumeName := "pool", "image", "vol"
   613  	podMountPath := filepath.Join(tmpDir, "pods/pod123/volumes/kubernetes.io~rbd", volumeName)
   614  	deprecatedDir := filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/rbd", fmt.Sprintf("%s-image-%s", pool, image))
   615  	canonicalDir := filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts", fmt.Sprintf("%s-image-%s", pool, image))
   616  
   617  	type testCase struct {
   618  		volumeName string
   619  		targetPath string
   620  	}
   621  
   622  	for _, c := range []testCase{
   623  		{"vol", canonicalDir},
   624  		{"vol", deprecatedDir},
   625  	} {
   626  		if err := os.MkdirAll(c.targetPath, 0700); err != nil {
   627  			t.Fatalf("Create mount path %s failed: %v", c.targetPath, err)
   628  		}
   629  		if err = fakeMounter.Mount("/dev/rbd0", c.targetPath, "fake", nil); err != nil {
   630  			t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
   631  		}
   632  		if err = fakeMounter.Mount(c.targetPath, podMountPath, "fake", []string{"bind"}); err != nil {
   633  			t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
   634  		}
   635  		rec, err := plug.ConstructVolumeSpec(c.volumeName, podMountPath)
   636  		if err != nil {
   637  			t.Errorf("ConstructVolumeSpec failed: %v", err)
   638  		} else {
   639  			if rec.Spec.Volume.RBD.RBDPool != pool {
   640  				t.Errorf("Mismatch rbd pool: wanted %s, got %s", pool, rec.Spec.Volume.RBD.RBDPool)
   641  			}
   642  			if rec.Spec.Volume.RBD.RBDImage != image {
   643  				t.Fatalf("Mismatch rbd image: wanted %s, got %s", image, rec.Spec.Volume.RBD.RBDImage)
   644  			}
   645  		}
   646  		if err = fakeMounter.Unmount(podMountPath); err != nil {
   647  			t.Fatalf("Unmount pod path %s failed: %v", podMountPath, err)
   648  		}
   649  		if err = fakeMounter.Unmount(c.targetPath); err != nil {
   650  			t.Fatalf("Unmount device path %s failed: %v", c.targetPath, err)
   651  		}
   652  	}
   653  }
   654  
   655  func TestGetAccessModes(t *testing.T) {
   656  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   657  	if err != nil {
   658  		t.Fatalf("error creating temp dir: %v", err)
   659  	}
   660  	defer os.RemoveAll(tmpDir)
   661  
   662  	plugMgr := volume.VolumePluginMgr{}
   663  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
   664  
   665  	plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/rbd")
   666  	if err != nil {
   667  		t.Errorf("Can't find the plugin by name")
   668  	}
   669  	modes := plug.GetAccessModes()
   670  	for _, v := range modes {
   671  		if !volumetest.ContainsAccessMode(modes, v) {
   672  			t.Errorf("Expected AccessModeTypes: %s", v)
   673  		}
   674  	}
   675  }
   676  
   677  func TestRequiresRemount(t *testing.T) {
   678  	tmpDir, _ := utiltesting.MkTmpdir("rbd_test")
   679  	defer os.RemoveAll(tmpDir)
   680  	plugMgr := volume.VolumePluginMgr{}
   681  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
   682  	plug, _ := plugMgr.FindPluginByName("kubernetes.io/rbd")
   683  	has := plug.RequiresRemount(nil)
   684  	if has {
   685  		t.Errorf("Expected RequiresRemount to be false, got %t", has)
   686  	}
   687  }
   688  
   689  func TestGetRbdImageSize(t *testing.T) {
   690  	for i, c := range []struct {
   691  		Output     string
   692  		TargetSize int
   693  	}{
   694  		{
   695  			Output:     `{"name":"kubernetes-dynamic-pvc-18e7a4d9-050d-11e9-b905-548998f3478f","size":10737418240,"objects":2560,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.9f4ff7238e1f29","format":2}`,
   696  			TargetSize: 10240,
   697  		},
   698  		{
   699  			Output:     `{"name":"kubernetes-dynamic-pvc-070635bf-e33f-11e8-aab7-548998f3478f","size":1073741824,"objects":256,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.670ac4238e1f29","format":2}`,
   700  			TargetSize: 1024,
   701  		},
   702  	} {
   703  		size, err := getRbdImageSize([]byte(c.Output))
   704  		if err != nil {
   705  			t.Errorf("Case %d: getRbdImageSize failed: %v", i, err)
   706  			continue
   707  		}
   708  		if size != c.TargetSize {
   709  			t.Errorf("Case %d: unexpected size, wanted %d, got %d", i, c.TargetSize, size)
   710  		}
   711  	}
   712  }
   713  
   714  func TestGetRbdImageInfo(t *testing.T) {
   715  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   716  	if err != nil {
   717  		t.Fatalf("error creating temp dir: %v", err)
   718  	}
   719  	defer os.RemoveAll(tmpDir)
   720  
   721  	for i, c := range []struct {
   722  		DeviceMountPath    string
   723  		TargetRbdImageInfo *rbdImageInfo
   724  	}{
   725  		{
   726  			DeviceMountPath:    fmt.Sprintf("%s/plugins/kubernetes.io/rbd/rbd/pool1-image-image1", tmpDir),
   727  			TargetRbdImageInfo: &rbdImageInfo{pool: "pool1", name: "image1"},
   728  		},
   729  		{
   730  			DeviceMountPath:    fmt.Sprintf("%s/plugins/kubernetes.io/rbd/mounts/pool2-image-image2", tmpDir),
   731  			TargetRbdImageInfo: &rbdImageInfo{pool: "pool2", name: "image2"},
   732  		},
   733  	} {
   734  		rbdImageInfo, err := getRbdImageInfo(c.DeviceMountPath)
   735  		if err != nil {
   736  			t.Errorf("Case %d: getRbdImageInfo failed: %v", i, err)
   737  			continue
   738  		}
   739  		if !reflect.DeepEqual(rbdImageInfo, c.TargetRbdImageInfo) {
   740  			t.Errorf("Case %d: unexpected RbdImageInfo, wanted %v, got %v", i, c.TargetRbdImageInfo, rbdImageInfo)
   741  		}
   742  	}
   743  }
   744  
   745  func TestUnsupportedVolumeHost(t *testing.T) {
   746  	tmpDir, err := utiltesting.MkTmpdir("rbd_test")
   747  	if err != nil {
   748  		t.Fatalf("error creating temp dir: %v", err)
   749  	}
   750  	defer os.RemoveAll(tmpDir)
   751  
   752  	plugMgr := volume.VolumePluginMgr{}
   753  	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
   754  
   755  	plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
   756  	if err != nil {
   757  		t.Fatal("Can't find the plugin by name")
   758  	}
   759  
   760  	_, err = plug.ConstructVolumeSpec("", "")
   761  	if err == nil {
   762  		t.Errorf("Expected failure constructing volume spec with unsupported VolumeHost")
   763  	}
   764  }
   765  

View as plain text