Skip to content

Commit

Permalink
Added CustomRun references and specifications to v1beta1
Browse files Browse the repository at this point in the history
Prior to this commit, we proposed migrating
`Custom Tasks` and `Runs` to beta. Today, [embedded specs](https://github.com/tektoncd/pipeline/blob/main/docs/runs.md#2-specifying-the-target-custom-task-by-embedding-its-spec)
are in `Run.Spec.Spec`.

In this commit, we will align the embedded specs
with the rest of the API such that it's
`CustomRun.Spec.CustomSpec`.

Fixes issue [#5154](#5154)
/cc @jerop
/cc @dibyom

/kind feature
  • Loading branch information
Varun Singhai committed Aug 31, 2022
1 parent 05f28f2 commit 0b691ed
Show file tree
Hide file tree
Showing 4 changed files with 493 additions and 0 deletions.
249 changes: 249 additions & 0 deletions pkg/apis/pipeline/v1beta1/customrun_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*
Copyright 2020 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 v1beta1

import (
"fmt"
"time"

apisconfig "github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
pod "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod"
runv1beta1 "github.com/tektoncd/pipeline/pkg/apis/run/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/clock"
"knative.dev/pkg/apis"
duckv1 "knative.dev/pkg/apis/duck/v1"
)

// EmbeddedCustomRunSpec allows custom task definitions to be embedded
type EmbeddedCustomRunSpec struct {
runtime.TypeMeta `json:",inline"`

// +optional
Metadata PipelineTaskMetadata `json:"metadata,omitempty"`

// Spec is a specification of a custom task
// +optional
Spec runtime.RawExtension `json:"spec,omitempty"`
}

// CustomRunSpec defines the desired state of CustomRun
type CustomRunSpec struct {
// +optional
Ref *TaskRef `json:"ref,omitempty"`

// Spec is a specification of a custom task
// +optional
Spec *EmbeddedCustomRunSpec `json:"spec,omitempty"`

// +optional
Params []Param `json:"params,omitempty"`

// Used for cancelling a customrun (and maybe more later on)
// +optional
Status CustomRunSpecStatus `json:"status,omitempty"`

// Status message for cancellation.
// +optional
StatusMessage CustomRunSpecStatusMessage `json:"statusMessage,omitempty"`

// Used for propagating retries count to custom tasks
// +optional
Retries int `json:"retries,omitempty"`

// +optional
ServiceAccountName string `json:"serviceAccountName"`

// PodTemplate holds pod specific configuration
// +optional
PodTemplate *pod.PodTemplate `json:"podTemplate,omitempty"`

// Time after which the custom-task times out.
// Refer Go's ParseDuration documentation for expected format: https://golang.org/pkg/time/#ParseDuration
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`

// Workspaces is a list of WorkspaceBindings from volumes to workspaces.
// +optional
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
}

// CustomRunSpecStatus defines the taskrun spec status the user can provide
type CustomRunSpecStatus string

const (
// CustomRunSpecStatusCancelled indicates that the user wants to cancel the run,
// if not already cancelled or terminated
CustomRunSpecStatusCancelled CustomRunSpecStatus = "RunCancelled"
)

// CustomRunSpecStatusMessage defines human readable status messages for the TaskRun.
type CustomRunSpecStatusMessage string

const (
// CustomRunCancelledByPipelineMsg indicates that the PipelineRun of which part this CustomRun was
// has been cancelled.
CustomRunCancelledByPipelineMsg CustomRunSpecStatusMessage = "CustomRun cancelled as the PipelineRun it belongs to has been cancelled."
// RunCancelledByPipelineTimeoutMsg indicates that the Run was cancelled because the PipelineRun running it timed out.
CustomRunCancelledByPipelineTimeoutMsg CustomRunSpecStatusMessage = "CustomRun cancelled as the PipelineRun it belongs to has timed out."
)

// GetParam gets the Param from the CustomRunSpec with the given name
// TODO(jasonhall): Move this to a Params type so other code can use it?
func (rs CustomRunSpec) GetParam(name string) *Param {
for _, p := range rs.Params {
if p.Name == name {
return &p
}
}
return nil
}

const (
// CustomRunReasonCancelled must be used in the Condition Reason to indicate that a CustomRun was cancelled.
CustomRunReasonCancelled = "CustomRunCancelled"
// CustomRunReasonTimedOut must be used in the Condition Reason to indicate that a CustomRun was timed out.
CustomRunReasonTimedOut = "CustomRunTimedOut"
// CustomRunReasonWorkspaceNotSupported can be used in the Condition Reason to indicate that the
// CustomRun contains a workspace which is not supported by this custom task.
CustomRunReasonWorkspaceNotSupported = "CustomRunWorkspaceNotSupported"
// CustomRunReasonPodTemplateNotSupported can be used in the Condition Reason to indicate that the
// CustomRun contains a pod template which is not supported by this custom task.
CustomRunReasonPodTemplateNotSupported = "CustomRunPodTemplateNotSupported"
)

// CustomRunStatus defines the observed state of CustomRun.
type CustomRunStatus = runv1beta1.CustomRunStatus

var customrunCondSet = apis.NewBatchConditionSet()

// GetConditionSet retrieves the condition set for this resource. Implements
// the KRShaped interface.
func (r *CustomRun) GetConditionSet() apis.ConditionSet { return customrunCondSet }

// GetStatus retrieves the status of the Parallel. Implements the KRShaped
// interface.
func (r *CustomRun) GetStatus() *duckv1.Status { return &r.Status.Status }

// CustomRunStatusFields holds the fields of CustomRun's status. This is defined
// separately and inlined so that other types can readily consume these fields
// via duck typing.
type CustomRunStatusFields = runv1beta1.CustomRunStatusFields

// CustomRunResult used to describe the results of a task
type CustomRunResult = runv1beta1.CustomRunResult

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

// CustomRun represents a single execution of a Custom Task.
//
// +k8s:openapi-gen=true
type CustomRun struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`

// +optional
Spec CustomRunSpec `json:"spec,omitempty"`
// +optional
Status CustomRunStatus `json:"status,omitempty"`
}

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

// CustomRunList contains a list of CustomRun
type CustomRunList struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
Items []CustomRun `json:"items"`
}

// GetStatusCondition returns the task run status as a ConditionAccessor
func (r *CustomRun) GetStatusCondition() apis.ConditionAccessor {
return &r.Status
}

// GetGroupVersionKind implements kmeta.OwnerRefable.
func (*CustomRun) GetGroupVersionKind() schema.GroupVersionKind {
return SchemeGroupVersion.WithKind(pipeline.RunControllerName)
}

// HasPipelineRunOwnerReference returns true of CustomRun has
// owner reference of type PipelineRun
func (r *CustomRun) HasPipelineRunOwnerReference() bool {
for _, ref := range r.GetOwnerReferences() {
if ref.Kind == pipeline.PipelineRunControllerName {
return true
}
}
return false
}

// IsCancelled returns true if the CustomRun's spec status is set to Cancelled state
func (r *CustomRun) IsCancelled() bool {
return r.Spec.Status == CustomRunSpecStatusCancelled
}

// IsDone returns true if the CustomRun's status indicates that it is done.
func (r *CustomRun) IsDone() bool {
return !r.Status.GetCondition(apis.ConditionSucceeded).IsUnknown()
}

// HasStarted function check whether taskrun has valid start time set in its status
func (r *CustomRun) HasStarted() bool {
return r.Status.StartTime != nil && !r.Status.StartTime.IsZero()
}

// IsSuccessful returns true if the CustomRun's status indicates that it is done.
func (r *CustomRun) IsSuccessful() bool {
return r != nil && r.Status.GetCondition(apis.ConditionSucceeded).IsTrue()
}

// GetRunKey return the customrun's key for timeout handler map
func (r *CustomRun) GetCustomRunKey() string {
// The address of the pointer is a threadsafe unique identifier for the customrun
return fmt.Sprintf("%s/%p", "CustomRun", r)
}

// HasTimedOut returns true if the CustomRun's running time is beyond the allowed timeout
func (r *CustomRun) HasTimedOut(c clock.PassiveClock) bool {
if r.Status.StartTime == nil || r.Status.StartTime.IsZero() {
return false
}
timeout := r.GetTimeout()
// If timeout is set to 0 or defaulted to 0, there is no timeout.
if timeout == apisconfig.NoTimeoutDuration {
return false
}
runtime := c.Since(r.Status.StartTime.Time)
return runtime > timeout
}

// GetTimeout returns the timeout for this customrun, or the default if not configured
func (r *CustomRun) GetTimeout() time.Duration {
// Use the platform default if no timeout is set
if r.Spec.Timeout == nil {
return apisconfig.DefaultTimeoutMinutes * time.Minute
}
return r.Spec.Timeout.Duration
}
148 changes: 148 additions & 0 deletions pkg/apis/run/v1beta1/customrunstatus_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
Copyright 2020 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 v1beta1

import (
"encoding/json"
"time"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"knative.dev/pkg/apis"
duckv1 "knative.dev/pkg/apis/duck/v1"
)

// This package exists to avoid an import cycle between v1beta1 and v1beta1.
// It contains common definitions needed by v1beta1.CustomRun and v1beta1.PipelineRun.

// +k8s:deepcopy-gen=true

// CustomRunStatus defines the observed state of CustomRun
type CustomRunStatus struct {
duckv1.Status `json:",inline"`

// CustomRunStatusFields inlines the status fields.
CustomRunStatusFields `json:",inline"`
}

// +k8s:deepcopy-gen=true

// CustomRunStatusFields holds the fields of CustomRun's status. This is defined
// separately and inlined so that other types can readily consume these fields
// via duck typing.
type CustomRunStatusFields struct {
// StartTime is the time the build is actually started.
// +optional
StartTime *metav1.Time `json:"startTime,omitempty"`

// CompletionTime is the time the build completed.
// +optional
CompletionTime *metav1.Time `json:"completionTime,omitempty"`

// Results reports any output result values to be consumed by later
// tasks in a pipeline.
// +optional
Results []CustomRunResult `json:"results,omitempty"`

// RetriesStatus contains the history of CustomRunStatus, in case of a retry.
// +optional
RetriesStatus []CustomRunStatus `json:"retriesStatus,omitempty"`

// ExtraFields holds arbitrary fields provided by the custom task
// controller.
ExtraFields runtime.RawExtension `json:"extraFields,omitempty"`
}

// CustomRunResult used to describe the results of a task
type CustomRunResult struct {
// Name the given name
Name string `json:"name"`
// Value the given value of the result
Value string `json:"value"`
}

var customRunCondSet = apis.NewBatchConditionSet()

// GetCondition returns the Condition matching the given type.
func (r *CustomRunStatus) GetCondition(t apis.ConditionType) *apis.Condition {
return customRunCondSet.Manage(r).GetCondition(t)
}

// InitializeConditions will set all conditions in customRunCondSet to unknown for the PipelineRun
// and set the started time to the current time
func (r *CustomRunStatus) InitializeConditions() {
started := false
if r.StartTime.IsZero() {
r.StartTime = &metav1.Time{Time: time.Now()}
started = true
}
conditionManager := customRunCondSet.Manage(r)
conditionManager.InitializeConditions()
// Ensure the started reason is set for the "Succeeded" condition
if started {
initialCondition := conditionManager.GetCondition(apis.ConditionSucceeded)
initialCondition.Reason = "Started"
conditionManager.SetCondition(*initialCondition)
}
}

// SetCondition sets the condition, unsetting previous conditions with the same
// type as necessary.
func (r *CustomRunStatus) SetCondition(newCond *apis.Condition) {
if newCond != nil {
customRunCondSet.Manage(r).SetCondition(*newCond)
}
}

// MarkCustomRunSucceeded changes the Succeeded condition to True with the provided reason and message.
func (r *CustomRunStatus) MarkCustomRunSucceeded(reason, messageFormat string, messageA ...interface{}) {
customRunCondSet.Manage(r).MarkTrueWithReason(apis.ConditionSucceeded, reason, messageFormat, messageA...)
succeeded := r.GetCondition(apis.ConditionSucceeded)
r.CompletionTime = &succeeded.LastTransitionTime.Inner
}

// MarkRunFailed changes the Succeeded condition to False with the provided reason and message.
func (r *CustomRunStatus) MarkCustomRunFailed(reason, messageFormat string, messageA ...interface{}) {
customRunCondSet.Manage(r).MarkFalse(apis.ConditionSucceeded, reason, messageFormat, messageA...)
succeeded := r.GetCondition(apis.ConditionSucceeded)
r.CompletionTime = &succeeded.LastTransitionTime.Inner
}

// MarkCustomRunRunning changes the Succeeded condition to Unknown with the provided reason and message.
func (r *CustomRunStatus) MarkCustomRunRunning(reason, messageFormat string, messageA ...interface{}) {
customRunCondSet.Manage(r).MarkUnknown(apis.ConditionSucceeded, reason, messageFormat, messageA...)
}

// DecodeExtraFields deserializes the extra fields in the CustomRun status.
func (r *CustomRunStatus) DecodeExtraFields(into interface{}) error {
if len(r.ExtraFields.Raw) == 0 {
return nil
}
return json.Unmarshal(r.ExtraFields.Raw, into)
}

// EncodeExtraFields serializes the extra fields in the CustomRun status.
func (r *CustomRunStatus) EncodeExtraFields(from interface{}) error {
data, err := json.Marshal(from)
if err != nil {
return err
}
r.ExtraFields = runtime.RawExtension{
Raw: data,
}
return nil
}
Loading

0 comments on commit 0b691ed

Please sign in to comment.