github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/utils/mount/mount_service.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mount 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/alibaba/sealer/utils/ssh" 22 "github.com/shirou/gopsutil/disk" 23 24 "github.com/alibaba/sealer/logger" 25 "github.com/alibaba/sealer/utils" 26 ) 27 28 type Service interface { 29 TempMount() error 30 TempUMount() error 31 CleanUp() 32 GetMountTarget() string 33 GetMountUpper() string 34 GetLowLayers() []string 35 } 36 37 type mounter struct { 38 driver Interface 39 TempTarget string 40 TempUpper string 41 //driver.Mount will reverse lowers,so here we keep the order same with the image layer. 42 LowLayers []string 43 } 44 45 func (m mounter) TempMount() error { 46 err := m.driver.Mount(m.TempTarget, m.TempUpper, m.LowLayers...) 47 if err != nil { 48 return fmt.Errorf("failed to mount target %s:%v", m.TempTarget, err) 49 } 50 return nil 51 } 52 53 func (m mounter) TempUMount() error { 54 err := m.driver.Unmount(m.TempTarget) 55 if err != nil { 56 return fmt.Errorf("failed to umount target %s:%v", m.TempTarget, err) 57 } 58 return nil 59 } 60 61 func (m mounter) CleanUp() { 62 if err := m.driver.Unmount(m.TempTarget); err != nil { 63 logger.Warn(fmt.Errorf("failed to umount %s:%v", m.TempTarget, err)) 64 } 65 66 utils.CleanDirs(m.TempUpper, m.TempTarget) 67 } 68 69 func (m mounter) GetMountUpper() string { 70 return m.TempUpper 71 } 72 73 func (m mounter) GetLowLayers() []string { 74 return m.LowLayers 75 } 76 77 func (m mounter) GetMountTarget() string { 78 return m.TempTarget 79 } 80 81 //NewMountService will create temp dir if target or upper is nil. it is convenient for use in build stage 82 func NewMountService(target, upper string, lowLayers []string) (Service, error) { 83 if len(lowLayers) == 0 { 84 tmp, err := utils.MkTmpdir() 85 if err != nil { 86 return nil, fmt.Errorf("failed to create tmp lower %s:%v", tmp, err) 87 } 88 lowLayers = append(lowLayers, tmp) 89 } 90 if target == "" { 91 tmp, err := utils.MkTmpdir() 92 if err != nil { 93 return nil, fmt.Errorf("failed to create tmp target %s:%v", tmp, err) 94 } 95 target = tmp 96 } 97 if upper == "" { 98 tmp, err := utils.MkTmpdir() 99 if err != nil { 100 return nil, fmt.Errorf("failed to create tmp upper %s:%v", tmp, err) 101 } 102 upper = tmp 103 } 104 return &mounter{ 105 driver: NewMountDriver(), 106 TempTarget: target, 107 TempUpper: upper, 108 LowLayers: lowLayers, 109 }, nil 110 } 111 112 //NewMountServiceByTarget will filter file system by target,if not existed,return false. 113 func NewMountServiceByTarget(target string) Service { 114 mounted, info := GetMountDetails(target) 115 if !mounted { 116 return nil 117 } 118 return &mounter{ 119 driver: NewMountDriver(), 120 TempTarget: target, 121 TempUpper: info.Upper, 122 LowLayers: info.Lowers, 123 } 124 } 125 126 type Info struct { 127 Target string 128 Upper string 129 Lowers []string 130 } 131 132 func GetMountDetails(target string) (bool, *Info) { 133 cmd := fmt.Sprintf("mount | grep %s", target) 134 result, err := utils.RunSimpleCmd(cmd) 135 if err != nil { 136 return false, nil 137 } 138 return mountCmdResultSplit(result, target) 139 } 140 141 func GetRemoteMountDetails(s ssh.Interface, ip string, target string) (bool, *Info) { 142 result, err := s.Cmd(ip, fmt.Sprintf("mount | grep %s", target)) 143 if err != nil { 144 return false, nil 145 } 146 return mountCmdResultSplit(string(result), target) 147 } 148 149 func mountCmdResultSplit(result string, target string) (bool, *Info) { 150 if !strings.Contains(result, target) { 151 return false, nil 152 } 153 154 data := strings.Split(result, ",upperdir=") 155 if len(data) < 2 { 156 return false, nil 157 } 158 159 lowers := strings.Split(strings.Split(data[0], ",lowerdir=")[1], ":") 160 upper := strings.TrimSpace(strings.Split(data[1], ",workdir=")[0]) 161 return true, &Info{ 162 Target: target, 163 Upper: upper, 164 Lowers: utils.Reverse(lowers), 165 } 166 } 167 168 func GetBuildMountInfo(filter string) []Info { 169 var infos []Info 170 var mp []string 171 ps, _ := disk.Partitions(true) 172 for _, p := range ps { 173 if p.Fstype == "overlay" && strings.Contains(p.Mountpoint, "sealer") && 174 strings.Contains(p.Mountpoint, filter) { 175 mp = append(mp, p.Mountpoint) 176 } 177 } 178 for _, p := range mp { 179 _, info := GetMountDetails(p) 180 if info != nil { 181 infos = append(infos, *info) 182 } 183 } 184 return infos 185 }