Skip to content

Commit

Permalink
set digest-only for each mirror
Browse files Browse the repository at this point in the history
Close: #1407
Add the `digest-only` field to each mirror table, so it will
be configured for each mirror instead of for primary registry.
For the same primary registry, it can support both digest only pull
and tag allowed pull.

The `mirror-by-digest-only` for primary is still allowed configuring,
and it is honored for compatibility

Signed-off-by: Qi Wang <qiwan@redhat.com>
  • Loading branch information
QiWang19 committed Jan 18, 2022
1 parent 05b2244 commit 6603bcd
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 14 deletions.
22 changes: 16 additions & 6 deletions docs/containers-registries.conf.5.md
Expand Up @@ -104,20 +104,30 @@ contacted and contains the image will be used (and if none of the mirrors contai
the primary location specified by the `registry.location` field, or using the unmodified
user-specified reference, is tried last).

Each TOML table in the `mirror` array can contain the following fields, with the same semantics
as if specified in the `[[registry]]` TOML table directly:
- `location`
- `insecure`
Each TOML table in the `mirror` array can contain the following fields:
- `location`: same semantics
as specified in the `[[registry]]` TOML table
- `insecure`: same semantics
as specified in the `[[registry]]` TOML table
- `digest-only``true` or `false`. If `true` an individual mirror will only be used during pulling if the image reference includes a digest.
Note that digest-only will be overridden if mirror-by-digest is set for the entire registry.

`mirror-by-digest-only`
: `true` or `false`.
If `true`, mirrors will only be used during pulling if the image reference includes a digest.
Note that if all mirrors are configured to be digest-only, images referenced by a tag will only use the primary
registry, failing if that registry is not accessible.

`digest-only`: `true` or `false`.
: if `true` an individual mirror will only be used during pulling if the image reference includes a digest.
Note that digest-only will be overridden if mirror-by-digest is set for the entire registry.
Also note that if all mirrors in the `mirror` array have `digest-only = true`, images referenced by a tag will only use the primary
registry, failing if that registry is not accessible.

Referencing an image by digest ensures that the same is always used
(whereas referencing an image by a tag may cause different registries to return
different images if the tag mapping is out of sync).

Note that if this is `true`, images referenced by a tag will only use the primary
registry, failing if that registry is not accessible.

*Note*: Redirection and mirrors are currently processed only when reading images, not when pushing
to a registry; that may change in the future.
Expand Down
30 changes: 22 additions & 8 deletions pkg/sysregistriesv2/system_registries_v2.go
Expand Up @@ -53,6 +53,12 @@ type Endpoint struct {
// If true, certs verification will be skipped and HTTP (non-TLS)
// connections will be allowed.
Insecure bool `toml:"insecure,omitempty"`
// If true, the mirror will only be used for digest pulls. Pulling images by
// tag can potentially yield different images, depending on which endpoint
// we pull from. Restricting mirrors to pulls by digest avoids that issue.
// This can only be set in a registry's Mirror field, not in the registry's primary Endpoint.
// If mirror-by-digest-only is set to true for the primary registry, this per-mirror setting is ignored.
DigestOnly bool `toml:"digest-only,omitempty"`
}

// userRegistriesFile is the path to the per user registry configuration file.
Expand Down Expand Up @@ -115,7 +121,7 @@ type Registry struct {
Blocked bool `toml:"blocked,omitempty"`
// If true, mirrors will only be used for digest pulls. Pulling images by
// tag can potentially yield different images, depending on which endpoint
// we pull from. Forcing digest-pulls for mirrors avoids that issue.
// we pull from. Restricting mirrors to pulls for mirrors avoids that issue.
MirrorByDigestOnly bool `toml:"mirror-by-digest-only,omitempty"`
}

Expand All @@ -130,17 +136,21 @@ type PullSource struct {
// reference.
func (r *Registry) PullSourcesFromReference(ref reference.Named) ([]PullSource, error) {
var endpoints []Endpoint

_, isDigested := ref.(reference.Canonical)
if r.MirrorByDigestOnly {
// Only use mirrors when the reference is a digest one.
if _, isDigested := ref.(reference.Canonical); isDigested {
endpoints = append(r.Mirrors, r.Endpoint)
} else {
endpoints = []Endpoint{r.Endpoint}
// Only use mirrors when the reference is a digested one.
if isDigested {
endpoints = append(endpoints, r.Mirrors...)
}
} else {
endpoints = append(r.Mirrors, r.Endpoint)
// check digest-only for each mirror if non mirror-by-digest-only set, since mirror-by-digest-only is honored
for _, mirror := range r.Mirrors {
if !mirror.DigestOnly || isDigested {
endpoints = append(endpoints, mirror)
}
}
}
endpoints = append(endpoints, r.Endpoint)

sources := []PullSource{}
for _, ep := range endpoints {
Expand Down Expand Up @@ -374,6 +384,10 @@ func (config *V2RegistriesConf) postProcessRegistries() error {
}
}

// validate the mirror usage settings does not apply to primary registry
if reg.DigestOnly {
return fmt.Errorf("digest-only must not be set for a non-mirror registry %s", reg.Prefix)
}
// make sure mirrors are valid
for _, mir := range reg.Mirrors {
mir.Location, err = parseLocation(mir.Location)
Expand Down
65 changes: 65 additions & 0 deletions pkg/sysregistriesv2/system_registries_v2_test.go
Expand Up @@ -675,6 +675,71 @@ func TestPullSourcesFromReference(t *testing.T) {
assert.Equal(t, 1, len(pullSources))
}

func TestPullSourcesMirrorFromReference(t *testing.T) {
sys := &types.SystemContext{
SystemRegistriesConfPath: "testdata/pull-sources-mirror-reference.conf",
SystemRegistriesConfDirPath: "testdata/this-does-not-exist",
}
registries, err := GetRegistries(sys)
assert.Nil(t, err)
assert.Equal(t, 4, len(registries))

digest := "@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
tag := "aaa"
for _, tc := range []struct {
registry string
digestSources []string
tagSources []string
}{
// Registry A has mirrors allow any kind of pull
{
"registry-a.com/foo/image:latest",
[]string{"mirror-1.registry-a.com", "mirror-2.registry-a.com", "registry-a.com/bar"},
[]string{"mirror-1.registry-a.com", "mirror-2.registry-a.com", "registry-a.com/bar"},
},
// Registry B has mirrors allow digests pull only
{
"registry-b.com/foo/image:latest",
[]string{"mirror-1.registry-b.com", "mirror-2.registry-b.com", "registry-b.com/bar"},
[]string{"registry-b.com/bar"},
},
// Registry C has a mirror allows digest pull only and a mirror allows any kind of pull
{
"registry-c.com/foo/image:latest",
[]string{"mirror-1.registry-c.com", "mirror-2.registry-c.com", "registry-c.com/bar"},
[]string{"mirror-1.registry-c.com", "registry-c.com/bar"},
},
// Registry D set mirror-by-digest-only, honor this configuration for registry
// Regsitry D has no digest-only set for mirrors table
{
"registry-d.com/foo/image:latest",
[]string{"mirror-1.registry-d.com", "mirror-2.registry-d.com", "registry-d.com/bar"},
[]string{"registry-d.com/bar"},
},
} {
// Digest
digestedRef := toNamedRef(t, tc.registry+digest)
registry, err := FindRegistry(sys, digestedRef.Name())
assert.Nil(t, err)
assert.NotNil(t, registry)
pullSource, err := registry.PullSourcesFromReference(digestedRef)
assert.Nil(t, err)
for i, s := range tc.digestSources {
assert.Equal(t, s, pullSource[i].Endpoint.Location)
}
// Tag
taggedRef := toNamedRef(t, tc.registry+tag)
registry, err = FindRegistry(sys, taggedRef.Name())
assert.Nil(t, err)
assert.NotNil(t, registry)
pullSource, err = registry.PullSourcesFromReference(taggedRef)
assert.Nil(t, err)
for i, s := range tc.tagSources {
assert.Equal(t, s, pullSource[i].Endpoint.Location)
}
}
}

func TestTryUpdatingCache(t *testing.T) {
ctx := &types.SystemContext{
SystemRegistriesConfPath: "testdata/try-update-cache-valid.conf",
Expand Down
44 changes: 44 additions & 0 deletions pkg/sysregistriesv2/testdata/pull-sources-mirror-reference.conf
@@ -0,0 +1,44 @@
[[registry]]
prefix = "registry-a.com/foo"
location = "registry-a.com/bar"

[[registry.mirror]]
location = "mirror-1.registry-a.com"

[[registry.mirror]]
location = "mirror-2.registry-a.com"
insecure = true

[[registry]]
prefix = "registry-b.com/foo"
location = "registry-b.com/bar"

[[registry.mirror]]
digest-only = true
location = "mirror-1.registry-b.com"

[[registry.mirror]]
digest-only = true
location = "mirror-2.registry-b.com"

[[registry]]
prefix = "registry-c.com/foo"
location = "registry-c.com/bar"

[[registry.mirror]]
location = "mirror-1.registry-c.com"

[[registry.mirror]]
digest-only = true
location = "mirror-2.registry-c.com"

[[registry]]
prefix = "registry-d.com/foo"
location = "registry-d.com/bar"
mirror-by-digest-only = true

[[registry.mirror]]
location = "mirror-1.registry-d.com"

[[registry.mirror]]
location = "mirror-2.registry-d.com"

0 comments on commit 6603bcd

Please sign in to comment.