1// +build !providerless 2 3/* 4Copyright 2017 The Kubernetes Authors. 5 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17*/ 18 19package azuredd 20 21import ( 22 "fmt" 23 "os" 24 "runtime" 25 26 "k8s.io/klog/v2" 27 "k8s.io/mount-utils" 28 29 v1 "k8s.io/api/core/v1" 30 "k8s.io/kubernetes/pkg/volume" 31 "k8s.io/kubernetes/pkg/volume/util" 32) 33 34type azureDiskMounter struct { 35 *dataDisk 36 spec *volume.Spec 37 plugin *azureDataDiskPlugin 38 options volume.VolumeOptions 39} 40 41type azureDiskUnmounter struct { 42 *dataDisk 43 plugin *azureDataDiskPlugin 44} 45 46var _ volume.Unmounter = &azureDiskUnmounter{} 47var _ volume.Mounter = &azureDiskMounter{} 48 49func (m *azureDiskMounter) GetAttributes() volume.Attributes { 50 readOnly := false 51 volumeSource, _, err := getVolumeSource(m.spec) 52 if err != nil { 53 klog.Infof("azureDisk - mounter failed to get volume source for spec %s %v", m.spec.Name(), err) 54 } else if volumeSource.ReadOnly != nil { 55 readOnly = *volumeSource.ReadOnly 56 } 57 return volume.Attributes{ 58 ReadOnly: readOnly, 59 Managed: !readOnly, 60 SupportsSELinux: true, 61 } 62} 63 64func (m *azureDiskMounter) CanMount() error { 65 return nil 66} 67 68func (m *azureDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { 69 return m.SetUpAt(m.GetPath(), mounterArgs) 70} 71 72func (m *azureDiskMounter) GetPath() string { 73 return getPath(m.dataDisk.podUID, m.dataDisk.volumeName, m.plugin.host) 74} 75 76func (m *azureDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { 77 mounter := m.plugin.host.GetMounter(m.plugin.GetPluginName()) 78 volumeSource, _, err := getVolumeSource(m.spec) 79 80 if err != nil { 81 klog.Infof("azureDisk - mounter failed to get volume source for spec %s", m.spec.Name()) 82 return err 83 } 84 85 diskName := volumeSource.DiskName 86 mountPoint, err := mounter.IsLikelyNotMountPoint(dir) 87 88 if err != nil && !os.IsNotExist(err) { 89 klog.Infof("azureDisk - cannot validate mount point for disk %s on %s %v", diskName, dir, err) 90 return err 91 } 92 if !mountPoint { 93 // testing original mount point, make sure the mount link is valid 94 _, err := (&osIOHandler{}).ReadDir(dir) 95 if err == nil { 96 klog.V(4).Infof("azureDisk - already mounted to target %s", dir) 97 return nil 98 } 99 // mount link is invalid, now unmount and remount later 100 klog.Warningf("azureDisk - ReadDir %s failed with %v, unmount this directory", dir, err) 101 if err := mounter.Unmount(dir); err != nil { 102 klog.Errorf("azureDisk - Unmount directory %s failed with %v", dir, err) 103 return err 104 } 105 } 106 107 if runtime.GOOS != "windows" { 108 // in windows, we will use mklink to mount, will MkdirAll in Mount func 109 if err := os.MkdirAll(dir, 0750); err != nil { 110 klog.Errorf("azureDisk - mkdir failed on disk %s on dir: %s (%v)", diskName, dir, err) 111 return err 112 } 113 } 114 115 options := []string{"bind"} 116 117 if volumeSource.ReadOnly != nil && *volumeSource.ReadOnly { 118 options = append(options, "ro") 119 } 120 121 if m.options.MountOptions != nil { 122 options = util.JoinMountOptions(m.options.MountOptions, options) 123 } 124 125 klog.V(4).Infof("azureDisk - Attempting to mount %s on %s", diskName, dir) 126 isManagedDisk := (*volumeSource.Kind == v1.AzureManagedDisk) 127 globalPDPath, err := makeGlobalPDPath(m.plugin.host, volumeSource.DataDiskURI, isManagedDisk) 128 129 if err != nil { 130 return err 131 } 132 133 mountErr := mounter.MountSensitiveWithoutSystemd(globalPDPath, dir, *volumeSource.FSType, options, nil) 134 // Everything in the following control flow is meant as an 135 // attempt cleanup a failed setupAt (bind mount) 136 if mountErr != nil { 137 klog.Infof("azureDisk - SetupAt:Mount disk:%s at dir:%s failed during mounting with error:%v, will attempt to clean up", diskName, dir, mountErr) 138 mountPoint, err := mounter.IsLikelyNotMountPoint(dir) 139 if err != nil { 140 return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup IsLikelyNotMountPoint check failed for disk:%s on dir:%s with error %v original-mountErr:%v", diskName, dir, err, mountErr) 141 } 142 143 if !mountPoint { 144 if err = mounter.Unmount(dir); err != nil { 145 return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup failed to unmount disk:%s on dir:%s with error:%v original-mountErr:%v", diskName, dir, err, mountErr) 146 } 147 mountPoint, err := mounter.IsLikelyNotMountPoint(dir) 148 if err != nil { 149 return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup IsLikelyNotMountPoint for disk:%s on dir:%s check failed with error:%v original-mountErr:%v", diskName, dir, err, mountErr) 150 } 151 if !mountPoint { 152 // not cool. leave for next sync loop. 153 return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup disk %s is still mounted on %s during cleanup original-mountErr:%v, despite call to unmount() - will try again next sync loop", diskName, dir, mountErr) 154 } 155 } 156 157 if err = os.Remove(dir); err != nil { 158 return fmt.Errorf("azureDisk - SetupAt:Mount:Failure error cleaning up (removing dir:%s) with error:%v original-mountErr:%v", dir, err, mountErr) 159 } 160 161 klog.V(2).Infof("azureDisk - Mount of disk:%s on dir:%s failed with mount error:%v post failure clean up was completed", diskName, dir, mountErr) 162 return mountErr 163 } 164 165 if volumeSource.ReadOnly == nil || !*volumeSource.ReadOnly { 166 volume.SetVolumeOwnership(m, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy, util.FSGroupCompleteHook(m.plugin, m.spec)) 167 } 168 169 klog.V(2).Infof("azureDisk - successfully mounted disk %s on %s", diskName, dir) 170 return nil 171} 172 173func (u *azureDiskUnmounter) TearDown() error { 174 return u.TearDownAt(u.GetPath()) 175} 176 177func (u *azureDiskUnmounter) TearDownAt(dir string) error { 178 if pathExists, pathErr := mount.PathExists(dir); pathErr != nil { 179 return fmt.Errorf("error checking if path exists: %w", pathErr) 180 } else if !pathExists { 181 klog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir) 182 return nil 183 } 184 185 klog.V(4).Infof("azureDisk - TearDownAt: %s", dir) 186 mounter := u.plugin.host.GetMounter(u.plugin.GetPluginName()) 187 mountPoint, err := mounter.IsLikelyNotMountPoint(dir) 188 if err != nil { 189 return fmt.Errorf("azureDisk - TearDownAt: %s failed to do IsLikelyNotMountPoint %s", dir, err) 190 } 191 if mountPoint { 192 if err := os.Remove(dir); err != nil { 193 return fmt.Errorf("azureDisk - TearDownAt: %s failed to do os.Remove %s", dir, err) 194 } 195 } 196 if err := mounter.Unmount(dir); err != nil { 197 return fmt.Errorf("azureDisk - TearDownAt: %s failed to do mounter.Unmount %s", dir, err) 198 } 199 mountPoint, err = mounter.IsLikelyNotMountPoint(dir) 200 if err != nil { 201 return fmt.Errorf("azureDisk - TearTownAt:IsLikelyNotMountPoint check failed: %v", err) 202 } 203 204 if mountPoint { 205 return os.Remove(dir) 206 } 207 208 return fmt.Errorf("azureDisk - failed to un-bind-mount volume dir") 209} 210 211func (u *azureDiskUnmounter) GetPath() string { 212 return getPath(u.dataDisk.podUID, u.dataDisk.volumeName, u.plugin.host) 213} 214