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 }