github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/filesystem/cloudimage/cloudimage.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 cloudimage
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"time"
    23  
    24  	"github.com/alibaba/sealer/pkg/env"
    25  
    26  	"github.com/alibaba/sealer/utils/platform"
    27  
    28  	"github.com/alibaba/sealer/common"
    29  	"github.com/alibaba/sealer/pkg/image"
    30  	"github.com/alibaba/sealer/pkg/image/store"
    31  	v2 "github.com/alibaba/sealer/types/api/v2"
    32  	"github.com/alibaba/sealer/utils"
    33  	"github.com/alibaba/sealer/utils/mount"
    34  	"github.com/alibaba/sealer/utils/ssh"
    35  )
    36  
    37  type Interface interface {
    38  	MountImage(cluster *v2.Cluster) error
    39  	UnMountImage(cluster *v2.Cluster) error
    40  }
    41  
    42  type mounter struct {
    43  	imageStore store.ImageStore
    44  }
    45  
    46  func (m *mounter) MountImage(cluster *v2.Cluster) error {
    47  	return m.mountImage(cluster)
    48  }
    49  
    50  func (m *mounter) UnMountImage(cluster *v2.Cluster) error {
    51  	return m.umountImage(cluster)
    52  }
    53  
    54  func (m *mounter) umountImage(cluster *v2.Cluster) error {
    55  	mountRootDir := filepath.Join(common.DefaultClusterRootfsDir, cluster.Name, "mount")
    56  	if !utils.IsFileExist(mountRootDir) {
    57  		return nil
    58  	}
    59  	dir, err := ioutil.ReadDir(mountRootDir)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	for _, f := range dir {
    64  		if !f.IsDir() {
    65  			continue
    66  		}
    67  		if isMount, _ := mount.GetMountDetails(filepath.Join(mountRootDir, f.Name())); isMount {
    68  			err := utils.Retry(10, time.Second, func() error {
    69  				return mount.NewMountDriver().Unmount(filepath.Join(mountRootDir, f.Name()))
    70  			})
    71  			if err != nil {
    72  				return fmt.Errorf("failed to unmount dir %s,err: %v", filepath.Join(mountRootDir, f.Name()), err)
    73  			}
    74  		}
    75  	}
    76  	return os.RemoveAll(mountRootDir)
    77  }
    78  
    79  func (m *mounter) mountImage(cluster *v2.Cluster) error {
    80  	var (
    81  		mountDirs = make(map[string]bool)
    82  		driver    = mount.NewMountDriver()
    83  		err       error
    84  	)
    85  	clusterPlatform, err := ssh.GetClusterPlatform(cluster)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	clusterPlatform["local"] = *platform.GetDefaultPlatform()
    90  	for _, v := range clusterPlatform {
    91  		pfm := v
    92  		mountDir := platform.GetMountCloudImagePlatformDir(cluster.Name, pfm)
    93  		upperDir := filepath.Join(mountDir, "upper")
    94  		if mountDirs[mountDir] {
    95  			continue
    96  		}
    97  		mountDirs[mountDir] = true
    98  		if isMount, _ := mount.GetMountDetails(mountDir); isMount {
    99  			err = driver.Unmount(mountDir)
   100  			if err != nil {
   101  				return fmt.Errorf("%s already mount, and failed to umount %v", mountDir, err)
   102  			}
   103  		}
   104  		if utils.IsFileExist(mountDir) {
   105  			if err = os.RemoveAll(mountDir); err != nil {
   106  				return fmt.Errorf("failed to clean %s, %v", mountDir, err)
   107  			}
   108  		}
   109  		Image, err := m.imageStore.GetByName(cluster.Spec.Image, &pfm)
   110  		if err != nil {
   111  			return err
   112  		}
   113  		layers, err := image.GetImageLayerDirs(Image)
   114  		if err != nil {
   115  			return fmt.Errorf("get layers failed: %v", err)
   116  		}
   117  
   118  		if err = os.MkdirAll(upperDir, common.FileMode0755); err != nil {
   119  			return fmt.Errorf("create upperdir failed, %s", err)
   120  		}
   121  		if err = driver.Mount(mountDir, upperDir, layers...); err != nil {
   122  			return fmt.Errorf("mount files failed %v", err)
   123  		}
   124  		// use env list to render image mount dir: etc,charts,manifests.
   125  		err = renderENV(mountDir, cluster.GetAllIPList(), env.NewEnvProcessor(cluster))
   126  		if err != nil {
   127  			return err
   128  		}
   129  	}
   130  	return nil
   131  }
   132  
   133  func renderENV(imageMountDir string, ipList []string, p env.Interface) error {
   134  	var (
   135  		renderEtc       = filepath.Join(imageMountDir, common.EtcDir)
   136  		renderChart     = filepath.Join(imageMountDir, common.RenderChartsDir)
   137  		renderManifests = filepath.Join(imageMountDir, common.RenderManifestsDir)
   138  	)
   139  
   140  	for _, ip := range ipList {
   141  		for _, dir := range []string{renderEtc, renderChart, renderManifests} {
   142  			if utils.IsExist(dir) {
   143  				err := p.RenderAll(ip, dir)
   144  				if err != nil {
   145  					return err
   146  				}
   147  			}
   148  		}
   149  	}
   150  	return nil
   151  }
   152  
   153  func NewCloudImageMounter(is store.ImageStore) (Interface, error) {
   154  	return &mounter{
   155  		imageStore: is,
   156  	}, nil
   157  }