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

Add container template configuration to Task #767

Merged
merged 1 commit into from
Apr 19, 2019

Conversation

abayer
Copy link
Contributor

@abayer abayer commented Apr 17, 2019

Changes

The container template defined on the Task will be propagated to all
steps within the Task, and can be overridden on individual steps.

fixes #254

Submitter Checklist

These are the criteria that every PR should meet, please check them off as you
review them:

See the contribution guide
for more details.

Release Notes

Adds `containerTemplate` to `TaskSpec`, allowing for configuration of a `Container` to be used as the basis for all steps within the `Task`.

@googlebot googlebot added the cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit label Apr 17, 2019
@tekton-robot tekton-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 17, 2019
@abayer
Copy link
Contributor Author

abayer commented Apr 17, 2019

/assign @dwnusbaum
/assign @vdemeester
/assign @bobcatfish

@vdemeester
Copy link
Member

@abayer linking @bobcatfish comment here too #714 (comment)

Consider having some other type that holds "templating" information about how a pod should be created?

This applies too 👼

@abayer
Copy link
Contributor Author

abayer commented Apr 17, 2019

@vdemeester Yeah, this was just me resurrecting my old PR that did Pipeline and TaskRun too, removing those bits, and opening a new PR - quite happy to iterate. =)

@abayer
Copy link
Contributor Author

abayer commented Apr 17, 2019

@bobcatfish @vdemeester re that - I'm thinking of maybe adding a BaseContainer field to TaskSpec, with the field just being a *corev1.Container, which is then used as an initial container that steps are merged onto. I've got similar logic in Jenkins X that's working great for us.

Copy link
Collaborator

@bobcatfish bobcatfish left a comment

Choose a reason for hiding this comment

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

PR is looking great!! 🎉 Just a few minor comments

@bobcatfish @vdemeester re that - I'm thinking of maybe adding a BaseContainer field to TaskSpec, with the field just being a *corev1.Container, which is then used as an initial container that steps are merged onto. I've got similar logic in Jenkins X that's working great for us.

I'm leaning toward this solution as well but I want to get some more opinions before we go ahead with it maybe @dlorenc @imjasonh @vdemeester I'm interested in what you think about this.

@abayer do you have other corev1.Container fields specifically that you'd find it handy to be able to declare at the Task level?

And I'm happy to either:

  • Put this PR on hold while we discuss adding a container spec OR
  • Merge this PR and iterate (would mean adding backwards incompatible changes if we decide to add the container spec tho since we'd remove env in that case)

- name: "FOO"
value: "baz"
```

Copy link
Collaborator

Choose a reason for hiding this comment

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

wooooot great docs 🙇‍♀️ :D

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Albeit ones I now have to rewrite...

Copy link
Collaborator

Choose a reason for hiding this comment

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

😅

Copy link
Collaborator

Choose a reason for hiding this comment

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

and the new ones are great too!!

@@ -524,6 +533,38 @@ func createRedirectedTaskSpec(kubeclient kubernetes.Interface, ts *v1alpha1.Task
return ts, nil
}

// combineEnvVars takes a base slice of environment variables and a slice of environment
// variables to overlay on top of the base slice, returning the result.
func combineEnvVars(base []corev1.EnvVar, override []corev1.EnvVar) []corev1.EnvVar {
Copy link
Collaborator

Choose a reason for hiding this comment

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

looks like a great interface! i think this is a good candidate for moving into its own package with its own unit tests 😜 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Welp, I switched to a new function. Which I will move etc. =)

envVars = append(envVars, k)
}

// Avoid nondeterministic results by sorting the keys and appending vars in that order.
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice!

step.Env = combineEnvVars(ts.Env, step.Env)
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this code is solid, but I'm not sure createRedirectedTaskSpec is the place to put it because I think that createRedirectedTaskSpec is specifically about adding our magic entrypoint override business, and manipulating the environment variables doesn't seem like part of that to me - maybe we could move this up into createPod? (open to other ideas too!)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Which is exactly what I did in the latest version. =)

@@ -82,6 +82,13 @@ var (

saTask = tb.Task("test-with-sa", "foo", tb.TaskSpec(tb.Step("sa-step", "foo", tb.Command("/mycmd"))))

taskEnvTask = tb.Task("test-task-env", "foo", tb.TaskSpec(
tb.TaskEnvVar("FRUIT", "APPLE"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe include one we don't override as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Latest iteration shows this working right - it shows up in the init containers and the nop container.

@abayer
Copy link
Contributor Author

abayer commented Apr 17, 2019

/hold

@bobcatfish @vdemeester Modified to add baseContainer and (for #714's use case) podSpec to TaskSpec. I need to add the logic and tests for podSpec, which I'll do tomorrow - I'm heading out shortly. =)

@tekton-robot tekton-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 17, 2019
@abayer abayer force-pushed the task-env-vars branch 4 times, most recently from 3e1f910 to 2389eb0 Compare April 17, 2019 19:46
@abayer abayer changed the title Add Task-level environment variables Add container and podspec base configuration to Task Apr 17, 2019
Copy link
Collaborator

@bobcatfish bobcatfish left a comment

Choose a reason for hiding this comment

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

Looking good (except the docs of course which I can totally understand your hesitance to update XD)! And I think we should tackle the pod spec separately with maybe a bit more deliberation.

I'd like to hear from a couple of @vdemeester @imjasonh @dlorenc on their thoughts on this before we go ahead with the container spec but I'd say 👍 from me.


// PodSpec can be used to specify advanced configuration for the pod used
// by the Task.
PodSpec *corev1.PodSpec `json:"podSpec,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

id prefer we start with just the BaseContainer for now and do the pod spec separately - specifically b/c if we have the pod spec we'll probably want to remove some attributes (e.g. affinity etc.) at the same time (and it seems like we want the pod spec to be a runtime thing... AND i wonder if we actually want it in the run, or referred to by the run... AND @chmouel has some interesting thoughts on that #714 (comment) long story short i think we should do a bit of design re. the pod spec before going for it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good!


// BaseContainer can be used as the basis for all step containers within the
// Task, so that the steps inherit settings on the base container.
BaseContainer *corev1.Container `json:"baseContainer,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

@vdemeester pointed out the similarity between what we're doing here and deployment.template and job.template so I think it could be good to try to stick to a similar naming scheme, maybe something like containerTemplate or stepTemplate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure thing.

@@ -229,7 +244,29 @@ func MakePod(taskRun *v1alpha1.TaskRun, taskSpec v1alpha1.TaskSpec, kubeclient k

nopContainer := &corev1.Container{Name: "nop", Image: *nopImage, Command: []string{"/ko-app/nop"}}
entrypoint.RedirectStep(cache, len(podContainers), nopContainer, kubeclient, taskRun, logger)
podContainers = append(podContainers, *nopContainer)
mergedStep, err := mergeStepWithBaseContainer(baseContainer, nopContainer)
Copy link
Collaborator

Choose a reason for hiding this comment

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

hm, instead of calling mergeStepWithBaseContainer several times, is there a way we can call it with all the steps together once we have them? (maybe on podContainers below?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, can do

return nil, err
}

mergedData, err := strategicpatch.StrategicMergePatchUsingLookupPatchMeta(baseData, patch, schema)
Copy link
Collaborator

Choose a reason for hiding this comment

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

would you mind adding some comments before each of the strategicpatch calls elaborating on what's going on (from my ignorant-of-strategic-merge point of view it seems weird that there are 3 different calls required here and im not sure about details like "why do we need 'using lookup patch meta'"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

...yeah, I’ll be honest, it’s a bit black magic to me - I just kept hitting things until I got the result I needed. =) But I got there right before wrapping up for the day, so I’ll add explanatory comments tomorrow.

}, nil
}


func mergeStepWithBaseContainer(base, override *corev1.Container) (*corev1.Container, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we could have this in it's own package with unit tests :D

(No worries if you want to wait to till we decide if we want to go forward with this impl vs the previous one)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

=)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

While I'm thinking of it, a question - what's the motivation for putting functions like this in their own packages, rather than just unit testing them in place? Just trying to understand. =)

@abayer abayer changed the title Add container and podspec base configuration to Task Add container template configuration to Task Apr 18, 2019
@abayer
Copy link
Contributor Author

abayer commented Apr 18, 2019

/hold cancel

Ok, I think we're good now, so I'm removing the hold.

@tekton-robot tekton-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 18, 2019
@abayer abayer force-pushed the task-env-vars branch 2 times, most recently from 04b8078 to d433124 Compare April 18, 2019 13:57
@tekton-robot tekton-robot removed the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 18, 2019
@tekton-robot tekton-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Apr 18, 2019
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.

Few comments — the merging piece is interesting… is it how deployment & co do it ?

@@ -23,6 +23,7 @@ import (
"encoding/hex"
"flag"
"fmt"
"github.com/tektoncd/pipeline/pkg/merge"
Copy link
Member

Choose a reason for hiding this comment

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

nit: misplaced import 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

stupid IDE!

@@ -170,17 +171,19 @@ func MakePod(taskRun *v1alpha1.TaskRun, taskSpec v1alpha1.TaskSpec, kubeclient k
}
annotations["sidecar.istio.io/inject"] = "false"

baseContainer := taskSpec.ContainerTemplate
Copy link
Member

Choose a reason for hiding this comment

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

nit: s/baseContainer/containerTemplate/g ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixing!

@abayer
Copy link
Contributor Author

abayer commented Apr 18, 2019

@vdemeester This is basically how kubectl does it - that's what I derived this from.

Container configuration defined on the `Task` will be propagated to all
steps within the `Task`, and can be overridden on individual steps.
abayer added a commit to abayer/jx that referenced this pull request Apr 18, 2019
Derived from what I've done over at
tektoncd/pipeline#767 - this is just cleaner,
simpler, better.
abayer added a commit to abayer/jx that referenced this pull request Apr 18, 2019
Derived from what I've done over at
tektoncd/pipeline#767 - this is just cleaner,
simpler, better.
abayer added a commit to abayer/jx that referenced this pull request Apr 18, 2019
Derived from what I've done over at
tektoncd/pipeline#767 - this is just cleaner,
simpler, better.
jenkins-x-bot pushed a commit to jenkins-x/jx that referenced this pull request Apr 18, 2019
Derived from what I've done over at
tektoncd/pipeline#767 - this is just cleaner,
simpler, better.
Copy link
Collaborator

@bobcatfish bobcatfish left a comment

Choose a reason for hiding this comment

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

Looks awesome @abayer ! For once in my life I have nothing to nit, it all looks great :D

p.s. I also spoke briefly with @dlorenc and @imjasonh offline and they're on board with this approach.

Thanks again for this (so quickly!) and also thanks for your patience re. my original reluctance to add this feature 🙇‍♀️

/approve
/lgtm
/meow space

@@ -72,7 +73,9 @@ following fields:
- [`outputs`](#outputs) - Specifies [`PipelineResources`](resources.md) needed
by your `Task`
- [`volumes`](#volumes) - Specifies one or more volumes that you want to make
available to your build.
available to your `Task`'s steps.
Copy link
Collaborator

Choose a reason for hiding this comment

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

whoops, thanks for fixing! ❤️

- name: "FOO"
value: "baz"
```

Copy link
Collaborator

Choose a reason for hiding this comment

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

and the new ones are great too!!

return nil, err
}

// Actually apply the merge patch to the template JSON.
Copy link
Collaborator

Choose a reason for hiding this comment

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

thanks so much for these detailed comments, I think it really clears up what's going on! 🙏 🎉

@tekton-robot
Copy link
Collaborator

@bobcatfish: cat image

In response to this:

Looks awesome @abayer ! For once in my life I have nothing to nit, it all looks great :D

p.s. I also spoke briefly with @dlorenc and @imjasonh offline and they're on board with this approach.

Thanks again for this (so quickly!) and also thanks for your patience re. my original reluctance to add this feature 🙇‍♀️

/approve
/lgtm
/meow space

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@tekton-robot tekton-robot added the lgtm Indicates that a PR is ready to be merged. label Apr 19, 2019
@tekton-robot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: abayer, bobcatfish

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 19, 2019
@abayer
Copy link
Contributor Author

abayer commented Apr 19, 2019

/test pull-tekton-pipeline-integration-tests

@tekton-robot tekton-robot merged commit 4a84deb into tektoncd:master Apr 19, 2019
@vdemeester vdemeester mentioned this pull request Apr 23, 2019
3 tasks
bobcatfish added a commit to bobcatfish/pipeline that referenced this pull request Jul 22, 2019
@abayer has contributed features such as step templating
(tektoncd#767) and Pipeline level
params (tektoncd#471), as well as many
general tweaks and fixes, and 40+ reviews! Not to mention that since he
works on Jenkins X (built on Tekton) he has invaluable feedback from the
perspective of someone actively building on top of Tekton!

Let it be noted forever that @bobcatfish should have gotten around to
doing this ages ago and she very much appreciates @abayer's patience 🙏
@bobcatfish bobcatfish mentioned this pull request Jul 22, 2019
1 task
tekton-robot pushed a commit that referenced this pull request Jul 23, 2019
@abayer has contributed features such as step templating
(#767) and Pipeline level
params (#471), as well as many
general tweaks and fixes, and 40+ reviews! Not to mention that since he
works on Jenkins X (built on Tekton) he has invaluable feedback from the
perspective of someone actively building on top of Tekton!

Let it be noted forever that @bobcatfish should have gotten around to
doing this ages ago and she very much appreciates @abayer's patience 🙏
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit lgtm Indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for defining Task-wide environment variables
6 participants