Skip to content

Conversation

@vrothberg
Copy link
Member

@vrothberg vrothberg commented Mar 19, 2018

Introduce sysregistriesv2, which changes the format of the
registries.conf TOML configuration. Instead of having different lists
to specify search registries, blocked and insecure ones, all data is
encapsulated into one registry type. The registry type allows to
specify a list of mirrors, which can be used in the endpoint lookup to
serve, for instance, as pull through caches for the associated registry.

An example configuration may look as follows:

[[registry]]
url = "https://registry.com"
prefix = "another-registry.com"

[[registry.mirror]]
url = "http://registry-mirror.com"
insecure = true

The upper example shows the configuration for https://registry.com.
The prefix is used for matching images, and to translate one namespace
to another. If prefix="example.com/bar", url="https://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.

Ease migration from sysregistries v1 to v2 by also loading
configurations in the v1 TOML format. Throw an error in case a config
tries to mix both formats. This allows a smoother migration for
developers, maintainers and the user, who can switch to the new config
format once all tools have been updated to v2.

Signed-off-by: Valentin Rothberg vrothberg@suse.com
Closes: #397

@vrothberg
Copy link
Member Author

vrothberg commented Mar 19, 2018

I had a close look at how we can proceed. With the current implementation of the Registry type (see https://github.com/vrothberg/image/blob/b1a645d862102aa1fc1933a9b9ecbd01608dd90b/pkg/sysregistries/system_registries.go#L30) we can achieve full backward compat, which has a price as we're stuck with the old API that is based on arrays of strings.

I see three options:

  1. Implement backward compat. The old types can easily be mapped to the new ones, but we're stuck with the functions returning []string. How could we come up with new functions (that are easy to understand for a user) to make use of the new types?
  2. Implement a sysregistriesV2 package (or something similar) to have a clear separation. This would entail many benefits, such as implementing sanity checks, using net.URL for parsing registries, etc.
  3. Do not change the config as suggested above, but add a new field registries.mirrors, which is a map for registry->[mirrors]. That's a trivial extension and allows to easily extend existing code, for instance, in libpod/image by prepending mirrors to the pull list.

I am in favor of 2), as we add sanity checks, parsing of URL's, change from string to net.URL etc, but I am very curious to hear more opinions.

@vrothberg
Copy link
Member Author

Ping @mtrmac, @baude, @rhatdan.

@rhatdan
Copy link
Member

rhatdan commented Mar 20, 2018

I am for you option 2, gives us a way forward, as long as we don't have to update all packages at the same time.

@baude
Copy link
Member

baude commented Mar 20, 2018

yeah #2 is fine to me as well.

@vrothberg
Copy link
Member Author

vrothberg commented Mar 21, 2018

@rhatdan @baude The latest commit is a concrete suggestion. I did not add any unit tests yet as I want to wait for your opinions and for an agreement on the design.

The Registry type includes all data to support the old semantics (search, block, insecure) and it also implements prefix semantics (similar to the open Moby PR). I implemented a FindRegistries function, which demonstrates how the new API could be used:

// FindRegistries returns all registries matching the specified image reference.
// In case of an unqualified image reference, all registries that are configured
// for unqualified image search are returned.  In case of a fully qualified
// image reference, the registry with the longest prefix is returned.  An empty
// array is returned in case no matching registry is found.
func FindRegistries(imgRef reference.Reference, registries []Registry) ([]Registry, error)

@baude
Copy link
Member

baude commented Mar 22, 2018

I like the direction you are headed ... good work

@mtrmac
Copy link
Collaborator

mtrmac commented Mar 22, 2018

  1. Implement a sysregistriesV2 package (or something similar) to have a clear separation. This would entail many benefits, such as implementing sanity checks, using net.URL for parsing registries, etc.

Out of the three alternatives, I prefer 2. as well.

But I’d rather have a single implementation, not two that will inevitably drift and differ. Either provide them from a single package, share the underlying implementation in an internal subpackage, or—maybe even preferably—just break the existing API. For better or worse, c/image does not currently have a stable API commitment, and the existing sysregistries package only exports two functions, so that should not be an extreme burden on consumers.

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments on the code, but the two major questions are: (This may have been already discussed elsewhere; feel free to point me to that, I may have missed that or forgotten.)


Does this need to be coordinated with the moby/moby PR introducing similar functionality? Should this me merged independently, or only after the two arrive on some shared consensus?

Is there any chance at all of sharing the file between the two? Would we rely on the atomic-registries conversion? Or not even that?


The API change is not the big worry, we can deal with that. This completely changes the format of the configuration file, and affects users. Is everyone OK with that? @rhatdan @baude

Or do we need to still accept the old input and transparently convert?


// RegURL represents a Registry's URl. This abstraction is required to
// unmarshal the non-primitive and non-local url.URL type when loading the
// toml config.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s awkward to expose this implementation detail to callers. Could this be a private type, used in a private clone of the Registry type, used only for the unmarshaling?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look into this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


// String returns host:port/path of the RegURL's URL.
func (r *RegURL) String() string {
return r.URL.Host + r.URL.Path
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s extremely surprising that this throws away the rest of r.URL. Is that necessary?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Do the String methods even need to exist? It may be better to force the caller to think about formatting than being surprising about it.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's currently used to match an image reference against registries, but this doesn't need to be public at all.

URL RegURL `toml:"url"`
Blocked bool `toml:"blocked"`
Insecure bool `toml:"insecure"`
Search bool `toml:"unqualified-search"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean/do? Please add documentation to the field. (Others could benefit from that as well, but for the new ones it’s especially necessary to record the intent and consensus.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In v1 of the API, search registries are used to allow unqualified image pulling. When pulling an unqualified image, the image will effectively be appended to all specified search registries. The first hit wins. The Search field does exactly that. If a registry has this switch set to true, then the registry (and it's mirrors) will be used to pull unqualified images.

Blocked bool `toml:"blocked"`
Insecure bool `toml:"insecure"`
Search bool `toml:"unqualified-search"`
Prefix string `toml:"prefix"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean/do? Please add documentation to the field.

(And about url = "foo"; prefix = "bar"? Is that allowed? Reasonable?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add documentation. Sorry, in case that's confusing. Some discussion happened in IRC.

This is something similar to the moby/moby PR. The Prefix effectively allows to translate one namespace into another. So url = "foo"; prefix = "bar"; would be allowed.

Notice that specifying a prefix is not mandatory.

// image reference, the registry with the longest prefix is returned. An empty
// array is returned in case no matching registry is found.
func FindRegistries(imgRef reference.Reference, registries []Registry) ([]Registry, error) {
domain := reference.Domain(imgRef.(reference.Named))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the function crashes with a non-reference.Named, why not make the input parameter a reference.Named in the first place?


I’m not sure this is going to actually work, though; c/image/docker/reference.Reference is not the Fedora /usr/bin/docker-like docker/docker/reference package which implements unqualified names as a first-class concept, its the upstream-like one where a reference always implicitly includes a domain. ParseNormalizedNamed will add a docker.io host name; ParseNamed will refuse an unqualified name.

reference.Parse does make it possible to create a domain-less value, but that value would be dangerous to pass to any other user in c/image which expects normalization to happen. And it incorrectly parses notlocalhost/busybox as domain=notlocalhost, path=busybox, instead of domain=unknown, path=notlocalhost/busybox.

[The search semantics is really problematic for security: with it, and a pull fedora command, the user never knows what image will be downloaded.]

If this needs to exist at all (which, sadly, seems to be the case), the imgRef should probably just be a string; reference.Named would only be created by the result of combining the domain and the input string.


And maybe the public API should not combine the unqualified/qualified cases at all; AFAICT the caller needs to treat them differently anyway (for unqualified, combine the search registry and the input; for qualified, use the input as specified, and only use the flags), so the caller can just as well call two different public API endpoints here (GetUnqualifiedSearchRegistries/GetRegistryForReference or something like that); then, the qualified case could return a *Registry instead of an array, and the caller would not need to worry about what happens when there is >1 element.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the detailed feedback; very helpful input. I agree that splitting it up into two functions is a good way to tackle the problem.

}
}
if prefixLen != 0 {
regs = append(regs, reg)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Non-blocking: The regs variable seems ultimately unnecessary; it has either zero or one member, so a return here would do just as well.)

for _, reg := range registries {
// default to the URL if Prefix isn't specified
if reg.Prefix == "" {
reg.Prefix = reg.String()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function modifies its input, that needs to be clear from its name and description.

if mir.Prefix != "" {
logrus.Warnf("specified prefix for mirror '%s' has no effect", mir.String())
}
if mir.Insecure != reg.Insecure {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really undesirable? A private mirror on a private network is exactly the kind of thing many (sure, irresponsibly too many) users run with self-signed certificates.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's undesirable. I have such a thing running 24/7 🤣 But to avoid accidents I think that it's worth throwing a warning.

return fmt.Errorf("mirror '%s' of registry '%s' cannot be mirrored", mir.String(), reg.String())
}
if mir.Prefix != "" {
logrus.Warnf("specified prefix for mirror '%s' has no effect", mir.String())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cleaner to add a separate Mirror type than to try to handle these inconsistencies in behavior after the fact. It really isn’t a recursive structure, so let’s not declare it like one.

Already this consistency check is costing about as many lines as reusing the Registry type has saved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@vrothberg
Copy link
Member Author

@mtrmac

Does this need to be coordinated with the moby/moby PR introducing similar functionality? Should this me merged independently, or only after the two arrive on some shared consensus?
Is there any chance at all of sharing the file between the two? Would we rely on the atomic-registries conversion? Or not even that?

It would be ideal to go in the same direction and share the configuration at best, but I do not see any realistic chance. The moby/moby PR is blocked by upstream. There have been multiple attempts over the past years to implement registry mirroring but all have been silenced with blinding grenades. The current one came far, but I am losing hope it will be merged. The current status is to wait until upstream has an agreement on what they actually want. Hence, I suggest paving the way forward here. We use mirroring already in production (for Docker) and backport the upstream PR. As we're working on offering crio as a tech preview, having the necessary pieces upstream here would be perfect.


The API change is not the big worry, we can deal with that. This completely changes the format of the configuration file, and affects users. Is everyone OK with that? @rhatdan @baude
Or do we need to still accept the old input and transparently convert?

It's just my 2 cents but I would not accept the old input anymore. The old API is based entirely on strings, so a clean cut and clean separation of v1 and v2 of the API may just avoid confusion.

@vrothberg vrothberg force-pushed the mirror-support branch 4 times, most recently from a5ba20f to 742f597 Compare March 23, 2018 13:30
@vrothberg
Copy link
Member Author

vrothberg commented Mar 23, 2018

@mtrmac @baude I just updated the PR, with the following changes:

  • Refined the types: add Mirror, changed to generalized tomlURL for Mirror and Registry.
  • Added documentation to all functions, methods, types, and fields.
  • Added GetRegistries function to load registries. If no prefix is specified, Registry.Prefix will default to the specified URL without the URI scheme. This is required when searching for matching registries based on an image reference.
  • The upper change implies that there's no String() methods anymore.
  • Splitted FindRegistries into FindUnqualifiedSearchRegistries and FindRegistry.

That's basically it. One thing I am not very sure about is the Registry.Insecure field. May we just rename it to SkipVerify?

@mtrmac
Copy link
Collaborator

mtrmac commented Mar 27, 2018

The API change is not the big worry, we can deal with that. This completely changes the format of the configuration file, and affects users. Is everyone OK with that? @rhatdan @baude
Or do we need to still accept the old input and transparently convert?

It's just my 2 cents but I would not accept the old input anymore. The old API is based entirely on strings, so a clean cut and clean separation of v1 and v2 of the API may just avoid confusion.

Again, I don’t care so much about the API; that affects maybe 10 people maintaining the Golang programs that import this package. I care about the file format as an end-user interface; the worst case here is ignoring, or rejecting, configuration files managed by someone’s config management system, and bringing a few (thousand?) 100-node clusters down. The file format and the API are not the same thing.

@rhatdan @baude This is probably up to you (or does someone else own the registries.conf file?)

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main blocker is @rhatdan and/or @baude ACKing the new file format, and the possible lack of transition path.

// registries.
type Mirror struct {
// The mirror's URL
URL tomlURL `toml:"url"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This use of tomlURL is still visible to consumers (in that they have to say Mirror.URL.url - and is the private url field even visible?

I was thinking something like

// All existing docstrings [this is the API provided to Golang callers]
type Mirror struct {
    URL url.URL
    Insecure bool
}

// [this is the raw format of the config file]
type tomlMirror struct {
    URL tomlURL
    Insecure bool
}

unmarshal into tomlMirror, and then initialize a Mirror from it. (Maybe the toml package supports a nicer way to achieve the same thing.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look into this.

URL tomlURL `toml:"url"`
// If true, pulling from the registry will be blocked
Blocked bool `toml:"blocked"`
// If true, certs verification will be skipped
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

… and HTTP (non-TLS) connections will be allowed.

(for both Insecure members.)

Search bool `toml:"unqualified-search"`
// If it prefixes an image, the registry will be used for pulling
// (defaults to the URL without the URI scheme)
Prefix string `toml:"prefix"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the Prefix used only for matching, or stripped? E.g. with URL=https://example.com/foo and Prefix=example.net/bar, is example.net/bar/baz downloaded from https://example.com/foo/bar/baz or from https://example.com/foo/baz ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Prefix is used only for matching. If we have URL=https://example.com/foo and Prefix=example.net/bar, then it depends on what the user of the API decides to do. I would suggest downloading baz:latest from https://example.com/foo/baz:latest. If we want to have the other mapping, we are free to configure URL=https://example.com/foo/bar and Prefix=example.net/bar.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then it depends on what the user of the API decides to do

I’d much prefer having it explicitly defined. Having two different applications on the same machine interpret the same configuration file differently would not do.

Your example shows stripping the prefix, and you’re right that that gives the user more freedom. So, just explicitly document that, please.

// if no prefix is specified default to specified URL without the URI scheme
for i, reg := range config.Registries {
if reg.Prefix == "" {
prefix := strings.TrimPrefix(reg.URL.url.String(), reg.URL.url.Scheme)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn’t this strip only http from http://example.com, leaving prefix set to ://example.com?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I will check this. Once we have an agreement on the design, I will make sure to add unit tests.

@mtrmac
Copy link
Collaborator

mtrmac commented Mar 27, 2018

One thing I am not very sure about is the Registry.Insecure field. May we just rename it to SkipVerify?

  • It does not just skip HTTPS verification, it also allows use of unencrypted/unauthenticated HTTP.
  • There’s some value in making the effect (”this is insecure! you probably shouldn’t be doing this without a good reason!”) very visible.

Still, the “insecure” name is not perfect, e.g. it’s pretty non-descriptive in what it does. I’m not sure that there is any other short and descriptive alternative, and the “insecure” naming is at least somewhat traditional for distribution/docker registries by now.

I don’t feel strongly about this, up to @rhatdan / @baude again.

@vrothberg
Copy link
Member Author

Ping @rhatdan, @baude : Could you share your thoughts on the upper comments?

@vrothberg vrothberg changed the title [WIP] sysregistries: support mirrors sysregistriesv2: support mirrors and extend configuration Apr 10, 2018
@vrothberg vrothberg force-pushed the mirror-support branch 4 times, most recently from 420981e to 8eeadab Compare April 10, 2018 09:15
@vrothberg
Copy link
Member Author

@mtrmac I have updated the PR.

  • Split Mirror and Registry into internal types (transparent to the user), which are then converted to API types.

  • The main API to interact with is GetRegistries, FindUnqualifiedSearchRegistries and FindRegistry. I'd like to discuss if the latter two should return an error in case no registries are found. I think we could add a NoRegistryFound error.

  • Added unit tests.

@rhatdan @baude PTAL. To continue, we need to agree on how an upgrade path from v1 to v2 should look like regarding backward compat, etc.

@mtrmac
Copy link
Collaborator

mtrmac commented Apr 10, 2018

@mtrmac I have updated the PR.

Thanks; looks good to me.

  • The main API to interact with is GetRegistries, FindUnqualifiedSearchRegistries and FindRegistry. I'd like to discuss if the latter two should return an error in case no registries are found. I think we could add a NoRegistryFound error.

At least for FindRegistry, I think it makes good sense to keep it like it is, with error used for unexpected errors, while the unwanted but possibly quite frequent situation of finding no match is handled by returning (nil, nil). A reg == nil check is easier to read than err != nil && err == package.NoRegistryFound.

I don’t have a strong opinion about FindUnqualifiedSearchRegistries—it could be convenient to return an error string so that the caller doesn’t need to provide one, OTOH this might be a case that the caller wants to treat specially.

I’m not entirely sure about forcing the caller to keep a []Registry variable; the Find* functions could load the configuration automatically. Do you expect the calls to be so frequent that caching the []Registry array would be noticeable?

Anyway, now it’s primarily up to @rhatdan and @baude .

@baude
Copy link
Member

baude commented Apr 10, 2018

I'm cool with this. It's V2 so immediate impact is minimal. @rhatdan final approval by you?

@mtrmac
Copy link
Collaborator

mtrmac commented Apr 10, 2018

It's V2 so immediate impact is minimal.

That’s a name of the Go package, not of the config file. This proposes a completely different format of /etc/containers/registries.conf, so the two Go packages can’t very well live side by side.

@vrothberg
Copy link
Member Author

@rhatdan I have just added another commit adding the backwards compatibility to a v1 config. The commit includes more unit tests.

@mtrmac @baude @rhatdan If I see it correctly, the last "open" topic is the signature of the API functions: Should the config get loaded for each call? Should we operate on a []Registry or encapsulate that into another type, e.g. Config, which exposes the API functions as methods? I am okay with the current state, but I just want to make sure we discussed it.

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! The backward compatibility eliminates my only major worry.

regs[reg.Prefix] = up
return
}
reg.Mirrors = []Mirror{}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems to be a better fit with the rest of the intialization in makeRegistry

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

reg.URL = url
reg.Prefix = stripURIScheme(url)
return reg, nil
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be simpler, roughly like:

regs := make(map[string]*Registry)
getRegistry := func(s string) (*Registry, error) { // Note: _pointer_ to a long-lived object
    prefix =reg, exists := regs[prefix]
    if !exists {
        reg := &Registry{}
        // initialize reg
        regs[prefix] = reg
    }
   return reg, nil
}
…
for _, search := range config.V1Registries.Search.Registries {
    reg, err := getRegistry(search)
    if err != nil {
        return []Registry{}, err
    }
    reg.Search = true
}

notably all of the || updates go away, and we don’t need to worry about what parts of reg have been discarded in the exists case of addRegistry.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your great review. This one made the code much simpler and more readable.

for _, search := range config.V1Registries.Search.Registries {
reg, err := makeRegistry(search)
if err != nil {
return []Registry{}, err
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Non-blocking nit: error cases like this could be return nil, err throughout.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

// backwards compatibility for v1 configs
v2Registries, err := getV1Registries(config)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t this be v1Registries?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch :)

assert.NotNil(t, reg)
}

func TestV1BackwardsCompatibility(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also preserve the original, ~unchanged system_registries_test.go as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extended the v2 ones a bit, which test more cases now, so I don't think we need that.

@mtrmac
Copy link
Collaborator

mtrmac commented Apr 11, 2018

@mtrmac Yes, I expect it to be noticeable. … When being used by a daemon, I would expect to reload the daemon (or send sighup) to reload the config. In case of libpod, a user might do frequent queries etc.

All good points, let’s leave the load+filtering separate then.

Should we operate on a []Registry or encapsulate that into another type, e.g. Config, which exposes the API functions as methods? I am okay with the current state, but I just want to make sure we discussed it.

I don’t feel strongly about this. It would be a tiny bit simpler for the caller to have an opaque “state”, but e.g. dumping the full configuration for debugging would be easier with the full data available. Either is fine with me.

@vrothberg vrothberg force-pushed the mirror-support branch 2 times, most recently from 40e911e to 45e2af9 Compare April 12, 2018 08:29
@vrothberg vrothberg changed the title sysregistriesv2: support mirrors and extend configuration introduce sysregistriesv2 Apr 12, 2018
@vrothberg vrothberg force-pushed the mirror-support branch 3 times, most recently from a81beb1 to a0856d5 Compare April 12, 2018 09:36
@vrothberg
Copy link
Member Author

The PR is updated including @mtrmac's latest comments. I stashed the changes into one commit with a proper description.

The CI has some hiccups from skopeo at the moment.

@mtrmac
Copy link
Collaborator

mtrmac commented Apr 12, 2018

👍 Thanks! The code LGTM.

The CI has some hiccups from skopeo at the moment.

Sorry about that, I left the two repos inconsistent overnight. I have restarted the tests now.

@rhatdan / @baude can you ACK the new format, please?

Also, RFC on the transition plan. This introduces a new subpackage, meaning that any consumer can migrate at its leisure, but also nothing is pushing them to migrate. Alternatively we could replace the existing sysregistries package, breaking all users and forcing them to accept the new format soon. I don’t have a strong opinion.

Approved with PullApprove

@vrothberg
Copy link
Member Author

@mtrmac Wonderful, thanks a lot for your great reviews. I really like the outcome. My plan would be to update libpod soon to make use of the new format in order to support mirrors. I suggest to use this as a first user, see how things are going and once that's done and "known to work", we can port other tools. What do you think?

@rhatdan
Copy link
Member

rhatdan commented Apr 12, 2018

LGTM

@vrothberg
Copy link
Member Author

We need another approval to get this PR merged. Ping @mtrmac @baude.

@mtrmac
Copy link
Collaborator

mtrmac commented Apr 19, 2018

@vrothberg Please rebase one last time and I’ll merge this.

@vrothberg
Copy link
Member Author

@mtrmac I just rebased on the latest master. Thanks!

@mtrmac
Copy link
Collaborator

mtrmac commented Apr 20, 2018

(The test failure is almost certainly unrelated; I may not be able to debug it today I’m afraid.)

@vrothberg
Copy link
Member Author

/test all

@rhatdan
Copy link
Member

rhatdan commented Apr 28, 2018

@vrothberg Could you just amend you PR and push again to retrigger tests.

Introduce sysregistriesv2, which changes the format of the
`registries.conf` TOML configuration.  Instead of having different lists
to specify search registries, blocked and insecure ones, all data is
encapsulated into one registry type.  The registry type allows to
specify a list of mirrors, which can be used in the endpoint lookup to
serve, for instance, as pull through caches for the associated registry.

An example configuration may look as follows:

```toml
[[registry]]
url = "https://registry.com"
prefix = "another-registry.com"

[[registry.mirror]]
url = "http://registry-mirror.com"
insecure = true
```

The upper example shows the configuration for `https://registry.com`.
The prefix is used for matching images, and to translate one namespace
to another.  If `prefix="example.com/bar"`, `url="https://example.com/foo/bar"`
and we pull from `example.com/bar/myimage:latest`, the image can
effectively be pulled from `example.com/foo/bar/myimage:latest`. If no
prefix is specified, it defaults to the specified URL.

Ease migration from sysregistries v1 to v2 by also loading
configurations in the v1 TOML format.  Throw an error in case a config
tries to mix both formats.  This allows a smoother migration for
developers, maintainers and the user, who can switch to the new config
format once all tools have been updated to v2.

Signed-off-by: Valentin Rothberg <vrothberg@suse.com>
@vrothberg
Copy link
Member Author

@rhatdan Done.

@vrothberg
Copy link
Member Author

CI seems to be stable now. @mtrmac, can you approve this PR?

@rhatdan
Copy link
Member

rhatdan commented Apr 30, 2018

@mtrmac @runcom PTAL

@runcom
Copy link
Member

runcom commented Apr 30, 2018

LGTM

Approved with PullApprove

@runcom runcom merged commit d4e2aad into containers:master Apr 30, 2018
@vrothberg vrothberg deleted the mirror-support branch April 30, 2018 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support registry mirrors

5 participants