mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-17 23:25:32 +02:00
vendor: GoogleCloudPlatform/container-diff is now GoogleContainerTools/container-diff
This commit is contained in:
Generated
Vendored
+259
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
Copyright 2018 Google, Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package image
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"github.com/containers/image/docker"
|
||||
img "github.com/containers/image/image"
|
||||
"github.com/containers/image/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/manifest"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
type MutableSource struct {
|
||||
ProxySource
|
||||
mfst *manifest.Schema2
|
||||
cfg *manifest.Schema2Image
|
||||
extraBlobs map[string][]byte
|
||||
extraLayers []digest.Digest
|
||||
}
|
||||
|
||||
func NewMutableSource(r types.ImageReference) (*MutableSource, error) {
|
||||
if r == nil {
|
||||
return MutableSourceFromScratch()
|
||||
}
|
||||
src, err := r.NewImageSource(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img, err := r.NewImage(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ms := &MutableSource{
|
||||
ProxySource: ProxySource{
|
||||
Ref: r,
|
||||
ImageSource: src,
|
||||
img: img,
|
||||
},
|
||||
extraBlobs: make(map[string][]byte),
|
||||
}
|
||||
if err := ms.populateManifestAndConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
func MutableSourceFromScratch() (*MutableSource, error) {
|
||||
config := &manifest.Schema2Image{
|
||||
Schema2V1Image: manifest.Schema2V1Image{
|
||||
Config: &manifest.Schema2Config{},
|
||||
},
|
||||
RootFS: &manifest.Schema2RootFS{},
|
||||
History: []manifest.Schema2History{},
|
||||
}
|
||||
ref, err := docker.ParseReference("//scratch")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
src, err := ref.NewImageSource(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ms := &MutableSource{
|
||||
ProxySource: ProxySource{
|
||||
Ref: &ProxyReference{
|
||||
ImageReference: ref,
|
||||
},
|
||||
ImageSource: src,
|
||||
},
|
||||
extraBlobs: make(map[string][]byte),
|
||||
cfg: config,
|
||||
mfst: &manifest.Schema2{},
|
||||
}
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
// Manifest marshals the stored manifest to the byte format.
|
||||
func (m *MutableSource) GetManifest(_ *digest.Digest) ([]byte, string, error) {
|
||||
if err := m.saveConfig(); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
s, err := json.Marshal(m.mfst)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return s, manifest.DockerV2Schema2MediaType, err
|
||||
}
|
||||
|
||||
// populateManifestAndConfig parses the raw manifest and configs, storing them on the struct.
|
||||
func (m *MutableSource) populateManifestAndConfig() error {
|
||||
context := &types.SystemContext{
|
||||
OSChoice: "linux",
|
||||
ArchitectureChoice: "amd64",
|
||||
}
|
||||
image, err := m.ProxySource.Ref.NewImage(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer image.Close()
|
||||
// First get manifest
|
||||
mfstBytes, mfstType, err := image.Manifest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mfstType == manifest.DockerV2ListMediaType {
|
||||
// We need to select a manifest digest from the manifest list
|
||||
unparsedImage := img.UnparsedInstance(m.ImageSource, nil)
|
||||
|
||||
mfstDigest, err := img.ChooseManifestInstanceFromManifestList(context, unparsedImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mfstBytes, _, err = m.ProxySource.GetManifest(&mfstDigest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m.mfst, err = manifest.Schema2FromManifest(mfstBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now, get config
|
||||
configBlob, err := image.ConfigBlob()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(configBlob, &m.cfg)
|
||||
}
|
||||
|
||||
// GetBlob first checks the stored "extra" blobs, then proxies the call to the original source.
|
||||
func (m *MutableSource) GetBlob(bi types.BlobInfo) (io.ReadCloser, int64, error) {
|
||||
if b, ok := m.extraBlobs[bi.Digest.String()]; ok {
|
||||
return ioutil.NopCloser(bytes.NewReader(b)), int64(len(b)), nil
|
||||
}
|
||||
return m.ImageSource.GetBlob(bi)
|
||||
}
|
||||
|
||||
func gzipBytes(b []byte) ([]byte, error) {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
w := gzip.NewWriter(buf)
|
||||
_, err := w.Write(b)
|
||||
w.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// appendLayer appends an uncompressed blob to the image, preserving the invariants required across the config and manifest.
|
||||
func (m *MutableSource) AppendLayer(content []byte, author string) error {
|
||||
compressedBlob, err := gzipBytes(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dgst := digest.FromBytes(compressedBlob)
|
||||
|
||||
// Add the layer to the manifest.
|
||||
descriptor := manifest.Schema2Descriptor{
|
||||
MediaType: manifest.DockerV2Schema2LayerMediaType,
|
||||
Size: int64(len(content)),
|
||||
Digest: dgst,
|
||||
}
|
||||
m.mfst.LayersDescriptors = append(m.mfst.LayersDescriptors, descriptor)
|
||||
|
||||
m.extraBlobs[dgst.String()] = compressedBlob
|
||||
m.extraLayers = append(m.extraLayers, dgst)
|
||||
|
||||
// Also add it to the config.
|
||||
diffID := digest.FromBytes(content)
|
||||
m.cfg.RootFS.DiffIDs = append(m.cfg.RootFS.DiffIDs, diffID)
|
||||
m.AppendConfigHistory(author, false)
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveConfig marshals the stored image config, and updates the references to it in the manifest.
|
||||
func (m *MutableSource) saveConfig() error {
|
||||
cfgBlob, err := json.Marshal(m.cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfgDigest := digest.FromBytes(cfgBlob)
|
||||
m.extraBlobs[cfgDigest.String()] = cfgBlob
|
||||
m.mfst.ConfigDescriptor = manifest.Schema2Descriptor{
|
||||
MediaType: manifest.DockerV2Schema2ConfigMediaType,
|
||||
Size: int64(len(cfgBlob)),
|
||||
Digest: cfgDigest,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Env returns a map of environment variables stored in the image config
|
||||
// Converts each variable from a string of the form KEY=VALUE to a map of KEY:VALUE
|
||||
func (m *MutableSource) Env() map[string]string {
|
||||
envArray := m.cfg.Schema2V1Image.Config.Env
|
||||
envMap := make(map[string]string)
|
||||
for _, env := range envArray {
|
||||
entry := strings.Split(env, "=")
|
||||
envMap[entry[0]] = entry[1]
|
||||
}
|
||||
return envMap
|
||||
}
|
||||
|
||||
// SetEnv takes a map of environment variables, and converts them to an array of strings
|
||||
// in the form KEY=VALUE, and then sets the image config
|
||||
func (m *MutableSource) SetEnv(envMap map[string]string, author string) {
|
||||
envArray := []string{}
|
||||
for key, value := range envMap {
|
||||
entry := key + "=" + value
|
||||
envArray = append(envArray, entry)
|
||||
}
|
||||
m.cfg.Schema2V1Image.Config.Env = envArray
|
||||
m.AppendConfigHistory(author, true)
|
||||
}
|
||||
|
||||
func (m *MutableSource) Config() *manifest.Schema2Config {
|
||||
return m.cfg.Schema2V1Image.Config
|
||||
}
|
||||
|
||||
func (m *MutableSource) SetConfig(config *manifest.Schema2Config, author string, emptyLayer bool) {
|
||||
m.cfg.Schema2V1Image.Config = config
|
||||
m.AppendConfigHistory(author, emptyLayer)
|
||||
}
|
||||
|
||||
func (m *MutableSource) AppendConfigHistory(author string, emptyLayer bool) {
|
||||
history := manifest.Schema2History{
|
||||
Created: time.Now(),
|
||||
Author: author,
|
||||
EmptyLayer: emptyLayer,
|
||||
}
|
||||
m.cfg.History = append(m.cfg.History, history)
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2018 Google, Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package image
|
||||
|
||||
import (
|
||||
"github.com/containers/image/types"
|
||||
)
|
||||
|
||||
// ProxySource is a type that implements types.ImageSource by proxying all calls to an underlying implementation.
|
||||
type ProxySource struct {
|
||||
Ref types.ImageReference
|
||||
types.ImageSource
|
||||
img types.Image
|
||||
}
|
||||
|
||||
func NewProxySource(ref types.ImageReference) (*ProxySource, error) {
|
||||
src, err := ref.NewImageSource(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer src.Close()
|
||||
img, err := ref.NewImage(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ProxySource{
|
||||
Ref: ref,
|
||||
img: img,
|
||||
ImageSource: src,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *ProxySource) Reference() types.ImageReference {
|
||||
return p.Ref
|
||||
}
|
||||
|
||||
func (p *ProxySource) LayerInfosForCopy() []types.BlobInfo {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxyReference implements types.Reference by proxying calls to an underlying implementation.
|
||||
type ProxyReference struct {
|
||||
types.ImageReference
|
||||
Src types.ImageSource
|
||||
}
|
||||
|
||||
func (p *ProxyReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
|
||||
return p.Src, nil
|
||||
}
|
||||
Reference in New Issue
Block a user