-
Notifications
You must be signed in to change notification settings - Fork 18.9k
daemon: Improve NetworkingConfig & EndpointSettings validation #46183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ee0eae0 to
b227bc4
Compare
| ) | ||
|
|
||
| // Test case for 35752 | ||
| func TestVerifyNetworkingConfig(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer not to delete this test, and I'd even prefer to expand it to test interesting cases. But given that verifyNetworkingConfig is now a method of daemon, it's quite hard. I'd have to instantiate a daemon with a working libnetwork controller.
To make it easier to test, I thought about keeping verifyNetworkingConfig as a function and add a new networkFinder func(string) *libnetwork.Network parameter to it. It'd take daemon.FindNetwork in the daemon code, and a mock in this test. However, I'm not sure if that's a common / acceptable pattern.
thaJeztah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some quick comments from having a first glance.
daemon/container_operations.go
Outdated
| if !hasUserDefinedIPAddress(epConfig.IPAMConfig) { | ||
| return errors.Join(errs...) | ||
| } | ||
| if epConfig.IPAMConfig.IPv4Address != "" && net.ParseIP(epConfig.IPAMConfig.IPv4Address).To4() == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a bunch of these are also done in buildCreateEndpointOptions. Wondering if we can extract some of these checks, and make both use the same validation 🤔
Lines 808 to 838 in 220fba0
| if epConfig != nil { | |
| if ipam := epConfig.IPAMConfig; ipam != nil { | |
| var ipList []net.IP | |
| for _, ips := range ipam.LinkLocalIPs { | |
| linkIP := net.ParseIP(ips) | |
| if linkIP == nil && ips != "" { | |
| return nil, fmt.Errorf("invalid link-local IP address: %s", ipam.LinkLocalIPs) | |
| } | |
| ipList = append(ipList, linkIP) | |
| } | |
| ip := net.ParseIP(ipam.IPv4Address) | |
| if ip == nil && ipam.IPv4Address != "" { | |
| return nil, fmt.Errorf("invalid IPv4 address: %s", ipam.IPv4Address) | |
| } | |
| ip6 := net.ParseIP(ipam.IPv6Address) | |
| if ip6 == nil && ipam.IPv6Address != "" { | |
| return nil, fmt.Errorf("invalid IPv6 address: %s", ipam.IPv6Address) | |
| } | |
| createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil)) | |
| } | |
| for _, alias := range epConfig.Aliases { | |
| createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) | |
| } | |
| for k, v := range epConfig.DriverOpts { | |
| createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v})) | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm not sure what to do with these errors. For me, there're more like defensive checks than data validation. And there're needed because we actually need "strong-type".
From that perspective we could potentially do a quick check on well-formed-ness of options (we should really look if we can do such parsing/conversions earlier, and get to a "strong-type" ASAP in the process, as we're sometimes parsing the same string multiple times), and only if we get that far, proceed with the heavier lifting.
IMHO the best way to solve that would be to create an intermediate representation that's stored in-memory (and on-disk?) and not exposed on the API. Then, the validation step could be made responsible of instantiating these "stronger types". But that's a non-trivial chunk of work, and this PR is required by docker/cli#4493 (which in turn is required by docker/cli#4419, itself required by the other PRs adding proper support for multi --network parameters).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As shared privately, for now we can't really drop the validation steps in buildCreateEndpointOptions. We first need to make some refactorings to make sure user-supplied data are correctly sanitized and transformed into useful structs instead of keeping literals everywhere.
This will be addressed in a follow-up PR.
daemon/container_operations.go
Outdated
| } | ||
| } | ||
|
|
||
| if nw == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation is called from 2 places;
In Daemon.updateNetworkConfig();
if err := validateEndpointSettings(n, n.Name(), endpointConfig); err != nil {
return err
}In Daemon.validateNetworkingConfig();
// The referenced network k might not exist when the container is created, so don't fail if that's the case.
// If any other error happen, it's not a validation error, so better early exit.
nw, err := daemon.FindNetwork(k)
if err != nil && !errdefs.IsNotFound(err) {
return err
}
if err := validateEndpointSettings(nw, k, v); err != nil {
errs = append(errs, fmt.Errorf("invalid endpoint config for network %s: %w", k, err))
}- in both cases, I think we'd already barf out if the network is not to be found
- and, I think in both cases
nwNameis effectively equivalent tonw.Name()(although I'm not 100% sure for the second case; can it use network ID instead of name? does that matter for this case?)
So I'm wondering if we should continue to bail out early if there's no network (instead of continuing with other checks), as we probably would never reach this validation
Also slightly looking if we should split "heavy" and "lightweight" validation; e.g. validating for invalid / invalidly formatted IP-addresses is something that's relatively lightweight, whereas fetching the network (knowing libnetwork ...) may "not be". From that perspective we could potentially do a quick check on well-formed-ness of options (we should really look if we can do such parsing/conversions earlier, and get to a "strong-type" ASAP in the process, as we're sometimes parsing the same string multiple times), and only if we get that far, proceed with the heavier lifting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in both cases, I think we'd already barf out if the network is not to be found
Nope, we actually accept a ContainerCreate request with a reference to a non-existant network:
moby/daemon/container_operations.go
Lines 577 to 580 in b227bc4
| // validateEndpointSettings checks whether the given epConfig is valid. The nw parameter might be nil as a container | |
| // can be created with a reference to a network that don't exist yet. In that case, only partial validation will be | |
| // done. | |
| func validateEndpointSettings(nw *libnetwork.Network, nwName string, epConfig *networktypes.EndpointSettings) error { |
It's not a hypothetical case, it's how things are working right now 😉
$ docker network inspect foobar
[]
Error response from daemon: network foobar not found
$ docker container create --network foobar busybox
6697a506ee56c76d770218b49794255b8059a0f6deec836a0c26778379612b6a
we should really look if we can do such parsing/conversions earlier, and get to a "strong-type" ASAP in the process
Yeah, I looked into this a bit already. I'd like to have netip.* instead of strings, as it'd remove the need of constantly parsing the same thing. But that imply quite a bunch of work. I didn't had time to create the CLI PR that depends on this one, but it all have to do with the ability to provide multiple --network flags, hence I'd prefer to keep this one simple.
EDIT: For the record, here's the CLI PR that requires this one: docker/cli#4493
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, we actually accept a ContainerCreate request with a reference to a non-existant network:
For context here (I stumbled upon that recently); I think this is the commit that changed that behavior; 99a98cc (part of #25962). In that commit, it's no longer checked if the network exists, with the assumption that it may be a dynamically rolled-out (but "attachable") network, and will be created "lazily"".
(also related: #26449, #27466)
Honestly, looking at some of that, I'm not sure I'm a "fan". Perhaps we should indeed;
- Always have the network "available" on every node (but it could be a "definition-only" for dynamically rolled-out networks)
- Or, for
attachablenetworks, and a container attaching to it, we could still consider to initialize it when attaching
But this definitely requires some digging into the internals / underlying mechanisms to see if that's possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the digging!
- Always have the network "available" on every node (but it could be a "definition-only" for dynamically rolled-out networks)
- Or, for attachable networks, and a container attaching to it, we could still consider to initialize it when attaching
Once this PR is merged, I'll submit a follow-up refactor PR to move attachment requests out of findAndAttachNetwork to a dedicated method called before doing anything else in initializeNetworking. With that change:
- On
ContainerCreate, only soundness checks will be done ; - On
ContainerStart(andNetworkConnect), we'll determine whether referenced network exists locally, attach it if it's swarm scoped, or bail out because if it doesn't. And then, we can normalize and validate the settings thoroughly ;
I started doing some work in that direction here: fba50d6.
I think it'd be "conceptually" better to go back to the original semantic: you can only attach to a network that exists locally; but it'd be more work to implement and I guess we'd probably need to gate that behind an API version check, so anyway... I think we can get the same result by shuffling a bit the order of operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be "conceptually" better to go back to the original semantic: you can only attach to a network that exists locally; but it'd be more work to implement and I guess we'd probably need to gate that behind an API version check, so anyway... I think we can get the same result by shuffling a bit the order of operations.
Yes, we need to look at that! I guess overall the tricky bit is that we must assume that there's potentially many nodes and many networks, and not all of those networks to be used on each node.
- For "attachable" networks, it would be good to have a ("stub?") network on each node, so that
docker network attachecan be used for containers; we could probably still make it a stub (so that it doesn't take up resources on all notes in the swarm), and make it an actual network when attaching. - For "non-attachable" networks, I guess it's TBD; do we want to show stubs for those? (if it's a worker node, the worker itself wouldn't have much purpose for it until a swarm task lands on the node).
- For managers it would be more useful (as you could run
docker network rm <some swarm-scope network>)
Either way; all of that is for a follow-up discussion. We could create a ticket for it though (perhaps copy/paste some of the above)
daemon/container_operations.go
Outdated
| var errs []error | ||
| if !containertypes.NetworkMode(nwName).IsUserDefined() { | ||
| // On Linux, user specified IP address is accepted only for networks with user specified subnets. | ||
| if hasUserDefinedIPAddress(epConfig.IPAMConfig) && !enableIPOnPredefinedNetwork() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an observation here;
hasUserDefinedIPAddress()will always befalseif there's no ipamConfig, which may already invalidate other checks.- ^^ slightly leaning toward inlining that function here, and just make it a
hasUserDefinedIPAddressvariable that we set (and use), as that function is only used inside this check, and we're now potentially calling it twice with the same results - BOTH
enableIPOnPredefinedNetworkandserviceDiscoveryOnDefaultNetworkare effectivelyif runtime.GOOS == "windows") - ^^ wondering if we need to split the validation there, instead of having two utility functions that effectively means "different validation on windows vs linux" (not sure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, most of these would be better handled in their own PR. Also, the next step once we get proper support for multi --network flags, is to make the default bridge just a "normal" bridge (ie. no more links, no more artificial restriction, etc...). So better keep these refactorings for that time (unless you want to go ahead and do this beforehand).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- BOTH
enableIPOnPredefinedNetworkandserviceDiscoveryOnDefaultNetworkare effectively if runtime.GOOS == "windows")- ^^ wondering if we need to split the validation there, instead of having two utility functions that effectively means "different validation on windows vs linux" (not sure)
I added a TODO to remind us we should remove these functions once we remove legacy networking mode from the default bridge. As such, I think we shouldn't make the validation OS-dependent here, as it's going to be addressed (hopefully) soon.
Following flags are silently ignored when they're passed with no `--network` specified (ie. when the default network is used): - `--network-alias` - `--ip` - `--ip6` - `--link-local-ip` This is not really an issue right now since the first 3 parameters are not allowed on the default bridge network. However, with [moby/moby#45905][1], the container-wide MacAddress parameter will be deprecated and dismissed. Because of that, with [docker#4419][2], it's currently not possible to use the `--mac-address` flag with no default network specified. Morever, `docker network connect --link-local-ip ...` works properly, so it should also work on `docker container create`. This also lay the ground for making the default bridge network just a "normal" network. Since the 3 parameters in the list above aren't ignored anymore, if users provide them, moby's ContainerStart endpoint will complain about those. To provide better UX, [moby/moby#46183][3] make sure these invalid parameters lead to a proper error message on `docker container create` / `docker run`. [1]: moby/moby#45905 [2]: docker#4419 [3]: moby/moby#46183 Signed-off-by: Albin Kerouanton <albinker@gmail.com>
b227bc4 to
08c7515
Compare
08c7515 to
2daa7e4
Compare
daemon/create.go
Outdated
|
|
||
| // The referenced network k might not exist when the container is created, so don't fail if that's the case. | ||
| nw, err := daemon.FindNetwork(k) | ||
| if err != nil && !errdefs.IsNotFound(err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test TestCreateWithDuplicateNetworkNames from the service suite is failing because this condition will return a validation error if two networks with conflicting names are created.
Instead of working around this, I drop TestCreateWithDuplicateNetworkNames in #46251.
47d1652 to
cbe536e
Compare
Following flags are silently ignored when they're passed with no `--network` specified (ie. when the default network is used): - `--network-alias` - `--ip` - `--ip6` - `--link-local-ip` This is not really an issue right now since the first 3 parameters are not allowed on the default bridge network. However, with [moby/moby#45905][1], the container-wide MacAddress parameter will be deprecated and dismissed. Because of that, with [docker#4419][2], it's currently not possible to use the `--mac-address` flag with no default network specified. Morever, `docker network connect --link-local-ip ...` works properly, so it should also work on `docker container create`. This also lay the ground for making the default bridge network just a "normal" network. Since the 3 parameters in the list above aren't ignored anymore, if users provide them, moby's ContainerStart endpoint will complain about those. To provide better UX, [moby/moby#46183][3] make sure these invalid parameters lead to a proper error message on `docker container create` / `docker run`. [1]: moby/moby#45905 [2]: docker#4419 [3]: moby/moby#46183 Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Following flags are silently ignored when they're passed with no `--network` specified (ie. when the default network is used): - `--network-alias` - `--ip` - `--ip6` - `--link-local-ip` This is not really an issue right now since the first 3 parameters are not allowed on the default bridge network. However, with [moby/moby#45905][1], the container-wide MacAddress parameter will be deprecated and dismissed. Because of that, with [docker#4419][2], it's currently not possible to use the `--mac-address` flag with no default network specified. Morever, `docker network connect --link-local-ip ...` works properly, so it should also work on `docker container create`. This also lay the ground for making the default bridge network just a "normal" network. Since the 3 parameters in the list above aren't ignored anymore, if users provide them, moby's ContainerStart endpoint will complain about those. To provide better UX, [moby/moby#46183][3] make sure these invalid parameters lead to a proper error message on `docker container create` / `docker run`. [1]: moby/moby#45905 [2]: docker#4419 [3]: moby/moby#46183 Signed-off-by: Albin Kerouanton <albinker@gmail.com>
270d738 to
a285549
Compare
08ed707 to
d8173af
Compare
|
|
||
| // TODO(aker): add a proper multierror.Append | ||
| if err := ipamConfig.Validate(); err != nil { | ||
| errs = append(errs, err.(interface{ Unwrap() []error }).Unwrap()...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this, we need a proper multierror.Append instead. But I think it's ok to address that in a follow-up PR. @thaJeztah Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not against having a utility to add it.
I guess in that case we also may be able to skip the multierrors.Join() ? (i.e., an nil vs empty slice), and perhaps just return errs in that case?
I'm fine with improving in a follow-up though.
4f3bf30 to
2fc216b
Compare
thaJeztah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall looks good; there were some changes that landed in the wrong commit, so left comments about those, and I left a comment about a commit (renaming cfg => ipamConfig) that I think would be ok to squash with the commit after it)
| nw, _ := daemon.FindNetwork(k) | ||
| if err := validateEndpointSettings(nw, k, v); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're passing both k, and v as arguments, and nw may not be needed if we fail early inside the function.
Would it make sense to
- remove the
nw, _ := daemon.FindNetwork(k)here - make
validateEndpointSettingsa method ondaemon(func (daemon *daemon) validateEndpointSettings( nwName string, epConfig *networktypes.EndpointSettings) - perform looking up the network inside the function (if we reach that point)
However, it may still be an indicator that this function is trying to do too much, and maybe we should split parts of it (i.e. being able to validate the endpoint settings themselves, and settings that depend on the network's setting)
FWIW, not necessarily a blocker, but mostly considering "what's the overhead of getting the network"? (could this be trying plugins etc?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, it may still be an indicator that this function is trying to do too much
Mh, I have fixed feelings about whether it does too much things or not. But once the refactor PR I mentioned previously is merged, attachSwarmNetworks will happen first and we'll be able to take for granted that all networks exist when we start validation. This should make the code easier to follow, and help us draw a line between the "soundness checks" I mentioned and in-depth validation.
As some of this is already addressed in daemon: move most of validateEndpointSettings into api/t/net, I'll keep the code as-is in this commit.
daemon/container_operations.go
Outdated
| } | ||
| } | ||
|
|
||
| if nw == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, we actually accept a ContainerCreate request with a reference to a non-existant network:
For context here (I stumbled upon that recently); I think this is the commit that changed that behavior; 99a98cc (part of #25962). In that commit, it's no longer checked if the network exists, with the assumption that it may be a dynamically rolled-out (but "attachable") network, and will be created "lazily"".
(also related: #26449, #27466)
Honestly, looking at some of that, I'm not sure I'm a "fan". Perhaps we should indeed;
- Always have the network "available" on every node (but it could be a "definition-only" for dynamically rolled-out networks)
- Or, for
attachablenetworks, and a container attaching to it, we could still consider to initialize it when attaching
But this definitely requires some digging into the internals / underlying mechanisms to see if that's possible.
api/types/network/endpoint.go
Outdated
| func (ipamConfig *EndpointIPAMConfig) Copy() *EndpointIPAMConfig { | ||
| cfgCopy := *ipamConfig | ||
| cfgCopy.LinkLocalIPs = make([]string, 0, len(ipamConfig.LinkLocalIPs)) | ||
| cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, ipamConfig.LinkLocalIPs...) | ||
| return &cfgCopy | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit on the fence on this one; generally, "the closer" a variable is define to where it's used, the shorter the name should be. For receivers, it's very common to use a single letter (as all code generally uses it very nearby)
If this was to prevent a conflict, perhaps just c works (although I don't think the original cfg was very ambiguous).
never mind, I see the follow-up commit, and there's some functions that are pretty long, so I guess it somewhat makes sense.
(I'd be OK with combining those in a single commit though, so that it's clear why you're renaming!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went the other way around and dropped this commit as I think it's okay to stick to cfg.
|
|
||
| // TODO(aker): add a proper multierror.Append | ||
| if err := ipamConfig.Validate(); err != nil { | ||
| errs = append(errs, err.(interface{ Unwrap() []error }).Unwrap()...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not against having a utility to add it.
I guess in that case we also may be able to skip the multierrors.Join() ? (i.e., an nil vs empty slice), and perhaps just return errs in that case?
I'm fine with improving in a follow-up though.
api/types/network/endpoint.go
Outdated
| if net.ParseIP(addr) == nil { | ||
| errs = append(errs, fmt.Errorf("invalid link-local IP address %s", addr)) | ||
| errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to suggest: could we use the underlying netip.Parse instead, so that we can return an actual error with details "what is invalid"??
... only to realise that's new in Go 1.21 https://github.com/golang/go/blob/2c1e5b05fe39fc5e6c730dd60e82946b8e67c6ba/src/net/ip.go#L489-L502
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
... only to realise that's new in Go 1.21
netip.ParseAddr is actually available since go 1.18, so we can perfectly use it. But looking at the git blame, it looks like net parsers will use netip ones starting with go 1.21.
As a consequence, we might start accepting IPv6 addresses with scope zone (eg. fe80::1cc0:3e8c:119f:c2e1%ens18), whereas it's invalid. I need to double-check but we probably need a proper error for that.
EDIT: re-reading the diff, net.ParseIP will continue to return a nil if the IPv6 address includes a zone, so no need to worry about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, that's what errors netip.ParseAddr(...) produces: ParseAddr("foo"): unable to parse IP. So, it'd look like this if we use it here:
* invalid IPv4 address foo: ParseAddr("foo"): unable to parse IP
* invalid IPv6 address bar: ParseAddr("bar"): unable to parse IP
* invalid link-local IP address baz: ParseAddr("baz"): unable to parse IP
* invalid link-local IP address foobar: ParseAddr("foobar"): unable to parse IP
I think we should rather stick with net.ParseIP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes, that doesn't provide much more context indeed. I was hoping it would give the user more context what's wrong. Thanks for looking!
| scope string // network data scope | ||
| labels map[string]string | ||
| ipamType string | ||
| ipamType string // ipamType is the name of the IPAM driver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should rename this to ipamDriver at some point 😂
| // IpamConf contains all the ipam related configurations for a network | ||
| // TODO(aker): use proper net/* structs instead of string literals. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're updating, can you add an empty line in between? ISTR GoDoc can hide "TODO" comments in the generated documentation as long as there's an empty comment-line in between, so;
// IpamConf contains all the ipam related configurations for a network.
//
// TODO(aker): use proper net/* structs instead of string literals.(LOL, also this struct should really be named IPAMConf (to be properly camelcase, but that's a different topic)
So far, only a subset of NetworkingConfig was validated when calling ContainerCreate. Other parameters would be validated when the container was started. And the same goes for EndpointSettings on NetworkConnect. This commit adds two validation steps: 1. Check if the IP addresses set in endpoint's IPAMConfig are valid, when ContainerCreate and ConnectToNetwork is called ; 2. Check if the network allows static IP addresses, only on ConnectToNetwork as we need the libnetwork's Network for that and it might not exist until NetworkAttachment requests are sent to the Swarm leader (which happens only when starting the container) ; Signed-off-by: Albin Kerouanton <albinker@gmail.com>
…tSettings Thus far, validation code would stop as soon as a bad value was found. Now, we try to validate as much as we can, to return all errors to the API client. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
This issue wasn't caught on ContainerCreate or NetworkConnect (when container wasn't started yet). Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2fc216b to
87d611f
Compare
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
87d611f to
e19e541
Compare
thaJeztah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Depends on:
- What I did
So far, only a subset of
NetworkingConfigwas validated when callingContainerCreate. Other parameters would be validated when the container was started. And the same goes forEndpointSettingsonNetworkConnect.Also, the validation code was early exiting as soon as it caught an error. It now tries to validate as much as it can, and returns all the errors.
- How to verify it
Testing with the CLI won't work because it has its own client-side layer of validation (although incomplete). Some Go code has to be written to test all validation cases.
- Description for the changelog
NetworkConnectandContainerCreatehave improved data validation, and now return all validation errors at once.