Skip to content

Commit

Permalink
Add support for overriding default pod specs (#307)
Browse files Browse the repository at this point in the history
* Support to override default pod specs from blueprint args

Signed-off-by: Prasad Ghangal <prasad.ghangal@gmail.com>

* Add support to pass pod specs as ActionSet field

Signed-off-by: Prasad Ghangal <prasad.ghangal@gmail.com>

* Add pod override support in all kanister functions

Signed-off-by: Prasad Ghangal <prasad.ghangal@gmail.com>

* Update unit tests to support podOverride field

Signed-off-by: Prasad Ghangal <prasad.ghangal@gmail.com>

* Resolve rebase commit

Signed-off-by: Prasad Ghangal <prasad.ghangal@gmail.com>
  • Loading branch information
PrasadG193 authored and mergify[bot] committed Sep 24, 2019
1 parent cfce745 commit eb7dcde
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 57 deletions.
21 changes: 19 additions & 2 deletions pkg/function/copy_volume_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package function
import (
"context"
"fmt"
"reflect"

"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
Expand All @@ -43,6 +44,7 @@ const (
CopyVolumeDataOutputBackupArtifactLocation = "backupArtifactLocation"
CopyVolumeDataEncryptionKeyArg = "encryptionKey"
CopyVolumeDataOutputBackupTag = "backupTag"
CopyVolumeDataPodOverrideArg = "podOverride"
)

func init() {
Expand All @@ -57,7 +59,7 @@ func (*copyVolumeDataFunc) Name() string {
return "CopyVolumeData"
}

func copyVolumeData(ctx context.Context, cli kubernetes.Interface, tp param.TemplateParams, namespace, pvc, targetPath, encryptionKey string) (map[string]interface{}, error) {
func copyVolumeData(ctx context.Context, cli kubernetes.Interface, tp param.TemplateParams, namespace, pvc, targetPath, encryptionKey string, podOverride v1.PodSpec) (map[string]interface{}, error) {
// Validate PVC exists
if _, err := cli.CoreV1().PersistentVolumeClaims(namespace).Get(pvc, metav1.GetOptions{}); err != nil {
return nil, errors.Wrapf(err, "Failed to retrieve PVC. Namespace %s, Name %s", namespace, pvc)
Expand All @@ -70,6 +72,7 @@ func copyVolumeData(ctx context.Context, cli kubernetes.Interface, tp param.Temp
Image: kanisterToolsImage,
Command: []string{"sh", "-c", "tail -f /dev/null"},
Volumes: map[string]string{pvc: mountPoint},
PodOverride: podOverride,
}
pr := kube.NewPodRunner(cli, options)
podFunc := copyVolumeDataPodFunc(cli, tp, namespace, mountPoint, targetPath, encryptionKey)
Expand Down Expand Up @@ -120,6 +123,7 @@ func copyVolumeDataPodFunc(cli kubernetes.Interface, tp param.TemplateParams, na

func (*copyVolumeDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var namespace, vol, targetPath, encryptionKey string
var podOverride v1.PodSpec
var err error
if err = Arg(args, CopyVolumeDataNamespaceArg, &namespace); err != nil {
return nil, err
Expand All @@ -133,11 +137,24 @@ func (*copyVolumeDataFunc) Exec(ctx context.Context, tp param.TemplateParams, ar
if err = OptArg(args, CopyVolumeDataEncryptionKeyArg, &encryptionKey, restic.GeneratePassword()); err != nil {
return nil, err
}
if err = OptArg(args, CopyVolumeDataPodOverrideArg, &podOverride, v1.PodSpec{}); err != nil {
return nil, err
}

// Check if PodOverride specs are passed through actionset
// If yes, override podOverride specs
if !reflect.DeepEqual(tp.PodOverride, v1.PodSpec{}) {
podOverride, err = kube.PodSpecOverride(ctx, podOverride, tp.PodOverride)
if err != nil {
return nil, err
}
}

cli, err := kube.NewClient()
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Kubernetes client")
}
return copyVolumeData(ctx, cli, tp, namespace, vol, targetPath, encryptionKey)
return copyVolumeData(ctx, cli, tp, namespace, vol, targetPath, encryptionKey, podOverride)
}

func (*copyVolumeDataFunc) RequiredArgs() []string {
Expand Down
23 changes: 20 additions & 3 deletions pkg/function/delete_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package function

import (
"context"
"reflect"
"strings"

"github.com/pkg/errors"
Expand All @@ -42,7 +43,9 @@ const (
DeleteDataEncryptionKeyArg = "encryptionKey"
// DeleteDataReclaimSpace provides a way to specify if space should be reclaimed
DeleteDataReclaimSpace = "reclaimSpace"
deleteDataJobPrefix = "delete-data-"
// DeleteDataPodOverrideArg contains pod specs to override default pod specs
DeleteDataPodOverrideArg = "podOverride"
deleteDataJobPrefix = "delete-data-"
)

func init() {
Expand All @@ -57,12 +60,13 @@ func (*deleteDataFunc) Name() string {
return "DeleteData"
}

func deleteData(ctx context.Context, cli kubernetes.Interface, tp param.TemplateParams, reclaimSpace bool, namespace, encryptionKey string, targetPaths, deleteTags, deleteIdentifiers []string, jobPrefix string) (map[string]interface{}, error) {
func deleteData(ctx context.Context, cli kubernetes.Interface, tp param.TemplateParams, reclaimSpace bool, namespace, encryptionKey string, targetPaths, deleteTags, deleteIdentifiers []string, jobPrefix string, podOverride v1.PodSpec) (map[string]interface{}, error) {
options := &kube.PodOptions{
Namespace: namespace,
GenerateName: jobPrefix,
Image: kanisterToolsImage,
Command: []string{"sh", "-c", "tail -f /dev/null"},
PodOverride: podOverride,
}
pr := kube.NewPodRunner(cli, options)
podFunc := deleteDataPodFunc(cli, tp, reclaimSpace, namespace, encryptionKey, targetPaths, deleteTags, deleteIdentifiers)
Expand Down Expand Up @@ -137,6 +141,7 @@ func pruneData(cli kubernetes.Interface, tp param.TemplateParams, pod *v1.Pod, n
func (*deleteDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var namespace, deleteArtifactPrefix, deleteIdentifier, deleteTag, encryptionKey string
var reclaimSpace bool
var podOverride v1.PodSpec
var err error
if err = Arg(args, DeleteDataNamespaceArg, &namespace); err != nil {
return nil, err
Expand All @@ -156,6 +161,18 @@ func (*deleteDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args m
if err = OptArg(args, DeleteDataReclaimSpace, &reclaimSpace, false); err != nil {
return nil, err
}
if err = OptArg(args, DeleteDataPodOverrideArg, &podOverride, v1.PodSpec{}); err != nil {
return nil, err
}

// Check if PodOverride specs are passed through actionset
// If yes, override podOverride specs
if !reflect.DeepEqual(tp.PodOverride, v1.PodSpec{}) {
podOverride, err = kube.PodSpecOverride(ctx, podOverride, tp.PodOverride)
if err != nil {
return nil, err
}
}
// Validate profile
if err = validateProfile(tp.Profile); err != nil {
return nil, err
Expand All @@ -164,7 +181,7 @@ func (*deleteDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args m
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Kubernetes client")
}
return deleteData(ctx, cli, tp, reclaimSpace, namespace, encryptionKey, strings.Fields(deleteArtifactPrefix), strings.Fields(deleteTag), strings.Fields(deleteIdentifier), deleteDataJobPrefix)
return deleteData(ctx, cli, tp, reclaimSpace, namespace, encryptionKey, strings.Fields(deleteArtifactPrefix), strings.Fields(deleteTag), strings.Fields(deleteIdentifier), deleteDataJobPrefix, podOverride)
}

func (*deleteDataFunc) RequiredArgs() []string {
Expand Down
8 changes: 6 additions & 2 deletions pkg/function/delete_data_all.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

"github.com/pkg/errors"
"k8s.io/api/core/v1"

kanister "github.com/kanisterio/kanister/pkg"
"github.com/kanisterio/kanister/pkg/kube"
Expand All @@ -38,7 +39,9 @@ const (
DeleteDataAllReclaimSpace = "reclaimSpace"
// DeleteDataAllBackupInfo provides backup info required for delete
DeleteDataAllBackupInfo = "backupInfo"
deleteDataAllJobPrefix = "delete-data-all-"
// DeleteDataAllPodOverrideArg contains pod specs to override default pod specs
DeleteDataAllPodOverrideArg = "podOverride"
deleteDataAllJobPrefix = "delete-data-all-"
)

func init() {
Expand All @@ -55,6 +58,7 @@ func (*deleteDataAllFunc) Name() string {

func (*deleteDataAllFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var namespace, deleteArtifactPrefix, backupInfo, encryptionKey string
var podOverride v1.PodSpec
var reclaimSpace bool
var err error
if err = Arg(args, DeleteDataAllNamespaceArg, &namespace); err != nil {
Expand Down Expand Up @@ -92,7 +96,7 @@ func (*deleteDataAllFunc) Exec(ctx context.Context, tp param.TemplateParams, arg
deleteIdentifiers = append(deleteIdentifiers, info.BackupID)
}

return deleteData(ctx, cli, tp, reclaimSpace, namespace, encryptionKey, targetPaths, nil, deleteIdentifiers, deleteDataAllJobPrefix)
return deleteData(ctx, cli, tp, reclaimSpace, namespace, encryptionKey, targetPaths, nil, deleteIdentifiers, deleteDataAllJobPrefix, podOverride)
}

func (*deleteDataAllFunc) RequiredArgs() []string {
Expand Down
30 changes: 24 additions & 6 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"
"reflect"

"github.com/pkg/errors"
"k8s.io/api/core/v1"
Expand All @@ -30,10 +31,11 @@ import (
)

const (
jobPrefix = "kanister-job-"
KubeTaskNamespaceArg = "namespace"
KubeTaskImageArg = "image"
KubeTaskCommandArg = "command"
jobPrefix = "kanister-job-"
KubeTaskNamespaceArg = "namespace"
KubeTaskImageArg = "image"
KubeTaskCommandArg = "command"
KubeTaskPodOverrideArg = "podOverride"
)

func init() {
Expand All @@ -48,7 +50,7 @@ func (*kubeTaskFunc) Name() string {
return "KubeTask"
}

func kubeTask(ctx context.Context, cli kubernetes.Interface, namespace, image string, command []string) (map[string]interface{}, error) {
func kubeTask(ctx context.Context, cli kubernetes.Interface, namespace, image string, command []string, podOverride v1.PodSpec) (map[string]interface{}, error) {
var serviceAccount string
var err error
if namespace == "" {
Expand All @@ -67,7 +69,9 @@ func kubeTask(ctx context.Context, cli kubernetes.Interface, namespace, image st
Image: image,
Command: command,
ServiceAccountName: serviceAccount,
PodOverride: podOverride,
}

pr := kube.NewPodRunner(cli, options)
podFunc := kubeTaskPodFunc(cli)
return pr.Run(ctx, podFunc)
Expand Down Expand Up @@ -99,6 +103,7 @@ func kubeTaskPodFunc(cli kubernetes.Interface) func(ctx context.Context, pod *v1
func (ktf *kubeTaskFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var namespace, image string
var command []string
var podOverride v1.PodSpec
var err error
if err = Arg(args, KubeTaskImageArg, &image); err != nil {
return nil, err
Expand All @@ -109,11 +114,24 @@ func (ktf *kubeTaskFunc) Exec(ctx context.Context, tp param.TemplateParams, args
if err = OptArg(args, KubeTaskNamespaceArg, &namespace, ""); err != nil {
return nil, err
}
if err = OptArg(args, KubeTaskPodOverrideArg, &podOverride, v1.PodSpec{}); err != nil {
return nil, err
}

// Check if PodOverride specs are passed through actionset
// If yes, override podOverride specs
if !reflect.DeepEqual(tp.PodOverride, v1.PodSpec{}) {
podOverride, err = kube.PodSpecOverride(ctx, podOverride, tp.PodOverride)
if err != nil {
return nil, err
}
}

cli, err := kube.NewClient()
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Kubernetes client")
}
return kubeTask(ctx, cli, namespace, image, command)
return kubeTask(ctx, cli, namespace, image, command, podOverride)
}

func (*kubeTaskFunc) RequiredArgs() []string {
Expand Down
7 changes: 7 additions & 0 deletions pkg/function/kube_task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ func (s *KubeTaskSuite) TestKubeTask(c *C) {
StatefulSet: &param.StatefulSetParams{
Namespace: s.namespace,
},
PodOverride: v1.PodSpec{
Containers: []v1.Container{
{
ImagePullPolicy: "Always",
},
},
},
}
action := "test"
for _, tc := range []struct {
Expand Down
21 changes: 19 additions & 2 deletions pkg/function/prepare_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package function
import (
"context"
"fmt"
"reflect"

"github.com/pkg/errors"
"k8s.io/api/core/v1"
Expand All @@ -37,6 +38,7 @@ const (
PrepareDataCommandArg = "command"
PrepareDataVolumes = "volumes"
PrepareDataServiceAccount = "serviceaccount"
PrepareDataPodOverrideArg = "podOverride"
)

func init() {
Expand Down Expand Up @@ -73,7 +75,7 @@ func getVolumes(tp param.TemplateParams) (map[string]string, error) {
return vols, nil
}

func prepareData(ctx context.Context, cli kubernetes.Interface, namespace, serviceAccount, image string, vols map[string]string, command ...string) (map[string]interface{}, error) {
func prepareData(ctx context.Context, cli kubernetes.Interface, namespace, serviceAccount, image string, vols map[string]string, podOverride v1.PodSpec, command ...string) (map[string]interface{}, error) {
// Validate volumes
for pvc := range vols {
if _, err := cli.CoreV1().PersistentVolumeClaims(namespace).Get(pvc, metav1.GetOptions{}); err != nil {
Expand All @@ -87,6 +89,7 @@ func prepareData(ctx context.Context, cli kubernetes.Interface, namespace, servi
Command: command,
Volumes: vols,
ServiceAccountName: serviceAccount,
PodOverride: podOverride,
}
pr := kube.NewPodRunner(cli, options)
podFunc := prepareDataPodFunc(cli)
Expand Down Expand Up @@ -114,6 +117,7 @@ func (*prepareDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args
var namespace, image, serviceAccount string
var command []string
var vols map[string]string
var podOverride v1.PodSpec
var err error
if err = Arg(args, PrepareDataNamespaceArg, &namespace); err != nil {
return nil, err
Expand All @@ -130,6 +134,19 @@ func (*prepareDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args
if err = OptArg(args, PrepareDataServiceAccount, &serviceAccount, ""); err != nil {
return nil, err
}
if err = OptArg(args, PrepareDataPodOverrideArg, &podOverride, v1.PodSpec{}); err != nil {
return nil, err
}

// Check if PodOverride specs are passed through actionset
// If yes, override podOverride specs
if !reflect.DeepEqual(tp.PodOverride, v1.PodSpec{}) {
podOverride, err = kube.PodSpecOverride(ctx, podOverride, tp.PodOverride)
if err != nil {
return nil, err
}
}

cli, err := kube.NewClient()
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Kubernetes client")
Expand All @@ -139,7 +156,7 @@ func (*prepareDataFunc) Exec(ctx context.Context, tp param.TemplateParams, args
return nil, err
}
}
return prepareData(ctx, cli, namespace, serviceAccount, image, vols, command...)
return prepareData(ctx, cli, namespace, serviceAccount, image, vols, podOverride, command...)
}

func (*prepareDataFunc) RequiredArgs() []string {
Expand Down
Loading

0 comments on commit eb7dcde

Please sign in to comment.