Skip to content

Commit

Permalink
[TEP-0142] Remote Resolution for StepAction
Browse files Browse the repository at this point in the history
This commit is part of tektoncd#7259. It adds the remote resolution for
StepAction.

Signed-off-by: Yongxuan Zhang [email protected]
  • Loading branch information
Yongxuanzhang committed Nov 1, 2023
1 parent 7069889 commit ad975cc
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 82 deletions.
4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1/container_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ type Step struct {
type Ref struct {
// Name of the referenced step
Name string `json:"name,omitempty"`
// ResolverRef allows referencing a StepAction in a remote location
// like a git repo.
// +optional
ResolverRef `json:",omitempty"`
}

// OnErrorType defines a list of supported exiting behavior of a container on error
Expand Down
31 changes: 27 additions & 4 deletions pkg/reconciler/taskrun/resources/taskref.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,18 @@ func GetTaskFunc(ctx context.Context, k8s kubernetes.Interface, tekton clientset
}

// GetStepActionFunc is a factory function that will use the given Ref as context to return a valid GetStepAction function.
func GetStepActionFunc(tekton clientset.Interface, namespace string) GetStepAction {
func GetStepActionFunc(tekton clientset.Interface, k8s kubernetes.Interface, requester remoteresource.Requester, tr *v1.TaskRun, step *v1.Step) GetStepAction {
kind := "StepAction"
trName := tr.Name
namespace := tr.Namespace
if step.Ref != nil && step.Ref.Resolver != "" && requester != nil {
// Return an inline function that implements GetTask by calling Resolver.Get with the specified task type and
// casting it to a TaskObject.
return func(ctx context.Context, ref *v1.Ref) (*v1alpha1.StepAction, *v1.RefSource, error) {
resolver := resolution.NewResolver(requester, tr, string(ref.Resolver), trName, namespace, v1.Params{})
return resolveStepAction(ctx, resolver, ref.Name, namespace, kind, k8s, tekton)
}
}
local := &LocalStepActionRefResolver{
Namespace: namespace,
Tektonclient: tekton,
Expand All @@ -151,6 +162,18 @@ func resolveTask(ctx context.Context, resolver remote.Resolver, name, namespace
return taskObj, refSource, vr, nil
}

func resolveStepAction(ctx context.Context, resolver remote.Resolver, name, namespace, kind string, k8s kubernetes.Interface, tekton clientset.Interface) (*v1alpha1.StepAction, *v1.RefSource, error) {
obj, refSource, err := resolver.Get(ctx, strings.TrimSuffix(strings.ToLower(string(kind)), "s"), name)
if err != nil {
return nil, nil, err
}
switch obj := obj.(type) {
case *v1alpha1.StepAction:
return obj, refSource, nil
}
return nil, nil, errors.New("resource is not a step action")
}

// readRuntimeObjectAsTask tries to convert a generic runtime.Object
// into a *v1.Task type so that its meta and spec fields
// can be read. v1beta1 object will be converted to v1 and returned.
Expand Down Expand Up @@ -239,12 +262,12 @@ type LocalStepActionRefResolver struct {

// GetStepAction will resolve a StepAction from the local cluster using a versioned Tekton client.
// It will return an error if it can't find an appropriate StepAction for any reason.
func (l *LocalStepActionRefResolver) GetStepAction(ctx context.Context, name string) (*v1alpha1.StepAction, *v1.RefSource, error) {
func (l *LocalStepActionRefResolver) GetStepAction(ctx context.Context, ref *v1.Ref) (*v1alpha1.StepAction, *v1.RefSource, error) {
// If we are going to resolve this reference locally, we need a namespace scope.
if l.Namespace == "" {
return nil, nil, fmt.Errorf("must specify namespace to resolve reference to step action %s", name)
return nil, nil, fmt.Errorf("must specify namespace to resolve reference to step action %s", ref.Name)
}
stepAction, err := l.Tektonclient.TektonV1alpha1().StepActions(l.Namespace).Get(ctx, name, metav1.GetOptions{})
stepAction, err := l.Tektonclient.TektonV1alpha1().StepActions(l.Namespace).Get(ctx, ref.Name, metav1.GetOptions{})
if err != nil {
return nil, nil, err
}
Expand Down
27 changes: 19 additions & 8 deletions pkg/reconciler/taskrun/resources/taskref_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ func TestStepActionRef(t *testing.T) {
Tektonclient: tektonclient,
}

task, refSource, err := lc.GetStepAction(ctx, tc.ref.Name)
task, refSource, err := lc.GetStepAction(ctx, tc.ref)
if err != nil {
t.Fatalf("Received unexpected error ( %#v )", err)
}
Expand Down Expand Up @@ -435,7 +435,7 @@ func TestStepActionRef_Error(t *testing.T) {
Tektonclient: tektonclient,
}

_, _, err := lc.GetStepAction(ctx, tc.ref.Name)
_, _, err := lc.GetStepAction(ctx, tc.ref)
if err == nil {
t.Fatal("Expected error but found nil instead")
}
Expand Down Expand Up @@ -561,14 +561,26 @@ func TestGetStepActionFunc_Local(t *testing.T) {
testcases := []struct {
name string
localStepActions []runtime.Object
ref *v1.Ref
taskRun *v1.TaskRun
expected runtime.Object
}{
{
name: "local-step-action",
localStepActions: []runtime.Object{simpleNamespacedStepAction},
ref: &v1.Ref{
Name: "simple",
taskRun: &v1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-tr",
Namespace: "default",
},
Spec: v1.TaskRunSpec{
TaskSpec: &v1.TaskSpec{
Steps: []v1.Step{{
Ref: &v1.Ref{
Name: "simple",
},
}},
},
},
},
expected: simpleNamespacedStepAction,
},
Expand All @@ -577,10 +589,9 @@ func TestGetStepActionFunc_Local(t *testing.T) {
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
tektonclient := fake.NewSimpleClientset(tc.localStepActions...)
fn := resources.GetStepActionFunc(tektonclient, nil, nil, tc.taskRun, &tc.taskRun.Spec.TaskSpec.Steps[0])

fn := resources.GetStepActionFunc(tektonclient, "default")

stepAction, refSource, err := fn(ctx, tc.ref.Name)
stepAction, refSource, err := fn(ctx, tc.taskRun.Spec.TaskSpec.Steps[0].Ref)
if err != nil {
t.Fatalf("failed to call stepActionfn: %s", err.Error())
}
Expand Down
14 changes: 9 additions & 5 deletions pkg/reconciler/taskrun/resources/taskspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ import (

v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
clientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned"
resolutionutil "github.com/tektoncd/pipeline/pkg/internal/resolution"
remoteresource "github.com/tektoncd/pipeline/pkg/resolution/resource"
"github.com/tektoncd/pipeline/pkg/trustedresources"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

// ResolvedTask contains the data that is needed to execute
Expand All @@ -39,7 +42,7 @@ type ResolvedTask struct {
}

// GetStepAction is a function used to retrieve StepActions.
type GetStepAction func(context.Context, string) (*v1alpha1.StepAction, *v1.RefSource, error)
type GetStepAction func(context.Context, *v1.Ref) (*v1alpha1.StepAction, *v1.RefSource, error)

// GetTask is a function used to retrieve Tasks.
// VerificationResult is the result from trusted resources if the feature is enabled.
Expand All @@ -51,7 +54,7 @@ type GetTaskRun func(string) (*v1.TaskRun, error)
// GetTaskData will retrieve the Task metadata and Spec associated with the
// provided TaskRun. This can come from a reference Task or from the TaskRun's
// metadata and embedded TaskSpec.
func GetTaskData(ctx context.Context, taskRun *v1.TaskRun, getTask GetTask, getStepAction GetStepAction) (*resolutionutil.ResolvedObjectMeta, *v1.TaskSpec, error) {
func GetTaskData(ctx context.Context, taskRun *v1.TaskRun, getTask GetTask, tekton clientset.Interface, k8s kubernetes.Interface, requester remoteresource.Requester) (*resolutionutil.ResolvedObjectMeta, *v1.TaskSpec, error) {
taskMeta := metav1.ObjectMeta{}
taskSpec := v1.TaskSpec{}
var refSource *v1.RefSource
Expand Down Expand Up @@ -89,7 +92,7 @@ func GetTaskData(ctx context.Context, taskRun *v1.TaskRun, getTask GetTask, getS
return nil, nil, fmt.Errorf("taskRun %s not providing TaskRef or TaskSpec", taskRun.Name)
}

steps, err := extractStepActions(ctx, taskSpec, getStepAction)
steps, err := extractStepActions(ctx, taskSpec, taskRun, tekton, k8s, requester)
if err != nil {
return nil, nil, err
} else {
Expand All @@ -105,13 +108,14 @@ func GetTaskData(ctx context.Context, taskRun *v1.TaskRun, getTask GetTask, getS
}

// extractStepActions extracts the StepActions and merges them with the inlined Step specification.
func extractStepActions(ctx context.Context, taskSpec v1.TaskSpec, getStepAction GetStepAction) ([]v1.Step, error) {
func extractStepActions(ctx context.Context, taskSpec v1.TaskSpec, taskRun *v1.TaskRun, tekton clientset.Interface, k8s kubernetes.Interface, requester remoteresource.Requester) ([]v1.Step, error) {
steps := []v1.Step{}
for _, step := range taskSpec.Steps {
s := step.DeepCopy()
if step.Ref != nil {
s.Ref = nil
stepAction, _, err := getStepAction(ctx, step.Ref.Name)
getStepAction := GetStepActionFunc(tekton, k8s, requester, taskRun, &step)
stepAction, _, err := getStepAction(ctx, step.Ref)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit ad975cc

Please sign in to comment.