github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/imagedistributor/mount.go (about)

     1  // Copyright © 2022 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 imagedistributor
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"os"
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	"github.com/sealerio/sealer/pkg/define/options"
    25  	"github.com/sealerio/sealer/pkg/imageengine"
    26  	v1 "github.com/sealerio/sealer/types/api/v1"
    27  	"github.com/sealerio/sealer/utils/os/fs"
    28  )
    29  
    30  type buildAhMounter struct {
    31  	imageEngine imageengine.Interface
    32  }
    33  
    34  func (b buildAhMounter) Mount(imageName string, platform v1.Platform, dest string) (string, string, string, error) {
    35  	mountDir := filepath.Join(dest,
    36  		strings.ReplaceAll(imageName, "/", "_"),
    37  		strings.Join([]string{platform.OS, platform.Architecture, platform.Variant}, "_"))
    38  
    39  	imageID, err := b.imageEngine.Pull(&options.PullOptions{
    40  		Quiet:      false,
    41  		PullPolicy: "missing",
    42  		Image:      imageName,
    43  		Platform:   platform.ToString(),
    44  	})
    45  	if err != nil {
    46  		return "", "", "", err
    47  	}
    48  
    49  	if err := fs.FS.MkdirAll(filepath.Dir(mountDir)); err != nil {
    50  		return "", "", "", err
    51  	}
    52  
    53  	id, err := b.imageEngine.CreateWorkingContainer(&options.BuildRootfsOptions{
    54  		DestDir:       mountDir,
    55  		ImageNameOrID: imageID,
    56  	})
    57  
    58  	if err != nil {
    59  		return "", "", "", err
    60  	}
    61  	return mountDir, id, imageID, nil
    62  }
    63  
    64  func (b buildAhMounter) Umount(mountDir, cid string) error {
    65  	if err := fs.FS.RemoveAll(mountDir); err != nil {
    66  		return fmt.Errorf("failed to remove mount dir %s: %v", mountDir, err)
    67  	}
    68  
    69  	if err := b.imageEngine.RemoveContainer(&options.RemoveContainerOptions{
    70  		ContainerNamesOrIDs: []string{cid},
    71  	}); err != nil {
    72  		return fmt.Errorf("failed to remove working container: %v", err)
    73  	}
    74  
    75  	return nil
    76  }
    77  
    78  func NewBuildAhMounter(imageEngine imageengine.Interface) Mounter {
    79  	return buildAhMounter{
    80  		imageEngine: imageEngine,
    81  	}
    82  }
    83  
    84  type ImagerMounter struct {
    85  	Mounter
    86  	rootDir       string
    87  	hostsPlatform map[v1.Platform][]net.IP
    88  }
    89  
    90  type ClusterImageMountInfo struct {
    91  	// target hosts ip list, not all cluster ips.
    92  	Hosts       []net.IP
    93  	Platform    v1.Platform
    94  	MountDir    string
    95  	ContainerID string
    96  	ImageID     string
    97  }
    98  
    99  func (c ImagerMounter) Mount(imageName string) ([]ClusterImageMountInfo, error) {
   100  	var imageMountInfos []ClusterImageMountInfo
   101  	for platform, hosts := range c.hostsPlatform {
   102  		mountDir, cid, imageID, err := c.Mounter.Mount(imageName, platform, c.rootDir)
   103  		if err != nil {
   104  			return nil, fmt.Errorf("failed to mount image %s with platform %s:%v", imageName, platform.ToString(), err)
   105  		}
   106  		imageMountInfos = append(imageMountInfos, ClusterImageMountInfo{
   107  			Hosts:       hosts,
   108  			Platform:    platform,
   109  			MountDir:    mountDir,
   110  			ContainerID: cid,
   111  			ImageID:     imageID,
   112  		})
   113  	}
   114  
   115  	return imageMountInfos, nil
   116  }
   117  
   118  func (c ImagerMounter) Umount(imageName string, imageMountInfo []ClusterImageMountInfo) error {
   119  	for _, info := range imageMountInfo {
   120  		err := c.Mounter.Umount(info.MountDir, info.ContainerID)
   121  		if err != nil {
   122  			return fmt.Errorf("failed to umount %s:%v", info.MountDir, err)
   123  		}
   124  	}
   125  
   126  	// delete all mounted images
   127  	if err := fs.FS.RemoveAll(c.rootDir); err != nil {
   128  		return err
   129  	}
   130  	return nil
   131  }
   132  
   133  func NewImageMounter(imageEngine imageengine.Interface, hostsPlatform map[v1.Platform][]net.IP) (*ImagerMounter, error) {
   134  	tempDir, err := os.MkdirTemp("", "sealer-mount-tmp")
   135  	if err != nil {
   136  		return nil, fmt.Errorf("failed to create tmp mount dir, err: %v", err)
   137  	}
   138  
   139  	c := &ImagerMounter{
   140  		// todo : user could set this value by env or sealer config
   141  		rootDir:       tempDir,
   142  		hostsPlatform: hostsPlatform,
   143  	}
   144  
   145  	c.Mounter = NewBuildAhMounter(imageEngine)
   146  	return c, nil
   147  }