123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- /*
- 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 testing
- import (
- "fmt"
- "sync"
- "time"
- "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/apimachinery/pkg/watch"
- "k8s.io/client-go/kubernetes/fake"
- core "k8s.io/client-go/testing"
- "k8s.io/klog"
- "k8s.io/kubernetes/pkg/volume"
- "k8s.io/kubernetes/pkg/volume/util"
- )
- const TestPluginName = "kubernetes.io/testPlugin"
- // GetTestVolumeSpec returns a test volume spec
- func GetTestVolumeSpec(volumeName string, diskName v1.UniqueVolumeName) *volume.Spec {
- return &volume.Spec{
- Volume: &v1.Volume{
- Name: volumeName,
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: string(diskName),
- FSType: "fake",
- ReadOnly: false,
- },
- },
- },
- PersistentVolume: &v1.PersistentVolume{
- Spec: v1.PersistentVolumeSpec{
- AccessModes: []v1.PersistentVolumeAccessMode{
- v1.ReadWriteOnce,
- },
- },
- },
- }
- }
- var extraPods *v1.PodList
- func CreateTestClient() *fake.Clientset {
- fakeClient := &fake.Clientset{}
- extraPods = &v1.PodList{}
- fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
- obj := &v1.PodList{}
- podNamePrefix := "mypod"
- namespace := "mynamespace"
- for i := 0; i < 5; i++ {
- podName := fmt.Sprintf("%s-%d", podNamePrefix, i)
- pod := v1.Pod{
- Status: v1.PodStatus{
- Phase: v1.PodRunning,
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: podName,
- UID: types.UID(podName),
- Namespace: namespace,
- Labels: map[string]string{
- "name": podName,
- },
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Name: "containerName",
- Image: "containerImage",
- VolumeMounts: []v1.VolumeMount{
- {
- Name: "volumeMountName",
- ReadOnly: false,
- MountPath: "/mnt",
- },
- },
- },
- },
- Volumes: []v1.Volume{
- {
- Name: "volumeName",
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "pdName",
- FSType: "ext4",
- ReadOnly: false,
- },
- },
- },
- },
- NodeName: "mynode",
- },
- }
- obj.Items = append(obj.Items, pod)
- }
- obj.Items = append(obj.Items, extraPods.Items...)
- return true, obj, nil
- })
- fakeClient.AddReactor("create", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
- createAction := action.(core.CreateAction)
- pod := createAction.GetObject().(*v1.Pod)
- extraPods.Items = append(extraPods.Items, *pod)
- return true, createAction.GetObject(), nil
- })
- fakeClient.AddReactor("list", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
- obj := &v1.NodeList{}
- nodeNamePrefix := "mynode"
- for i := 0; i < 5; i++ {
- var nodeName string
- if i != 0 {
- nodeName = fmt.Sprintf("%s-%d", nodeNamePrefix, i)
- } else {
- // We want also the "mynode" node since all the testing pods live there
- nodeName = nodeNamePrefix
- }
- node := v1.Node{
- ObjectMeta: metav1.ObjectMeta{
- Name: nodeName,
- Labels: map[string]string{
- "name": nodeName,
- },
- Annotations: map[string]string{
- util.ControllerManagedAttachAnnotation: "true",
- },
- },
- Status: v1.NodeStatus{
- VolumesAttached: []v1.AttachedVolume{
- {
- Name: TestPluginName + "/lostVolumeName",
- DevicePath: "fake/path",
- },
- },
- },
- }
- obj.Items = append(obj.Items, node)
- }
- return true, obj, nil
- })
- fakeWatch := watch.NewFake()
- fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil))
- return fakeClient
- }
- // NewPod returns a test pod object
- func NewPod(uid, name string) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- UID: types.UID(uid),
- Name: name,
- Namespace: name,
- },
- }
- }
- // NewPod returns a test pod object
- func NewPodWithVolume(podName, volumeName, nodeName string) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- UID: types.UID(podName),
- Name: podName,
- Namespace: "mynamespace",
- Labels: map[string]string{
- "name": podName,
- },
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Name: "containerName",
- Image: "containerImage",
- VolumeMounts: []v1.VolumeMount{
- {
- Name: "volumeMountName",
- ReadOnly: false,
- MountPath: "/mnt",
- },
- },
- },
- },
- Volumes: []v1.Volume{
- {
- Name: volumeName,
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "pdName",
- FSType: "ext4",
- ReadOnly: false,
- },
- },
- },
- },
- NodeName: nodeName,
- },
- }
- }
- type TestPlugin struct {
- ErrorEncountered bool
- attachedVolumeMap map[string][]string
- detachedVolumeMap map[string][]string
- pluginLock *sync.RWMutex
- }
- func (plugin *TestPlugin) Init(host volume.VolumeHost) error {
- return nil
- }
- func (plugin *TestPlugin) GetPluginName() string {
- return TestPluginName
- }
- func (plugin *TestPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
- plugin.pluginLock.Lock()
- defer plugin.pluginLock.Unlock()
- if spec == nil {
- klog.Errorf("GetVolumeName called with nil volume spec")
- plugin.ErrorEncountered = true
- }
- return spec.Name(), nil
- }
- func (plugin *TestPlugin) CanSupport(spec *volume.Spec) bool {
- plugin.pluginLock.Lock()
- defer plugin.pluginLock.Unlock()
- if spec == nil {
- klog.Errorf("CanSupport called with nil volume spec")
- plugin.ErrorEncountered = true
- }
- return true
- }
- func (plugin *TestPlugin) IsMigratedToCSI() bool {
- return false
- }
- func (plugin *TestPlugin) RequiresRemount() bool {
- return false
- }
- func (plugin *TestPlugin) NewMounter(spec *volume.Spec, podRef *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
- plugin.pluginLock.Lock()
- defer plugin.pluginLock.Unlock()
- if spec == nil {
- klog.Errorf("NewMounter called with nil volume spec")
- plugin.ErrorEncountered = true
- }
- return nil, nil
- }
- func (plugin *TestPlugin) NewUnmounter(name string, podUID types.UID) (volume.Unmounter, error) {
- return nil, nil
- }
- func (plugin *TestPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
- fakeVolume := &v1.Volume{
- Name: volumeName,
- VolumeSource: v1.VolumeSource{
- GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
- PDName: "pdName",
- FSType: "ext4",
- ReadOnly: false,
- },
- },
- }
- return volume.NewSpecFromVolume(fakeVolume), nil
- }
- func (plugin *TestPlugin) NewAttacher() (volume.Attacher, error) {
- attacher := testPluginAttacher{
- ErrorEncountered: &plugin.ErrorEncountered,
- attachedVolumeMap: plugin.attachedVolumeMap,
- pluginLock: plugin.pluginLock,
- }
- return &attacher, nil
- }
- func (plugin *TestPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
- return plugin.NewAttacher()
- }
- func (plugin *TestPlugin) NewDetacher() (volume.Detacher, error) {
- detacher := testPluginDetacher{
- detachedVolumeMap: plugin.detachedVolumeMap,
- pluginLock: plugin.pluginLock,
- }
- return &detacher, nil
- }
- func (plugin *TestPlugin) CanAttach(spec *volume.Spec) (bool, error) {
- return true, nil
- }
- func (plugin *TestPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
- return true, nil
- }
- func (plugin *TestPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
- return plugin.NewDetacher()
- }
- func (plugin *TestPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
- return []string{}, nil
- }
- func (plugin *TestPlugin) SupportsMountOption() bool {
- return false
- }
- func (plugin *TestPlugin) SupportsBulkVolumeVerification() bool {
- return false
- }
- func (plugin *TestPlugin) GetErrorEncountered() bool {
- plugin.pluginLock.RLock()
- defer plugin.pluginLock.RUnlock()
- return plugin.ErrorEncountered
- }
- func (plugin *TestPlugin) GetAttachedVolumes() map[string][]string {
- plugin.pluginLock.RLock()
- defer plugin.pluginLock.RUnlock()
- ret := make(map[string][]string)
- for nodeName, volumeList := range plugin.attachedVolumeMap {
- ret[nodeName] = make([]string, len(volumeList))
- copy(ret[nodeName], volumeList)
- }
- return ret
- }
- func (plugin *TestPlugin) GetDetachedVolumes() map[string][]string {
- plugin.pluginLock.RLock()
- defer plugin.pluginLock.RUnlock()
- ret := make(map[string][]string)
- for nodeName, volumeList := range plugin.detachedVolumeMap {
- ret[nodeName] = make([]string, len(volumeList))
- copy(ret[nodeName], volumeList)
- }
- return ret
- }
- func CreateTestPlugin() []volume.VolumePlugin {
- attachedVolumes := make(map[string][]string)
- detachedVolumes := make(map[string][]string)
- return []volume.VolumePlugin{&TestPlugin{
- ErrorEncountered: false,
- attachedVolumeMap: attachedVolumes,
- detachedVolumeMap: detachedVolumes,
- pluginLock: &sync.RWMutex{},
- }}
- }
- // Attacher
- type testPluginAttacher struct {
- ErrorEncountered *bool
- attachedVolumeMap map[string][]string
- pluginLock *sync.RWMutex
- }
- func (attacher *testPluginAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) {
- attacher.pluginLock.Lock()
- defer attacher.pluginLock.Unlock()
- if spec == nil {
- *attacher.ErrorEncountered = true
- klog.Errorf("Attach called with nil volume spec")
- return "", fmt.Errorf("Attach called with nil volume spec")
- }
- attacher.attachedVolumeMap[string(nodeName)] = append(attacher.attachedVolumeMap[string(nodeName)], spec.Name())
- return spec.Name(), nil
- }
- func (attacher *testPluginAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) {
- return nil, nil
- }
- func (attacher *testPluginAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) {
- attacher.pluginLock.Lock()
- defer attacher.pluginLock.Unlock()
- if spec == nil {
- *attacher.ErrorEncountered = true
- klog.Errorf("WaitForAttach called with nil volume spec")
- return "", fmt.Errorf("WaitForAttach called with nil volume spec")
- }
- fakePath := fmt.Sprintf("%s/%s", devicePath, spec.Name())
- return fakePath, nil
- }
- func (attacher *testPluginAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) {
- attacher.pluginLock.Lock()
- defer attacher.pluginLock.Unlock()
- if spec == nil {
- *attacher.ErrorEncountered = true
- klog.Errorf("GetDeviceMountPath called with nil volume spec")
- return "", fmt.Errorf("GetDeviceMountPath called with nil volume spec")
- }
- return "", nil
- }
- func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
- attacher.pluginLock.Lock()
- defer attacher.pluginLock.Unlock()
- if spec == nil {
- *attacher.ErrorEncountered = true
- klog.Errorf("MountDevice called with nil volume spec")
- return fmt.Errorf("MountDevice called with nil volume spec")
- }
- return nil
- }
- // Detacher
- type testPluginDetacher struct {
- detachedVolumeMap map[string][]string
- pluginLock *sync.RWMutex
- }
- func (detacher *testPluginDetacher) Detach(volumeName string, nodeName types.NodeName) error {
- detacher.pluginLock.Lock()
- defer detacher.pluginLock.Unlock()
- detacher.detachedVolumeMap[string(nodeName)] = append(detacher.detachedVolumeMap[string(nodeName)], volumeName)
- return nil
- }
- func (detacher *testPluginDetacher) UnmountDevice(deviceMountPath string) error {
- return nil
- }
|