fake.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package mount
  14. import (
  15. "errors"
  16. "os"
  17. "path/filepath"
  18. "sync"
  19. "k8s.io/klog"
  20. )
  21. // FakeMounter implements mount.Interface for tests.
  22. type FakeMounter struct {
  23. MountPoints []MountPoint
  24. Log []FakeAction
  25. Filesystem map[string]FileType
  26. // Error to return for a path when calling IsLikelyNotMountPoint
  27. MountCheckErrors map[string]error
  28. // Some tests run things in parallel, make sure the mounter does not produce
  29. // any golang's DATA RACE warnings.
  30. mutex sync.Mutex
  31. }
  32. var _ Interface = &FakeMounter{}
  33. // Values for FakeAction.Action
  34. const FakeActionMount = "mount"
  35. const FakeActionUnmount = "unmount"
  36. // FakeAction objects are logged every time a fake mount or unmount is called.
  37. type FakeAction struct {
  38. Action string // "mount" or "unmount"
  39. Target string // applies to both mount and unmount actions
  40. Source string // applies only to "mount" actions
  41. FSType string // applies only to "mount" actions
  42. }
  43. func (f *FakeMounter) ResetLog() {
  44. f.mutex.Lock()
  45. defer f.mutex.Unlock()
  46. f.Log = []FakeAction{}
  47. }
  48. func (f *FakeMounter) Mount(source string, target string, fstype string, options []string) error {
  49. f.mutex.Lock()
  50. defer f.mutex.Unlock()
  51. opts := []string{}
  52. for _, option := range options {
  53. // find 'bind' option
  54. if option == "bind" {
  55. // This is a bind-mount. In order to mimic linux behaviour, we must
  56. // use the original device of the bind-mount as the real source.
  57. // E.g. when mounted /dev/sda like this:
  58. // $ mount /dev/sda /mnt/test
  59. // $ mount -o bind /mnt/test /mnt/bound
  60. // then /proc/mount contains:
  61. // /dev/sda /mnt/test
  62. // /dev/sda /mnt/bound
  63. // (and not /mnt/test /mnt/bound)
  64. // I.e. we must use /dev/sda as source instead of /mnt/test in the
  65. // bind mount.
  66. for _, mnt := range f.MountPoints {
  67. if source == mnt.Path {
  68. source = mnt.Device
  69. break
  70. }
  71. }
  72. }
  73. // reuse MountPoint.Opts field to mark mount as readonly
  74. opts = append(opts, option)
  75. }
  76. // If target is a symlink, get its absolute path
  77. absTarget, err := filepath.EvalSymlinks(target)
  78. if err != nil {
  79. absTarget = target
  80. }
  81. f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: opts})
  82. klog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget)
  83. f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype})
  84. return nil
  85. }
  86. func (f *FakeMounter) Unmount(target string) error {
  87. f.mutex.Lock()
  88. defer f.mutex.Unlock()
  89. // If target is a symlink, get its absolute path
  90. absTarget, err := filepath.EvalSymlinks(target)
  91. if err != nil {
  92. absTarget = target
  93. }
  94. newMountpoints := []MountPoint{}
  95. for _, mp := range f.MountPoints {
  96. if mp.Path == absTarget {
  97. klog.V(5).Infof("Fake mounter: unmounted %s from %s", mp.Device, absTarget)
  98. // Don't copy it to newMountpoints
  99. continue
  100. }
  101. newMountpoints = append(newMountpoints, MountPoint{Device: mp.Device, Path: mp.Path, Type: mp.Type})
  102. }
  103. f.MountPoints = newMountpoints
  104. f.Log = append(f.Log, FakeAction{Action: FakeActionUnmount, Target: absTarget})
  105. delete(f.MountCheckErrors, target)
  106. return nil
  107. }
  108. func (f *FakeMounter) List() ([]MountPoint, error) {
  109. f.mutex.Lock()
  110. defer f.mutex.Unlock()
  111. return f.MountPoints, nil
  112. }
  113. func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
  114. return mp.Path == dir
  115. }
  116. func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
  117. f.mutex.Lock()
  118. defer f.mutex.Unlock()
  119. err := f.MountCheckErrors[file]
  120. if err != nil {
  121. return false, err
  122. }
  123. _, err = os.Stat(file)
  124. if err != nil {
  125. return true, err
  126. }
  127. // If file is a symlink, get its absolute path
  128. absFile, err := filepath.EvalSymlinks(file)
  129. if err != nil {
  130. absFile = file
  131. }
  132. for _, mp := range f.MountPoints {
  133. if mp.Path == absFile {
  134. klog.V(5).Infof("isLikelyNotMountPoint for %s: mounted %s, false", file, mp.Path)
  135. return false, nil
  136. }
  137. }
  138. klog.V(5).Infof("isLikelyNotMountPoint for %s: true", file)
  139. return true, nil
  140. }
  141. func (f *FakeMounter) DeviceOpened(pathname string) (bool, error) {
  142. f.mutex.Lock()
  143. defer f.mutex.Unlock()
  144. for _, mp := range f.MountPoints {
  145. if mp.Device == pathname {
  146. return true, nil
  147. }
  148. }
  149. return false, nil
  150. }
  151. func (f *FakeMounter) PathIsDevice(pathname string) (bool, error) {
  152. return true, nil
  153. }
  154. func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
  155. return getDeviceNameFromMount(f, mountPath, pluginMountDir)
  156. }
  157. func (f *FakeMounter) MakeRShared(path string) error {
  158. return nil
  159. }
  160. func (f *FakeMounter) GetFileType(pathname string) (FileType, error) {
  161. if t, ok := f.Filesystem[pathname]; ok {
  162. return t, nil
  163. }
  164. return FileType("Directory"), nil
  165. }
  166. func (f *FakeMounter) MakeDir(pathname string) error {
  167. return nil
  168. }
  169. func (f *FakeMounter) MakeFile(pathname string) error {
  170. return nil
  171. }
  172. func (f *FakeMounter) ExistsPath(pathname string) (bool, error) {
  173. if _, ok := f.Filesystem[pathname]; ok {
  174. return true, nil
  175. }
  176. return false, nil
  177. }
  178. func (f *FakeMounter) EvalHostSymlinks(pathname string) (string, error) {
  179. return pathname, nil
  180. }
  181. func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) {
  182. realpath, err := filepath.EvalSymlinks(pathname)
  183. if err != nil {
  184. // Ignore error in FakeMounter, because we actually didn't create files.
  185. realpath = pathname
  186. }
  187. return getMountRefsByDev(f, realpath)
  188. }
  189. func (f *FakeMounter) GetFSGroup(pathname string) (int64, error) {
  190. return -1, errors.New("GetFSGroup not implemented")
  191. }
  192. func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
  193. return false, errors.New("GetSELinuxSupport not implemented")
  194. }
  195. func (f *FakeMounter) GetMode(pathname string) (os.FileMode, error) {
  196. return 0, errors.New("not implemented")
  197. }