...

Source file src/k8s.io/kubernetes/pkg/volume/secret/secret_test.go

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

     1  /*
     2  Copyright 2015 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 secret
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"reflect"
    25  	"runtime"
    26  	"strings"
    27  	"testing"
    28  
    29  	"k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	clientset "k8s.io/client-go/kubernetes"
    33  	"k8s.io/client-go/kubernetes/fake"
    34  	"k8s.io/kubernetes/pkg/volume"
    35  	"k8s.io/kubernetes/pkg/volume/emptydir"
    36  	volumetest "k8s.io/kubernetes/pkg/volume/testing"
    37  	"k8s.io/kubernetes/pkg/volume/util"
    38  
    39  	"github.com/stretchr/testify/assert"
    40  )
    41  
    42  func TestMakePayload(t *testing.T) {
    43  	caseMappingMode := int32(0400)
    44  	cases := []struct {
    45  		name     string
    46  		mappings []v1.KeyToPath
    47  		secret   *v1.Secret
    48  		mode     int32
    49  		optional bool
    50  		payload  map[string]util.FileProjection
    51  		success  bool
    52  	}{
    53  		{
    54  			name: "no overrides",
    55  			secret: &v1.Secret{
    56  				Data: map[string][]byte{
    57  					"foo": []byte("foo"),
    58  					"bar": []byte("bar"),
    59  				},
    60  			},
    61  			mode: 0644,
    62  			payload: map[string]util.FileProjection{
    63  				"foo": {Data: []byte("foo"), Mode: 0644},
    64  				"bar": {Data: []byte("bar"), Mode: 0644},
    65  			},
    66  			success: true,
    67  		},
    68  		{
    69  			name: "basic 1",
    70  			mappings: []v1.KeyToPath{
    71  				{
    72  					Key:  "foo",
    73  					Path: "path/to/foo.txt",
    74  				},
    75  			},
    76  			secret: &v1.Secret{
    77  				Data: map[string][]byte{
    78  					"foo": []byte("foo"),
    79  					"bar": []byte("bar"),
    80  				},
    81  			},
    82  			mode: 0644,
    83  			payload: map[string]util.FileProjection{
    84  				"path/to/foo.txt": {Data: []byte("foo"), Mode: 0644},
    85  			},
    86  			success: true,
    87  		},
    88  		{
    89  			name: "subdirs",
    90  			mappings: []v1.KeyToPath{
    91  				{
    92  					Key:  "foo",
    93  					Path: "path/to/1/2/3/foo.txt",
    94  				},
    95  			},
    96  			secret: &v1.Secret{
    97  				Data: map[string][]byte{
    98  					"foo": []byte("foo"),
    99  					"bar": []byte("bar"),
   100  				},
   101  			},
   102  			mode: 0644,
   103  			payload: map[string]util.FileProjection{
   104  				"path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
   105  			},
   106  			success: true,
   107  		},
   108  		{
   109  			name: "subdirs 2",
   110  			mappings: []v1.KeyToPath{
   111  				{
   112  					Key:  "foo",
   113  					Path: "path/to/1/2/3/foo.txt",
   114  				},
   115  			},
   116  			secret: &v1.Secret{
   117  				Data: map[string][]byte{
   118  					"foo": []byte("foo"),
   119  					"bar": []byte("bar"),
   120  				},
   121  			},
   122  			mode: 0644,
   123  			payload: map[string]util.FileProjection{
   124  				"path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
   125  			},
   126  			success: true,
   127  		},
   128  		{
   129  			name: "subdirs 3",
   130  			mappings: []v1.KeyToPath{
   131  				{
   132  					Key:  "foo",
   133  					Path: "path/to/1/2/3/foo.txt",
   134  				},
   135  				{
   136  					Key:  "bar",
   137  					Path: "another/path/to/the/esteemed/bar.bin",
   138  				},
   139  			},
   140  			secret: &v1.Secret{
   141  				Data: map[string][]byte{
   142  					"foo": []byte("foo"),
   143  					"bar": []byte("bar"),
   144  				},
   145  			},
   146  			mode: 0644,
   147  			payload: map[string]util.FileProjection{
   148  				"path/to/1/2/3/foo.txt":                {Data: []byte("foo"), Mode: 0644},
   149  				"another/path/to/the/esteemed/bar.bin": {Data: []byte("bar"), Mode: 0644},
   150  			},
   151  			success: true,
   152  		},
   153  		{
   154  			name: "non existent key",
   155  			mappings: []v1.KeyToPath{
   156  				{
   157  					Key:  "zab",
   158  					Path: "path/to/foo.txt",
   159  				},
   160  			},
   161  			secret: &v1.Secret{
   162  				Data: map[string][]byte{
   163  					"foo": []byte("foo"),
   164  					"bar": []byte("bar"),
   165  				},
   166  			},
   167  			mode:    0644,
   168  			success: false,
   169  		},
   170  		{
   171  			name: "mapping with Mode",
   172  			mappings: []v1.KeyToPath{
   173  				{
   174  					Key:  "foo",
   175  					Path: "foo.txt",
   176  					Mode: &caseMappingMode,
   177  				},
   178  				{
   179  					Key:  "bar",
   180  					Path: "bar.bin",
   181  					Mode: &caseMappingMode,
   182  				},
   183  			},
   184  			secret: &v1.Secret{
   185  				Data: map[string][]byte{
   186  					"foo": []byte("foo"),
   187  					"bar": []byte("bar"),
   188  				},
   189  			},
   190  			mode: 0644,
   191  			payload: map[string]util.FileProjection{
   192  				"foo.txt": {Data: []byte("foo"), Mode: caseMappingMode},
   193  				"bar.bin": {Data: []byte("bar"), Mode: caseMappingMode},
   194  			},
   195  			success: true,
   196  		},
   197  		{
   198  			name: "mapping with defaultMode",
   199  			mappings: []v1.KeyToPath{
   200  				{
   201  					Key:  "foo",
   202  					Path: "foo.txt",
   203  				},
   204  				{
   205  					Key:  "bar",
   206  					Path: "bar.bin",
   207  				},
   208  			},
   209  			secret: &v1.Secret{
   210  				Data: map[string][]byte{
   211  					"foo": []byte("foo"),
   212  					"bar": []byte("bar"),
   213  				},
   214  			},
   215  			mode: 0644,
   216  			payload: map[string]util.FileProjection{
   217  				"foo.txt": {Data: []byte("foo"), Mode: 0644},
   218  				"bar.bin": {Data: []byte("bar"), Mode: 0644},
   219  			},
   220  			success: true,
   221  		},
   222  		{
   223  			name: "optional non existent key",
   224  			mappings: []v1.KeyToPath{
   225  				{
   226  					Key:  "zab",
   227  					Path: "path/to/foo.txt",
   228  				},
   229  			},
   230  			secret: &v1.Secret{
   231  				Data: map[string][]byte{
   232  					"foo": []byte("foo"),
   233  					"bar": []byte("bar"),
   234  				},
   235  			},
   236  			mode:     0644,
   237  			optional: true,
   238  			payload:  map[string]util.FileProjection{},
   239  			success:  true,
   240  		},
   241  	}
   242  
   243  	for _, tc := range cases {
   244  		actualPayload, err := MakePayload(tc.mappings, tc.secret, &tc.mode, tc.optional)
   245  		if err != nil && tc.success {
   246  			t.Errorf("%v: unexpected failure making payload: %v", tc.name, err)
   247  			continue
   248  		}
   249  
   250  		if err == nil && !tc.success {
   251  			t.Errorf("%v: unexpected success making payload", tc.name)
   252  			continue
   253  		}
   254  
   255  		if !tc.success {
   256  			continue
   257  		}
   258  
   259  		if e, a := tc.payload, actualPayload; !reflect.DeepEqual(e, a) {
   260  			t.Errorf("%v: expected and actual payload do not match", tc.name)
   261  		}
   262  	}
   263  }
   264  
   265  func newTestHost(t *testing.T, clientset clientset.Interface) (string, volume.VolumeHost) {
   266  	tempDir, err := ioutil.TempDir("", "secret_volume_test.")
   267  	if err != nil {
   268  		t.Fatalf("can't make a temp rootdir: %v", err)
   269  	}
   270  
   271  	return tempDir, volumetest.NewFakeVolumeHost(t, tempDir, clientset, emptydir.ProbeVolumePlugins())
   272  }
   273  
   274  func TestCanSupport(t *testing.T) {
   275  	pluginMgr := volume.VolumePluginMgr{}
   276  	tempDir, host := newTestHost(t, nil)
   277  	defer os.RemoveAll(tempDir)
   278  	pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
   279  
   280  	plugin, err := pluginMgr.FindPluginByName(secretPluginName)
   281  	if err != nil {
   282  		t.Fatal("Can't find the plugin by name")
   283  	}
   284  	if plugin.GetPluginName() != secretPluginName {
   285  		t.Errorf("Wrong name: %s", plugin.GetPluginName())
   286  	}
   287  	if !plugin.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: ""}}}}) {
   288  		t.Errorf("Expected true")
   289  	}
   290  	if plugin.CanSupport(&volume.Spec{}) {
   291  		t.Errorf("Expected false")
   292  	}
   293  }
   294  
   295  func TestPlugin(t *testing.T) {
   296  	var (
   297  		testPodUID     = types.UID("test_pod_uid")
   298  		testVolumeName = "test_volume_name"
   299  		testNamespace  = "test_secret_namespace"
   300  		testName       = "test_secret_name"
   301  
   302  		volumeSpec    = volumeSpec(testVolumeName, testName, 0644)
   303  		secret        = secret(testNamespace, testName)
   304  		client        = fake.NewSimpleClientset(&secret)
   305  		pluginMgr     = volume.VolumePluginMgr{}
   306  		rootDir, host = newTestHost(t, client)
   307  	)
   308  	defer os.RemoveAll(rootDir)
   309  	pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
   310  
   311  	plugin, err := pluginMgr.FindPluginByName(secretPluginName)
   312  	if err != nil {
   313  		t.Fatal("Can't find the plugin by name")
   314  	}
   315  
   316  	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
   317  	mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
   318  	if err != nil {
   319  		t.Errorf("Failed to make a new Mounter: %v", err)
   320  	}
   321  	if mounter == nil {
   322  		t.Fatalf("Got a nil Mounter")
   323  	}
   324  
   325  	volumePath := mounter.GetPath()
   326  	if !hasPathSuffix(volumePath, "pods/test_pod_uid/volumes/kubernetes.io~secret/test_volume_name") {
   327  		t.Errorf("Got unexpected path: %s", volumePath)
   328  	}
   329  
   330  	err = mounter.SetUp(volume.MounterArgs{})
   331  	if err != nil {
   332  		t.Errorf("Failed to setup volume: %v", err)
   333  	}
   334  	if _, err := os.Stat(volumePath); err != nil {
   335  		if os.IsNotExist(err) {
   336  			t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
   337  		} else {
   338  			t.Errorf("SetUp() failed: %v", err)
   339  		}
   340  	}
   341  
   342  	// secret volume should create its own empty wrapper path
   343  	podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir)
   344  
   345  	if _, err := os.Stat(podWrapperMetadataDir); err != nil {
   346  		if os.IsNotExist(err) {
   347  			t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)
   348  		} else {
   349  			t.Errorf("SetUp() failed: %v", err)
   350  		}
   351  	}
   352  	doTestSecretDataInVolume(volumePath, secret, t)
   353  	defer doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
   354  
   355  	// Metrics only supported on linux
   356  	metrics, err := mounter.GetMetrics()
   357  	if runtime.GOOS == "linux" {
   358  		assert.NotEmpty(t, metrics)
   359  		assert.NoError(t, err)
   360  	} else {
   361  		t.Skipf("Volume metrics not supported on %s", runtime.GOOS)
   362  	}
   363  }
   364  
   365  func TestInvalidPathSecret(t *testing.T) {
   366  	var (
   367  		testPodUID     = types.UID("test_pod_uid")
   368  		testVolumeName = "test_volume_name"
   369  		testNamespace  = "test_secret_namespace"
   370  		testName       = "test_secret_name"
   371  
   372  		volumeSpec    = volumeSpec(testVolumeName, testName, 0644)
   373  		secret        = secret(testNamespace, testName)
   374  		client        = fake.NewSimpleClientset(&secret)
   375  		pluginMgr     = volume.VolumePluginMgr{}
   376  		rootDir, host = newTestHost(t, client)
   377  	)
   378  	volumeSpec.Secret.Items = []v1.KeyToPath{
   379  		{Key: "missing", Path: "missing"},
   380  	}
   381  
   382  	defer os.RemoveAll(rootDir)
   383  	pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
   384  
   385  	plugin, err := pluginMgr.FindPluginByName(secretPluginName)
   386  	if err != nil {
   387  		t.Fatal("Can't find the plugin by name")
   388  	}
   389  
   390  	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
   391  	mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
   392  	if err != nil {
   393  		t.Errorf("Failed to make a new Mounter: %v", err)
   394  	}
   395  	if mounter == nil {
   396  		t.Fatalf("Got a nil Mounter")
   397  	}
   398  
   399  	volumePath := mounter.GetPath()
   400  	if !hasPathSuffix(volumePath, "pods/test_pod_uid/volumes/kubernetes.io~secret/test_volume_name") {
   401  		t.Errorf("Got unexpected path: %s", volumePath)
   402  	}
   403  
   404  	var mounterArgs volume.MounterArgs
   405  	err = mounter.SetUp(mounterArgs)
   406  	if err == nil {
   407  		t.Errorf("Expected error while setting up secret")
   408  	}
   409  
   410  	_, err = os.Stat(volumePath)
   411  	if err == nil {
   412  		t.Errorf("Expected path %s to not exist", volumePath)
   413  	}
   414  }
   415  
   416  // Test the case where the plugin's ready file exists, but the volume dir is not a
   417  // mountpoint, which is the state the system will be in after reboot.  The dir
   418  // should be mounter and the secret data written to it.
   419  func TestPluginReboot(t *testing.T) {
   420  	var (
   421  		testPodUID     = types.UID("test_pod_uid3")
   422  		testVolumeName = "test_volume_name"
   423  		testNamespace  = "test_secret_namespace"
   424  		testName       = "test_secret_name"
   425  
   426  		volumeSpec    = volumeSpec(testVolumeName, testName, 0644)
   427  		secret        = secret(testNamespace, testName)
   428  		client        = fake.NewSimpleClientset(&secret)
   429  		pluginMgr     = volume.VolumePluginMgr{}
   430  		rootDir, host = newTestHost(t, client)
   431  	)
   432  	defer os.RemoveAll(rootDir)
   433  	pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
   434  
   435  	plugin, err := pluginMgr.FindPluginByName(secretPluginName)
   436  	if err != nil {
   437  		t.Fatal("Can't find the plugin by name")
   438  	}
   439  
   440  	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
   441  	mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
   442  	if err != nil {
   443  		t.Errorf("Failed to make a new Mounter: %v", err)
   444  	}
   445  	if mounter == nil {
   446  		t.Fatalf("Got a nil Mounter")
   447  	}
   448  
   449  	podMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid3/plugins/kubernetes.io~secret/test_volume_name", rootDir)
   450  	util.SetReady(podMetadataDir)
   451  	volumePath := mounter.GetPath()
   452  	if !hasPathSuffix(volumePath, "pods/test_pod_uid3/volumes/kubernetes.io~secret/test_volume_name") {
   453  		t.Errorf("Got unexpected path: %s", volumePath)
   454  	}
   455  
   456  	err = mounter.SetUp(volume.MounterArgs{})
   457  	if err != nil {
   458  		t.Errorf("Failed to setup volume: %v", err)
   459  	}
   460  	if _, err := os.Stat(volumePath); err != nil {
   461  		if os.IsNotExist(err) {
   462  			t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
   463  		} else {
   464  			t.Errorf("SetUp() failed: %v", err)
   465  		}
   466  	}
   467  
   468  	doTestSecretDataInVolume(volumePath, secret, t)
   469  	doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
   470  }
   471  
   472  func TestPluginOptional(t *testing.T) {
   473  	var (
   474  		testPodUID     = types.UID("test_pod_uid")
   475  		testVolumeName = "test_volume_name"
   476  		testNamespace  = "test_secret_namespace"
   477  		testName       = "test_secret_name"
   478  		trueVal        = true
   479  
   480  		volumeSpec    = volumeSpec(testVolumeName, testName, 0644)
   481  		client        = fake.NewSimpleClientset()
   482  		pluginMgr     = volume.VolumePluginMgr{}
   483  		rootDir, host = newTestHost(t, client)
   484  	)
   485  	volumeSpec.Secret.Optional = &trueVal
   486  	defer os.RemoveAll(rootDir)
   487  	pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
   488  
   489  	plugin, err := pluginMgr.FindPluginByName(secretPluginName)
   490  	if err != nil {
   491  		t.Fatal("Can't find the plugin by name")
   492  	}
   493  
   494  	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
   495  	mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
   496  	if err != nil {
   497  		t.Errorf("Failed to make a new Mounter: %v", err)
   498  	}
   499  	if mounter == nil {
   500  		t.Errorf("Got a nil Mounter")
   501  	}
   502  
   503  	volumePath := mounter.GetPath()
   504  	if !hasPathSuffix(volumePath, "pods/test_pod_uid/volumes/kubernetes.io~secret/test_volume_name") {
   505  		t.Errorf("Got unexpected path: %s", volumePath)
   506  	}
   507  
   508  	err = mounter.SetUp(volume.MounterArgs{})
   509  	if err != nil {
   510  		t.Errorf("Failed to setup volume: %v", err)
   511  	}
   512  	if _, err := os.Stat(volumePath); err != nil {
   513  		if os.IsNotExist(err) {
   514  			t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
   515  		} else {
   516  			t.Errorf("SetUp() failed: %v", err)
   517  		}
   518  	}
   519  
   520  	// secret volume should create its own empty wrapper path
   521  	podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir)
   522  
   523  	if _, err := os.Stat(podWrapperMetadataDir); err != nil {
   524  		if os.IsNotExist(err) {
   525  			t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)
   526  		} else {
   527  			t.Errorf("SetUp() failed: %v", err)
   528  		}
   529  	}
   530  
   531  	datadirSymlink := filepath.Join(volumePath, "..data")
   532  	datadir, err := os.Readlink(datadirSymlink)
   533  	if err != nil && os.IsNotExist(err) {
   534  		t.Fatalf("couldn't find volume path's data dir, %s", datadirSymlink)
   535  	} else if err != nil {
   536  		t.Fatalf("couldn't read symlink, %s", datadirSymlink)
   537  	}
   538  	datadirPath := filepath.Join(volumePath, datadir)
   539  
   540  	infos, err := ioutil.ReadDir(volumePath)
   541  	if err != nil {
   542  		t.Fatalf("couldn't find volume path, %s", volumePath)
   543  	}
   544  	if len(infos) != 0 {
   545  		for _, fi := range infos {
   546  			if fi.Name() != "..data" && fi.Name() != datadir {
   547  				t.Errorf("empty data volume directory, %s, is not empty. Contains: %s", datadirSymlink, fi.Name())
   548  			}
   549  		}
   550  	}
   551  
   552  	infos, err = ioutil.ReadDir(datadirPath)
   553  	if err != nil {
   554  		t.Fatalf("couldn't find volume data path, %s", datadirPath)
   555  	}
   556  	if len(infos) != 0 {
   557  		t.Errorf("empty data directory, %s, is not empty. Contains: %s", datadirSymlink, infos[0].Name())
   558  	}
   559  
   560  	defer doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
   561  }
   562  
   563  func TestPluginOptionalKeys(t *testing.T) {
   564  	var (
   565  		testPodUID     = types.UID("test_pod_uid")
   566  		testVolumeName = "test_volume_name"
   567  		testNamespace  = "test_secret_namespace"
   568  		testName       = "test_secret_name"
   569  		trueVal        = true
   570  
   571  		volumeSpec    = volumeSpec(testVolumeName, testName, 0644)
   572  		secret        = secret(testNamespace, testName)
   573  		client        = fake.NewSimpleClientset(&secret)
   574  		pluginMgr     = volume.VolumePluginMgr{}
   575  		rootDir, host = newTestHost(t, client)
   576  	)
   577  	volumeSpec.VolumeSource.Secret.Items = []v1.KeyToPath{
   578  		{Key: "data-1", Path: "data-1"},
   579  		{Key: "data-2", Path: "data-2"},
   580  		{Key: "data-3", Path: "data-3"},
   581  		{Key: "missing", Path: "missing"},
   582  	}
   583  	volumeSpec.Secret.Optional = &trueVal
   584  	defer os.RemoveAll(rootDir)
   585  	pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
   586  
   587  	plugin, err := pluginMgr.FindPluginByName(secretPluginName)
   588  	if err != nil {
   589  		t.Fatal("Can't find the plugin by name")
   590  	}
   591  
   592  	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
   593  	mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
   594  	if err != nil {
   595  		t.Errorf("Failed to make a new Mounter: %v", err)
   596  	}
   597  	if mounter == nil {
   598  		t.Errorf("Got a nil Mounter")
   599  	}
   600  
   601  	volumePath := mounter.GetPath()
   602  	if !hasPathSuffix(volumePath, "pods/test_pod_uid/volumes/kubernetes.io~secret/test_volume_name") {
   603  		t.Errorf("Got unexpected path: %s", volumePath)
   604  	}
   605  
   606  	err = mounter.SetUp(volume.MounterArgs{})
   607  	if err != nil {
   608  		t.Errorf("Failed to setup volume: %v", err)
   609  	}
   610  	if _, err := os.Stat(volumePath); err != nil {
   611  		if os.IsNotExist(err) {
   612  			t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
   613  		} else {
   614  			t.Errorf("SetUp() failed: %v", err)
   615  		}
   616  	}
   617  
   618  	// secret volume should create its own empty wrapper path
   619  	podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir)
   620  
   621  	if _, err := os.Stat(podWrapperMetadataDir); err != nil {
   622  		if os.IsNotExist(err) {
   623  			t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)
   624  		} else {
   625  			t.Errorf("SetUp() failed: %v", err)
   626  		}
   627  	}
   628  	doTestSecretDataInVolume(volumePath, secret, t)
   629  	defer doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
   630  
   631  	// Metrics only supported on linux
   632  	metrics, err := mounter.GetMetrics()
   633  	if runtime.GOOS == "linux" {
   634  		assert.NotEmpty(t, metrics)
   635  		assert.NoError(t, err)
   636  	} else {
   637  		t.Skipf("Volume metrics not supported on %s", runtime.GOOS)
   638  	}
   639  }
   640  
   641  func volumeSpec(volumeName, secretName string, defaultMode int32) *v1.Volume {
   642  	return &v1.Volume{
   643  		Name: volumeName,
   644  		VolumeSource: v1.VolumeSource{
   645  			Secret: &v1.SecretVolumeSource{
   646  				SecretName:  secretName,
   647  				DefaultMode: &defaultMode,
   648  			},
   649  		},
   650  	}
   651  }
   652  
   653  func secret(namespace, name string) v1.Secret {
   654  	return v1.Secret{
   655  		ObjectMeta: metav1.ObjectMeta{
   656  			Namespace: namespace,
   657  			Name:      name,
   658  		},
   659  		Data: map[string][]byte{
   660  			"data-1": []byte("value-1"),
   661  			"data-2": []byte("value-2"),
   662  			"data-3": []byte("value-3"),
   663  		},
   664  	}
   665  }
   666  
   667  func doTestSecretDataInVolume(volumePath string, secret v1.Secret, t *testing.T) {
   668  	for key, value := range secret.Data {
   669  		secretDataHostPath := filepath.Join(volumePath, key)
   670  		if _, err := os.Stat(secretDataHostPath); err != nil {
   671  			t.Fatalf("SetUp() failed, couldn't find secret data on disk: %v", secretDataHostPath)
   672  		} else {
   673  			actualSecretBytes, err := ioutil.ReadFile(secretDataHostPath)
   674  			if err != nil {
   675  				t.Fatalf("Couldn't read secret data from: %v", secretDataHostPath)
   676  			}
   677  
   678  			actualSecretValue := string(actualSecretBytes)
   679  			if string(value) != actualSecretValue {
   680  				t.Errorf("Unexpected value; expected %q, got %q", value, actualSecretValue)
   681  			}
   682  		}
   683  	}
   684  }
   685  
   686  func doTestCleanAndTeardown(plugin volume.VolumePlugin, podUID types.UID, testVolumeName, volumePath string, t *testing.T) {
   687  	unmounter, err := plugin.NewUnmounter(testVolumeName, podUID)
   688  	if err != nil {
   689  		t.Errorf("Failed to make a new Unmounter: %v", err)
   690  	}
   691  	if unmounter == nil {
   692  		t.Fatalf("Got a nil Unmounter")
   693  	}
   694  
   695  	if err := unmounter.TearDown(); err != nil {
   696  		t.Errorf("Expected success, got: %v", err)
   697  	}
   698  	if _, err := os.Stat(volumePath); err == nil {
   699  		t.Errorf("TearDown() failed, volume path still exists: %s", volumePath)
   700  	} else if !os.IsNotExist(err) {
   701  		t.Errorf("TearDown() failed: %v", err)
   702  	}
   703  }
   704  
   705  func hasPathSuffix(s, suffix string) bool {
   706  	return strings.HasSuffix(s, filepath.FromSlash(suffix))
   707  }
   708  

View as plain text