github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/image/store/layer_store.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 store
    16  
    17  import (
    18  	"compress/gzip"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"sync"
    25  
    26  	"github.com/opencontainers/go-digest"
    27  	"github.com/vbatts/tar-split/tar/asm"
    28  	"github.com/vbatts/tar-split/tar/storage"
    29  
    30  	"github.com/alibaba/sealer/common"
    31  	"github.com/alibaba/sealer/logger"
    32  	"github.com/alibaba/sealer/pkg/image/reference"
    33  	"github.com/alibaba/sealer/utils/archive"
    34  )
    35  
    36  type layerStore struct {
    37  	mux    sync.RWMutex
    38  	layers map[LayerID]*ROLayer
    39  	Backend
    40  }
    41  
    42  func (ls *layerStore) Get(id LayerID) Layer {
    43  	ls.mux.RLock()
    44  	defer ls.mux.RUnlock()
    45  	l, ok := ls.layers[id]
    46  	if !ok {
    47  		return nil
    48  	}
    49  	return l
    50  }
    51  
    52  func (ls *layerStore) RegisterLayerIfNotPresent(layer Layer) error {
    53  	layerExist := ls.Get(layer.ID())
    54  	if layerExist != nil {
    55  		return nil
    56  	}
    57  
    58  	curLayerDBDir := ls.LayerDBDir(layer.ID().ToDigest())
    59  	err := os.MkdirAll(curLayerDBDir, common.FileMode0755)
    60  	if err != nil {
    61  		return fmt.Errorf("failed to init layer db for %s, err: %s", curLayerDBDir, err)
    62  	}
    63  
    64  	layerTarReader, err := layer.TarStream()
    65  	if err != nil {
    66  		return err
    67  	}
    68  	defer layerTarReader.Close()
    69  
    70  	err = ls.DisassembleTar(layer.ID().ToDigest(), layerTarReader)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	err = ls.storeROLayer(layer)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	ls.mux.Lock()
    81  	defer ls.mux.Unlock()
    82  	if roLayer, ok := layer.(*ROLayer); ok {
    83  		ls.layers[layer.ID()] = roLayer
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  func (ls *layerStore) RegisterLayerForBuilder(path string) (digest.Digest, error) {
    90  	dist, size, err := archive.TarCanonicalDigest(path)
    91  	if err != nil {
    92  		return "", err
    93  	}
    94  
    95  	if dist == "" {
    96  		return "", nil
    97  	}
    98  
    99  	// layerContentDigest is the layer id at the build stage.
   100  	// and the layer id won't change anymore
   101  	roLayer, err := NewROLayer(dist, size, nil)
   102  	if err != nil {
   103  		return "", fmt.Errorf("failed to create a new rolayer, err: %s", err)
   104  	}
   105  	layerDataDir := ls.LayerDataDir(roLayer.ID().ToDigest())
   106  
   107  	// remove before mv files to target
   108  	_, err = os.Stat(layerDataDir)
   109  	if err == nil {
   110  		err = os.RemoveAll(layerDataDir)
   111  		if err != nil {
   112  			return "", err
   113  		}
   114  	}
   115  
   116  	err = os.Rename(path, layerDataDir)
   117  	if err != nil {
   118  		return "", err
   119  	}
   120  
   121  	return dist, ls.RegisterLayerIfNotPresent(roLayer)
   122  }
   123  
   124  func (ls *layerStore) DisassembleTar(layerID digest.Digest, streamReader io.ReadCloser) error {
   125  	layerDBDir := ls.LayerDBDir(layerID)
   126  	// #nosec
   127  	mf, err := os.OpenFile(filepath.Join(layerDBDir, tarDataGZ), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	defer func() {
   133  		if err := mf.Close(); err != nil {
   134  			logger.Fatal("failed to close file")
   135  		}
   136  	}()
   137  	mfz := gzip.NewWriter(mf)
   138  
   139  	defer func() {
   140  		if err := mfz.Close(); err != nil {
   141  			logger.Fatal("failed to close file")
   142  		}
   143  	}()
   144  	metaPacker := storage.NewJSONPacker(mfz)
   145  	// we're passing nil here for the file putter, because the ApplyDiff will
   146  	// handle the extraction of the archive
   147  	its, err := asm.NewInputTarStream(streamReader, metaPacker, nil)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	_, err = io.Copy(ioutil.Discard, its)
   153  	return err
   154  }
   155  
   156  func (ls *layerStore) Delete(id LayerID) error {
   157  	digs := id.ToDigest()
   158  	if layer := ls.Get(id); layer == nil {
   159  		logger.Debug("layer %s is already deleted", id)
   160  		return nil
   161  	}
   162  
   163  	layerDataPath := ls.LayerDataDir(digs)
   164  	if err := os.RemoveAll(layerDataPath); err != nil {
   165  		return err
   166  	}
   167  
   168  	layerDBDir := ls.LayerDBDir(digs)
   169  	if err := os.RemoveAll(layerDBDir); err != nil {
   170  		return err
   171  	}
   172  
   173  	ls.mux.Lock()
   174  	defer ls.mux.Unlock()
   175  	delete(ls.layers, id)
   176  	return nil
   177  }
   178  
   179  func (ls *layerStore) AddDistributionMetadata(layerID LayerID, named reference.Named, descriptorDigest digest.Digest) error {
   180  	return ls.addDistributionMetadata(layerID, map[string]digest.Digest{
   181  		named.Domain() + "/" + named.Repo(): descriptorDigest,
   182  	})
   183  }
   184  
   185  func (ls *layerStore) loadAllROLayers() error {
   186  	roLayers, err := ls.Backend.loadAllROLayers()
   187  	if err != nil {
   188  		return fmt.Errorf("failed to load all layers, err: %s", err)
   189  	}
   190  
   191  	ls.mux.Lock()
   192  	defer ls.mux.Unlock()
   193  	for _, layer := range roLayers {
   194  		ls.layers[layer.id] = layer
   195  	}
   196  	return nil
   197  }
   198  
   199  func NewDefaultLayerStore() (LayerStore, error) {
   200  	sb, err := NewFSStoreBackend()
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  
   205  	ls := &layerStore{
   206  		layers:  map[LayerID]*ROLayer{},
   207  		Backend: sb,
   208  	}
   209  	err = ls.loadAllROLayers()
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	return ls, nil
   214  }