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  }