Skip to content

Commit

Permalink
Implement API which simiplifies resource binding
Browse files Browse the repository at this point in the history
This updates the API and supporting logic to allow Pipelines to declare
the resources they will use, and provide placeholder names for them,
which PipelineRuns can bind to. This significantly simplifies
PipelineRun binding logic.

This is toward fixing tektoncd#320
  • Loading branch information
bobcatfish committed Jan 23, 2019
1 parent 96a4453 commit 11e6ffc
Show file tree
Hide file tree
Showing 28 changed files with 741 additions and 508 deletions.
58 changes: 47 additions & 11 deletions pkg/apis/pipeline/v1alpha1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import (

// PipelineSpec defines the desired state of PipeLine.
type PipelineSpec struct {
Tasks []PipelineTask `json:"tasks"`
Generation int64 `json:"generation,omitempty"`
Resources []PipelineDeclaredResource `json:"resources"`
Tasks []PipelineTask `json:"tasks"`
Generation int64 `json:"generation,omitempty"`
}

// PipelineStatus does not contain anything because Pipelines on their own
Expand All @@ -50,9 +51,8 @@ const (
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Pipeline describes a DAG of Tasks to execute. It expresses how outputs
// of tasks feed into inputs of subsequent tasks. The DAG is constructed
// from the 'prev' and 'next' of each PipelineTask as well as Task dependencies.
// Pipeline describes a list of Tasks to execute. It expresses how outputs
// of tasks feed into inputs of subsequent tasks.
// +k8s:openapi-gen=true
type Pipeline struct {
metav1.TypeMeta `json:",inline"`
Expand All @@ -73,7 +73,7 @@ type PipelineTask struct {
Name string `json:"name"`
TaskRef TaskRef `json:"taskRef"`
// +optional
ResourceDependencies []ResourceDependency `json:"resources,omitempty"`
Resources *PipelineTaskResources `json:"resources,omitempty"`
// +optional
Params []Param `json:"params,omitempty"`
}
Expand All @@ -84,17 +84,53 @@ type PipelineTaskParam struct {
Value string `json:"value"`
}

// ResourceDependency is used when a PipelineResource required by a Task is requird to be provided by
// a previous Task, i.e. that Task needs to operate on the PipelineResource before this Task can be
// executed. It is from this dependency that the Pipeline's DAG is constructed.
type ResourceDependency struct {
// Name is the name of the Task's input that this Resource should be used for.
// PipelineDeclaredResource is used by a Pipeline to declare the types of the
// PipelineResources that it will required to run and names which can be used to
// refer to these PipelineResources in PipelineTaskResourceBindings.
type PipelineDeclaredResource struct {
// Name is the name that will be used by the Pipeline to refer to this resource.
// It does not directly correspond to the name of any PipelineResources Task
// inputs or outputs, and it does not correspond to the actual names of the
// PipelineResources that will be bound in the PipelineRun.
Name string `json:"name"`
// Type is the type of the PipelineResource.
Type PipelineResourceType `json:"type"`
}

// PipelineTaskResources allows a Pipeline to declare how its DeclaredPipelineResources
// 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.
Inputs []PipelineTaskInputResource `json:"inputs"`
// Outputs holds the mapping from the PipelineResources declared in
// DeclaredPipelineResources to the input PipelineResources reuqired by the Task.
Outputs []PipelineTaskOutputResource `json:"outputs"`
}

// PipelineTaskInputResource maps the name of a declared PipelineResource input
// dependency in a Task to the resource in the Pipeline's DeclaredPipelineResources
// that should be used. This input may come from a previous task.
type PipelineTaskInputResource struct {
// Name is the name of the PipelineResource as declared by the Task.
Name string `json:"name"`
// Resource is the name of the DeclaredPipelineResource to use.
Resource string `json:"resource"`
// ProvidedBy is the list of PipelineTask names that the resource has to come from.
// +optional
ProvidedBy []string `json:"providedBy,omitempty"`
}

// PipelineTaskOutputResource maps the name of a declared PipelineResource output
// dependency in a Task to the resource in the Pipeline's DeclaredPipelineResources
// that should be used.
type PipelineTaskOutputResource struct {
// Name is the name of the PipelineResource as declared by the Task.
Name string `json:"name"`
// Resource is the name of the DeclaredPipelienResource to use.
Resource string `json:"resource"`
}

// TaskRef can be used to refer to a specific instance of a task.
// Copied from CrossVersionObjectReference: https://github.com/kubernetes/kubernetes/blob/169df7434155cbbc22f1532cba8e0a9588e29ad8/pkg/apis/autoscaling/types.go#L64
type TaskRef struct {
Expand Down
10 changes: 6 additions & 4 deletions pkg/apis/pipeline/v1alpha1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ func (ps *PipelineSpec) Validate() *apis.FieldError {

// providedBy should match other tasks.
for _, t := range ps.Tasks {
for _, rd := range t.ResourceDependencies {
for _, pb := range rd.ProvidedBy {
if _, ok := taskNames[pb]; !ok {
return apis.ErrInvalidKeyName(pb, fmt.Sprintf("spec.tasks.resources.%s", pb))
if t.Resources != nil {
for _, rd := range t.Resources.Inputs {
for _, pb := range rd.ProvidedBy {
if _, ok := taskNames[pb]; !ok {
return apis.ErrInvalidKeyName(pb, fmt.Sprintf("spec.tasks.resources.%s", pb))
}
}
}
}
Expand Down
16 changes: 10 additions & 6 deletions pkg/apis/pipeline/v1alpha1/pipeline_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ func TestPipelineSpec_Validate_Error(t *testing.T) {
fields: fields{
Tasks: []PipelineTask{{
Name: "foo",
ResourceDependencies: []ResourceDependency{{
ProvidedBy: []string{"bar"},
}},
Resources: &PipelineTaskResources{
Inputs: []PipelineTaskInputResource{{
ProvidedBy: []string{"bar"},
}},
},
}},
},
},
Expand Down Expand Up @@ -88,9 +90,11 @@ func TestPipelineSpec_Validate_Valid(t *testing.T) {
fields: fields{
Tasks: []PipelineTask{{
Name: "foo",
ResourceDependencies: []ResourceDependency{{
ProvidedBy: []string{"bar"},
}},
Resources: &PipelineTaskResources{
Inputs: []PipelineTaskInputResource{{
ProvidedBy: []string{"bar"},
}},
},
}, {
Name: "bar",
}},
Expand Down
23 changes: 6 additions & 17 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ var _ webhook.GenericCRD = (*TaskRun)(nil)

// PipelineRunSpec defines the desired state of PipelineRun
type PipelineRunSpec struct {
PipelineRef PipelineRef `json:"pipelineRef"`
Trigger PipelineTrigger `json:"trigger"`
PipelineTaskResources []PipelineTaskResource `json:"resources"`
PipelineRef PipelineRef `json:"pipelineRef"`
Trigger PipelineTrigger `json:"trigger"`
// Resources is a list of bindings specifying which actual instances of
// PipelineResources to use for the resources the Pipeline has declared
// it needs.
Resources []PipelineResourceBinding `json:"resources"`
// +optional
ServiceAccount string `json:"serviceAccount"`
// +optional
Expand All @@ -63,20 +66,6 @@ const (
PipelineRunSpecStatusCancelled = "PipelineRunCancelled"
)

// PipelineTaskResource maps Task inputs and outputs to existing PipelineResources by their names.
type PipelineTaskResource struct {
// Name is the name of the `PipelineTask` for which these PipelineResources are being provided.
Name string `json:"name"`

// Inputs is a list containing mapping from the input Resources which the Task has declared it needs
// and the corresponding Resource instance in the system which should be used.
Inputs []TaskResourceBinding `json:"inputs"`

// Outputs is a list containing mapping from the output Resources which the Task has declared it needs
// and the corresponding Resource instance in the system which should be used.
Outputs []TaskResourceBinding `json:"outputs"`
}

// PipelineResourceRef can be used to refer to a specific instance of a Resource
type PipelineResourceRef struct {
// Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/pipeline/v1alpha1/resource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ type PipelineResource struct {
Status PipelineResourceStatus `json:"status,omitempty"`
}

// PipelineResourceBinding connects a reference to an instance of a PipelineResource
// with a PipelineResource dependency that the Pipeline has declared
type PipelineResourceBinding struct {
// Name is the name of the PipelineResource in the Pipeline's declaration
Name string `json:"name"`
// ResourceRef is a reference to the instance of the actual PipelineResource
// that should be used
ResourceRef PipelineResourceRef `json:"resourceRef"`
}

// TaskResourceBinding points to the PipelineResource that
// will be used for the Task input or output called Name. The optional Path field
// corresponds to a path on disk at which the Resource can be found (used when providing
Expand Down
134 changes: 93 additions & 41 deletions pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 11e6ffc

Please sign in to comment.