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

[Builder] Cleanup unnecessary mutate then revert of b.runConfig #32773

Merged
merged 1 commit into from
May 3, 2017

Conversation

dnephin
Copy link
Member

@dnephin dnephin commented Apr 21, 2017

This PR changes how runConfig is modified by the builder dispatchers. Previously a single runConfig reference was passed around everywhere. This made it possible for the builder to modify (either accidentally or intentionally) the config of an already created container without using the established interface.

Instead of passing around a single reference, copies of runConfig are created when the dispatcher needs to make a temporary modification to runConfig. Creating a copy removes the need to setup a defer to revert the temporary modification. It also avoids any accidental modification of a container configuration.

ContainerConfig was added to the commit options to support the existing behaviour of dispatchers.run(). Cmd was modified after the container was created, and this change was picked up by commit() because of the shared reference. With this API change the behaviour is a lot more obvious.

I think this changes makes the dispatchers and builder internals much easier to understand. It also removes some dead code from run() which wasn't obvious because of the clutter.

if id == "" {
cmd := b.runConfig.Cmd
b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), "#(nop) ", comment))
defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
Copy link
Member Author

@dnephin dnephin Apr 21, 2017

Choose a reason for hiding this comment

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

There was an inconsistency here. The other two places that added a #(nop) comment did it with string concat, where as this adds it as another item in the slice.

I'm not sure if this will cause a cache miss, but at least it's consistent now.

@dnephin dnephin added status/failing-ci Indicates that the PR in its current state fails the test suite status/2-code-review and removed status/0-triage labels Apr 21, 2017
@dnephin dnephin force-pushed the refactor-builder-split-commit-2 branch 2 times, most recently from d5a2cc4 to 510b888 Compare April 22, 2017 22:10
// daemon.Commit() does a daemon.getContainer() to build the history, and
// this modifies the config after the container has been run, changing it
// to the updated Cmd
// saveCmd
Copy link
Member Author

Choose a reason for hiding this comment

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

@tonistiigi this is a big surprise to me. I wonder if it is to you as well.

I guess this has been the case for a while, but nothing relied on it until #31584. It looks like there was lots of discussion about design and docs in that issue, but not much about the implementation.

This was relying of the fact ContainerCreate used the reference directly, so it was possible for the builder to modify runConfig and it would change the config of the already created container!

I'm trying to find a way to implement this without this hack. I think Commit() will need to change to accept more args? Maybe it should accept the history?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I fixed this by adding a CreatedBy field to ContainerCommitConfig.

@dnephin dnephin force-pushed the refactor-builder-split-commit-2 branch 2 times, most recently from 4614f99 to 5f00665 Compare April 27, 2017 16:12
@dnephin dnephin force-pushed the refactor-builder-split-commit-2 branch 4 times, most recently from caa55c2 to ec27c6f Compare April 28, 2017 16:22
@@ -316,6 +316,10 @@ func (b *Builder) hasFromImage() bool {
//
// TODO: Remove?
func BuildFromConfig(config *container.Config, changes []string) (*container.Config, error) {
if len(changes) == 0 {
return config, nil
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This change wasn't strictly necessary, but I think it helps clarify the behaviour of this function when changes is empty.

BuildFromConfig() needs a much larger cleanup, but this PR isn't the place.

defer func(cmd strslice.StrSlice) { req.runConfig.Cmd = cmd }(cmd)
// TODO: why is this done here. This seems to be done at random places all over
// the builder
req.runConfig.Image = req.builder.image
Copy link
Member Author

Choose a reason for hiding this comment

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

These TODO comments about setting runConfig.Image from b.Image are addressed in a follow up PR #32749

Copy link
Member

@tonistiigi tonistiigi left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -98,6 +99,9 @@ type ExecProcessConfig struct {
type ContainerCommitConfig struct {
types.ContainerCommitConfig
Changes []string
// TODO: ContainerConfig is only used by the dockerfile Builder, so remove it
// once the Builder has been updated to use a different interface
ContainerConfig *container.Config
Copy link
Member

Choose a reason for hiding this comment

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

Should we mark in the name that this should not be used by the API so we don't need to deprecate it? Or maybe it could be useful for docker commit 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.

This is not actually part of the HTTP API (even though it's under api/types). It's only in the interface between the router and the daemon. I don't think we'll have to deprecate it, we can just remove it at some point.

@dnephin dnephin force-pushed the refactor-builder-split-commit-2 branch from f452a2e to 9f738cc Compare May 1, 2017 22:36
Instead of mutating and reverting, just create a copy and pass the copy
around.

Add a unit test for builder dispatcher.run

Fix two test failures

Fix image history by adding a CreatedBy to commit options. Previously the
createdBy field was being created by modifying a reference to the runConfig that
was held from when the container was created.

Fix a test that expected a trailing slash. Previously the runConfig was being
modified by container create. Now that we're creating a copy of runConfig
instead of sharing a reference the runConfig retains the trailing slash.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
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 🐯

@vdemeester vdemeester merged commit d35fc14 into moby:master May 3, 2017
@GordonTheTurtle GordonTheTurtle added this to the 17.06.0 milestone May 3, 2017
@dnephin dnephin deleted the refactor-builder-split-commit-2 branch May 3, 2017 14:43
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.

None yet

4 participants