-
Notifications
You must be signed in to change notification settings - Fork 886
Global Default Address Pool support #2241
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
3f5865d to
53d6c60
Compare
7500c9b to
2a40767
Compare
ipams/builtin/builtin_unix.go
Outdated
| // defaultAddressPool Stores user configured subnet list | ||
| defaultAddressPool []*ipamutils.NetworkToSplit | ||
| // isGlobalScopePool indicates if it is global or local | ||
| isGlobalScopePool bool |
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.
How does this work? How can I set default address pools on the daemon (bridge networks), and global address pools (for swarm)?
| RUN apt-get update && apt-get -y install iptables \ | ||
| protobuf-compiler | ||
|
|
||
| RUN go get -d github.com/gogo/protobuf/protoc-gen-gogo && \ |
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.
code got merged, you can rebase
1b5e43f to
4b4b319
Compare
| FROM golang:1.10.2 as dev | ||
| RUN apt-get update && apt-get -y install iptables \ | ||
| protobuf-compiler | ||
|
|
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 checkout this file, no need to add these changes
ipamutils/utils.go
Outdated
|
|
||
| // InitNetworks initializes the broad network pool and the granular network pool | ||
| func InitNetworks(defaultAddressPool []*NetworkToSplit) { | ||
| func InitNetworks(defaultAddressPool []*NetworkToSplit, isGlobalScope bool) { |
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.
does not seem a clean solution this one.
I would create a Reinit function if needed
10f1257 to
1e555c7
Compare
|
@thaJeztah @fcrisciani @ctelfer As per our discussion I cleaned up the code along with review comments. |
ipamutils/utils.go
Outdated
| } | ||
|
|
||
| // ConfigGlobalScopeDefaultNetworks initializes the global scope default network pool | ||
| func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) { |
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 define this function as: func ConfigGlobalScopeDefaultNetworks(defaultAddressPool *NetworkToSplit...) {
You can avoid from other places to call it with nil, but you will be able to call the method as:
ConfigGlobalScopeDefaultNetworks() that is nicer
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.
swarm init is the only place we are going to call. we can reuse the same function for swarm update. We are not going to call from any other place.
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.
sorry I was referring to the fact that there is a nil check at line 54. If that is needed, means that this method can be called with nil, I was just suggesting that in that case, would be nicer to have a method that takes 0 arguments instead of 1 argument set to 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.
Added unit test to cover new changes
1ce1f3e to
20e5a92
Compare
ipamutils/utils.go
Outdated
| } | ||
| mutex.Unlock() | ||
| if defaultAddressPool != nil { | ||
| logrus.Infof("Swarm init global scope default address pool succeeded") |
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.
Info
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.
done
ipamutils/utils.go
Outdated
| } | ||
| var err error | ||
| if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(defaultAddressPool); err != nil { | ||
| logrus.WithError(err).Error("InitAddressPools failed to initialize the local scope default address pool") |
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.
don't we want to return the err to the caller?
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 is kind of Init function for swarmKit. We dont return error. Ideally this should never fail. Thats why we just log the error message. All the validations are done at CLI level.
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.
Hrmm.. I'm not sure that I agree in this case or in the InitNetworks case. But especially in this case. The reason is that both functions take potentially erroneous parameters that can come from user input. Even though it should never fail, by not returning an error here we are implicitly forcing the caller to know all the rules for input validation that this library requires. Clearly the CLI and swarmkit should do some input validation. But IMHO, they should only have to do enough to ensure that the input is parses correctly. Things like invalid parameter combinations should really be handled here. This way, if the design or functionality changes, (e.g. becoming more restrictive or less restrictive) the changes don't have to happen in multiple locations in the code for it to validate the input correctly. I'd also think that the caller should be given the option to panic or abort the code entirely if such an error occurs.
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 agree with you on caller should get notified. We dont pass user input while calling Libnetwork API the way we used to do. Instead of passing CLI input deep into stack, I was asked to change APIs params such a way that we pass well defined structure. when we receive input from CLI , now the parser does all validation and converts into []IPNet object. So if there is failure in the user input we reject way before it reaches swarmKit or Libnetwork. When we call, Libnetwork Init we dont pass wrong structure from swarmkit. So it is protected at CLI and swarmKit modules. Like I mentioned existing Init APIs also behave in the same way.
ipamutils/utils.go
Outdated
| if defaultAddressPool == nil { | ||
| defaultAddressPool = globalScopeDefaultNetworks | ||
| } | ||
| var err error |
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.
why this err is defined here and not in the next line if not used later?
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.
while re writing , I missed it out. corrected it.
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 I move err inside if block, I am getting below error. So moved it back up.
ipamutils/utils.go:60:2: PredefinedGlobalScopeDefaultNetworks declared and not used
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.
Agree. This is one of those ... er ... charming Go scope behaviors with := ... Go will assume that PredefinedGlobalScopeDefaultNetworks is also a local variable in need of fresh declaration. Go allows for partial redeclaration of variables ... except when it doesn't ... by overriding the outer declaration with an inner one.
ipamutils/utils.go
Outdated
| initNetworksOnce.Do(func() { | ||
| // error ingnored should never fail | ||
| PredefinedGranularNetworks, _ = splitNetworks(defaultGranularNetwork) | ||
| mutex.Lock() |
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 the lock here can be removed and you can directly call the method ConfigGlobalScopeDefaultNetworks
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.
Idea is ConfigGlobalScopeDefaultNetworks is invoked only from swarmkit and init network will be invoked only during Daemon Init. Later if we plan to support swarmkit update , we dont can modify ConfigGlobalScopeDefaultNetworks without worrying about InitNetworks calling this API. would like to keep it that way .
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 want to keep it this way I think you should add a comment explaining why. Otherwise someone may come along later and refactor InitNetworks() to call ConfigGlobalScopeDefaultNetworks() as the logic is (more or less) duplicated.
ipamutils/utils.go
Outdated
| // error ignored should never fail | ||
| PredefinedGlobalScopeDefaultNetworks, _ = splitNetworks(globalScopeDefaultNetworks) | ||
| mutex.Unlock() | ||
| if defaultAddressPool == 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.
do you want to call this one localAddressPool?
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 guess its not required. Daemon Init will be called only once and we will be initializing local pool only one time during Init. So I feel its not required. WDYT?
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 the point was more just for code clarity. We are initializing two default address pools in this function. Renaming the parameter makes it clear that one only can modify the local address pool using InitNetworks().
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 agree, renaming the parameter to localAddressPool would make the intent clearer.
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.
Sorry, wrote this in the wrong browser tab. Will review soon. Pls disregard ... github doesn't seem to want to let me delete the comment.
20e5a92 to
00d711d
Compare
ipamutils/utils.go
Outdated
| } | ||
| var err error | ||
| if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(defaultAddressPool); err != nil { | ||
| logrus.WithError(err).Error("InitAddressPools failed to initialize the local scope default address pool") |
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.
Hrmm.. I'm not sure that I agree in this case or in the InitNetworks case. But especially in this case. The reason is that both functions take potentially erroneous parameters that can come from user input. Even though it should never fail, by not returning an error here we are implicitly forcing the caller to know all the rules for input validation that this library requires. Clearly the CLI and swarmkit should do some input validation. But IMHO, they should only have to do enough to ensure that the input is parses correctly. Things like invalid parameter combinations should really be handled here. This way, if the design or functionality changes, (e.g. becoming more restrictive or less restrictive) the changes don't have to happen in multiple locations in the code for it to validate the input correctly. I'd also think that the caller should be given the option to panic or abort the code entirely if such an error occurs.
ipamutils/utils_test.go
Outdated
|
|
||
| assert.Check(t, is.Len(m, 0)) | ||
|
|
||
| } |
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.
nit: probably delete at least one of the extra blank lines here.
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.
done
ipamutils/utils.go
Outdated
| // error ignored should never fail | ||
| PredefinedGlobalScopeDefaultNetworks, _ = splitNetworks(globalScopeDefaultNetworks) | ||
| mutex.Unlock() | ||
| if defaultAddressPool == 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.
I think the point was more just for code clarity. We are initializing two default address pools in this function. Renaming the parameter makes it clear that one only can modify the local address pool using InitNetworks().
|
@ctelfer somehow I see your comments are duplicated twice in some cases. Not sure why :) |
c5b9182 to
69adc43
Compare
|
Ping @ctelfer @fcrisciani @abhi |
ipamutils/utils.go
Outdated
| Size int `json:"size"` | ||
| } | ||
|
|
||
| // InitNetworks initializes the broad network pool and the granular network pool |
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.
Please change 'broad network' and 'granular network' to 'local scope' and 'global scope' to match the new variable names.
ipamutils/utils.go
Outdated
| // error ignored should never fail | ||
| PredefinedGlobalScopeDefaultNetworks, _ = splitNetworks(globalScopeDefaultNetworks) | ||
| mutex.Unlock() | ||
| if defaultAddressPool == 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.
I agree, renaming the parameter to localAddressPool would make the intent clearer.
ipamutils/utils.go
Outdated
| initNetworksOnce.Do(func() { | ||
| // error ingnored should never fail | ||
| PredefinedGranularNetworks, _ = splitNetworks(defaultGranularNetwork) | ||
| mutex.Lock() |
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 want to keep it this way I think you should add a comment explaining why. Otherwise someone may come along later and refactor InitNetworks() to call ConfigGlobalScopeDefaultNetworks() as the logic is (more or less) duplicated.
|
@selansen yeah, I have been seeing comments duplicated in other PRs as well. Weird. |
d4c567d to
600c483
Compare
ctelfer
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.
The refactoring generally looks fine. Just a few nits re testing for exceptional conditions. I'll check on this early tomorrow and merge ASAP if we can answer these. BTW, do the unit tests pass cleanly with the changes? (I assume they do, but want to be sure.)
| var err error | ||
| if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil { | ||
| logrus.WithError(err).Error("InitAddressPools failed to initialize the global scope default address pool") | ||
| } |
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.
Since this default initialization only occurs on compile-time constant input it must always work. Therefore, it should be OK to panic() if some kind of error occurs. This is similar to https://golang.org/pkg/regexp/#MustCompile which panics if a regex is malformed. (again, one invokes this on compile-time regex strings that are known to be good.)
|
|
||
| if defaultAddressPool == nil { | ||
| defaultAddressPool = globalScopeDefaultNetworks | ||
| } |
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.
Since the globalScopeDefaultNetworks are already installed, why not just do:
if defaultAddressPool == nil {
return nil
}
at the start of the function? (even before the lock/deferred unlock) Re-invoking configureDefaultNetworks() again on globalScopeDefaultNetworks isn't going to change the configuration.
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.
No. This is one of the issue I found out during testing and added as extra requirement after I & @mark-church discussed.
here is the scenario which I am trying to address
- swarm init happens with new "subnet-pool"
- tearing down swarm cluster
- now bring up swarm init without "subnet-pool" option
- we should init global pool back to inbuilt pool as it used to work without this feature.
so I will have to set it back to in built values and re initialize it again. else swam cluster will have old IPs for overlay networks.
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.
ok, got it. leave as is, then.
ipamutils/utils.go
Outdated
| mutex.Lock() | ||
| return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks) | ||
| } | ||
| return 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.
Same could be done here (early return if parameter is nil). I believe this is the preferred form in go. (i.e. keep indentation down by returning early). @abhi please correct me if I'm wrong.
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.
make sense. will change it.
600c483 to
db6bd79
Compare
|
CI unit test failed few places after refactor but fixed them all. |
db6bd79 to
fbdfb1f
Compare
|
@ctelfer All set to go. pls let me know if everything looks good to you |
|
LGTM The |
| }) | ||
| func init() { | ||
| var err error | ||
| if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); 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.
Can't you use configDefaultNetworks() here as well?
fbdfb1f to
b7458ad
Compare
This change brings global default address pool feature into libnetwork. Idea is to reuse same code flow and functions that were implemented for local scope default address pool. Function InitNetworks carries most of the changes. local scope default address pool init should always happen only once. But Global scope default address pool can be initialized multiple times. Signed-off-by: selansen <elango.siva@docker.com>
b7458ad to
8d8ab67
Compare
This change brings global default address pool feature into
libnetwork. Idea is to reuse same code flow and functions that were
implemented for local scope default address pool.
Function InitNetworks carries most of the changes. local scope default
address pool init should always happen only once. But Global scope
default address pool can be initialized multiple times.
Signed-off-by: selansen elango.siva@docker.com