github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/build/buildimage/differ.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  	"context"
    19  	"fmt"
    20  	"io/fs"
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	v1 "github.com/alibaba/sealer/types/api/v1"
    25  
    26  	"github.com/alibaba/sealer/build/layerutils/charts"
    27  	manifest "github.com/alibaba/sealer/build/layerutils/manifests"
    28  	"github.com/alibaba/sealer/common"
    29  	"github.com/alibaba/sealer/pkg/image/save"
    30  	"github.com/alibaba/sealer/pkg/runtime"
    31  	"github.com/alibaba/sealer/utils"
    32  	"golang.org/x/sync/errgroup"
    33  )
    34  
    35  var (
    36  	copyToManifests = "manifests"
    37  	copyToChart     = "charts"
    38  	copyToImageList = "imageList"
    39  	dispatch        map[string]func(srcPath string) ([]string, error)
    40  )
    41  
    42  func init() {
    43  	dispatch = map[string]func(srcPath string) ([]string, error){
    44  		copyToManifests: parseYamlImages,
    45  		copyToChart:     parseChartImages,
    46  		copyToImageList: parseRawImageList,
    47  	}
    48  }
    49  
    50  type registry struct {
    51  	platform v1.Platform
    52  	puller   save.ImageSave
    53  }
    54  
    55  func (r registry) Process(srcPath, rootfs string) error {
    56  	eg, _ := errgroup.WithContext(context.Background())
    57  
    58  	var images []string
    59  	for t, p := range dispatch {
    60  		dispatchType := t
    61  		parse := p
    62  		eg.Go(func() error {
    63  			ima, err := parse(srcPath)
    64  			if err != nil {
    65  				return fmt.Errorf("failed to parse images from %s error is : %v", dispatchType, err)
    66  			}
    67  			images = append(images, ima...)
    68  			return nil
    69  		})
    70  	}
    71  
    72  	if err := eg.Wait(); err != nil {
    73  		return err
    74  	}
    75  
    76  	return r.puller.SaveImages(images, filepath.Join(rootfs, common.RegistryDirName), r.platform)
    77  }
    78  
    79  func NewRegistryDiffer(platform v1.Platform) Differ {
    80  	ctx := context.Background()
    81  	return registry{
    82  		platform: platform,
    83  		puller:   save.NewImageSaver(ctx),
    84  	}
    85  }
    86  
    87  func parseChartImages(srcPath string) ([]string, error) {
    88  	chartsPath := filepath.Join(srcPath, copyToChart)
    89  	if !utils.IsExist(chartsPath) {
    90  		return nil, nil
    91  	}
    92  
    93  	var images []string
    94  	imageSearcher, err := charts.NewCharts()
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	err = filepath.Walk(chartsPath, func(path string, f fs.FileInfo, err error) error {
   100  		if err != nil {
   101  			return err
   102  		}
   103  
   104  		if !f.IsDir() {
   105  			return nil
   106  		}
   107  
   108  		if utils.IsExist(filepath.Join(path, "Chart.yaml")) && utils.IsExist(filepath.Join(path, "values.yaml")) &&
   109  			utils.IsExist(filepath.Join(path, "templates")) {
   110  			ima, err := imageSearcher.ListImages(path)
   111  			if err != nil {
   112  				return err
   113  			}
   114  			images = append(images, ima...)
   115  		}
   116  		return nil
   117  	})
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	return FormatImages(images), nil
   122  }
   123  
   124  func parseYamlImages(srcPath string) ([]string, error) {
   125  	manifestsPath := filepath.Join(srcPath, copyToManifests)
   126  	if !utils.IsExist(manifestsPath) {
   127  		return nil, nil
   128  	}
   129  	var images []string
   130  
   131  	imageSearcher, err := manifest.NewManifests()
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	err = filepath.Walk(manifestsPath, func(path string, f fs.FileInfo, err error) error {
   137  		if err != nil {
   138  			return err
   139  		}
   140  		if f.IsDir() {
   141  			return nil
   142  		}
   143  
   144  		ext := strings.ToLower(filepath.Ext(f.Name()))
   145  		if ext != ".yaml" && ext != ".yml" && ext != ".tmpl" {
   146  			return nil
   147  		}
   148  
   149  		ima, err := imageSearcher.ListImages(path)
   150  
   151  		if err != nil {
   152  			return err
   153  		}
   154  		images = append(images, ima...)
   155  		return nil
   156  	})
   157  
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	return FormatImages(images), nil
   162  }
   163  
   164  func parseRawImageList(srcPath string) ([]string, error) {
   165  	imageListFilePath := filepath.Join(srcPath, copyToManifests, copyToImageList)
   166  	if !utils.IsExist(imageListFilePath) {
   167  		return nil, nil
   168  	}
   169  
   170  	images, err := utils.ReadLines(imageListFilePath)
   171  	if err != nil {
   172  		return nil, fmt.Errorf("failed to read file content %s:%v", imageListFilePath, err)
   173  	}
   174  	return FormatImages(images), nil
   175  }
   176  
   177  type metadata struct {
   178  }
   179  
   180  func (m metadata) Process(srcPath, rootfs string) error {
   181  	// check "KubeVersion" of Chart.yaml under charts dir,to overwrite the metadata.
   182  	kv := getKubeVersion(srcPath)
   183  	if kv == "" {
   184  		return nil
   185  	}
   186  
   187  	md, err := m.loadMetadata(srcPath, rootfs)
   188  	if err != nil {
   189  		return err
   190  	}
   191  
   192  	if md.KubeVersion == kv {
   193  		return nil
   194  	}
   195  	md.KubeVersion = kv
   196  	mf := filepath.Join(rootfs, common.DefaultMetadataName)
   197  	if err = utils.MarshalJSONToFile(mf, md); err != nil {
   198  		return fmt.Errorf("failed to set image Metadata file, err: %v", err)
   199  	}
   200  
   201  	return nil
   202  }
   203  
   204  func (m metadata) loadMetadata(srcPath, rootfs string) (*runtime.Metadata, error) {
   205  	// if Metadata file existed in srcPath, load and marshal to check the legality of it's content.
   206  	// if not, use rootfs Metadata.
   207  	smd, err := runtime.LoadMetadata(srcPath)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	if smd != nil {
   212  		return smd, nil
   213  	}
   214  
   215  	md, err := runtime.LoadMetadata(rootfs)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	if md != nil {
   221  		return md, nil
   222  	}
   223  	return nil, fmt.Errorf("failed to load rootfs Metadata")
   224  }
   225  
   226  func NewMetadataDiffer() Differ {
   227  	return metadata{}
   228  }