Skip to content
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

Fix to address regression caused by PR 30897 #36316

Merged
merged 1 commit into from
Mar 6, 2018
Merged

Conversation

selansen
Copy link
Contributor

@selansen selansen commented Feb 15, 2018

fixes #36247

With the inclusion of PR #30897, creating service for host network fails in 18.02. Modified IsPreDefinedNetwork check and return NetworkNameError instead of errdefs.Forbidden to address this issue

Signed-off-by: selansen [email protected]

- What I did

- How I did it

- How to verify it

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

return nil, errdefs.Forbidden(err)
if runconfig.IsPreDefinedNetwork(create.Name) {
logrus.Debugf("%s is a pre-defined network and cannot be created", create.Name)
return nil, libnetwork.NetworkNameError(create.Name)
Copy link
Member

Choose a reason for hiding this comment

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

I still think this should be wrapped in a errdefs.Forbidden(err), but callers that need to check the error for NetworkNameError should check against errors.Cause(err)

@selansen
Copy link
Contributor Author

selansen commented Feb 15, 2018 via email

@cpuguy83
Copy link
Member

The error wrapping in this case is so that we return the correct error code to the API.

@cpuguy83
Copy link
Member

04:57:16 FAIL: docker_api_network_test.go:241: DockerSuite.TestAPICreateDeletePredefinedNetworks
04:57:16 
04:57:16 docker_api_network_test.go:243:
04:57:16     createDeletePredefinedNetwork(c, "bridge")
04:57:16 docker_api_network_test.go:323:
04:57:16     c.Assert(resp.StatusCode, checker.Equals, expectedStatusCode)
04:57:16 ... obtained int = 409
04:57:16 ... expected int = 403

@selansen
Copy link
Contributor Author

selansen commented Feb 15, 2018 via email

@thaJeztah
Copy link
Member

thaJeztah commented Feb 15, 2018

@selansen this fixes #36247 correct?

@selansen
Copy link
Contributor Author

selansen commented Feb 15, 2018 via email

@thaJeztah
Copy link
Member

errr, copy/pasta error, yes, meant #36247

@selansen
Copy link
Contributor Author

selansen commented Feb 15, 2018 via email

@ddebroy
Copy link
Contributor

ddebroy commented Feb 15, 2018

We also need a test to make sure similar regression does not happen. Maybe add a test to make sure attaching to host and other "predefined" networks work fine with both swarm services and regular containers as well as a unit test to make sure the "predefined" networks are properly rejected.

@@ -153,6 +154,11 @@ func (c *containerAdapter) createNetworks(ctx context.Context) error {
if _, ok := err.(libnetwork.NetworkNameError); ok {
continue
}
// We will continue if CreateManagedNetwork returns forbidden error.
// Other callers still can treat it as Error.
if errdefs.IsForbidden(err) {
Copy link
Member

Choose a reason for hiding this comment

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

I’ll have to give this more thinking (haven’t looked at what other situations return), but isn’t the case where we try to create a pre-defined network a conflict (i.e. the network already “exists”).

Forbidden sounds like “you don’t have access to this endpoint” (but you do). Other options would be “invalid argument” (passed value is not valid)

Just dumping my thinking here, so that I don’t forget 😄

Copy link
Member

Choose a reason for hiding this comment

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

Conflict would imply that if the state changed then it would be possible to perform the action. In this case it is not allowed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Predefined networks are created when Daemon starts. When user creates service with predefined network, we know that network already exists and return saying you can't create. But service creation still can go ahead as the predefined network exists already. so we can ignore this error and continue in this scenario.

Copy link
Member

Choose a reason for hiding this comment

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

Conflict would imply that if the state changed then it would be possible to perform the action. In this case it is not allowed.

Right, yes. I was looking at the 403 because I wondered if it could cause issues in situations where a 403 could also occur due to authentication issues to the API. A generic 400 (bad request - the name is reserved/invalid) could've been an option for that.

Looking at NetworkNameError, I see that is also a "Forbidden" error; should we be more specific in this case, and check if it's actually a "forbidden" error, because it's a predefined network?

Given that we already walk different paths inside createNetwork() if the caller is agent, we could also use the agent option to just return a nil instead;

if runconfig.IsPreDefinedNetwork(create.Name) {
   if agent {
      return nil, nil
   }
    err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name)
    return nil, errdefs.Forbidden(err)
}

@selansen
Copy link
Contributor Author

selansen commented Feb 21, 2018 via email

@thaJeztah
Copy link
Member

I still believe instead of returning nil in case of agent is true, we let the caller decides the error information. Because setupIngress() also calls createNetwork with agent=true option.

Yeah not a big fan of the agent boolean (it's changing the behaviour of that function; perhaps that needs a refactor).

If we keep the check in the other location, should we be more specific though (as I mentioned above)?

@selansen
Copy link
Contributor Author

@thaJeztah , I can add new Forbidden Error type say "PredefinedNetworkExistError" and use it in all the places accordingly. Would that be ok with you?

@thaJeztah
Copy link
Member

@selansen yes, if you can add an error so that we can distinguish if the error was due to "predefined network" and not some other "forbidden" error, that would be good.

@@ -267,7 +267,7 @@ func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.N
}

func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) {
if runconfig.IsPreDefinedNetwork(create.Name) && !agent {
if runconfig.IsPreDefinedNetwork(create.Name) {
Copy link
Contributor

@ddebroy ddebroy Feb 26, 2018

Choose a reason for hiding this comment

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

Sorry for this late comment. Do we really need the IsPreDefinedNetwork logic here? I was discussing with Flavio a bit and it seems the logic around daemon.GetNetworkByName right below should be able to reject all PreDefined networks (besides user defined networks). This way, we will not even need IsPreDefinedNetwork above.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just discussed a bit and we do need separate code paths for Pre-Defined vs User-defined as we do allow name conflicts for the latter category.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thats is what I h added originally. I was reluctant to change. But we need to be able to differentiate regular network name exist and predefined network exist . Review comments were asking me to be more specific to error reports to the callers. Hence I added new type .

@codecov
Copy link

codecov bot commented Feb 28, 2018

Codecov Report

❗ No coverage uploaded for pull request base (master@3e1505e). Click here to learn what that means.
The diff coverage is 0%.

@@            Coverage Diff            @@
##             master   #36316   +/-   ##
=========================================
  Coverage          ?   34.89%           
=========================================
  Files             ?      613           
  Lines             ?    45413           
  Branches          ?        0           
=========================================
  Hits              ?    15847           
  Misses            ?    27465           
  Partials          ?     2101

@selansen
Copy link
Contributor Author

selansen commented Mar 2, 2018

@thaJeztah CI tests results looks good. only one test is failing . That is failing due to below test case. I looked into it. Its not related to above changes.

18:25:05 FAIL: check_test.go:366: DockerSwarmSuite.TearDownTest
18:25:05
18:25:05 unmount of /tmp/docker-execroot/d9cc520883592/netns failed: invalid argument
18:25:05 unmount of /tmp/docker-execroot/d9cc520883592/netns failed: no such file or directory
18:25:05 check_test.go:371:
18:25:05 d.Stop(c)
18:25:05 daemon/daemon.go:389:
18:25:05 t.Fatalf("Error while stopping the daemon %s : %v", d.id, err)
18:25:05 ... Error: Error while stopping the daemon d58c8df026d8e : exit status 130
18:25:05

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

one nit/question, but otherwise looks good

@@ -528,6 +537,7 @@ func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error {
if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic {
err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
return errdefs.Forbidden(err)
//return PredefinedNetworkError(nw.Name())
Copy link
Member

Choose a reason for hiding this comment

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

Can you remove this? (or should this be a PredefinedNetworkError?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me remove it. I was testing it . but forgot to remove it.

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

LGTM

@thaJeztah
Copy link
Member

@selansen looks like there's a golint failure:

23:16:50 integration/network/service_test.go:67:10:warning: if block ends with a return statement, so drop this else and outdent its block (golint)
23:16:50 Build step 'Execute shell' marked build as failure

return poll.Error(err)
}

if len(services) != int(instances) {
Copy link
Member

Choose a reason for hiding this comment

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

To make golint happy, change this to

		if len(services) != int(instances) {
			return poll.Continue("Service count at %d waiting for %d", len(services), instances)
		}
		return poll.Success()

Copy link
Contributor Author

@selansen selansen Mar 6, 2018

Choose a reason for hiding this comment

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

Already fixed golint issue and all test cases passed now.

    With the inclusion of PR 30897, creating service for host network
    fails in 18.02. Modified IsPreDefinedNetwork check and return
    NetworkNameError instead of errdefs.Forbidden to address this issue

Signed-off-by: selansen <[email protected]>
Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

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

LGTM 🐯

func serviceRunningCount(client client.ServiceAPIClient, serviceID string, instances uint64) func(log poll.LogT) poll.Result {
return func(log poll.LogT) poll.Result {
filter := filters.NewArgs()
filter.Add("service", serviceID)
Copy link
Member

Choose a reason for hiding this comment

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

This filter is not used. Was it supposed to be set in ServiceListOptions ?

You can build these inline now, which would prevent such an issue:

filters.NewArgs(filter.Arg("service", serviceID))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[18.02.0] Swarm service cannot attach to host network - "only one instance of "host" network is allowed"
8 participants