Skip to content

Commit

Permalink
Add TaskRun to v1alpha2 🎋
Browse files Browse the repository at this point in the history
This modify how `TaskRunSpec` looks from v1alpha1:
- params is now directly under spec
- no more inputs and outputs, get replaced by resources
- resource has input and output resource declaration fields, similar
  to how it is used in Pipeline

The next step are :
- Add more types (Pipeline, PipelineRun, Condition)
- Refactor v1alpha1 to embedded v1alpha2 (for storage purpose)
- Auto-conversion from v1alpha1

Signed-off-by: Vincent Demeester <vdemeest@redhat.com>
  • Loading branch information
vdemeester committed Jan 20, 2020
1 parent eb26f85 commit b9de9ac
Show file tree
Hide file tree
Showing 28 changed files with 2,632 additions and 37 deletions.
17 changes: 5 additions & 12 deletions pkg/apis/pipeline/v1alpha1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1alpha1

import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2"
"github.com/tektoncd/pipeline/pkg/reconciler/pipeline/dag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand All @@ -35,13 +36,13 @@ type PipelineSpec struct {

// Check that Pipeline may be validated and defaulted.
// TaskKind defines the type of Task used by the pipeline.
type TaskKind string
type TaskKind = v1alpha2.TaskKind

const (
// NamespacedTaskKind indicates that the task type has a namepace scope.
NamespacedTaskKind TaskKind = "Task"
NamespacedTaskKind TaskKind = v1alpha2.NamespacedTaskKind
// ClusterTaskKind indicates that task type has a cluster scope.
ClusterTaskKind TaskKind = "ClusterTask"
ClusterTaskKind TaskKind = v1alpha2.ClusterTaskKind
)

// +genclient
Expand Down Expand Up @@ -225,15 +226,7 @@ type PipelineTaskOutputResource struct {

// 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 {
// Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names
Name string `json:"name,omitempty"`
// TaskKind inficates the kind of the task, namespaced or cluster scoped.
Kind TaskKind `json:"kind,omitempty"`
// API version of the referent
// +optional
APIVersion string `json:"apiVersion,omitempty"`
}
type TaskRef = v1alpha2.TaskRef

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

Expand Down
5 changes: 3 additions & 2 deletions pkg/apis/pipeline/v1alpha1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"time"

"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
Expand Down Expand Up @@ -59,12 +60,12 @@ type TaskRunSpec struct {
}

// TaskRunSpecStatus defines the taskrun spec status the user can provide
type TaskRunSpecStatus string
type TaskRunSpecStatus = v1alpha2.TaskRunSpecStatus

const (
// TaskRunSpecStatusCancelled indicates that the user wants to cancel the task,
// if not already cancelled or terminated
TaskRunSpecStatusCancelled = "TaskRunCancelled"
TaskRunSpecStatusCancelled = v1alpha2.TaskRunSpecStatusCancelled
)

// TaskRunInputs holds the input values that this task was invoked with.
Expand Down
20 changes: 2 additions & 18 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.

22 changes: 22 additions & 0 deletions pkg/apis/pipeline/v1alpha2/pod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright 2019 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha2

import "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod"

// PodTemplate holds pod specific configuration
type PodTemplate = pod.Template
17 changes: 17 additions & 0 deletions pkg/apis/pipeline/v1alpha2/pod_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
Copyright 2019 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha2_test
40 changes: 40 additions & 0 deletions pkg/apis/pipeline/v1alpha2/resource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,53 @@ type TaskResource struct {
ResourceDeclaration `json:",inline"`
}

// TaskRunResources allows a TaskRun to declare inputs and outputs TaskResourceBinding
type TaskRunResources struct {
// Inputs holds the inputs resources this task was invoked with
Inputs []TaskResourceBinding `json:"inputs,omitempty"`
// Outputs holds the inputs resources this task was invoked with
Outputs []TaskResourceBinding `json:"outputs,omitempty"`
}

// ResourceDeclaration defines an input or output PipelineResource declared as a requirement
// by another type such as a Task or Condition. The Name field will be used to refer to these
// PipelineResources within the type's definition, and when provided as an Input, the Name will be the
// path to the volume mounted containing this PipelineResource as an input (e.g.
// an input Resource named `workspace` will be mounted at `/workspace`).
type ResourceDeclaration = resource.ResourceDeclaration

// 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,omitempty"`
// ResourceRef is a reference to the instance of the actual PipelineResource
// that should be used
// +optional
ResourceRef *PipelineResourceRef `json:"resourceRef,omitempty"`

// ResourceSpec is specification of a resource that should be created and
// consumed by the task
// +optional
ResourceSpec *resource.PipelineResourceSpec `json:"resourceSpec,omitempty"`
}

// PipelineResourceResult used to export the image name and digest as json
type PipelineResourceResult struct {
Key string `json:"key"`
Value string `json:"value"`
ResourceRef PipelineResourceRef `json:"resourceRef,omitempty"`
}

// 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
Name string `json:"name,omitempty"`
// API version of the referent
// +optional
APIVersion string `json:"apiVersion,omitempty"`
}

// TaskModifier is an interface to be implemented by different PipelineResources
type TaskModifier interface {
GetStepsToPrepend() []Step
Expand Down
44 changes: 43 additions & 1 deletion pkg/apis/pipeline/v1alpha2/resource_types_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (tr *TaskResources) Validate(ctx context.Context) *apis.FieldError {

func validateTaskResources(resources []TaskResource, name string) *apis.FieldError {
for _, resource := range resources {
if err := validateResourceType(resource, fmt.Sprintf("taskspec.resources.%s.%s.Type", name, resource.Name)); err != nil {
if err := validateResourceType(resource, fmt.Sprintf("taskspec.resources.%s.%s.type", name, resource.Name)); err != nil {
return err
}
}
Expand Down Expand Up @@ -68,3 +68,45 @@ func validateResourceType(r TaskResource, path string) *apis.FieldError {
}
return apis.ErrInvalidValue(string(r.Type), path)
}

func (tr *TaskRunResources) Validate(ctx context.Context) *apis.FieldError {
if tr == nil {
return nil
}
if err := validateTaskRunResources(ctx, tr.Inputs, "spec.resources.inputs.name"); err != nil {
return err
}
if err := validateTaskRunResources(ctx, tr.Outputs, "spec.resources.outputs.name"); err != nil {
return err
}
return nil
}

// validateTaskRunResources validates that
// 1. resource is not declared more than once
// 2. if both resource reference and resource spec is defined at the same time
// 3. at least resource ref or resource spec is defined
func validateTaskRunResources(ctx context.Context, resources []TaskResourceBinding, path string) *apis.FieldError {
encountered := map[string]struct{}{}
for _, r := range resources {
// We should provide only one binding for each resource required by the Task.
name := strings.ToLower(r.Name)
if _, ok := encountered[strings.ToLower(name)]; ok {
return apis.ErrMultipleOneOf(path)
}
encountered[name] = struct{}{}
// Check that both resource ref and resource Spec are not present
if r.ResourceRef != nil && r.ResourceSpec != nil {
return apis.ErrDisallowedFields(fmt.Sprintf("%s.resourceRef", path), fmt.Sprintf("%s.resourceSpec", path))
}
// Check that one of resource ref and resource Spec is present
if (r.ResourceRef == nil || r.ResourceRef.Name == "") && r.ResourceSpec == nil {
return apis.ErrMissingField(fmt.Sprintf("%s.resourceRef", path), fmt.Sprintf("%s.resourceSpec", path))
}
if r.ResourceSpec != nil && r.ResourceSpec.Validate(ctx) != nil {
return r.ResourceSpec.Validate(ctx)
}

}
return nil
}
23 changes: 23 additions & 0 deletions pkg/apis/pipeline/v1alpha2/task_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,26 @@ type TaskList struct {
metav1.ListMeta `json:"metadata,omitempty"`
Items []Task `json:"items"`
}

// 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 {
// Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names
Name string `json:"name,omitempty"`
// TaskKind inficates the kind of the task, namespaced or cluster scoped.
Kind TaskKind `json:"kind,omitempty"`
// API version of the referent
// +optional
APIVersion string `json:"apiVersion,omitempty"`
}

// Check that Pipeline may be validated and defaulted.
// TaskKind defines the type of Task used by the pipeline.
type TaskKind string

const (
// NamespacedTaskKind indicates that the task type has a namepace scope.
NamespacedTaskKind TaskKind = "Task"
// ClusterTaskKind indicates that task type has a cluster scope.
ClusterTaskKind TaskKind = "ClusterTask"
)
8 changes: 4 additions & 4 deletions pkg/apis/pipeline/v1alpha2/task_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func TestTaskSpecValidateError(t *testing.T) {
},
expectedError: apis.FieldError{
Message: `invalid value: what`,
Paths: []string{"taskspec.resources.inputs.source.Type"},
Paths: []string{"taskspec.resources.inputs.source.type"},
},
}, {
name: "one invalid input resource",
Expand All @@ -279,7 +279,7 @@ func TestTaskSpecValidateError(t *testing.T) {
},
expectedError: apis.FieldError{
Message: `invalid value: what`,
Paths: []string{"taskspec.resources.inputs.source.Type"},
Paths: []string{"taskspec.resources.inputs.source.type"},
},
}, {
name: "duplicated inputs resources",
Expand All @@ -304,7 +304,7 @@ func TestTaskSpecValidateError(t *testing.T) {
},
expectedError: apis.FieldError{
Message: `invalid value: what`,
Paths: []string{"taskspec.resources.outputs.source.Type"},
Paths: []string{"taskspec.resources.outputs.source.type"},
},
}, {
name: "one invalid output resource",
Expand All @@ -316,7 +316,7 @@ func TestTaskSpecValidateError(t *testing.T) {
},
expectedError: apis.FieldError{
Message: `invalid value: what`,
Paths: []string{"taskspec.resources.outputs.source.Type"},
Paths: []string{"taskspec.resources.outputs.source.type"},
},
}, {
name: "duplicated outputs resources",
Expand Down
63 changes: 63 additions & 0 deletions pkg/apis/pipeline/v1alpha2/taskrun_defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright 2019 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha2

import (
"context"
"time"

"github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/contexts"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
)

var _ apis.Defaultable = (*TaskRun)(nil)

func (tr *TaskRun) SetDefaults(ctx context.Context) {
tr.Spec.SetDefaults(ctx)
}

func (trs *TaskRunSpec) SetDefaults(ctx context.Context) {
cfg := config.FromContextOrDefaults(ctx)
if trs.TaskRef != nil && trs.TaskRef.Kind == "" {
trs.TaskRef.Kind = NamespacedTaskKind
}

if trs.Timeout == nil {
var timeout *metav1.Duration
if contexts.IsUpgradeViaDefaulting(ctx) {
// This case is for preexisting `TaskRun` before 0.5.0, so let's
// add the old default timeout.
// Most likely those TaskRun passing here are already done and/or already running
timeout = &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}
} else {
timeout = &metav1.Duration{Duration: time.Duration(cfg.Defaults.DefaultTimeoutMinutes) * time.Minute}
}
trs.Timeout = timeout
}

defaultSA := cfg.Defaults.DefaultServiceAccount
if trs.ServiceAccountName == "" && defaultSA != "" {
trs.ServiceAccountName = defaultSA
}

// If this taskrun has an embedded task, apply the usual task defaults
if trs.TaskSpec != nil {
trs.TaskSpec.SetDefaults(ctx)
}
}
Loading

0 comments on commit b9de9ac

Please sign in to comment.