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

Declare resources in pipeline 😇 #415

Merged

Conversation

bobcatfish
Copy link
Collaborator

@bobcatfish bobcatfish commented Jan 22, 2019

Now resources will be bound to a "name" which is used in the Pipeline
to refer to them. This will simplify the binding declarations in
PipelineRun and also make the Pipeline definition solely responsible
for linking resources to Tasks.

This will let users effectively say something like:

“For the Pipeline, use git resource W, image resources Y + X, and deploy to cluster Z.”

Instead of previously, where it was more like:

“For Task A use git resource W and image X, for Task B use git resource W and image Y, for Task C use git resource W and image Y and image X and cluster Z…”

This also has some side benefits in allowing us to do some extra validation at creation time for Pipelines.

Also includes:

  • Updating the creation time validation of Pipelines to verify that providedBy constraints make sense (i.e. the order can be satisfied) - since we only have linear execution, this meanscanTaskRun is no longer needed 😇
  • Moving some docs out of concepts.md (keeping this high level) and into using.md (putting the nitty gritty in here)

Question for reviewers:

  • Should we actually have a type at all in the declared resources in the Pipeline? @sebgoa had suggested removing in the type, in which case we could just declare a list of names of resources. At the moment this doesn't really give us a lot in the way of extra validation b/c we'd still have to fetch Tasks to see if the types match up, which we only do at runtime. I do feel like there is value in telling the user what types these should be so they know what to bind though 🤔

I think the end to end and sample tests may fail but I wanted to get this PR out and start the review process asap! 😅

(This fixes most of #320! 🎉 )

p.s. sorry this is so huge! couldn't figure out how to break it up 😅

@knative-prow-robot knative-prow-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Jan 22, 2019
@bobcatfish bobcatfish force-pushed the declare_resources_in_pipeline branch from fd6472f to b3262b7 Compare January 22, 2019 00:34
@bobcatfish bobcatfish changed the title Declare resources in pipeline Declare resources in pipeline 😇 Jan 22, 2019
@bobcatfish bobcatfish requested review from shashwathi, vdemeester and nader-ziada and removed request for dlorenc and srinivashegde86 January 22, 2019 00:39
@bobcatfish
Copy link
Collaborator Author

image

@bobcatfish
Copy link
Collaborator Author

I0122 00:44:20.781] --- SKIP: TestStorageTaskRun (0.00s)
I0122 00:44:20.781]     gcs_taskrun_test.go:40: KANIKO_SECRET_CONFIG_FILE variable is not set.

@shashwathi is that test supposed to get skipped in CI?


// providedBy should match future tasks
// TODO(#168) when pipelines don't just execute linearly this will need to be more sophisticated
for i, t := range ps.Tasks {
Copy link
Member

Choose a reason for hiding this comment

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

We may want to extract that (or part of it 👼). Like validateProvidedBy or something.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oh yeah, that's a good call!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i think for now ill leave the testing at the level of the Validate function 🤔 kinda wondering if we should be testing these functions directly instead 🤔🤔🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nice this makes it much easier to have meaningful errors :D

docs/using.md Outdated

We express this ordering by adding `providedBy` on `Resources` that our `Tasks`
We express this dependency by adding `providedBy` on `Resources` that our `Tasks`
Copy link
Member

Choose a reason for hiding this comment

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

"This dependency is expressed by …" (if we want to avoid the use of we – #k8s-docs-guidelines)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

whoops, this is gonna be a hard habit to break for us me 😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

maybe "Express this dependency by adding..." - avoiding passive voice? :D

docs/using.md Outdated
You can see that the `builtImage` output from `build-skaffold-app` is bound to
the `skaffold-image-leeroy-app` `PipelineResource`, and the same
`PipelineResource` is bound to `image` for `deploy-app`.
The `my-image` resource is expected to be provided to the `deploy-app` `Task` from
Copy link
Member

Choose a reason for hiding this comment

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

"The resource my-image …"

docs/using.md Outdated
### Resource shared between tasks
##### Configure Entrypoint image

To run a step needs to pull an `Entrypoint` image. Maybe the image is hard to
Copy link
Member

Choose a reason for hiding this comment

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

I think something is missing in the first sentence

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

lol whoops 😅

docs/using.md Outdated
mounted under path `/pvc`.
### Resource sharing between tasks

Pipeline Tasks are allowed to pass resources from previous tasks via the
Copy link
Member

Choose a reason for hiding this comment

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

s/tasks/Tasks/

}

func validateDeclaredResources(ps *PipelineSpec) error {
needed := []string{}
Copy link
Member

Choose a reason for hiding this comment

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

s/needed/required/g ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

kk

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

now these lines are exactly the same length, very satisfying 😎

	required := []string{"elsa", "anna", "olaf", "kristoff"}
	provided := []string{"elsa", "anna", "olaf", "kristoff"}

fields: fields{
Resources: []PipelineDeclaredResource{{
Copy link
Member

Choose a reason for hiding this comment

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

We're gonna need builders for those 🕺

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i actually did add builders for these! pipeline_validation_test isn't using any builders cuz it's doing this odd (where odd = different from all the other tests) thing where it's declaring "fields" and using those to instantiate a Pipeline 🤔

ill see what i can do!

func GetResourcesFromBindings(p *v1alpha1.Pipeline, pr *v1alpha1.PipelineRun) (map[string]v1alpha1.PipelineResourceRef, error) {
resources := map[string]v1alpha1.PipelineResourceRef{}

needed := make([]string, 0, len(p.Spec.Resources))
Copy link
Member

Choose a reason for hiding this comment

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

Same s/needed/required/g ?

Copy link
Contributor

@tejal29 tejal29 left a comment

Choose a reason for hiding this comment

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

Can we move all the documentation changes that are not relevant to this change in another PR?

I know you mention it in "Also includes" however, i feel reviewers give more attention to code review then docs and it might be lost. Also will make review easier.

@bobcatfish
Copy link
Collaborator Author

Can we move all the documentation changes that are not relevant to this change in another PR?

kk i'll give it a shot!

@bobcatfish
Copy link
Collaborator Author

Can we move all the documentation changes that are not relevant to this change in another PR?
I know you mention it in "Also includes" however, i feel reviewers give more attention to code review then docs and it might be lost. Also will make review easier.

Actually on second thought @tejal29 how strongly do you feel about this? It's going to be a bit hard to break up, and @vdemeester has already added a bunch of comments on the doc changes in this PR.

The "PipelineResources in a Pipeline" section in using.md and the examples in docs/tutorial.md are the most relevant to the functionality that's changing in this PR, so:

  • If a reviewer want to focus on the doc changes, they could look just at the .md files and be aware of those sections being new
  • If a reviewer wants to focus only on the API changes, just look at the "PipelineResources in a Pipeline" section in using.md and the examples in docs/tutorial.md, otherwise ignore the .md files

I'll try to break it up if you feel really strongly but it's gonna be tough - I'll try to be more aware in the future to create separate PRs.

Copy link
Member

@nader-ziada nader-ziada left a comment

Choose a reason for hiding this comment

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

looks good to me! great job @bobcatfish

@nader-ziada
Copy link
Member

are you planning on doing the other items in #302 in a different PR?

@nader-ziada
Copy link
Member

not sure why the test is not passing, I going to run it again to see if this was a flake

/test pull-knative-build-pipeline-integration-tests

Copy link
Contributor

@shashwathi shashwathi left a comment

Choose a reason for hiding this comment

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

Great PR. I have suggested couple of missing test cases and nil pointer check. Rest looks awesome! 👍 🎆

I am stressing unit test cases because we are relying on this to catch most use cases. (I just noticed my suggested test cases have "crazy" in them. Please change that :D )

// should be provided to a Task as its inputs and outputs.
type PipelineTaskResources struct {
// Inputs holds the mapping from the PipelineResources declared in
// DeclaredPipelineResources to the input PipelineResources reuqired by the Task.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: reuqired in both Inputs, Outputs

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

😅

@@ -32,6 +33,39 @@ func (p *Pipeline) Validate() *apis.FieldError {
return nil
}

func isOutput(task PipelineTask, resource string) bool {
for _, output := range task.Resources.Outputs {
Copy link
Contributor

Choose a reason for hiding this comment

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

task.Resources is pointer. We need to check here if its nil. An example test case

{
			name: "providedBy resource isn't present in task",
			fields: fields{
				Resources: []PipelineDeclaredResource{{
					Name: "wonderful-resource",
					Type: "image",
				}},
				Tasks: []PipelineTask{{
					Name: "bar",
// no resources used
				}, {
					Name: "foo",
					Resources: &PipelineTaskResources{
						Inputs: []PipelineTaskInputResource{{
							Name:       "wow-image",
							Resource:   "wonderful-resource",
							ProvidedBy: []string{"bar"},
						}},
					},
				}},
			},
		}

Copy link
Collaborator Author

@bobcatfish bobcatfish Jan 23, 2019

Choose a reason for hiding this comment

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

task.Resources is pointer

yeah i missed that a couple of times in my earlier iterations :S definitely had some panics 😅

An example test case

hmmm technically the "no duplicate tasks" test case cover this but I'm cool with adding another case explicitly!

ProvidedBy: []string{"bar"},

gonna remove that tho since that would mean bar would have to have an output

},
},
{
name: "providedBy resource isn't output by task",
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you also add a test case for 2nd task referring resource from non existent task? (found variable should catch that use case

{
			name: "providedBy resource refers non existent task name",
			fields: fields{
				Resources: []PipelineDeclaredResource{{
					Name: "wonderful-resource",
					Type: "git",
				}},
				Tasks: []PipelineTask{{
					Name: "bar",
				}, {
					Name: "foo",
					Resources: &PipelineTaskResources{
						Inputs: []PipelineTaskInputResource{{
							Name:       "wow-image",
							Resource:   "wonderful-resource",
							ProvidedBy: []string{"bar-crazy"},
						}},
					},
				}},
			},
		}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i think this is caught by providedby task doesnt exist?

Copy link
Contributor

Choose a reason for hiding this comment

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

providedby task doesnt exist test has resource dependency on a task that does not exist but it is the first task. The code path in this test case is

if i == 0 {
.. "first task cant depend on anything"
}

The test I have given above has 2 tasks and 2nd task refers a dependency that does not exist. It takes diff code paths in pipeline validation. In the code there is found variable which is suppose to catch this test case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ohhh okay I think I finally see what you're saying!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sorry I was so slow to catch on, and thanks for noticing this!

@@ -149,7 +163,11 @@ func ResolvePipelineRun(getTask resources.GetTask, getClusterTask resources.GetC
}

// Get all the resources that this task will be using, if any
inputs, outputs := getPipelineRunTaskResources(pt.Name, pr)
inputs, outputs, err := getPipelineRunTaskResources(pt, providedResources)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am guessing that error code path is defined to have clean code but we do not expect to be in this code path right?
there are couple tests cases in pipeline task resources that are missing(like missing input/output resource for task) but I can understand that we do not expect to be here since webhook catch it way before. It makes sense

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah exactly! i have pretty mixed feelings about it, but i thought it was better to err on the safer side, just in case validation was changed later on to not catch this (would be very hard to remember to change logic here as a result!)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i see what you mean tho, it feels weird not to have test coverage for this! ill try adding it and see how we feel about it

Name: "awesome-thing",
ProvidedBy: []string{"quest"},
}},
}},
Copy link
Contributor

@shashwathi shashwathi Jan 22, 2019

Choose a reason for hiding this comment

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

I am unable to tag the test in this comment: TestValidateProvidedBy_Invalid test is missing a case when ResolvedTaskResourceInput refer non existent resource

{
		name: "resolved task resource refers to non  existent input resource ",
		state: []*ResolvedPipelineRunTask{{
			PipelineTask: &v1alpha1.PipelineTask{
				Name: "winning",
				Resources: &v1alpha1.PipelineTaskResources{
					Inputs: []v1alpha1.PipelineTaskInputResource{{
						Name:       "sweet-artifact",
						ProvidedBy: []string{"quest"},
					}},
				}},
			ResolvedTaskResources: tb.ResolvedTaskResources(
				tb.ResolvedTaskResourcesTaskSpec(
					tb.TaskInputs(tb.InputsResource("sweet-artifact", v1alpha1.PipelineResourceTypeImage)),
				),
				tb.ResolvedTaskResourcesInputs("sweet-artifact-crazy", r), // non existent resource
			),
		}},
		errContains: "declare dependency",
	}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hm this is weird, i feel like this is another case that shouldnt actually happen - now that "providedBy" must be on inputs and its not possible to accidentally add it to outputs 🤔 ill try to add a test case for it tho!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

after thinking about it more i really dont think this if statement makes sense anymore and im going to remove it - thanks for catching this @shashwathi !!

// contain the same values.
func IsSame(needed, provided []string) error {
missing := DiffLeft(needed, provided)
if len(missing) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably another implementation would be to sort needed and provided array and pass them to cmp lib. Only benefit I can think of suggested approach is cmp checks both length and content of array. Just a suggestion. I don't have strong opinion about this

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

makes sense to me! do you mind if we table this for a future PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure 👍

@bobcatfish
Copy link
Collaborator Author

Can we move all the documentation changes that are not relevant to this change in another PR?

I keep thinking about this and realizing what a good suggestion this is - I should have done this from the start @tejal29 ! I could have gotten a lot of those doc changes up for review way sooner 🤦‍♀️ Next time for sure!

@bobcatfish
Copy link
Collaborator Author

are you planning on doing the other items in #302 in a different PR?

@pivotal-nader-ziada yes! i want to tackle the from change in another PR, and then I'll probably create a separate issue for adding runAfter which we can tackle separately

not sure why the test is not passing, I going to run it again to see if this was a flake

boo I guess it's not a flake :)

@bobcatfish
Copy link
Collaborator Author

I am stressing unit test cases because we are relying on this to catch most use cases

Definitely appreciated @shashwathi 🙏 ❤️ !!

Now resources will be bound to a "name" which is used in the `Pipeline`
to refer to them. This will simplify the binding declarations in
`PipelineRun` and also make the `Pipeline` definition solely responsible
for linking resources to Tasks.

Toward tektoncd#320
@bobcatfish bobcatfish force-pushed the declare_resources_in_pipeline branch from a61fb48 to 104a2cd Compare January 23, 2019 02:01
@bobcatfish
Copy link
Collaborator Author

boo I guess it's not a flake :)

Nice, there's actually a pretty good error message :D

    message: 'PipelineRun arendelle-ptetjjtc/helm-deploy-pipeline-run doesn''t bind
      Pipeline arendelle-ptetjjtc/helm-deploy-pipeline''s PipelineResources correctly:
      PipelineRun bound resources didn''t match Pipeline: Didn''t provide needed values:
      [git-repo]'

@bobcatfish bobcatfish force-pushed the declare_resources_in_pipeline branch from 104a2cd to 7b10398 Compare January 23, 2019 02:06
@bobcatfish
Copy link
Collaborator Author

Okay should be ready for another look @shashwathi @pivotal-nader-ziada @vdemeester @tejal29 !

We'll see if I fixed the e2e test 🤞

@bobcatfish bobcatfish added cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit and removed cla: no labels Jan 23, 2019
@googlebot
Copy link

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

@bobcatfish
Copy link
Collaborator Author

image

image

Copy link
Contributor

@shashwathi shashwathi left a comment

Choose a reason for hiding this comment

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

/lgtm

@knative-prow-robot knative-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Jan 23, 2019
@knative-prow-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

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

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:
  • OWNERS [bobcatfish,shashwathi]

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

@@ -155,7 +156,7 @@ func getCreateImageTask(namespace string, t *testing.T) *v1alpha1.Task {
}

imageName = fmt.Sprintf("%s/%s", dockerRepo, AppendRandomString(sourceImageName))
t.Logf("Image to be pusblished: %s", imageName)
logger.Infof("Image to be pusblished: %s", imageName)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

o no @jonjohnsonjr would be very upset about this

@shashwathi
Copy link
Contributor

@bobcatfish : Looks like yaml tests are failing.

@knative-prow-robot knative-prow-robot removed the lgtm Indicates that a PR is ready to be merged. label Jan 24, 2019
@googlebot
Copy link

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@googlebot googlebot added cla: no and removed cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit labels Jan 24, 2019
@bobcatfish
Copy link
Collaborator Author

@bobcatfish : Looks like yaml tests are failing.

whoops, thanks @shashwathi ! looks like I completely missed updating the output yaml examples 😅

@bobcatfish bobcatfish added cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit and removed cla: no labels Jan 24, 2019
@googlebot
Copy link

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

@knative-metrics-robot
Copy link

The following is the coverage report on pkg/.
Say /test pull-knative-build-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
pkg/apis/pipeline/v1alpha1/pipeline_validation.go 75.0% 91.7% 16.7
pkg/reconciler/v1alpha1/pipeline/resources/dag.go 97.7% 97.8% 0.1
pkg/reconciler/v1alpha1/pipelinerun/pipelinerun.go 76.5% 81.3% 4.8
pkg/reconciler/v1alpha1/pipelinerun/resources/input_output_steps.go 95.5% 95.2% -0.2
pkg/reconciler/v1alpha1/pipelinerun/resources/pipelinerunresolution.go 92.4% 93.0% 0.7
pkg/reconciler/v1alpha1/taskrun/validate_resources.go 98.1% 98.0% -0.1

@shashwathi
Copy link
Contributor

/lgtm

@knative-prow-robot knative-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Jan 24, 2019
@knative-prow-robot knative-prow-robot merged commit d34c72d into tektoncd:master Jan 24, 2019
@shashwathi
Copy link
Contributor

Lets have a party to celebrate this PR getting merged! 🎆 Great work @bobcatfish

@nader-ziada
Copy link
Member

awesome job on this PR @bobcatfish

@bobcatfish
Copy link
Collaborator Author

Thanks @shashwathi and @pivotal-nader-ziada ! Thanks to everyone's careful reviewing!! @shashwathi you caught a lot of things I missed, thanks!! 🤗

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.

8 participants