Skip to content

Commit

Permalink
Add various functional options to ActionConfigGetter and ActionClient…
Browse files Browse the repository at this point in the history
…Getter constructors

Signed-off-by: Joe Lanford <joe.lanford@gmail.com>
  • Loading branch information
joelanford committed Nov 11, 2022
1 parent 6f61067 commit 932d72c
Show file tree
Hide file tree
Showing 5 changed files with 409 additions and 21 deletions.
70 changes: 65 additions & 5 deletions pkg/client/actionclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,63 @@ type GetOption func(*action.Get) error
type InstallOption func(*action.Install) error
type UpgradeOption func(*action.Upgrade) error
type UninstallOption func(*action.Uninstall) error
type RollbackOption func(*action.Rollback) error

func NewActionClientGetter(acg ActionConfigGetter) ActionClientGetter {
return &actionClientGetter{acg}
type ActionClientGetterOption func(*actionClientGetter) error

func AppendGetOptions(opts ...GetOption) ActionClientGetterOption {
return func(getter *actionClientGetter) error {
getter.defaultGetOpts = append(getter.defaultGetOpts, opts...)
return nil
}
}

func AppendInstallOptions(opts ...InstallOption) ActionClientGetterOption {
return func(getter *actionClientGetter) error {
getter.defaultInstallOpts = append(getter.defaultInstallOpts, opts...)
return nil
}
}

func AppendUpgradeOptions(opts ...UpgradeOption) ActionClientGetterOption {
return func(getter *actionClientGetter) error {
getter.defaultUpgradeOpts = append(getter.defaultUpgradeOpts, opts...)
return nil
}
}

func AppendUninstallOptions(opts ...UninstallOption) ActionClientGetterOption {
return func(getter *actionClientGetter) error {
getter.defaultUninstallOpts = append(getter.defaultUninstallOpts, opts...)
return nil
}
}

func AppendRollbackOptions(opts ...RollbackOption) ActionClientGetterOption {
return func(getter *actionClientGetter) error {
getter.defaultRollbackOpts = append(getter.defaultRollbackOpts, opts...)
return nil
}
}

func NewActionClientGetter(acg ActionConfigGetter, opts ...ActionClientGetterOption) (ActionClientGetter, error) {
actionClientGetter := &actionClientGetter{acg: acg}
for _, opt := range opts {
if err := opt(actionClientGetter); err != nil {
return nil, err
}
}
return actionClientGetter, nil
}

type actionClientGetter struct {
acg ActionConfigGetter

defaultGetOpts []GetOption
defaultInstallOpts []InstallOption
defaultUpgradeOpts []UpgradeOption
defaultRollbackOpts []RollbackOption
defaultUninstallOpts []UninstallOption
}

var _ ActionClientGetter = &actionClientGetter{}
Expand All @@ -83,9 +133,13 @@ func (hcg *actionClientGetter) ActionClientFor(obj client.Object) (ActionInterfa
}
postRenderer := DefaultPostRendererFunc(rm, actionConfig.KubeClient, obj)
return &actionClient{
conf: actionConfig,
defaultInstallOpts: []InstallOption{WithInstallPostRenderer(postRenderer)},
defaultUpgradeOpts: []UpgradeOption{WithUpgradePostRenderer(postRenderer)},
conf: actionConfig,

defaultGetOpts: hcg.defaultGetOpts,
defaultInstallOpts: append([]InstallOption{WithInstallPostRenderer(postRenderer)}, hcg.defaultInstallOpts...),
defaultUpgradeOpts: append([]UpgradeOption{WithUpgradePostRenderer(postRenderer)}, hcg.defaultUpgradeOpts...),
defaultUninstallOpts: hcg.defaultUninstallOpts,
defaultRollbackOpts: hcg.defaultRollbackOpts,
}, nil
}

Expand All @@ -95,6 +149,7 @@ type actionClient struct {
defaultGetOpts []GetOption
defaultInstallOpts []InstallOption
defaultUpgradeOpts []UpgradeOption
defaultRollbackOpts []RollbackOption
defaultUninstallOpts []UninstallOption
}

Expand Down Expand Up @@ -161,6 +216,11 @@ func (c *actionClient) Upgrade(name, namespace string, chrt *chart.Chart, vals m
rollback := action.NewRollback(c.conf)
rollback.Force = true
rollback.MaxHistory = upgrade.MaxHistory
for _, o := range c.defaultRollbackOpts {
if err := o(rollback); err != nil {
return nil, err
}
}

// As of Helm 2.13, if Upgrade returns a non-nil release, that
// means the release was also recorded in the release store.
Expand Down
150 changes: 147 additions & 3 deletions pkg/client/actionclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"strconv"
"time"

"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2"
Expand All @@ -37,6 +38,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
apitypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -61,7 +63,147 @@ var _ = Describe("ActionClient", func() {
It("should return a valid ActionConfigGetter", func() {
actionConfigGetter, err := NewActionConfigGetter(cfg, rm, logr.Discard())
Expect(err).ShouldNot(HaveOccurred())
Expect(NewActionClientGetter(actionConfigGetter)).NotTo(BeNil())
acg, err := NewActionClientGetter(actionConfigGetter)
Expect(err).To(BeNil())
Expect(acg).NotTo(BeNil())
})

When("options are specified", func() {
expectErr := errors.New("expect this error")

var (
actionConfigGetter ActionConfigGetter
obj client.Object
)
BeforeEach(func() {
var err error
actionConfigGetter, err = NewActionConfigGetter(cfg, rm, logr.Discard())
Expect(err).ShouldNot(HaveOccurred())
obj = testutil.BuildTestCR(gvk)
})

It("should get clients with custom get options", func() {
expectVersion := rand.Int()
acg, err := NewActionClientGetter(actionConfigGetter, AppendGetOptions(
func(get *action.Get) error {
get.Version = expectVersion
return nil
},
func(get *action.Get) error {
Expect(get.Version).To(Equal(expectVersion))
return expectErr
},
))
Expect(err).To(BeNil())
Expect(acg).NotTo(BeNil())

ac, err := acg.ActionClientFor(obj)
Expect(err).To(BeNil())
Expect(ac).NotTo(BeNil())

_, err = ac.Get(obj.GetName())
Expect(err).To(MatchError(expectErr))
})
It("should get clients with custom install options", func() {
acg, err := NewActionClientGetter(actionConfigGetter, AppendInstallOptions(
func(install *action.Install) error {
install.Description = mockTestDesc
return nil
},
func(install *action.Install) error {
Expect(install.Description).To(Equal(mockTestDesc))
return expectErr
},
))
Expect(err).To(BeNil())
Expect(acg).NotTo(BeNil())

ac, err := acg.ActionClientFor(obj)
Expect(err).To(BeNil())
Expect(ac).NotTo(BeNil())

_, err = ac.Install(obj.GetName(), obj.GetNamespace(), &chrt, chartutil.Values{})
Expect(err).To(MatchError(expectErr))
})
It("should get clients with custom upgrade options", func() {
acg, err := NewActionClientGetter(actionConfigGetter, AppendUpgradeOptions(
func(upgrade *action.Upgrade) error {
upgrade.Description = mockTestDesc
return nil
},
func(upgrade *action.Upgrade) error {
Expect(upgrade.Description).To(Equal(mockTestDesc))
return expectErr
},
))
Expect(err).To(BeNil())
Expect(acg).NotTo(BeNil())

ac, err := acg.ActionClientFor(obj)
Expect(err).To(BeNil())
Expect(ac).NotTo(BeNil())

_, err = ac.Upgrade(obj.GetName(), obj.GetNamespace(), &chrt, chartutil.Values{})
Expect(err).To(MatchError(expectErr))
})
It("should get clients with custom uninstall options", func() {
acg, err := NewActionClientGetter(actionConfigGetter, AppendUninstallOptions(
func(uninstall *action.Uninstall) error {
uninstall.Description = mockTestDesc
return nil
},
func(uninstall *action.Uninstall) error {
Expect(uninstall.Description).To(Equal(mockTestDesc))
return expectErr
},
))
Expect(err).To(BeNil())
Expect(acg).NotTo(BeNil())

ac, err := acg.ActionClientFor(obj)
Expect(err).To(BeNil())
Expect(ac).NotTo(BeNil())

_, err = ac.Uninstall(obj.GetName())
Expect(err).To(MatchError(expectErr))
})
It("should get clients with custom rollback options", func() {
expectMaxHistory := rand.Int()
acg, err := NewActionClientGetter(actionConfigGetter, AppendRollbackOptions(
func(rollback *action.Rollback) error {
rollback.MaxHistory = expectMaxHistory
return nil
},
func(rollback *action.Rollback) error {
Expect(rollback.MaxHistory).To(Equal(expectMaxHistory))
return expectErr
},
))
Expect(err).To(BeNil())
Expect(acg).NotTo(BeNil())

ac, err := acg.ActionClientFor(obj)
Expect(err).To(BeNil())
Expect(ac).NotTo(BeNil())

// Install the chart so that we can try an upgrade.
rel, err := ac.Install(obj.GetName(), obj.GetNamespace(), &chrt, chartutil.Values{})
Expect(err).To(BeNil())
Expect(rel).NotTo(BeNil())

_, err = ac.Upgrade(obj.GetName(), obj.GetNamespace(), &chrt, chartutil.Values{}, func(upgrade *action.Upgrade) error {
// Force the upgrade to fail by using an impossibly short wait.
// When the upgrade fails, the rollback logic is attempted.
upgrade.Wait = true
upgrade.Timeout = time.Nanosecond * 1
return nil
})
Expect(err).To(MatchError(expectErr))

// Uninstall the chart to cleanup for other tests.
_, err = ac.Uninstall(obj.GetName())
Expect(err).To(BeNil())
})
})
})

Expand All @@ -88,7 +230,8 @@ var _ = Describe("ActionClient", func() {
It("should return a valid ActionClient", func() {
actionConfGetter, err := NewActionConfigGetter(cfg, rm, logr.Discard())
Expect(err).ShouldNot(HaveOccurred())
acg := NewActionClientGetter(actionConfGetter)
acg, err := NewActionClientGetter(actionConfGetter)
Expect(err).To(BeNil())
ac, err := acg.ActionClientFor(obj)
Expect(err).To(BeNil())
Expect(ac).NotTo(BeNil())
Expand All @@ -107,7 +250,8 @@ var _ = Describe("ActionClient", func() {

actionConfigGetter, err := NewActionConfigGetter(cfg, rm, logr.Discard())
Expect(err).ShouldNot(HaveOccurred())
acg := NewActionClientGetter(actionConfigGetter)
acg, err := NewActionClientGetter(actionConfigGetter)
Expect(err).To(BeNil())
ac, err = acg.ActionClientFor(obj)
Expect(err).To(BeNil())

Expand Down
Loading

0 comments on commit 932d72c

Please sign in to comment.