Skip to content

Commit

Permalink
Add pull-from-mirror
Browse files Browse the repository at this point in the history
Add pull-from-mirror: all, digest-only, tag-only for adding per-mirror level restrictions to image pull through mirrors.

Signed-off-by: Qi Wang <qiwan@redhat.com>
  • Loading branch information
QiWang19 committed Mar 24, 2022
1 parent cff8dd6 commit 84f966d
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 19 deletions.
10 changes: 5 additions & 5 deletions docs/containers-registries.conf.5.md
Expand Up @@ -109,15 +109,15 @@ Each TOML table in the `mirror` array can contain the following fields:
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-only is set for the entire registry.

- `pull-from-mirror`: `all`, `digest-only` or `tag-only`. If "digest-only", mirrors 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. If "tag-only", mirrors will only be used for tag pulls. For a more up-to-date and expensive mirror that it is less likely to be out of sync if tags move, it should not be unnecessarily used for digest references. Default is "all", mirrors will be used for both digest pulls and tag pulls unless the mirror-by-digest-only is set for the primary registry .
Note that pull-from-mirror can only be set in a registry's Mirror field, not in the registry's primary Endpoint. This per-mirror setting is allowed only when mirror-by-digest-only is not configured for the primary 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.
registry.
If all mirrors are configured to be tag-only, images referenced by a digest will only use the primary
registry.

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
Expand Down
42 changes: 34 additions & 8 deletions pkg/sysregistriesv2/system_registries_v2.go
Expand Up @@ -43,6 +43,14 @@ const builtinRegistriesConfDirPath = "/etc/containers/registries.conf.d"
// helper.
const AuthenticationFileHelper = "containers-auth.json"

type PullFromMirror string

const (
MirrorAll PullFromMirror = "all"
MirrorByDigestOnly PullFromMirror = "digest-only"
MirrorByTagOnly PullFromMirror = "tag-only"
)

// Endpoint describes a remote location of a registry.
type Endpoint struct {
// The endpoint's remote location. Can be empty iff Prefix contains
Expand All @@ -53,12 +61,18 @@ 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
// PullFromMirror is used for adding restrictions to image pull through the mirror.
// Set to "all", "digest-only", or "tag-only".
// If "digest-only", mirrors 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.
// If "tag-only", mirrors will only be used for tag pulls. For a more up-to-date and expensive mirror
// that it is less likely to be out of sync if tags move, it should not be unnecessarily
// used for digest references.
// Default is "all", mirrors will be used for both digest pulls and tag pulls unless the mirror-by-digest-only is set for the primary registry .
// 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"`
// This per-mirror setting is allowed only when mirror-by-digest-only is not configured for the primary registry.
PullFromMirror PullFromMirror `toml:"pull-from-mirror,omitempty"`
}

// userRegistriesFile is the path to the per user registry configuration file.
Expand Down Expand Up @@ -143,11 +157,15 @@ func (r *Registry) PullSourcesFromReference(ref reference.Named) ([]PullSource,
endpoints = append(endpoints, r.Mirrors...)
}
} else {
// 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)
// skip the mirror if per mirror setting exists but reference does not match the restriction
if mirror.PullFromMirror == MirrorByDigestOnly && !isDigested {
continue
}
if mirror.PullFromMirror == MirrorByTagOnly && isDigested {
continue
}
endpoints = append(endpoints, mirror)
}
}
endpoints = append(endpoints, r.Endpoint)
Expand Down Expand Up @@ -385,8 +403,8 @@ 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)
if reg.PullFromMirror != "" {
return fmt.Errorf("pull-from-mirror must not be set for a non-mirror registry %s", reg.Prefix)
}
// make sure mirrors are valid
for _, mir := range reg.Mirrors {
Expand All @@ -401,6 +419,14 @@ func (config *V2RegistriesConf) postProcessRegistries() error {
if mir.Location == "" {
return &InvalidRegistries{s: "invalid condition: mirror location is unset"}
}

if reg.MirrorByDigestOnly && mir.PullFromMirror != "" {
return &InvalidRegistries{s: "cannot set mirror usage mirror-by-digest-only for the registry and pull-from-mirror for per-mirror at the same time."}
}
if mir.PullFromMirror != "" && mir.PullFromMirror != MirrorAll &&
mir.PullFromMirror != MirrorByDigestOnly && mir.PullFromMirror != MirrorByTagOnly {
return &InvalidRegistries{s: fmt.Sprintf("unsupported pull-from-mirror value %q for mirror %q", mir.PullFromMirror, mir.Location)}
}
}
if reg.Location == "" {
regMap[reg.Prefix] = append(regMap[reg.Prefix], reg)
Expand Down
24 changes: 21 additions & 3 deletions pkg/sysregistriesv2/system_registries_v2_test.go
Expand Up @@ -678,7 +678,7 @@ func TestPullSourcesMirrorFromReference(t *testing.T) {
}
registries, err := GetRegistries(sys)
require.NoError(t, err)
assert.Equal(t, 4, len(registries))
assert.Equal(t, 7, len(registries))

digest := "@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
tag := ":aaa"
Expand All @@ -705,13 +705,31 @@ func TestPullSourcesMirrorFromReference(t *testing.T) {
[]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 set digest-only for registry level, allows only digest pulls
// Registry D has no digest-only set for mirrors table
{
"registry-d.com/foo/image",
[]string{"mirror-1.registry-d.com", "mirror-2.registry-d.com", "registry-d.com/bar"},
[]string{"registry-d.com/bar"},
},
// Registry E has mirrors only allows tag pull
{
"registry-e.com/foo/image",
[]string{"registry-e.com/bar"},
[]string{"mirror-1.registry-e.com", "mirror-2.registry-e.com", "registry-e.com/bar"},
},
// Registry F has one tag only mirror does not allow digest pull
{
"registry-f.com/foo/image",
[]string{"mirror-1.registry-f.com", "registry-f.com/bar"},
[]string{"mirror-1.registry-f.com", "mirror-2.registry-f.com", "registry-f.com/bar"},
},
// Registry G has one digest-only pull and one tag only pull
{
"registry-g.com/foo/image",
[]string{"mirror-1.registry-g.com", "mirror-3.registry-g.com", "mirror-4.registry-g.com", "registry-g.com/bar"},
[]string{"mirror-2.registry-g.com", "mirror-3.registry-g.com", "mirror-4.registry-g.com", "registry-g.com/bar"},
},
} {
// Digest
digestedRef := toNamedRef(t, tc.registry+digest)
Expand Down
48 changes: 45 additions & 3 deletions pkg/sysregistriesv2/testdata/pull-sources-mirror-reference.conf
Expand Up @@ -14,11 +14,11 @@ prefix = "registry-b.com/foo"
location = "registry-b.com/bar"

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

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

[[registry]]
Expand All @@ -29,7 +29,7 @@ location = "registry-c.com/bar"
location = "mirror-1.registry-c.com"

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

[[registry]]
Expand All @@ -42,3 +42,45 @@ location = "mirror-1.registry-d.com"

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

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

[[registry.mirror]]
pull-from-mirror = "tag-only"
location = "mirror-1.registry-e.com"

[[registry.mirror]]
pull-from-mirror = "tag-only"
location = "mirror-2.registry-e.com"

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

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

[[registry.mirror]]
pull-from-mirror = "tag-only"
location = "mirror-2.registry-f.com"

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

[[registry.mirror]]
pull-from-mirror = "digest-only"
location = "mirror-1.registry-g.com"

[[registry.mirror]]
pull-from-mirror = "tag-only"
location = "mirror-2.registry-g.com"

[[registry.mirror]]
location = "mirror-3.registry-g.com"

[[registry.mirror]]
pull-from-mirror = "all"
location = "mirror-4.registry-g.com"

0 comments on commit 84f966d

Please sign in to comment.