Skip to content

Commit

Permalink
Mark ephemeral pods created as part of kanister functions with JobID …
Browse files Browse the repository at this point in the history
…label (#2778)

* Identify 'kanister-job' prefix pods with jobID

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Nil pointer fix

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Addressed review comment

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Moved debug label addition logic to common place

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Adjusted imports

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Added debug label to additional ephemral pods

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Revert "Added debug label to additional ephemral pods"

This reverts commit 444786f.

* Addressed review comments

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Addressed review comments

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Added unit test for jobid debug label in ephemeral pod

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Fix lint error and addressed missed review comment

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Refactored add labels to pod function

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Rearranged imports

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Rearranged imports with minor refactor

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Simplify validateLabelKeyIsPresentFromContext and AddLabelToPodOptions funcs

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Rearrange utility func and imports

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Addressed review comment

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Refactor test cases

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>

* Addressed review comments w.r.t formatting

* Addressed review comment adding additional validation

---------

Signed-off-by: Abhijit Mukherjee <abhijit.mukherjee@infracloud.io>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
mabhi and mergify[bot] committed Apr 5, 2024
1 parent 5873c1f commit c214c35
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 2 deletions.
8 changes: 6 additions & 2 deletions pkg/function/kube_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package function

import (
"context"
"path"
"time"

"github.com/pkg/errors"
Expand All @@ -33,7 +34,9 @@ import (
)

const (
jobPrefix = "kanister-job-"
jobPrefix = "kanister-job-"
jobIDSuffix = "JobID"

// KubeTaskFuncName gives the function name
KubeTaskFuncName = "KubeTask"
KubeTaskNamespaceArg = "namespace"
Expand Down Expand Up @@ -64,7 +67,8 @@ func kubeTask(ctx context.Context, cli kubernetes.Interface, namespace, image st
Command: command,
PodOverride: podOverride,
}

// Mark pod with label having key `kanister.io/JobID`, the value of which is a reference to the origin of the pod.
kube.AddLabelsToPodOptionsFromContext(ctx, options, path.Join(consts.LabelPrefix, jobIDSuffix))
pr := kube.NewPodRunner(cli, options)
podFunc := kubeTaskPodFunc()
return pr.Run(ctx, podFunc)
Expand Down
83 changes: 83 additions & 0 deletions pkg/kube/pod_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ package kube
import (
"context"
"os"
"path"

"github.com/pkg/errors"
. "gopkg.in/check.v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/testing"

"github.com/kanisterio/kanister/pkg/consts"
"github.com/kanisterio/kanister/pkg/field"
)

type PodRunnerTestSuite struct{}
Expand Down Expand Up @@ -109,9 +114,87 @@ func (s *PodRunnerTestSuite) TestPodRunnerForSuccessCase(c *C) {
cancel()
}

// TestPodRunnerWithDebugLabelForSuccessCase adds a debug entry into the context and verifies the
// pod got created with corresponding label using the entry or not.
func (s *PodRunnerTestSuite) TestPodRunnerWithDebugLabelForSuccessCase(c *C) {
jobIDSuffix := "JobID"
for _, tc := range []struct {
name string
targetKey string
contextKey string
contextValue string
isLabelExpected bool
}{
{
name: "target key (kanister.io/JobID) present in pod labels",
targetKey: path.Join(consts.LabelPrefix, jobIDSuffix),
contextKey: path.Join(consts.LabelPrefix, jobIDSuffix),
contextValue: "xyz123",
isLabelExpected: true,
},
{
name: "target key (kanister.io/JobID) not present in pod labels",
targetKey: path.Join(consts.LabelPrefix, jobIDSuffix),
contextKey: path.Join(consts.LabelPrefix, "NonJobID"),
contextValue: "some-other-value",
isLabelExpected: false,
},
} {
ctx, cancel := context.WithCancel(context.Background())
ctx = field.Context(ctx, tc.contextKey, tc.contextValue)
cli := fake.NewSimpleClientset()
cli.PrependReactor("create", "pods", func(action testing.Action) (handled bool, ret runtime.Object, err error) {
return false, nil, nil
})
cli.PrependReactor("get", "pods", func(action testing.Action) (handled bool, ret runtime.Object, err error) {
p := &corev1.Pod{
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
}
return true, p, nil
})
po := &PodOptions{
Namespace: podRunnerNS,
Name: podName,
Command: []string{"sh", "-c", "tail -f /dev/null"},
}
deleted := make(chan struct{})
cli.PrependReactor("delete", "pods", func(action testing.Action) (handled bool, ret runtime.Object, err error) {
c.Log("Pod deleted due to Context Cancelled")
close(deleted)
return true, nil, nil
})
AddLabelsToPodOptionsFromContext(ctx, po, tc.targetKey)
pr := NewPodRunner(cli, po)
errorCh := make(chan error)
go func() {
_, err := pr.Run(ctx, afterPodRunTestKeyPresentFunc(tc.targetKey, tc.contextValue, tc.isLabelExpected, deleted))
errorCh <- err
}()
deleted <- struct{}{}
c.Assert(<-errorCh, IsNil)
cancel()
}
}

func makePodRunnerTestFunc(ch chan struct{}) func(ctx context.Context, pc PodController) (map[string]interface{}, error) {
return func(ctx context.Context, pc PodController) (map[string]interface{}, error) {
<-ch
return nil, nil
}
}

func afterPodRunTestKeyPresentFunc(labelKey, expectedLabelValue string, isLabelExpected bool, ch chan struct{}) func(ctx context.Context, pc PodController) (map[string]interface{}, error) {
return func(ctx context.Context, pc PodController) (map[string]interface{}, error) {
<-ch
labelValue, found := pc.Pod().Labels[labelKey]
if found != isLabelExpected {
return nil, errors.New("Got different label than expected")
}
if isLabelExpected && labelValue != expectedLabelValue {
return nil, errors.New("Found label doesn't match with expected label")
}
return nil, nil
}
}
24 changes: 24 additions & 0 deletions pkg/kube/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
osversioned "github.com/openshift/client-go/apps/clientset/versioned"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"

"github.com/kanisterio/kanister/pkg/field"
)

const (
Expand Down Expand Up @@ -171,3 +173,25 @@ func PVCContainsReadOnlyAccessMode(pvc *corev1.PersistentVolumeClaim) bool {

return false
}

// AddLabelsToPodOptionsFromContext adds a label to `PodOptions`. It extracts the value from the context
// if targetKey is present and assigns to the options.
func AddLabelsToPodOptionsFromContext(
ctx context.Context,
options *PodOptions,
targetKey string,
) {
fields := field.FromContext(ctx)
if fields == nil {
return
}
if options.Labels == nil {
options.Labels = make(map[string]string)
}
for _, f := range fields.Fields() {
if f.Key() == targetKey {
options.Labels[targetKey] = f.Value().(string)
return
}
}
}

0 comments on commit c214c35

Please sign in to comment.