github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/build/buildimage/utils.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 buildimage
    16  
    17  import (
    18  	"fmt"
    19  	"io/fs"
    20  	"path/filepath"
    21  	"strings"
    22  
    23  	"github.com/alibaba/sealer/build/buildinstruction"
    24  	"github.com/alibaba/sealer/common"
    25  	"github.com/alibaba/sealer/logger"
    26  	v1 "github.com/alibaba/sealer/types/api/v1"
    27  	v2 "github.com/alibaba/sealer/types/api/v2"
    28  	"github.com/alibaba/sealer/utils"
    29  	"github.com/alibaba/sealer/utils/mount"
    30  	"helm.sh/helm/v3/pkg/chartutil"
    31  
    32  	"github.com/alibaba/sealer/pkg/parser"
    33  	"sigs.k8s.io/yaml"
    34  )
    35  
    36  // initImageSpec init default Image metadata
    37  func initImageSpec(kubefile string) (*v1.Image, error) {
    38  	kubeFile, err := utils.ReadAll(kubefile)
    39  	if err != nil {
    40  		return nil, fmt.Errorf("failed to load kubefile: %v", err)
    41  	}
    42  
    43  	rawImage, err := parser.NewParse().Parse(kubeFile)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	layer0 := rawImage.Spec.Layers[0]
    49  	if layer0.Type != common.FROMCOMMAND {
    50  		return nil, fmt.Errorf("first line of kubefile must start with %s", common.FROMCOMMAND)
    51  	}
    52  
    53  	return rawImage, nil
    54  }
    55  
    56  func setClusterFileToImage(cluster *v2.Cluster, image *v1.Image) error {
    57  	clusterData, err := yaml.Marshal(cluster)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	if image.Annotations == nil {
    63  		image.Annotations = make(map[string]string)
    64  	}
    65  	image.Annotations[common.ImageAnnotationForClusterfile] = string(clusterData)
    66  	return nil
    67  }
    68  
    69  func getKubeVersion(rootfs string) string {
    70  	chartsPath := filepath.Join(rootfs, "charts")
    71  	if !utils.IsExist(chartsPath) {
    72  		return ""
    73  	}
    74  	return readCharts(chartsPath)
    75  }
    76  
    77  func readCharts(chartsPath string) string {
    78  	var kv string
    79  	err := filepath.Walk(chartsPath, func(path string, f fs.FileInfo, err error) error {
    80  		if kv != "" {
    81  			return nil
    82  		}
    83  		if f.IsDir() || f.Name() != "Chart.yaml" {
    84  			return nil
    85  		}
    86  		meta, walkErr := chartutil.LoadChartfile(path)
    87  		if walkErr != nil {
    88  			return walkErr
    89  		}
    90  		if meta.KubeVersion != "" {
    91  			kv = meta.KubeVersion
    92  		}
    93  		return nil
    94  	})
    95  
    96  	if err != nil {
    97  		return ""
    98  	}
    99  	return kv
   100  }
   101  
   102  func FormatImages(images []string) (res []string) {
   103  	for _, ima := range utils.RemoveDuplicate(images) {
   104  		if ima == "" {
   105  			continue
   106  		}
   107  		if strings.HasPrefix(ima, "#") {
   108  			continue
   109  		}
   110  		res = append(res, trimQuotes(strings.TrimSpace(ima)))
   111  	}
   112  	return
   113  }
   114  
   115  func trimQuotes(s string) string {
   116  	if len(s) >= 2 {
   117  		if c := s[len(s)-1]; s[0] == c && (c == '"' || c == '\'') {
   118  			return s[1 : len(s)-1]
   119  		}
   120  	}
   121  	return s
   122  }
   123  
   124  // GetLayerMountInfo to get rootfs mount info.if not mounted will mount it via base layers.
   125  //1, already mount: runtime docker registry mount info,just get related mount info.
   126  //2, already mount: if exec build cmd failed and return ,need to collect related old mount info
   127  //3, new mount: just mount and return related info.
   128  func GetLayerMountInfo(baseLayers []v1.Layer) (mount.Service, error) {
   129  	var filterArgs = "tmp"
   130  	mountInfos := mount.GetBuildMountInfo(filterArgs)
   131  	lowerLayers := buildinstruction.GetBaseLayersPath(baseLayers)
   132  	for _, info := range mountInfos {
   133  		// if info.Lowers equal lowerLayers,means image already mounted.
   134  		if strings.Join(lowerLayers, ":") == strings.Join(info.Lowers, ":") {
   135  			logger.Info("get mount dir :%s success ", info.Target)
   136  			//nolint
   137  			return mount.NewMountService(info.Target, info.Upper, info.Lowers)
   138  		}
   139  	}
   140  
   141  	return mountRootfs(lowerLayers)
   142  }
   143  
   144  func mountRootfs(res []string) (mount.Service, error) {
   145  	mounter, err := mount.NewMountService("", "", res)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	err = mounter.TempMount()
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	return mounter, nil
   155  }