mirror of
https://github.com/containers/skopeo.git
synced 2025-09-24 11:26:59 +00:00
Add skopeo registry mirror integration tests
- Update toml to latest release - Update containers/image - Add integration tests - Add hidden `--registry-conf` flag used by the integration tests Signed-off-by: Sascha Grunert <sgrunert@suse.com>
This commit is contained in:
73
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
73
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
@@ -81,10 +81,8 @@ type bearerToken struct {
|
||||
// dockerClient is configuration for dealing with a single Docker registry.
|
||||
type dockerClient struct {
|
||||
// The following members are set by newDockerClient and do not change afterwards.
|
||||
sys *types.SystemContext
|
||||
registry string
|
||||
client *http.Client
|
||||
insecureSkipTLSVerify bool
|
||||
sys *types.SystemContext
|
||||
registry string
|
||||
|
||||
// The following members are not set by newDockerClient and must be set by callers if needed.
|
||||
username string
|
||||
@@ -96,6 +94,10 @@ type dockerClient struct {
|
||||
scheme string // Empty value also used to indicate detectProperties() has not yet succeeded.
|
||||
challenges []challenge
|
||||
supportsSignatures bool
|
||||
// The tlsClientConfig is setup during the creation of the dockerClient and
|
||||
// will be updated by detectPropertiesHelper(). Any HTTP request the
|
||||
// dockerClient does will be done by this TLS client configuration.
|
||||
tlsClientConfig *tls.Config
|
||||
|
||||
// Private state for setupRequestAuth (key: string, value: bearerToken)
|
||||
tokenCache sync.Map
|
||||
@@ -229,8 +231,7 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
|
||||
if registry == dockerHostname {
|
||||
registry = dockerRegistry
|
||||
}
|
||||
tr := tlsclientconfig.NewTransport()
|
||||
tr.TLSClientConfig = serverDefault()
|
||||
tlsClientConfig := serverDefault()
|
||||
|
||||
// It is undefined whether the host[:port] string for dockerHostname should be dockerHostname or dockerRegistry,
|
||||
// because docker/docker does not read the certs.d subdirectory at all in that case. We use the user-visible
|
||||
@@ -241,38 +242,31 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tlsclientconfig.SetupCertificates(certDir, tr.TLSClientConfig); err != nil {
|
||||
if err := tlsclientconfig.SetupCertificates(certDir, tlsClientConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if TLS verification shall be skipped (default=false) which can
|
||||
// either be specified in the sysregistriesv2 configuration or via the
|
||||
// SystemContext, whereas the SystemContext is prioritized.
|
||||
// be specified in the sysregistriesv2 configuration.
|
||||
skipVerify := false
|
||||
if sys != nil && sys.DockerInsecureSkipTLSVerify != types.OptionalBoolUndefined {
|
||||
// Only use the SystemContext if the actual value is defined.
|
||||
skipVerify = sys.DockerInsecureSkipTLSVerify == types.OptionalBoolTrue
|
||||
} else {
|
||||
reg, err := sysregistriesv2.FindRegistry(sys, reference)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error loading registries")
|
||||
}
|
||||
if reg != nil {
|
||||
skipVerify = reg.Insecure
|
||||
}
|
||||
reg, err := sysregistriesv2.FindRegistry(sys, reference)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error loading registries")
|
||||
}
|
||||
tr.TLSClientConfig.InsecureSkipVerify = skipVerify
|
||||
if reg != nil {
|
||||
skipVerify = reg.Insecure
|
||||
}
|
||||
tlsClientConfig.InsecureSkipVerify = skipVerify
|
||||
|
||||
return &dockerClient{
|
||||
sys: sys,
|
||||
registry: registry,
|
||||
client: &http.Client{Transport: tr},
|
||||
insecureSkipTLSVerify: skipVerify,
|
||||
sys: sys,
|
||||
registry: registry,
|
||||
tlsClientConfig: tlsClientConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CheckAuth validates the credentials by attempting to log into the registry
|
||||
// returns an error if an error occcured while making the http request or the status code received was 401
|
||||
// returns an error if an error occurred while making the http request or the status code received was 401
|
||||
func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password, registry string) error {
|
||||
client, err := newDockerClient(sys, registry, registry)
|
||||
if err != nil {
|
||||
@@ -445,11 +439,18 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
|
||||
}
|
||||
}
|
||||
logrus.Debugf("%s %s", method, url)
|
||||
res, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
|
||||
// Build the transport and do the request by using the clients tlsclientconfig
|
||||
return c.doHTTP(req)
|
||||
}
|
||||
|
||||
// doHttp uses the clients internal TLS configuration for doing the
|
||||
// provided HTTP request. It returns the response and an error on failure.
|
||||
func (c *dockerClient) doHTTP(req *http.Request) (*http.Response, error) {
|
||||
tr := tlsclientconfig.NewTransport()
|
||||
tr.TLSClientConfig = c.tlsClientConfig
|
||||
httpClient := &http.Client{Transport: tr}
|
||||
return httpClient.Do(req)
|
||||
}
|
||||
|
||||
// we're using the challenges from the /v2/ ping response and not the one from the destination
|
||||
@@ -561,6 +562,12 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We overwrite the TLS clients `InsecureSkipVerify` only if explicitly
|
||||
// specified by the system context
|
||||
if c.sys != nil && c.sys.DockerInsecureSkipTLSVerify != types.OptionalBoolUndefined {
|
||||
c.tlsClientConfig.InsecureSkipVerify = c.sys.DockerInsecureSkipTLSVerify == types.OptionalBoolTrue
|
||||
}
|
||||
|
||||
ping := func(scheme string) error {
|
||||
url := fmt.Sprintf(resolvedPingV2URL, scheme, c.registry)
|
||||
resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
|
||||
@@ -579,7 +586,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
err := ping("https")
|
||||
if err != nil && c.insecureSkipTLSVerify {
|
||||
if err != nil && c.tlsClientConfig.InsecureSkipVerify {
|
||||
err = ping("http")
|
||||
}
|
||||
if err != nil {
|
||||
@@ -603,7 +610,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
|
||||
return true
|
||||
}
|
||||
isV1 := pingV1("https")
|
||||
if !isV1 && c.insecureSkipTLSVerify {
|
||||
if !isV1 && c.tlsClientConfig.InsecureSkipVerify {
|
||||
isV1 = pingV1("http")
|
||||
}
|
||||
if isV1 {
|
||||
|
2
vendor/github.com/containers/image/docker/docker_image.go
generated
vendored
2
vendor/github.com/containers/image/docker/docker_image.go
generated
vendored
@@ -25,7 +25,7 @@ type Image struct {
|
||||
// a client to the registry hosting the given image.
|
||||
// The caller must call .Close() on the returned Image.
|
||||
func newImage(ctx context.Context, sys *types.SystemContext, ref dockerReference) (types.ImageCloser, error) {
|
||||
s, err := newImageSource(sys, ref)
|
||||
s, err := newImageSource(ctx, sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
93
vendor/github.com/containers/image/docker/docker_image_src.go
generated
vendored
93
vendor/github.com/containers/image/docker/docker_image_src.go
generated
vendored
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/pkg/sysregistriesv2"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@@ -28,17 +29,89 @@ type dockerImageSource struct {
|
||||
cachedManifestMIMEType string // Only valid if cachedManifest != nil
|
||||
}
|
||||
|
||||
// newImageSource creates a new ImageSource for the specified image reference.
|
||||
// The caller must call .Close() on the returned ImageSource.
|
||||
func newImageSource(sys *types.SystemContext, ref dockerReference) (*dockerImageSource, error) {
|
||||
c, err := newDockerClientFromRef(sys, ref, false, "pull")
|
||||
// newImageSource creates a new `ImageSource` for the specified image reference
|
||||
// `ref`.
|
||||
//
|
||||
// The following steps will be done during the instance creation:
|
||||
//
|
||||
// - Lookup the registry within the configured location in
|
||||
// `sys.SystemRegistriesConfPath`. If there is no configured registry available,
|
||||
// we fallback to the provided docker reference `ref`.
|
||||
//
|
||||
// - References which contain a configured prefix will be automatically rewritten
|
||||
// to the correct target reference. For example, if the configured
|
||||
// `prefix = "example.com/foo"`, `location = "example.com"` and the image will be
|
||||
// pulled from the ref `example.com/foo/image`, then the resulting pull will
|
||||
// effectively point to `example.com/image`.
|
||||
//
|
||||
// - If the rewritten reference succeeds, it will be used as the `dockerRef`
|
||||
// in the client. If the rewrite fails, the function immediately returns an error.
|
||||
//
|
||||
// - Each mirror will be used (in the configured order) to test the
|
||||
// availability of the image manifest on the remote location. For example,
|
||||
// if the manifest is not reachable due to connectivity issues, then the next
|
||||
// mirror will be tested instead. If no mirror is configured or contains the
|
||||
// target manifest, then the initial `ref` will be tested as fallback. The
|
||||
// creation of the new `dockerImageSource` only succeeds if a remote
|
||||
// location with the available manifest was found.
|
||||
//
|
||||
// A cleanup call to `.Close()` is needed if the caller is done using the returned
|
||||
// `ImageSource`.
|
||||
func newImageSource(ctx context.Context, sys *types.SystemContext, ref dockerReference) (*dockerImageSource, error) {
|
||||
registry, err := sysregistriesv2.FindRegistry(sys, ref.ref.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "error loading registries configuration")
|
||||
}
|
||||
return &dockerImageSource{
|
||||
ref: ref,
|
||||
c: c,
|
||||
}, nil
|
||||
|
||||
if registry == nil {
|
||||
// No configuration was found for the provided reference, so we create
|
||||
// a fallback registry by hand to make the client creation below work
|
||||
// as intended.
|
||||
registry = &sysregistriesv2.Registry{
|
||||
Endpoint: sysregistriesv2.Endpoint{
|
||||
Location: ref.ref.String(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Found the registry within the sysregistriesv2 configuration. Now we test
|
||||
// all endpoints for the manifest availability. If a working image source
|
||||
// was found, it will be used for all future pull actions.
|
||||
var (
|
||||
imageSource *dockerImageSource
|
||||
manifestLoadErr error
|
||||
)
|
||||
for _, endpoint := range append(registry.Mirrors, registry.Endpoint) {
|
||||
logrus.Debugf("Trying to pull %q from endpoint %q", ref.ref, endpoint.Location)
|
||||
|
||||
newRef, err := endpoint.RewriteReference(ref.ref, registry.Prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dockerRef, err := newReference(newRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := newDockerClientFromRef(sys, dockerRef, false, "pull")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.tlsClientConfig.InsecureSkipVerify = endpoint.Insecure
|
||||
|
||||
testImageSource := &dockerImageSource{
|
||||
ref: dockerRef,
|
||||
c: client,
|
||||
}
|
||||
|
||||
manifestLoadErr = testImageSource.ensureManifestIsLoaded(ctx)
|
||||
if manifestLoadErr == nil {
|
||||
imageSource = testImageSource
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return imageSource, manifestLoadErr
|
||||
}
|
||||
|
||||
// Reference returns the reference used to set up this source, _as specified by the user_
|
||||
@@ -274,7 +347,7 @@ func (s *dockerImageSource) getOneSignature(ctx context.Context, url *url.URL) (
|
||||
return nil, false, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
res, err := s.c.client.Do(req)
|
||||
res, err := s.c.doHTTP(req)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
12
vendor/github.com/containers/image/docker/docker_transport.go
generated
vendored
12
vendor/github.com/containers/image/docker/docker_transport.go
generated
vendored
@@ -61,8 +61,13 @@ func ParseReference(refString string) (types.ImageReference, error) {
|
||||
|
||||
// NewReference returns a Docker reference for a named reference. The reference must satisfy !reference.IsNameOnly().
|
||||
func NewReference(ref reference.Named) (types.ImageReference, error) {
|
||||
return newReference(ref)
|
||||
}
|
||||
|
||||
// newReference returns a dockerReference for a named reference.
|
||||
func newReference(ref reference.Named) (dockerReference, error) {
|
||||
if reference.IsNameOnly(ref) {
|
||||
return nil, errors.Errorf("Docker reference %s has neither a tag nor a digest", reference.FamiliarString(ref))
|
||||
return dockerReference{}, errors.Errorf("Docker reference %s has neither a tag nor a digest", reference.FamiliarString(ref))
|
||||
}
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
// The docker/distribution API does not really support that (we can’t ask for an image with a specific
|
||||
@@ -72,8 +77,9 @@ func NewReference(ref reference.Named) (types.ImageReference, error) {
|
||||
_, isTagged := ref.(reference.NamedTagged)
|
||||
_, isDigested := ref.(reference.Canonical)
|
||||
if isTagged && isDigested {
|
||||
return nil, errors.Errorf("Docker references with both a tag and digest are currently not supported")
|
||||
return dockerReference{}, errors.Errorf("Docker references with both a tag and digest are currently not supported")
|
||||
}
|
||||
|
||||
return dockerReference{
|
||||
ref: ref,
|
||||
}, nil
|
||||
@@ -135,7 +141,7 @@ func (ref dockerReference) NewImage(ctx context.Context, sys *types.SystemContex
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
// The caller must call .Close() on the returned ImageSource.
|
||||
func (ref dockerReference) NewImageSource(ctx context.Context, sys *types.SystemContext) (types.ImageSource, error) {
|
||||
return newImageSource(sys, ref)
|
||||
return newImageSource(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageDestination returns a types.ImageDestination for this reference.
|
||||
|
77
vendor/github.com/containers/image/docs/containers-registries.conf.5.md
generated
vendored
77
vendor/github.com/containers/image/docs/containers-registries.conf.5.md
generated
vendored
@@ -7,14 +7,68 @@ containers-registries.conf - Syntax of System Registry Configuration File
|
||||
|
||||
# DESCRIPTION
|
||||
The CONTAINERS-REGISTRIES configuration file is a system-wide configuration
|
||||
file for container image registries. The file format is TOML. The valid
|
||||
categories are: 'registries.search', 'registries.insecure', and
|
||||
'registries.block'.
|
||||
file for container image registries. The file format is TOML.
|
||||
|
||||
By default, the configuration file is located at `/etc/containers/registries.conf`.
|
||||
|
||||
# FORMAT
|
||||
The TOML_format is used to build a simple list format for registries under three
|
||||
# FORMATS
|
||||
|
||||
## VERSION 2
|
||||
VERSION 2 is the latest format of the `registries.conf` and is currently in
|
||||
beta. This means in general VERSION 1 should be used in production environments
|
||||
for now.
|
||||
|
||||
Every registry can have its own mirrors configured. The mirrors will be tested
|
||||
in order for the availability of the remote manifest. This happens currently
|
||||
only during an image pull. If the manifest is not reachable due to connectivity
|
||||
issues or the unavailability of the remote manifest, then the next mirror will
|
||||
be tested instead. If no mirror is configured or contains the manifest to be
|
||||
pulled, then the initially provided reference will be used as fallback. It is
|
||||
possible to set the `insecure` option per mirror, too.
|
||||
|
||||
Furthermore it is possible to specify a `prefix` for a registry. The `prefix`
|
||||
is used to find the relevant target registry from where the image has to be
|
||||
pulled. During the test for the availability of the image, the prefixed
|
||||
location will be rewritten to the correct remote location. This applies to
|
||||
mirrors as well as the fallback `location`. If no prefix is specified, it
|
||||
defaults to the specified `location`. For example, if
|
||||
`prefix = "example.com/foo"`, `location = "example.com"` and the image will be
|
||||
pulled from `example.com/foo/image`, then the resulting pull will be effectively
|
||||
point to `example.com/image`.
|
||||
|
||||
By default container runtimes use TLS when retrieving images from a registry.
|
||||
If the registry is not setup with TLS, then the container runtime will fail to
|
||||
pull images from the registry. If you set `insecure = true` for a registry or a
|
||||
mirror you overwrite the `insecure` flag for that specific entry. This means
|
||||
that the container runtime will attempt use unencrypted HTTP to pull the image.
|
||||
It also allows you to pull from a registry with self-signed certificates.
|
||||
|
||||
If you set the `unqualified-search = true` for the registry, then it is possible
|
||||
to omit the registry hostname when pulling images. This feature does not work
|
||||
together with a specified `prefix`.
|
||||
|
||||
If `blocked = true` then it is not allowed to pull images from that registry.
|
||||
|
||||
### EXAMPLE
|
||||
|
||||
```
|
||||
[[registry]]
|
||||
location = "example.com"
|
||||
insecure = false
|
||||
prefix = "example.com/foo"
|
||||
unqualified-search = false
|
||||
blocked = false
|
||||
mirror = [
|
||||
{ location = "example-mirror-0.local", insecure = false },
|
||||
{ location = "example-mirror-1.local", insecure = true }
|
||||
]
|
||||
```
|
||||
|
||||
## VERSION 1
|
||||
VERSION 1 can be used as alternative to the VERSION 2, but it is not capable in
|
||||
using registry mirrors or a prefix.
|
||||
|
||||
The TOML_format is used to build a simple list for registries under three
|
||||
categories: `registries.search`, `registries.insecure`, and `registries.block`.
|
||||
You can list multiple registries using a comma separated list.
|
||||
|
||||
@@ -22,18 +76,13 @@ Search registries are used when the caller of a container runtime does not fully
|
||||
container image that they want to execute. These registries are prepended onto the front
|
||||
of the specified container image until the named image is found at a registry.
|
||||
|
||||
Insecure Registries. By default container runtimes use TLS when retrieving images
|
||||
from a registry. If the registry is not setup with TLS, then the container runtime
|
||||
will fail to pull images from the registry. If you add the registry to the list of
|
||||
insecure registries then the container runtime will attempt use standard web protocols to
|
||||
pull the image. It also allows you to pull from a registry with self-signed certificates.
|
||||
Note insecure registries can be used for any registry, not just the registries listed
|
||||
under search.
|
||||
|
||||
Block Registries. The registries in this category are are not pulled from when
|
||||
retrieving images.
|
||||
The fields `registries.insecure` and `registries.block` work as like as the
|
||||
`insecure` and `blocked` from VERSION 2.
|
||||
|
||||
# EXAMPLE
|
||||
### EXAMPLE
|
||||
The following example configuration defines two searchable registries, one
|
||||
insecure registry, and two blocked registries.
|
||||
|
||||
@@ -49,6 +98,8 @@ registries = ['registry.untrusted.com', 'registry.unsafe.com']
|
||||
```
|
||||
|
||||
# HISTORY
|
||||
Mar 2019, Added additional configuration format by Sascha Grunert <sgrunert@suse.com>
|
||||
|
||||
Aug 2018, Renamed to containers-registries.conf(5) by Valentin Rothberg <vrothberg@suse.com>
|
||||
|
||||
Jun 2018, Updated by Tom Sweeney <tsweeney@redhat.com>
|
||||
|
109
vendor/github.com/containers/image/docs/containers-transports.5.md
generated
vendored
Normal file
109
vendor/github.com/containers/image/docs/containers-transports.5.md
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
% CONTAINERS-TRANSPORTS(5) Containers Transports Man Page
|
||||
% Valentin Rothberg
|
||||
% April 2019
|
||||
|
||||
## NAME
|
||||
|
||||
containers-transports - description of supported transports for copying and storing container images
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Tools which use the containers/image library, including skopeo(1), buildah(1), podman(1), all share a common syntax for referring to container images in various locations.
|
||||
The general form of the syntax is _transport:details_, where details are dependent on the specified transport, which are documented below.
|
||||
|
||||
### **containers-storage:** [storage-specifier]{image-id|docker-reference[@image-id]}
|
||||
|
||||
An image located in a local containers storage.
|
||||
The format of _docker-reference_ is described in detail in the **docker** transport.
|
||||
|
||||
The _storage-specifier_ allows for referencing storage locations on the file system and has the format `[[driver@]root[+run-root][:options]]` where the optional `driver` refers to the storage driver (e.g., overlay or btrfs) and where `root` is an absolute path to the storage's root directory.
|
||||
The optional `run-root` can be used to specify the run directory of the storage where all temporary writable content is stored.
|
||||
The optional `options` are a comma-separated list of driver-specific options.
|
||||
Please refer to containers-storage.conf(5) for further information on the drivers and supported options.
|
||||
|
||||
### **dir:**_path_
|
||||
|
||||
An existing local directory _path_ storing the manifest, layer tarballs and signatures as individual files.
|
||||
This is a non-standardized format, primarily useful for debugging or noninvasive container inspection.
|
||||
|
||||
### **docker://**_docker-reference_
|
||||
|
||||
An image in a registry implementing the "Docker Registry HTTP API V2".
|
||||
By default, uses the authorization state in `$XDG_RUNTIME_DIR/containers/auth.json`, which is set using podman-login(1).
|
||||
If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using docker-login(1).
|
||||
The containers-registries.conf(5) further allows for configuring various settings of a registry.
|
||||
|
||||
Note that a _docker-reference_ has the following format: `name[:tag|@digest]`.
|
||||
While the docker transport does not support both a tag and a digest at the same time some formats like containers-storage do.
|
||||
Digests can also be used in an image destination as long as the manifest matches the provided digest.
|
||||
The digest of images can be explored with skopeo-inspect(1).
|
||||
If `name` does not contain a slash, it is treated as `docker.io/library/name`.
|
||||
Otherwise, the component before the first slash is checked if it is recognized as a `hostname[:port]` (i.e., it contains either a . or a :, or the component is exactly localhost).
|
||||
If the first component of name is not recognized as a `hostname[:port]`, `name` is treated as `docker.io/name`.
|
||||
|
||||
### **docker-archive:**_path[:docker-reference]_
|
||||
|
||||
An image is stored in the docker-save(1) formatted file.
|
||||
_docker-reference_ is only used when creating such a file, and it must not contain a digest.
|
||||
It is further possible to copy data to stdin by specifying `docker-archive:/dev/stdin` but note that the used file must be seekable.
|
||||
|
||||
### **docker-daemon:**_docker-reference|algo:digest_
|
||||
|
||||
An image stored in the docker daemon's internal storage.
|
||||
The image must be specified as a _docker-reference_ or in an alternative _algo:digest_ format when being used as an image source.
|
||||
The _algo:digest_ refers to the image ID reported by docker-inspect(1).
|
||||
|
||||
### **oci:**_path[:tag]_
|
||||
|
||||
An image compliant with the "Open Container Image Layout Specification" at _path_.
|
||||
Using a _tag_ is optional and allows for storing multiple images at the same _path_.
|
||||
|
||||
### **oci-archive:**_path[:tag]_
|
||||
|
||||
An image compliant with the "Open Container Image Layout Specification" stored as a tar(1) archive at _path_.
|
||||
|
||||
### **ostree:**_docker-reference[@/absolute/repo/path]_
|
||||
|
||||
An image in the local ostree(1) repository.
|
||||
_/absolute/repo/path_ defaults to _/ostree/repo_.
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples demonstrate how some of the containers transports can be used.
|
||||
The examples use skopeo-copy(1) for copying container images.
|
||||
|
||||
**Copying an image from one registry to another**:
|
||||
```
|
||||
$ skopeo copy docker://docker.io/library/alpine:latest docker://localhost:5000/alpine:latest
|
||||
```
|
||||
|
||||
**Copying an image from a running Docker daemon to a directory in the OCI layout**:
|
||||
```
|
||||
$ mkdir alpine-oci
|
||||
$ skopeo copy docker-daemon:alpine:latest oci:alpine-oci
|
||||
$ tree alpine-oci
|
||||
test-oci/
|
||||
├── blobs
|
||||
│ └── sha256
|
||||
│ ├── 83ef92b73cf4595aa7fe214ec6747228283d585f373d8f6bc08d66bebab531b7
|
||||
│ ├── 9a6259e911dcd0a53535a25a9760ad8f2eded3528e0ad5604c4488624795cecc
|
||||
│ └── ff8df268d29ccbe81cdf0a173076dcfbbea4bb2b6df1dd26766a73cb7b4ae6f7
|
||||
├── index.json
|
||||
└── oci-layout
|
||||
|
||||
2 directories, 5 files
|
||||
```
|
||||
|
||||
**Copying an image from a registry to the local storage**:
|
||||
```
|
||||
$ skopeo copy docker://docker.io/library/alpine:latest containers-storage:alpine:latest
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
docker-login(1), docker-save(1), ostree(1), podman-login(1), skopeo-copy(1), skopeo-inspect(1), tar(1), container-registries.conf(5), containers-storage.conf(5)
|
||||
|
||||
## AUTHORS
|
||||
|
||||
Miloslav Trmač <mitr@redhat.com>
|
||||
Valentin Rothberg <rothberg@redhat.com>
|
100
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
100
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
@@ -10,6 +10,10 @@ import (
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
)
|
||||
|
||||
// systemRegistriesConfPath is the path to the system-wide registry
|
||||
@@ -22,34 +26,56 @@ var systemRegistriesConfPath = builtinRegistriesConfPath
|
||||
// DO NOT change this, instead see systemRegistriesConfPath above.
|
||||
const builtinRegistriesConfPath = "/etc/containers/registries.conf"
|
||||
|
||||
// Mirror represents a mirror. Mirrors can be used as pull-through caches for
|
||||
// registries.
|
||||
type Mirror struct {
|
||||
// The mirror's URL.
|
||||
URL string `toml:"url"`
|
||||
// Endpoint describes a remote location of a registry.
|
||||
type Endpoint struct {
|
||||
// The endpoint's remote location.
|
||||
Location string `toml:"location"`
|
||||
// If true, certs verification will be skipped and HTTP (non-TLS)
|
||||
// connections will be allowed.
|
||||
Insecure bool `toml:"insecure"`
|
||||
}
|
||||
|
||||
// RewriteReference will substitute the provided reference `prefix` to the
|
||||
// endpoints `location` from the `ref` and creates a new named reference from it.
|
||||
// The function errors if the newly created reference is not parsable.
|
||||
func (e *Endpoint) RewriteReference(ref reference.Named, prefix string) (reference.Named, error) {
|
||||
if ref == nil {
|
||||
return nil, fmt.Errorf("provided reference is nil")
|
||||
}
|
||||
if prefix == "" {
|
||||
return ref, nil
|
||||
}
|
||||
refString := ref.String()
|
||||
if refMatchesPrefix(refString, prefix) {
|
||||
newNamedRef := strings.Replace(refString, prefix, e.Location, 1)
|
||||
newParsedRef, err := reference.ParseNamed(newNamedRef)
|
||||
if newParsedRef != nil {
|
||||
logrus.Debugf("reference rewritten from '%v' to '%v'", refString, newParsedRef.String())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error rewriting reference")
|
||||
}
|
||||
return newParsedRef, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid prefix '%v' for reference '%v'", prefix, refString)
|
||||
}
|
||||
|
||||
// Registry represents a registry.
|
||||
type Registry struct {
|
||||
// Serializable registry URL.
|
||||
URL string `toml:"url"`
|
||||
// A registry is an Endpoint too
|
||||
Endpoint
|
||||
// The registry's mirrors.
|
||||
Mirrors []Mirror `toml:"mirror"`
|
||||
Mirrors []Endpoint `toml:"mirror"`
|
||||
// If true, pulling from the registry will be blocked.
|
||||
Blocked bool `toml:"blocked"`
|
||||
// If true, certs verification will be skipped and HTTP (non-TLS)
|
||||
// connections will be allowed.
|
||||
Insecure bool `toml:"insecure"`
|
||||
// If true, the registry can be used when pulling an unqualified image.
|
||||
Search bool `toml:"unqualified-search"`
|
||||
// Prefix is used for matching images, and to translate one namespace to
|
||||
// another. If `Prefix="example.com/bar"`, `URL="example.com/foo/bar"`
|
||||
// another. If `Prefix="example.com/bar"`, `location="example.com/foo/bar"`
|
||||
// and we pull from "example.com/bar/myimage:latest", the image will
|
||||
// effectively be pulled from "example.com/foo/bar/myimage:latest".
|
||||
// If no Prefix is specified, it defaults to the specified URL.
|
||||
// If no Prefix is specified, it defaults to the specified location.
|
||||
Prefix string `toml:"prefix"`
|
||||
}
|
||||
|
||||
@@ -84,18 +110,18 @@ func (e *InvalidRegistries) Error() string {
|
||||
return e.s
|
||||
}
|
||||
|
||||
// parseURL parses the input string, performs some sanity checks and returns
|
||||
// parseLocation parses the input string, performs some sanity checks and returns
|
||||
// the sanitized input string. An error is returned if the input string is
|
||||
// empty or if contains an "http{s,}://" prefix.
|
||||
func parseURL(input string) (string, error) {
|
||||
func parseLocation(input string) (string, error) {
|
||||
trimmed := strings.TrimRight(input, "/")
|
||||
|
||||
if trimmed == "" {
|
||||
return "", &InvalidRegistries{s: "invalid URL: cannot be empty"}
|
||||
return "", &InvalidRegistries{s: "invalid location: cannot be empty"}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(trimmed, "http://") || strings.HasPrefix(trimmed, "https://") {
|
||||
msg := fmt.Sprintf("invalid URL '%s': URI schemes are not supported", input)
|
||||
msg := fmt.Sprintf("invalid location '%s': URI schemes are not supported", input)
|
||||
return "", &InvalidRegistries{s: msg}
|
||||
}
|
||||
|
||||
@@ -111,21 +137,21 @@ func getV1Registries(config *tomlConfig) ([]Registry, error) {
|
||||
// to minimize behavior inconsistency and not contribute to difficult-to-reproduce situations.
|
||||
registryOrder := []string{}
|
||||
|
||||
getRegistry := func(url string) (*Registry, error) { // Note: _pointer_ to a long-lived object
|
||||
getRegistry := func(location string) (*Registry, error) { // Note: _pointer_ to a long-lived object
|
||||
var err error
|
||||
url, err = parseURL(url)
|
||||
location, err = parseLocation(location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg, exists := regMap[url]
|
||||
reg, exists := regMap[location]
|
||||
if !exists {
|
||||
reg = &Registry{
|
||||
URL: url,
|
||||
Mirrors: []Mirror{},
|
||||
Prefix: url,
|
||||
Endpoint: Endpoint{Location: location},
|
||||
Mirrors: []Endpoint{},
|
||||
Prefix: location,
|
||||
}
|
||||
regMap[url] = reg
|
||||
registryOrder = append(registryOrder, url)
|
||||
regMap[location] = reg
|
||||
registryOrder = append(registryOrder, location)
|
||||
}
|
||||
return reg, nil
|
||||
}
|
||||
@@ -155,15 +181,15 @@ func getV1Registries(config *tomlConfig) ([]Registry, error) {
|
||||
}
|
||||
|
||||
registries := []Registry{}
|
||||
for _, url := range registryOrder {
|
||||
reg := regMap[url]
|
||||
for _, location := range registryOrder {
|
||||
reg := regMap[location]
|
||||
registries = append(registries, *reg)
|
||||
}
|
||||
return registries, nil
|
||||
}
|
||||
|
||||
// postProcessRegistries checks the consistency of all registries (e.g., set
|
||||
// the Prefix to URL if not set) and applies conflict checks. It returns an
|
||||
// the Prefix to Location if not set) and applies conflict checks. It returns an
|
||||
// array of cleaned registries and error in case of conflicts.
|
||||
func postProcessRegistries(regs []Registry) ([]Registry, error) {
|
||||
var registries []Registry
|
||||
@@ -172,16 +198,16 @@ func postProcessRegistries(regs []Registry) ([]Registry, error) {
|
||||
for _, reg := range regs {
|
||||
var err error
|
||||
|
||||
// make sure URL and Prefix are valid
|
||||
reg.URL, err = parseURL(reg.URL)
|
||||
// make sure Location and Prefix are valid
|
||||
reg.Location, err = parseLocation(reg.Location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reg.Prefix == "" {
|
||||
reg.Prefix = reg.URL
|
||||
reg.Prefix = reg.Location
|
||||
} else {
|
||||
reg.Prefix, err = parseURL(reg.Prefix)
|
||||
reg.Prefix, err = parseLocation(reg.Prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -189,13 +215,13 @@ func postProcessRegistries(regs []Registry) ([]Registry, error) {
|
||||
|
||||
// make sure mirrors are valid
|
||||
for _, mir := range reg.Mirrors {
|
||||
mir.URL, err = parseURL(mir.URL)
|
||||
mir.Location, err = parseLocation(mir.Location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
registries = append(registries, reg)
|
||||
regMap[reg.URL] = append(regMap[reg.URL], reg)
|
||||
regMap[reg.Location] = append(regMap[reg.Location], reg)
|
||||
}
|
||||
|
||||
// Given a registry can be mentioned multiple times (e.g., to have
|
||||
@@ -205,15 +231,15 @@ func postProcessRegistries(regs []Registry) ([]Registry, error) {
|
||||
// Note: we need to iterate over the registries array to ensure a
|
||||
// deterministic behavior which is not guaranteed by maps.
|
||||
for _, reg := range registries {
|
||||
others, _ := regMap[reg.URL]
|
||||
others, _ := regMap[reg.Location]
|
||||
for _, other := range others {
|
||||
if reg.Insecure != other.Insecure {
|
||||
msg := fmt.Sprintf("registry '%s' is defined multiple times with conflicting 'insecure' setting", reg.URL)
|
||||
msg := fmt.Sprintf("registry '%s' is defined multiple times with conflicting 'insecure' setting", reg.Location)
|
||||
|
||||
return nil, &InvalidRegistries{s: msg}
|
||||
}
|
||||
if reg.Blocked != other.Blocked {
|
||||
msg := fmt.Sprintf("registry '%s' is defined multiple times with conflicting 'blocked' setting", reg.URL)
|
||||
msg := fmt.Sprintf("registry '%s' is defined multiple times with conflicting 'blocked' setting", reg.Location)
|
||||
return nil, &InvalidRegistries{s: msg}
|
||||
}
|
||||
}
|
||||
|
44
vendor/github.com/containers/image/registries.conf
generated
vendored
44
vendor/github.com/containers/image/registries.conf
generated
vendored
@@ -1,5 +1,11 @@
|
||||
# For more information on this configuration file, see containers-registries.conf(5).
|
||||
#
|
||||
# There are multiple versions of the configuration syntax available, where the
|
||||
# second iteration is backwards compatible to the first one. Mixing up both
|
||||
# formats will result in an runtime error.
|
||||
#
|
||||
# The initial configuration format looks like this:
|
||||
#
|
||||
# Registries to search for images that are not fully-qualified.
|
||||
# i.e. foobar.com/my_image:latest vs my_image:latest
|
||||
[registries.search]
|
||||
@@ -19,3 +25,41 @@ registries = []
|
||||
# The atomic CLI `atomic trust` can be used to easily configure the policy.json file.
|
||||
[registries.block]
|
||||
registries = []
|
||||
|
||||
# The second version of the configuration format allows to specify registry
|
||||
# mirrors:
|
||||
#
|
||||
# [[registry]]
|
||||
# # The main location of the registry
|
||||
# location = "example.com"
|
||||
#
|
||||
# # If true, certs verification will be skipped and HTTP (non-TLS) connections
|
||||
# # will be allowed.
|
||||
# insecure = false
|
||||
#
|
||||
# # Prefix is used for matching images, and to translate one namespace to
|
||||
# # another. If `prefix = "example.com/foo"`, `location = "example.com"` and
|
||||
# # we pull from "example.com/foo/myimage:latest", the image will effectively be
|
||||
# # pulled from "example.com/myimage:latest". If no Prefix is specified,
|
||||
# # it defaults to the specified `location`. When a prefix is used, then a pull
|
||||
# # without specifying the prefix is not possible any more.
|
||||
# prefix = "example.com/foo"
|
||||
#
|
||||
# # If true, the registry can be used when pulling an unqualified image. If a
|
||||
# # prefix is specified, unqualified pull is not possible any more.
|
||||
# unqualified-search = false
|
||||
#
|
||||
# # If true, pulling from the registry will be blocked.
|
||||
# blocked = false
|
||||
#
|
||||
# # All available mirrors of the registry. The mirrors will be evaluated in
|
||||
# # order during an image pull. Furthermore it is possible to specify the
|
||||
# # `insecure` flag per registry mirror, too.
|
||||
# mirror = [
|
||||
# { location = "example-mirror-0.local", insecure = false },
|
||||
# { location = "example-mirror-1.local", insecure = true },
|
||||
# # It is also possible to specify an additional path within the `location`.
|
||||
# # A pull to `example.com/foo/image:latest` will then result in
|
||||
# # `example-mirror-2.local/path/image:latest`.
|
||||
# { location = "example-mirror-2.local/path" },
|
||||
# ]
|
||||
|
Reference in New Issue
Block a user