123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- /*
- Copyright 2016 The Kubernetes Authors.
- 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 kubelet
- import (
- "fmt"
- "testing"
- "github.com/stretchr/testify/assert"
- "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/types"
- core "k8s.io/client-go/testing"
- "k8s.io/kubernetes/pkg/volume"
- volumetest "k8s.io/kubernetes/pkg/volume/testing"
- "k8s.io/kubernetes/pkg/volume/util"
- )
- func TestListVolumesForPod(t *testing.T) {
- testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
- defer testKubelet.Cleanup()
- kubelet := testKubelet.kubelet
- pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol1",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device1",
- },
- },
- },
- {
- Name: "vol2",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device2",
- },
- },
- },
- },
- })
- stopCh := runVolumeManager(kubelet)
- defer close(stopCh)
- kubelet.podManager.SetPods([]*v1.Pod{pod})
- err := kubelet.volumeManager.WaitForAttachAndMount(pod)
- assert.NoError(t, err)
- podName := util.GetUniquePodName(pod)
- volumesToReturn, volumeExsit := kubelet.ListVolumesForPod(types.UID(podName))
- assert.True(t, volumeExsit, "expected to find volumes for pod %q", podName)
- outerVolumeSpecName1 := "vol1"
- assert.NotNil(t, volumesToReturn[outerVolumeSpecName1], "key %s", outerVolumeSpecName1)
- outerVolumeSpecName2 := "vol2"
- assert.NotNil(t, volumesToReturn[outerVolumeSpecName2], "key %s", outerVolumeSpecName2)
- }
- func TestPodVolumesExist(t *testing.T) {
- testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
- defer testKubelet.Cleanup()
- kubelet := testKubelet.kubelet
- pods := []*v1.Pod{
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "pod1",
- UID: "pod1uid",
- },
- Spec: v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol1",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device1",
- },
- },
- },
- },
- },
- },
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "pod2",
- UID: "pod2uid",
- },
- Spec: v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol2",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device2",
- },
- },
- },
- },
- },
- },
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "pod3",
- UID: "pod3uid",
- },
- Spec: v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol3",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device3",
- },
- },
- },
- },
- },
- },
- }
- stopCh := runVolumeManager(kubelet)
- defer close(stopCh)
- kubelet.podManager.SetPods(pods)
- for _, pod := range pods {
- err := kubelet.volumeManager.WaitForAttachAndMount(pod)
- assert.NoError(t, err)
- }
- for _, pod := range pods {
- podVolumesExist := kubelet.podVolumesExist(pod.UID)
- assert.True(t, podVolumesExist, "pod %q", pod.UID)
- }
- }
- func TestVolumeAttachAndMountControllerDisabled(t *testing.T) {
- testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
- defer testKubelet.Cleanup()
- kubelet := testKubelet.kubelet
- pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol1",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device",
- },
- },
- },
- },
- })
- stopCh := runVolumeManager(kubelet)
- defer close(stopCh)
- kubelet.podManager.SetPods([]*v1.Pod{pod})
- err := kubelet.volumeManager.WaitForAttachAndMount(pod)
- assert.NoError(t, err)
- podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
- util.GetUniquePodName(pod))
- expectedPodVolumes := []string{"vol1"}
- assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
- for _, name := range expectedPodVolumes {
- assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
- }
- assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
- assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
- 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyAttachCallCount(
- 1 /* expectedAttachCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
- 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifySetUpCallCount(
- 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
- }
- func TestVolumeUnmountAndDetachControllerDisabled(t *testing.T) {
- testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
- defer testKubelet.Cleanup()
- kubelet := testKubelet.kubelet
- pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol1",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device",
- },
- },
- },
- },
- })
- stopCh := runVolumeManager(kubelet)
- defer close(stopCh)
- // Add pod
- kubelet.podManager.SetPods([]*v1.Pod{pod})
- // Verify volumes attached
- err := kubelet.volumeManager.WaitForAttachAndMount(pod)
- assert.NoError(t, err)
- podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
- util.GetUniquePodName(pod))
- expectedPodVolumes := []string{"vol1"}
- assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
- for _, name := range expectedPodVolumes {
- assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
- }
- assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
- assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
- 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyAttachCallCount(
- 1 /* expectedAttachCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
- 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifySetUpCallCount(
- 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
- // Remove pod
- kubelet.podManager.SetPods([]*v1.Pod{})
- assert.NoError(t, waitForVolumeUnmount(kubelet.volumeManager, pod))
- // Verify volumes unmounted
- podVolumes = kubelet.volumeManager.GetMountedVolumesForPod(
- util.GetUniquePodName(pod))
- assert.Len(t, podVolumes, 0,
- "Expected volumes to be unmounted and detached. But some volumes are still mounted: %#v", podVolumes)
- assert.NoError(t, volumetest.VerifyTearDownCallCount(
- 1 /* expectedTearDownCallCount */, testKubelet.volumePlugin))
- // Verify volumes detached and no longer reported as in use
- assert.NoError(t, waitForVolumeDetach(v1.UniqueVolumeName("fake/fake-device"), kubelet.volumeManager))
- assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
- assert.NoError(t, volumetest.VerifyDetachCallCount(
- 1 /* expectedDetachCallCount */, testKubelet.volumePlugin))
- }
- func TestVolumeAttachAndMountControllerEnabled(t *testing.T) {
- testKubelet := newTestKubelet(t, true /* controllerAttachDetachEnabled */)
- defer testKubelet.Cleanup()
- kubelet := testKubelet.kubelet
- kubeClient := testKubelet.fakeKubeClient
- kubeClient.AddReactor("get", "nodes",
- func(action core.Action) (bool, runtime.Object, error) {
- return true, &v1.Node{
- ObjectMeta: metav1.ObjectMeta{Name: testKubeletHostname},
- Status: v1.NodeStatus{
- VolumesAttached: []v1.AttachedVolume{
- {
- Name: "fake/fake-device",
- DevicePath: "fake/path",
- },
- }},
- }, nil
- })
- kubeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
- return true, nil, fmt.Errorf("no reaction implemented for %s", action)
- })
- pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol1",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device",
- },
- },
- },
- },
- })
- stopCh := runVolumeManager(kubelet)
- defer close(stopCh)
- kubelet.podManager.SetPods([]*v1.Pod{pod})
- // Fake node status update
- go simulateVolumeInUseUpdate(
- v1.UniqueVolumeName("fake/fake-device"),
- stopCh,
- kubelet.volumeManager)
- assert.NoError(t, kubelet.volumeManager.WaitForAttachAndMount(pod))
- podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
- util.GetUniquePodName(pod))
- expectedPodVolumes := []string{"vol1"}
- assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
- for _, name := range expectedPodVolumes {
- assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
- }
- assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
- assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
- 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyZeroAttachCalls(testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
- 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifySetUpCallCount(
- 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
- }
- func TestVolumeUnmountAndDetachControllerEnabled(t *testing.T) {
- testKubelet := newTestKubelet(t, true /* controllerAttachDetachEnabled */)
- defer testKubelet.Cleanup()
- kubelet := testKubelet.kubelet
- kubeClient := testKubelet.fakeKubeClient
- kubeClient.AddReactor("get", "nodes",
- func(action core.Action) (bool, runtime.Object, error) {
- return true, &v1.Node{
- ObjectMeta: metav1.ObjectMeta{Name: testKubeletHostname},
- Status: v1.NodeStatus{
- VolumesAttached: []v1.AttachedVolume{
- {
- Name: "fake/fake-device",
- DevicePath: "fake/path",
- },
- }},
- }, nil
- })
- kubeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
- return true, nil, fmt.Errorf("no reaction implemented for %s", action)
- })
- pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
- Volumes: []v1.Volume{
- {
- Name: "vol1",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "fake-device",
- },
- },
- },
- },
- })
- stopCh := runVolumeManager(kubelet)
- defer close(stopCh)
- // Add pod
- kubelet.podManager.SetPods([]*v1.Pod{pod})
- // Fake node status update
- go simulateVolumeInUseUpdate(
- v1.UniqueVolumeName("fake/fake-device"),
- stopCh,
- kubelet.volumeManager)
- // Verify volumes attached
- assert.NoError(t, kubelet.volumeManager.WaitForAttachAndMount(pod))
- podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
- util.GetUniquePodName(pod))
- expectedPodVolumes := []string{"vol1"}
- assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
- for _, name := range expectedPodVolumes {
- assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
- }
- assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
- assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
- 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyZeroAttachCalls(testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
- 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
- assert.NoError(t, volumetest.VerifySetUpCallCount(
- 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
- // Remove pod
- kubelet.podManager.SetPods([]*v1.Pod{})
- assert.NoError(t, waitForVolumeUnmount(kubelet.volumeManager, pod))
- // Verify volumes unmounted
- podVolumes = kubelet.volumeManager.GetMountedVolumesForPod(
- util.GetUniquePodName(pod))
- assert.Len(t, podVolumes, 0,
- "Expected volumes to be unmounted and detached. But some volumes are still mounted: %#v", podVolumes)
- assert.NoError(t, volumetest.VerifyTearDownCallCount(
- 1 /* expectedTearDownCallCount */, testKubelet.volumePlugin))
- // Verify volumes detached and no longer reported as in use
- assert.NoError(t, waitForVolumeDetach(v1.UniqueVolumeName("fake/fake-device"), kubelet.volumeManager))
- assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
- assert.NoError(t, volumetest.VerifyZeroDetachCallCount(testKubelet.volumePlugin))
- }
- type stubVolume struct {
- path string
- volume.MetricsNil
- }
- func (f *stubVolume) GetPath() string {
- return f.path
- }
- func (f *stubVolume) GetAttributes() volume.Attributes {
- return volume.Attributes{}
- }
- func (f *stubVolume) CanMount() error {
- return nil
- }
- func (f *stubVolume) SetUp(mounterArgs volume.MounterArgs) error {
- return nil
- }
- func (f *stubVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
- return nil
- }
- type stubBlockVolume struct {
- dirPath string
- volName string
- }
- func (f *stubBlockVolume) GetGlobalMapPath(spec *volume.Spec) (string, error) {
- return "", nil
- }
- func (f *stubBlockVolume) GetPodDeviceMapPath() (string, string) {
- return f.dirPath, f.volName
- }
- func (f *stubBlockVolume) SetUpDevice() (string, error) {
- return "", nil
- }
- func (f stubBlockVolume) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
- return nil
- }
- func (f *stubBlockVolume) TearDownDevice(mapPath string, devicePath string) error {
- return nil
- }
|