support registry mirror config reload#29650
Conversation
af48291 to
16c8d98
Compare
16c8d98 to
07803d2
Compare
daemon/daemon.go
Outdated
There was a problem hiding this comment.
(just quickly peeking at the code changes); these whitespace changes are not related to this change, and not everyone like adding too much whitespace; could you remove these?
|
Feature-wise, I'm ok with adding this. I do think that the whole configuration (re)load functionality needs a massive overhaul / refactor though; I think the code is getting quite messy, and a lot of duplication |
|
Design-wise we're okay with this @aaronlehmann do you see any possible issues with live-reloading this list? |
75a22f8 to
d568ce3
Compare
registry/registry_test.go
Outdated
There was a problem hiding this comment.
Why did you change this test?
There was a problem hiding this comment.
since it fails in the test, when validateMirror.
Mirror address must have scheme. In all the test file, mirror has scheme, while this has no.
In addition, I need more investigation.
bf4ae87 to
04efd0d
Compare
registry/config.go
Outdated
There was a problem hiding this comment.
Since every mirror in the daemon no matter from flag, config or reload config, they will all be validated in LoadMirrors.
While ValidateMirror twice will lead to error, since the first ValidateMirror will add / at the end of the mirror address, if the new mirror enter the second ValidateMirror with a postfix of /, it will report error.
So I remove this part of ValidateMirror for flag options.
There was a problem hiding this comment.
Hm, I think we should fix ValidateMirror(); it basically does two things; validate the value, and "normalise" it to a standard format (to always have a trailing /). It's odd that we don't accept a trailing / as input but actually require it to be set in the output.
This should do the trick;
func ValidateMirror(val string) (string, error) {
return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
}
- if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
+ if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
}
- return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
+ return strings.TrimSuffix(val, "/") + "/", nil
}The unit test for ValidateMirror() will need to be updated as well, and some values moved from "invalid" to "valid"
There was a problem hiding this comment.
Actually, perhaps we should update those error messages a bit, as they are a bit inconsistent, and don't show which mirror/url was invalid;
// ValidateMirror validates an HTTP(S) registry mirror
func ValidateMirror(val string) (string, error) {
uri, err := url.Parse(val)
if err != nil {
return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
}
if uri.Scheme != "http" && uri.Scheme != "https" {
return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
}
if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
}
return strings.TrimSuffix(val, "/") + "/", nil
}diff --git a/registry/config.go b/registry/config.go
index 79819de..88b62af 100644
--- a/registry/config.go
+++ b/registry/config.go
@@ -247,18 +247,15 @@ func isSecureIndex(config *serviceConfig, indexName string) bool {
func ValidateMirror(val string) (string, error) {
uri, err := url.Parse(val)
if err != nil {
- return "", fmt.Errorf("%s is not a valid URI", val)
+ return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
}
-
if uri.Scheme != "http" && uri.Scheme != "https" {
- return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
+ return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
}
-
- if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
- return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
+ if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
+ return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
}
-
- return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
+ return strings.TrimSuffix(val, "/") + "/", nil
}There was a problem hiding this comment.
Oh, interesting; it marks URLs containing a username/password (http://user:[email protected]/) as "valid", but the original version silently strips them from the "normalised" URL
There was a problem hiding this comment.
This should probably do it;
// ValidateMirror validates an HTTP(S) registry mirror
func ValidateMirror(val string) (string, error) {
uri, err := url.Parse(val)
if err != nil {
return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
}
if uri.Scheme != "http" && uri.Scheme != "https" {
return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
}
if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
}
if uri.User != nil {
// strip password from output
uri.User = url.UserPassword(uri.User.Username(), "xxxxx")
return "", fmt.Errorf("invalid mirror: username/password not allowed in URI %q", uri)
}
return strings.TrimSuffix(val, "/") + "/", nil
}dcb312a to
621f082
Compare
thaJeztah
left a comment
There was a problem hiding this comment.
@allencloud I left some comments, will have another look after it's updated 😊
registry/config.go
Outdated
There was a problem hiding this comment.
I don't really like overwriting the configuration, and reverting if the values are invalid. How about something like this;
// LoadMirrors loads mirrors to config, after removing duplicates.
// Returns an error if mirrors contains an invalid mirror.
func (config *serviceConfig) LoadMirrors(mirrors []string) error {
seen := map[string]struct{}{}
unique := []string{}
for _, m := range mirrors {
m2, err := ValidateMirror(m)
if err != nil {
return err
}
if _, exist := seen[m2]; exist {
continue
}
unique = append(unique, m2)
seen[m2] = struct{}{}
}
config.Mirrors = unique
return nil
}
registry/config.go
Outdated
There was a problem hiding this comment.
Hm, I think we should fix ValidateMirror(); it basically does two things; validate the value, and "normalise" it to a standard format (to always have a trailing /). It's odd that we don't accept a trailing / as input but actually require it to be set in the output.
This should do the trick;
func ValidateMirror(val string) (string, error) {
return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
}
- if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
+ if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
}
- return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
+ return strings.TrimSuffix(val, "/") + "/", nil
}The unit test for ValidateMirror() will need to be updated as well, and some values moved from "invalid" to "valid"
registry/config.go
Outdated
There was a problem hiding this comment.
Actually, perhaps we should update those error messages a bit, as they are a bit inconsistent, and don't show which mirror/url was invalid;
// ValidateMirror validates an HTTP(S) registry mirror
func ValidateMirror(val string) (string, error) {
uri, err := url.Parse(val)
if err != nil {
return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
}
if uri.Scheme != "http" && uri.Scheme != "https" {
return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
}
if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
}
return strings.TrimSuffix(val, "/") + "/", nil
}diff --git a/registry/config.go b/registry/config.go
index 79819de..88b62af 100644
--- a/registry/config.go
+++ b/registry/config.go
@@ -247,18 +247,15 @@ func isSecureIndex(config *serviceConfig, indexName string) bool {
func ValidateMirror(val string) (string, error) {
uri, err := url.Parse(val)
if err != nil {
- return "", fmt.Errorf("%s is not a valid URI", val)
+ return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
}
-
if uri.Scheme != "http" && uri.Scheme != "https" {
- return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
+ return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
}
-
- if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
- return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
+ if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
+ return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
}
-
- return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
+ return strings.TrimSuffix(val, "/") + "/", nil
}
registry/config.go
Outdated
There was a problem hiding this comment.
Oh, interesting; it marks URLs containing a username/password (http://user:[email protected]/) as "valid", but the original version silently strips them from the "normalised" URL
registry/config.go
Outdated
There was a problem hiding this comment.
This should probably do it;
// ValidateMirror validates an HTTP(S) registry mirror
func ValidateMirror(val string) (string, error) {
uri, err := url.Parse(val)
if err != nil {
return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
}
if uri.Scheme != "http" && uri.Scheme != "https" {
return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
}
if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
}
if uri.User != nil {
// strip password from output
uri.User = url.UserPassword(uri.User.Username(), "xxxxx")
return "", fmt.Errorf("invalid mirror: username/password not allowed in URI %q", uri)
}
return strings.TrimSuffix(val, "/") + "/", nil
}621f082 to
69cb253
Compare
|
Thanks a lot. Really helpful comments. I updated this PR. PTAL |
registry/config.go
Outdated
There was a problem hiding this comment.
This naming part updated. PTAL
8071ded to
3ad1479
Compare
thaJeztah
left a comment
There was a problem hiding this comment.
oops, looks like I had a review "pending" here; see my comment
registry/config.go
Outdated
There was a problem hiding this comment.
Can you override the original password here, as I did in my example? #29650 (comment)
We don't want passwords to be printed/logged
registry/config_test.go
Outdated
There was a problem hiding this comment.
can you add a http://foo:[email protected]/ to the test?
daemon/daemon_test.go
Outdated
There was a problem hiding this comment.
I wonder if we should simplify this test, and have a single slice of test-cases, each with "before", "new", and "expected", and a property that indicates if it should fail.
There was a problem hiding this comment.
That is great. I will try that. Thanks a lot.
There was a problem hiding this comment.
Updated with clearer test. PTAL 😄
0222770 to
f7d552f
Compare
daemon/daemon.go
Outdated
There was a problem hiding this comment.
Non-blocking observation: I feel like none of the registry-related settings should be prefixed with "Daemon".
There was a problem hiding this comment.
removing is reasonable.
registry/config.go
Outdated
There was a problem hiding this comment.
Why not nil (i.e. omit this line)?
|
Code LGTM |
29b2e90 to
e90f36d
Compare
Signed-off-by: allencloud <[email protected]>
e90f36d to
5b9348c
Compare
Signed-off-by: allencloud [email protected]
fixes #29594
this PR makes docker daemon support reload config registry mirror.
- What I did
docker info- How I did it
- How to verify it
- Description for the changelog
- A picture of a cute animal (not mandatory but encouraged)