github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/image/store/layer.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  	"fmt"
    19  	"io"
    20  	"os"
    21  	"path/filepath"
    22  
    23  	"github.com/docker/distribution/manifest/schema2"
    24  	"github.com/opencontainers/go-digest"
    25  
    26  	"github.com/alibaba/sealer/logger"
    27  	"github.com/alibaba/sealer/utils/archive"
    28  )
    29  
    30  type LayerID digest.Digest
    31  
    32  func (li LayerID) String() string {
    33  	return string(li)
    34  }
    35  
    36  func (li LayerID) ToDigest() digest.Digest {
    37  	return digest.Digest(li)
    38  }
    39  
    40  func (li LayerID) Validate() error {
    41  	return li.ToDigest().Validate()
    42  }
    43  
    44  type ROLayer struct {
    45  	id                   LayerID
    46  	size                 int64
    47  	distributionMetadata map[string]digest.Digest
    48  }
    49  
    50  func (rl *ROLayer) ID() LayerID {
    51  	return rl.id
    52  }
    53  
    54  func (rl *ROLayer) SimpleID() string {
    55  	return rl.ID().ToDigest().Hex()[0:12]
    56  }
    57  
    58  func (rl *ROLayer) TarStream() (io.ReadCloser, error) {
    59  	layerBackend, err := NewFSStoreBackend()
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	var (
    65  		tarDataPath   = filepath.Join(layerBackend.LayerDBDir(rl.ID().ToDigest()), tarDataGZ)
    66  		layerDataPath = layerBackend.LayerDataDir(rl.ID().ToDigest())
    67  	)
    68  	_, err = os.Stat(tarDataPath)
    69  	// tar-data.json.gz does not exist
    70  	// at the pull stage, the file won't exist
    71  	// so we tar the layer dir.
    72  	if err != nil {
    73  		logger.Debug("failed to find %s for layer %s, use tar, err: %s", tarDataGZ, rl.ID(), err)
    74  		tarReader, tarErr := archive.TarWithoutRootDir(layerDataPath)
    75  		if tarErr != nil {
    76  			return nil, fmt.Errorf("failed to tar layer %s, err: %s", rl.ID(), tarErr)
    77  		}
    78  		return tarReader, nil
    79  	}
    80  
    81  	pr, pw := io.Pipe()
    82  	go func() {
    83  		err := layerBackend.assembleTar(rl.ID(), pw)
    84  		if err != nil {
    85  			_ = pw.CloseWithError(err)
    86  		} else {
    87  			_ = pw.Close()
    88  		}
    89  	}()
    90  
    91  	return pr, nil
    92  }
    93  
    94  func (rl *ROLayer) Size() int64 {
    95  	return rl.size
    96  }
    97  
    98  func (rl *ROLayer) SetSize(size int64) {
    99  	rl.size = size
   100  }
   101  
   102  func (rl *ROLayer) MediaType() string {
   103  	return schema2.MediaTypeLayer
   104  }
   105  
   106  func (rl *ROLayer) DistributionMetadata() map[string]digest.Digest {
   107  	return rl.distributionMetadata
   108  }
   109  
   110  func NewROLayer(layerDigest digest.Digest, size int64, distributionMetadata map[string]digest.Digest) (*ROLayer, error) {
   111  	if err := layerDigest.Validate(); err != nil {
   112  		return nil, err
   113  	}
   114  	if distributionMetadata == nil {
   115  		distributionMetadata = map[string]digest.Digest{}
   116  	}
   117  	return &ROLayer{
   118  		id:                   LayerID(layerDigest),
   119  		size:                 size,
   120  		distributionMetadata: distributionMetadata,
   121  	}, nil
   122  }