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

Added support for Docker ARG values. #12439

Merged
merged 1 commit into from
Mar 3, 2017
Merged

Added support for Docker ARG values. #12439

merged 1 commit into from
Mar 3, 2017

Conversation

oatmealraisin
Copy link

@oatmealraisin oatmealraisin commented Jan 10, 2017

https://trello.com/c/Yh9BPAGi/1051-5-support-dockerfile-args-in-docker-build-techdebt-builds

Through start-build, users are now able to fill ARG values in
Dockerfiles. For more information, see
https://docs.docker.com/engine/reference/builder/#/arg

This adds buildsArgs to the DockerBuildStrategy definition, and
BuildRequest definition.

@csrwng ptal?

@oatmealraisin oatmealraisin self-assigned this Jan 10, 2017
@oatmealraisin
Copy link
Author

[test]

@openshift-bot openshift-bot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. and removed needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Jan 11, 2017
@@ -937,6 +941,10 @@ type BuildRequest struct {
// Env contains additional environment variables you want to pass into a builder container.
Env []kapi.EnvVar

// Args contains any build arguments that are to be passed to Docker.
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't belong in this structure unless build args are going to be generic to all strategies.

Copy link
Author

Choose a reason for hiding this comment

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

Roger, it has been removed

Copy link
Author

Choose a reason for hiding this comment

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

@smarterclayton Looking for a different solution, maybe we should have a strategy specific struct in BuildRequest that doesn't always have to be present? Spoke with @csrwng about it for a bit, seems that this may be a good option.

@@ -562,6 +562,10 @@ type DockerBuildStrategy struct {
// Env contains additional environment variables you want to pass into a builder container
Env []kapi.EnvVar

// Args contains any build arguments that are to be passed to Docker. See
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are Env and BuildArgs distinct?

Copy link
Author

Choose a reason for hiding this comment

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

They are consumed at different parts of the build process. Env variables are put into the build container, the Build Args would be consumed by the docker invocation. Perhaps Env isn't used by Docker Strategies? In that case, we could use Env, but I think that would be a bit confusing in the future.

Copy link
Author

Choose a reason for hiding this comment

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

Env is used already, I don't think we could consolidate BuildArgs and Env together

Copy link
Contributor

Choose a reason for hiding this comment

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

Is Env used by docker build strategies today?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, here

@openshift-bot openshift-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 24, 2017
@oatmealraisin
Copy link
Author

Putting this on hold until next sprint

@oatmealraisin
Copy link
Author

@smarterclayton I've changed the BuildRequest to have a BuildStrategyOptions struct, which would allow for different options for different strategy types. ptal?

@openshift-bot openshift-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 1, 2017
@oatmealraisin
Copy link
Author

@smarterclayton ping

@oatmealraisin
Copy link
Author

Small change to GenericWebhookEvent, changed BuildArgs []kapi.EnvVar to BuildStrategyOptions

@bparees
Copy link
Contributor

bparees commented Feb 6, 2017

@openshift/api-review bump please.

@oatmealraisin
Copy link
Author

oatmealraisin commented Feb 7, 2017

@bparees I separated the api changes from the rest of the PR. This should be it's final state, sans your requests of couse ;) ptal?

Removing the WIP tag

@oatmealraisin oatmealraisin changed the title WIP Added support for Docker ARG values. Added support for Docker ARG values. Feb 7, 2017
Copy link
Contributor

@bparees bparees left a comment

Choose a reason for hiding this comment

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

needs tests for new-app/new-build

@@ -588,6 +588,11 @@ type DockerBuildStrategy struct {
// Env contains additional environment variables you want to pass into a builder container
Env []kapi.EnvVar

// Args contains any build arguments that are to be passed to Docker. See
// https://docs.docker.com/engine/reference/builder/#/arg for more details
// TODO: This should be a docker.BuildArg array, but protobuf has issues w/ it
Copy link
Contributor

Choose a reason for hiding this comment

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

i think you can remove this TODO. EnvVar serves the purpose just fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

i see a thumbs up but the line is still here...

@@ -318,6 +319,13 @@ func (d *DockerBuilder) dockerBuild(dir string, tag string, secrets []api.Secret
if d.build.Spec.Strategy.DockerStrategy.DockerfilePath != "" {
dockerfilePath = d.build.Spec.Strategy.DockerStrategy.DockerfilePath
}
// TODO: Check for non-existent build args here, if necessary
Copy link
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Author

Choose a reason for hiding this comment

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

Currently, if you pass a build arg to Docker which doesn't get used, the build fails. This is only reported in the Build logs, which may be a bit harder to debug. We could, alternatively, check for build args when we parse the Dockerfile, but this may be more complicated than we want.

Copy link
Author

Choose a reason for hiding this comment

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

I've removed this TODO, but the idea was mentioned elsewhere

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah i'm not a fan of us taking responsibility for sanity checking such things.

// TODO: Check for non-existent build args here, if necessary
if len(d.build.Spec.Strategy.DockerStrategy.BuildArgs) > 0 {
envVarBuildArgs := d.build.Spec.Strategy.DockerStrategy.BuildArgs
for _, ba := range envVarBuildArgs {
Copy link
Contributor

Choose a reason for hiding this comment

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

you don't need to do this assignment or the length check. just range over d.build.Spec.Strategy.DockerStrategy.BuildArgs

it won't do anything if it's nil or empty.

result = append(result, kapi.EnvVar{Name: k, Value: v})
}

*oldArgs = result
Copy link
Contributor

Choose a reason for hiding this comment

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

don't mutate the args, return the new array.

@@ -240,6 +263,19 @@ func (g *BuildGenerator) Instantiate(ctx kapi.Context, request *buildapi.BuildRe
return nil, errors.NewInternalError(err)
}

// Check if the user specified
Copy link
Contributor

Choose a reason for hiding this comment

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

specified what?

Copy link
Author

Choose a reason for hiding this comment

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

Changed to better describe the following code

@@ -278,6 +283,16 @@ func (o *StartBuildOptions) Complete(f *clientcmd.Factory, in io.Reader, out, er
}
o.EnvVar = env

// Handle Docker build arguments. In order to leverage existing logic, we
// first create an EnvVar array, then convert it to []docker.BuildArg
cmdutil.WarnAboutCommaSeparation(o.ErrOut, o.Args, "--build-args")
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't need to warn about comma separate for this flag because it never supported comma separation before.

// Handle Docker build arguments. In order to leverage existing logic, we
// first create an EnvVar array, then convert it to []docker.BuildArg
cmdutil.WarnAboutCommaSeparation(o.ErrOut, o.Args, "--build-args")
// TODO: This prints some stuff that's Env specific, need to change
Copy link
Contributor

Choose a reason for hiding this comment

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

?

@@ -90,6 +92,8 @@ func (pb *pipelineBuilder) NewBuildPipeline(from string, input *ImageRef, source
}
source.Name = name

// TODO: We could possibly pre-populate a list of build-args here to prevent
// incorrect use
Copy link
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Author

Choose a reason for hiding this comment

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

Removed

buildLog, err := br.Logs()
o.Expect(err).NotTo(o.HaveOccurred())
g.By(fmt.Sprintf("verifying the build failed due to Docker.", br.BuildPath))
o.Expect(buildLog).To(o.ContainSubstring("FOO"))
Copy link
Contributor

Choose a reason for hiding this comment

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

isn't the successful build also going to contain "FOO"? seems like we need a more stringent expected text to check for.

https://github.com/gabemontero/forcepull-extended-test-builder.git
git@github.com:mfojtik/sinatra-app-example
git://github.com/mfojtik/sinatra-example-2
git://github.com/mfojtik/sinatra-example-1
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume you didn't mean to deliver this file...

@oatmealraisin
Copy link
Author

@bparees Ready for another go, ptal?

@@ -588,6 +588,11 @@ type DockerBuildStrategy struct {
// Env contains additional environment variables you want to pass into a builder container
Env []kapi.EnvVar

// Args contains any build arguments that are to be passed to Docker. See
// https://docs.docker.com/engine/reference/builder/#/arg for more details
// TODO: This should be a docker.BuildArg array, but protobuf has issues w/ it
Copy link
Contributor

Choose a reason for hiding this comment

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

i see a thumbs up but the line is still here...


// Args contains any build arguments that are to be passed to Docker. See
// https://docs.docker.com/engine/reference/builder/#/arg for more details
// TODO: This should be a docker.BuildArg array, but protobuf has issues w/ it
Copy link
Contributor

Choose a reason for hiding this comment

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

get rid of the todo.

if newBuild.Spec.Strategy.DockerStrategy != nil {
newBuild.Spec.Strategy.DockerStrategy.BuildArgs = updateBuildArgs(&newBuild.Spec.Strategy.DockerStrategy.BuildArgs, dockerOpts.BuildArgs)
} else {
errors.NewBadRequest(fmt.Sprintf("Cannot specify build args on %s/%s, not a Docker build.", bc.Namespace, bc.ObjectMeta.Name))
Copy link
Contributor

Choose a reason for hiding this comment

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

don't you need to return this?

newBuild.Spec.Strategy.DockerStrategy.BuildArgs = updateBuildArgs(&newBuild.Spec.Strategy.DockerStrategy.BuildArgs, dockerOpts.BuildArgs)
} else {
return nil, errors.NewBadRequest(fmt.Sprintf("Cannot specify build args on %s/%s, not a Docker build.", buildConfig.Namespace, buildConfig.ObjectMeta.Name))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

if not_a_docker_build {
  return nil, errors.blahblah
}
newbuild.blahblah=updateblahblah()

@@ -95,6 +96,8 @@ type NewBuildOptions struct {
Output string
PrintObject func(obj runtime.Object) error
LogsForObject LogsForObjectFunc

BuildArgs []string
Copy link
Contributor

Choose a reason for hiding this comment

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

why isn't this part of Config like everything else?

Copy link
Author

Choose a reason for hiding this comment

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

I figured since it was new-build specific, it would be better here

Copy link
Contributor

Choose a reason for hiding this comment

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

i'd treat it the same way we treat BinaryBuild (which is also specific to new-build).

if err != nil {
return fmt.Errorf(strings.Replace(err.Error(), "environment variable", "build arg", -1))
}
o.Config.BuildArgs = buildArgs
Copy link
Contributor

Choose a reason for hiding this comment

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

i would expect this to be handled in the same place/manner as we handle o.Config.Environment

Copy link
Author

Choose a reason for hiding this comment

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

I didn't add handling of BuildArgs to (AppConfig) validate(), but we are now processing the BuildArgs in buildPipeline, where BuildEnvironment is handled.

// first create an EnvVar array, then convert it to []docker.BuildArg
buildArgs, _, err := cmdutil.ParseEnv(o.Args, in)
if err != nil {
return fmt.Errorf(strings.Replace(err.Error(), "environment variable", "build arg", -1))
Copy link
Contributor

Choose a reason for hiding this comment

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

this is fragile. better to just change ParseEnv to be more generic in its error messages.

@@ -163,6 +163,12 @@ os::cmd::expect_success "oc new-build --binary php --build-env-file /dev/null --
os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-build --binary php --build-env-file -" 'invalid parameter assignment'
os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-build --binary php --build-env-file -" 'invalid parameter assignment'

# new-build
# check that env vars are not split on commas and warning is printed where they previously have
Copy link
Contributor

Choose a reason for hiding this comment

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

comment is wrong.

@oatmealraisin
Copy link
Author

@bparees I've updated the PR, ptal?

Copy link
Contributor

@bparees bparees left a comment

Choose a reason for hiding this comment

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

@oatmealraisin one last thing and then lgtm. @openshift/api-review bump. this is for 3.6.

}
newBuild.Spec.Strategy.DockerStrategy.BuildArgs = updateBuildArgs(&newBuild.Spec.Strategy.DockerStrategy.BuildArgs, dockerOpts.BuildArgs)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

is the clone path ignoring the request.environment field? it looks like it is. that should be fixed while you're in here.

@@ -936,6 +943,43 @@ type BuildLog struct {
unversioned.TypeMeta
}

// DockerStrategyOptions contains extra strategy options for Docker builds
type DockerStrategyOptions struct {
unversioned.TypeMeta
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do these include TypeMeta? Are you using them somewhere as a RawExtension or a runtime.Object directly?

Copy link
Author

Choose a reason for hiding this comment

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

A couple reasons, none of which are important.

  • ./hack/update-generated-deep-copies.sh threw an error when it wasn't there.
  • I couldn't find a reason why/why not to have them, and I saw that many similar structs had it.
  • Some structs that are created have no fields, which also caused make update to fail

I've been able to remove it from DockerStrategyOptions and BuildStrategyOptions, but not from the empty stucts.

@oatmealraisin
Copy link
Author

@deads2k @bparees I need to edit the git history, but all the updated code is there. I removed the unused structs and removed the typemetas. Ptal?

@bparees
Copy link
Contributor

bparees commented Feb 18, 2017

@oatmealraisin lgtm, clean up whatever is causing the test failures and squash.

@openshift/api-review need signoff. this is for 1.6.

@bparees bparees added this to the 1.6.0 milestone Feb 18, 2017
@oatmealraisin
Copy link
Author

Squashed. Looks like there is a mix of flakes and stuff that is from the code, am working to resolve

@oatmealraisin
Copy link
Author

@bparees Tests passing now. I've added a Dockerfile to test/testdata FYI

@bparees
Copy link
Contributor

bparees commented Feb 21, 2017

@openshift/api-review bump

@@ -911,6 +915,9 @@ type GenericWebHookEvent struct {

// Env contains additional environment variables you want to pass into a builder container
Env []kapi.EnvVar

// StrategyOptions contains additional strategy-specific options for the build
StrategyOptions *BuildStrategyOptions
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like the use of "options" - is there an example from elsewhere that had this? I don't know that this makes sense nested, it's just extra abstraction.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, BinaryBuildRequestOptions and BuildLogOptions, in this file.

The nesting has value for options that are common across the strategies (if we had it to do over again, Env would probably go into BuildStrategyOptions), but i'm not going to fight unnesting it into an options field per strategy, as you suggest for the BuildRequest object below.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then DockerStrategy *DockerStrategyOptions. We don't use Options in any field names that I see and I'm not sure it adds anything.

Let's avoid nesting.

Copy link
Contributor

Choose a reason for hiding this comment

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

DockerStrategy doesn't sound like a good name for a field that doesn't hold a DockerStrategy object. That is what i'd expect a field with that name to hold.

Copy link
Contributor

Choose a reason for hiding this comment

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

@smarterclayton bump. i'm open to other naming suggestions but i don't want to just call it DockerStrategy.

@@ -966,6 +987,9 @@ type BuildRequest struct {
// TriggeredBy describes which triggers started the most recent update to the
// buildconfig and contains information about those triggers.
TriggeredBy []BuildTriggerCause

// StrategyOptions contains additional strategy-specific options for the build
StrategyOptions *BuildStrategyOptions
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems better as per strategy options:

DockerStrategy *DockerStrategyOptions
SourceStrategy *SourceStrategyOptions

However, this is really starting to fray the design - build requests was never intended to grow to match the build in complexity. The more we allow here the more we distract from Build as the intended unit of submission.

Copy link
Contributor

Choose a reason for hiding this comment

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

w/o fundamentally changing how start-build works (to have it create a build object instead of a buildrequest object), I don't know how we get there at this point.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's fine for now.

Copy link
Author

Choose a reason for hiding this comment

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

I've been implementing de-nesting this struct, but now anything that asks for a BuildStrategyOptions would need to ask for a SourceStrategyOptions, DockerStrategyOptions, etc. It's not an issue right now, but I think it will be a bit cumbersome in the future.

Maybe instead of having a containing struct (BuildStrategyOptions), we have an interface that each strategyoption implements?

Copy link
Contributor

Choose a reason for hiding this comment

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

how would the strategies implement that interface? you'd have to introduce getters and it would have to be the same getters on every implementation, implying they have the same fields.

we can introduce wrapper structs if desired in the future for passing things between methods, they don't have to be part of the api though.

Copy link
Author

Choose a reason for hiding this comment

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

true, sounds good

@oatmealraisin
Copy link
Author

@smarterclayton @bparees I de-nested DockerStrategyArgs and re-generated everything. ptal? What is the decision on renaming DockerStrategyOptions

@bparees
Copy link
Contributor

bparees commented Feb 22, 2017

I still prefer DockerStrategyOptions, or a compromise alternative, over DockerStrategy... so waiting on @smarterclayton to either suggest an alternative or overrule me.

@oatmealraisin
Copy link
Author

I split the PR into two commits for generated code for now, will squash before merge. This makes it easier for me to re-generate things.

@openshift-bot openshift-bot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. and removed needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Feb 24, 2017
@oatmealraisin
Copy link
Author

@openshift/api-review bump

@smarterclayton
Copy link
Contributor

API approved

@bparees
Copy link
Contributor

bparees commented Mar 1, 2017

@oatmealraisin squash

This includes a generic BuildStrategyOptions that will allow us to add
additional information to BuildRequest objects, such as BuildArgs for
Docker strategies.

Added support for Docker ARG values.

Through start-build, new-build, and generic webhooks, users are now able
to fill ARG values in Dockerfiles. For more information, see
https://docs.docker.com/engine/reference/builder/#/arg

For start-build, we add the BuildArgs to the DockerStrategyOptions of
the BuildRequest. This field was added in an earlier commit to
support this.

For new-build, we add BuildArgs to the AppConfig, which is then added to
a DockerStrategyOptions in buildPipeline(), and is added to the
BuildConfig that is created. These BuildArgs will be consumed when the
Build is triggered.

For webhook, we added a BuildStrategyOptions to the GenericWebhookEvent
object. This is consumed by the webhook code, and put into the resulting
BuildRequest, similarly to start-build.

Internally, the kapi.EnvVar BuildArgs are converted to docker.BuildArg
before being consumed by the Docker client. Originally, we used
docker.BuildArg throughout the code. However, due to Protobuf
complications, it is easier to convert kapi.EnvVar's into
docker.BuildArg when we need to.
@oatmealraisin
Copy link
Author

@bparees Squashed

@bparees
Copy link
Contributor

bparees commented Mar 1, 2017

[testextended][extended:core(builds)]

@bparees bparees self-assigned this Mar 1, 2017
@openshift-bot
Copy link
Contributor

Evaluated for origin testextended up to ce319b2

@bparees
Copy link
Contributor

bparees commented Mar 1, 2017

flake #12784
flake #11114
[test]

@oatmealraisin
Copy link
Author

@bparees Thanks

@openshift-bot
Copy link
Contributor

Evaluated for origin test up to ce319b2

@openshift-bot
Copy link
Contributor

continuous-integration/openshift-jenkins/testextended FAILURE (https://ci.openshift.redhat.com/jenkins/job/test_pr_origin_extended/1139/) (Base Commit: cb5d93e) (Extended Tests: core(builds))

@bparees
Copy link
Contributor

bparees commented Mar 1, 2017

the extended test failures look like all thin pool related issues which @csrwng is working on.
[merge]

@openshift-bot
Copy link
Contributor

Evaluated for origin merge up to ce319b2

@openshift-bot
Copy link
Contributor

continuous-integration/openshift-jenkins/test SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pull_requests_origin_future/701/) (Base Commit: 0fa7a48)

@openshift-bot
Copy link
Contributor

openshift-bot commented Mar 3, 2017

continuous-integration/openshift-jenkins/merge SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pull_requests_origin_future/776/) (Base Commit: 79264a2) (Image: devenv-rhel7_6025)

@openshift-bot openshift-bot merged commit e164e80 into openshift:master Mar 3, 2017
@oatmealraisin oatmealraisin deleted the rymurphy/docker-args branch March 3, 2017 18:22
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.

5 participants