k8s.io/kubernetes@v1.29.3/pkg/volume/flexvolume/flexvolume_test.go (about) 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 flexvolume 18 19 import ( 20 "bytes" 21 "fmt" 22 "os" 23 "path/filepath" 24 goruntime "runtime" 25 "testing" 26 "text/template" 27 28 "k8s.io/api/core/v1" 29 utiltesting "k8s.io/client-go/util/testing" 30 utilfs "k8s.io/kubernetes/pkg/util/filesystem" 31 "k8s.io/kubernetes/pkg/volume" 32 volumetest "k8s.io/kubernetes/pkg/volume/testing" 33 "k8s.io/utils/exec" 34 ) 35 36 const execScriptTempl1 = `#!/usr/bin/env bash 37 if [ "$1" == "init" -a $# -eq 1 ]; then 38 echo -n '{ 39 "status": "Success" 40 }' 41 exit 0 42 fi 43 44 PATH=$2 45 if [ "$1" == "attach" -a $# -eq 2 ]; then 46 echo -n '{ 47 "device": "{{.DevicePath}}", 48 "status": "Success" 49 }' 50 exit 0 51 elif [ "$1" == "detach" -a $# -eq 2 ]; then 52 echo -n '{ 53 "status": "Success" 54 }' 55 exit 0 56 elif [ "$1" == "getvolumename" -a $# -eq 4 ]; then 57 echo -n '{ 58 "status": "Success", 59 "volume": "fakevolume" 60 }' 61 exit 0 62 elif [ "$1" == "isattached" -a $# -eq 2 ]; then 63 echo -n '{ 64 "status": "Success", 65 "attached": true 66 }' 67 exit 0 68 fi 69 70 echo -n '{ 71 "status": "Not supported" 72 }' 73 exit 1 74 75 # Direct the arguments to a file to be tested against later 76 echo -n $@ &> {{.OutputFile}} 77 ` 78 79 // NOTE: Typically, Windows requires file extensions for executable files. If a file does not 80 // have a file extension, Windows will check if there is a file with the given name + one of the 81 // extensions from $env:PATHEXT (in order) and run that file with that extension. 82 // For example, if we have the file C:\\foo.bat, we can run C:\\foo. 83 // For these tests, .bat was chosen since it's one of the default values in $env.PATHEXT. .ps1 is 84 // not in that list, but it might be useful for flexvolumes to be able to handle powershell scripts. 85 // There's no argument count variable in batch. Instead, we can check that the n-th argument 86 // is an empty string. 87 const execScriptTemplBat = ` 88 @echo off 89 90 if "%1"=="init" if "%2"=="" ( 91 echo {"status": "Success"} 92 exit 0 93 ) 94 if "%1"=="attach" if "%3"=="" ( 95 echo {"device": "{{.DevicePath}}", "status": "Success"} 96 exit 0 97 ) 98 99 if "%1"=="detach" if "%3"=="" ( 100 echo {"status": "Success"} 101 exit 0 102 ) 103 104 if "%1"=="getvolumename" if "%5"=="" ( 105 echo {"status": "Success", "volume": "fakevolume"} 106 exit 0 107 ) 108 109 if "%1"=="isattached" if "%3"=="" ( 110 echo {"status": "Success", "attached": true} 111 exit 0 112 ) 113 114 echo {"status": "Not supported"} 115 exit 1 116 ` 117 118 func installPluginUnderTest(t *testing.T, vendorName, plugName, tmpDir string, execScriptTempl string, execTemplateData *map[string]interface{}) { 119 vendoredName := plugName 120 if vendorName != "" { 121 vendoredName = fmt.Sprintf("%s~%s", vendorName, plugName) 122 } 123 pluginDir := filepath.Join(tmpDir, vendoredName) 124 err := os.MkdirAll(pluginDir, 0777) 125 if err != nil { 126 t.Errorf("Failed to create plugin: %v", err) 127 } 128 pluginExec := filepath.Join(pluginDir, plugName) 129 if goruntime.GOOS == "windows" { 130 pluginExec = pluginExec + ".bat" 131 } 132 f, err := os.Create(pluginExec) 133 if err != nil { 134 t.Errorf("Failed to install plugin") 135 } 136 err = f.Chmod(0777) 137 if err != nil { 138 t.Errorf("Failed to set exec perms on plugin") 139 } 140 if execTemplateData == nil { 141 execTemplateData = &map[string]interface{}{ 142 "DevicePath": "/dev/sdx", 143 "OutputFile": filepath.Join(pluginDir, plugName+".out"), 144 } 145 } 146 147 tObj := template.Must(template.New("test").Parse(execScriptTempl)) 148 buf := &bytes.Buffer{} 149 if err := tObj.Execute(buf, *execTemplateData); err != nil { 150 t.Errorf("Error in executing script template - %v", err) 151 } 152 execScript := buf.String() 153 _, err = f.WriteString(execScript) 154 if err != nil { 155 t.Errorf("Failed to write plugin exec") 156 } 157 f.Close() 158 } 159 160 func TestCanSupport(t *testing.T) { 161 tmpDir, err := utiltesting.MkTmpdir("flexvolume_test") 162 if err != nil { 163 t.Fatalf("error creating temp dir: %v", err) 164 } 165 defer os.RemoveAll(tmpDir) 166 167 plugMgr := volume.VolumePluginMgr{} 168 runner := exec.New() 169 execScriptTempl := execScriptTempl1 170 if goruntime.GOOS == "windows" { 171 execScriptTempl = execScriptTemplBat 172 } 173 installPluginUnderTest(t, "kubernetes.io", "fakeAttacher", tmpDir, execScriptTempl, nil) 174 if err := plugMgr.InitPlugins(nil, GetDynamicPluginProberWithoutWatcher(tmpDir, runner), volumetest.NewFakeVolumeHost(t, "fake", nil, nil)); err != nil { 175 t.Fatalf("Could not initialize plugins: %v", err) 176 } 177 plugin, err := plugMgr.FindPluginByName("kubernetes.io/fakeAttacher") 178 if err != nil { 179 t.Fatalf("Can't find the plugin by name") 180 } 181 if plugin.GetPluginName() != "kubernetes.io/fakeAttacher" { 182 t.Errorf("Wrong name: %s", plugin.GetPluginName()) 183 } 184 if !plugin.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{FlexVolume: &v1.FlexVolumeSource{Driver: "kubernetes.io/fakeAttacher"}}}}) { 185 t.Errorf("Expected true") 186 } 187 if !plugin.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{FlexVolume: &v1.FlexPersistentVolumeSource{Driver: "kubernetes.io/fakeAttacher"}}}}}) { 188 t.Errorf("Expected true") 189 } 190 if plugin.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) { 191 t.Errorf("Expected false") 192 } 193 } 194 195 func TestGetAccessModes(t *testing.T) { 196 tmpDir, err := utiltesting.MkTmpdir("flexvolume_test") 197 if err != nil { 198 t.Fatalf("error creating temp dir: %v", err) 199 } 200 defer os.RemoveAll(tmpDir) 201 202 plugMgr := volume.VolumePluginMgr{} 203 runner := exec.New() 204 execScriptTempl := execScriptTempl1 205 if goruntime.GOOS == "windows" { 206 execScriptTempl = execScriptTemplBat 207 } 208 installPluginUnderTest(t, "kubernetes.io", "fakeAttacher", tmpDir, execScriptTempl, nil) 209 if err := plugMgr.InitPlugins(nil, GetDynamicPluginProberWithoutWatcher(tmpDir, runner), volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)); err != nil { 210 t.Fatalf("Could not initialize plugins: %v", err) 211 } 212 plugin, err := plugMgr.FindPersistentPluginByName("kubernetes.io/fakeAttacher") 213 if err != nil { 214 t.Fatalf("Can't find the plugin by name") 215 } 216 if !volumetest.ContainsAccessMode(plugin.GetAccessModes(), v1.ReadWriteOnce) || !volumetest.ContainsAccessMode(plugin.GetAccessModes(), v1.ReadOnlyMany) { 217 t.Errorf("Expected two AccessModeTypes: %s and %s", v1.ReadWriteOnce, v1.ReadOnlyMany) 218 } 219 } 220 221 func GetDynamicPluginProberWithoutWatcher(pluginDir string, runner exec.Interface) volume.DynamicPluginProber { 222 return &flexVolumeProber{ 223 pluginDir: pluginDir, 224 watcher: newFakeWatcher(), 225 factory: pluginFactory{}, 226 runner: runner, 227 fs: &utilfs.DefaultFs{}, 228 } 229 }