Update go-containerregistry.

This commit is contained in:
dlorenc
2018-08-23 11:33:36 -07:00
parent 8f71b7fb26
commit 6b3ab0d549
18 changed files with 2768 additions and 256 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ func (h *helper) Authorization() (string, error) {
// If we see this specific message, it means the domain wasn't found
// and we should fall back on anonymous auth.
output := out.String()
output := strings.TrimSpace(out.String())
if output == magicNotFoundMessage {
return Anonymous.Authorization()
}
+33
View File
@@ -0,0 +1,33 @@
// Copyright 2018 Google LLC 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 v1
import (
"github.com/google/go-containerregistry/pkg/v1/types"
)
type ImageIndex interface {
// MediaType of this image's manifest.
MediaType() (types.MediaType, error)
// Digest returns the sha256 of this index's manifest.
Digest() (Hash, error)
// IndexManifest returns this image index's manifest object.
IndexManifest() (*IndexManifest, error)
// RawIndexManifest returns the serialized bytes of IndexManifest().
RawIndexManifest() ([]byte, error)
}
+18
View File
@@ -30,6 +30,14 @@ type Manifest struct {
Annotations map[string]string `json:"annotations,omitempty"`
}
// IndexManifest represents an OCI image index in a structured way.
type IndexManifest struct {
SchemaVersion int64 `json:"schemaVersion"`
MediaType types.MediaType `json:"mediaType,omitempty"`
Manifests []Descriptor `json:"manifests"`
Annotations map[string]string `json:"annotations,omitempty"`
}
// Descriptor holds a reference from the manifest to one of its constituent elements.
type Descriptor struct {
MediaType types.MediaType `json:"mediaType"`
@@ -37,6 +45,7 @@ type Descriptor struct {
Digest Hash `json:"digest"`
URLs []string `json:"urls,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
Platform *Platform `json:"platform,omitempty"`
}
// ParseManifest parses the io.Reader's contents into a Manifest.
@@ -47,3 +56,12 @@ func ParseManifest(r io.Reader) (*Manifest, error) {
}
return &m, nil
}
// ParseIndexManifest parses the io.Reader's contents into an IndexManifest.
func ParseIndexManifest(r io.Reader) (*IndexManifest, error) {
im := IndexManifest{}
if err := json.NewDecoder(r).Decode(&im); err != nil {
return nil, err
}
return &im, nil
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2018 Google LLC 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 v1
// Platform represents the target os/arch for an image.
type Platform struct {
Architecture string `json:"architecture"`
OS string `json:"os"`
OSVersion string `json:"os.version,omitempty"`
OSFeatures []string `json:"os.features,omitempty"`
Variant string `json:"variant,omitempty"`
}
+9 -8
View File
@@ -144,14 +144,15 @@ func (r *remoteImage) RawManifest() ([]byte, error) {
if digest.String() != dgst.DigestStr() {
return nil, fmt.Errorf("manifest digest: %q does not match requested digest: %q for %q", digest, dgst.DigestStr(), r.ref)
}
} else if checksum := resp.Header.Get("Docker-Content-Digest"); checksum != "" && checksum != digest.String() {
err := fmt.Errorf("manifest digest: %q does not match Docker-Content-Digest: %q for %q", digest, checksum, r.ref)
if r.ref.Context().RegistryStr() == name.DefaultRegistry {
// TODO(docker/distribution#2395): Remove this check.
} else {
// When pulling by tag, we can only validate that the digest matches what the registry told us it should be.
return nil, err
}
} else {
// Do nothing for tags; I give up.
//
// We'd like to validate that the "Docker-Content-Digest" header matches what is returned by the registry,
// but so many registries implement this incorrectly that it's not worth checking.
//
// For reference:
// https://github.com/docker/distribution/issues/2395
// https://github.com/GoogleContainerTools/kaniko/issues/298
}
r.manifest = manifest
+30 -4
View File
@@ -120,6 +120,26 @@ func (w *writer) nextLocation(resp *http.Response) (string, error) {
return resp.Request.URL.ResolveReference(u).String(), nil
}
// checkExisting checks if a blob exists already in the repository by making a
// HEAD request to the blob store API. GCR performs an existence check on the
// initiation if "mount" is specified, even if no "from" sources are specified.
// However, this is not broadly applicable to all registries, e.g. ECR.
func (w *writer) checkExisting(h v1.Hash) (bool, error) {
u := w.url(fmt.Sprintf("/v2/%s/blobs/%s", w.ref.Context().RepositoryStr(), h.String()))
resp, err := w.client.Head(u.String())
if err != nil {
return false, err
}
defer resp.Body.Close()
if err := CheckError(resp, http.StatusOK, http.StatusNotFound); err != nil {
return false, err
}
return resp.StatusCode == http.StatusOK, nil
}
// initiateUpload initiates the blob upload, which starts with a POST that can
// optionally include the hash of the layer and a list of repositories from
// which that layer might be read. On failure, an error is returned.
@@ -135,10 +155,7 @@ func (w *writer) initiateUpload(h v1.Hash) (location string, mounted bool, err e
if err != nil {
return "", false, err
}
// We currently avoid HEAD because it's semi-redundant with the mount that is part
// of initiating the blob upload. GCR will perform an existence check on the initiation
// if "mount" is specified, even if no "from" sources are specified. If this turns out
// to not be broadly applicable then we should replace mounts without "from"s with a HEAD.
if ml, ok := l.(*MountableLayer); ok {
if w.ref.Context().RegistryStr() == ml.Reference.Context().RegistryStr() {
uv["from"] = []string{ml.Reference.Context().RepositoryStr()}
@@ -231,6 +248,15 @@ func (w *writer) commitBlob(h v1.Hash, location string) (err error) {
// uploadOne performs a complete upload of a single layer.
func (w *writer) uploadOne(h v1.Hash) error {
existing, err := w.checkExisting(h)
if err != nil {
return err
}
if existing {
log.Printf("existing blob: %v", h)
return nil
}
location, mounted, err := w.initiateUpload(h)
if err != nil {
return err
@@ -26,6 +26,11 @@ func (in *Config) DeepCopyInto(out *Config) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Healthcheck != nil {
in, out := &in.Healthcheck, &out.Healthcheck
*out = new(HealthConfig)
(*in).DeepCopyInto(*out)
}
if in.Entrypoint != nil {
in, out := &in.Entrypoint, &out.Entrypoint
*out = make([]string, len(*in))
@@ -51,15 +56,15 @@ func (in *Config) DeepCopyInto(out *Config) {
if in.Volumes != nil {
in, out := &in.Volumes, &out.Volumes
*out = make(map[string]struct{}, len(*in))
for key := range *in {
(*out)[key] = struct{}{}
for key, val := range *in {
(*out)[key] = val
}
}
if in.ExposedPorts != nil {
in, out := &in.ExposedPorts, &out.ExposedPorts
*out = make(map[string]struct{}, len(*in))
for key := range *in {
(*out)[key] = struct{}{}
for key, val := range *in {
(*out)[key] = val
}
}
if in.Shell != nil {
@@ -123,6 +128,11 @@ func (in *Descriptor) DeepCopyInto(out *Descriptor) {
(*out)[key] = val
}
}
if in.Platform != nil {
in, out := &in.Platform, &out.Platform
*out = new(Platform)
(*in).DeepCopyInto(*out)
}
return
}
@@ -152,6 +162,27 @@ func (in *Hash) DeepCopy() *Hash {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HealthConfig) DeepCopyInto(out *HealthConfig) {
*out = *in
if in.Test != nil {
in, out := &in.Test, &out.Test
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthConfig.
func (in *HealthConfig) DeepCopy() *HealthConfig {
if in == nil {
return nil
}
out := new(HealthConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *History) DeepCopyInto(out *History) {
*out = *in
@@ -169,6 +200,36 @@ func (in *History) DeepCopy() *History {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IndexManifest) DeepCopyInto(out *IndexManifest) {
*out = *in
if in.Manifests != nil {
in, out := &in.Manifests, &out.Manifests
*out = make([]Descriptor, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IndexManifest.
func (in *IndexManifest) DeepCopy() *IndexManifest {
if in == nil {
return nil
}
out := new(IndexManifest)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Manifest) DeepCopyInto(out *Manifest) {
*out = *in
@@ -200,6 +261,27 @@ func (in *Manifest) DeepCopy() *Manifest {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Platform) DeepCopyInto(out *Platform) {
*out = *in
if in.OSFeatures != nil {
in, out := &in.OSFeatures, &out.OSFeatures
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Platform.
func (in *Platform) DeepCopy() *Platform {
if in == nil {
return nil
}
out := new(Platform)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RootFS) DeepCopyInto(out *RootFS) {
*out = *in