diff --git a/pkg/apis/helm.cattle.io/v1/types.go b/pkg/apis/helm.cattle.io/v1/types.go index 1f63cd91..8e01cc39 100644 --- a/pkg/apis/helm.cattle.io/v1/types.go +++ b/pkg/apis/helm.cattle.io/v1/types.go @@ -32,6 +32,7 @@ type HelmChartSpec struct { Bootstrap bool `json:"bootstrap,omitempty"` ChartContent string `json:"chartContent,omitempty"` JobImage string `json:"jobImage,omitempty"` + BackOffLimit *int32 `json:"backOffLimit,omitempty"` Timeout *metav1.Duration `json:"timeout,omitempty"` FailurePolicy string `json:"failurePolicy,omitempty"` AuthSecret *corev1.LocalObjectReference `json:"authSecret,omitempty"` diff --git a/pkg/apis/helm.cattle.io/v1/zz_generated_deepcopy.go b/pkg/apis/helm.cattle.io/v1/zz_generated_deepcopy.go index 12a8d8c1..5e36c1ae 100644 --- a/pkg/apis/helm.cattle.io/v1/zz_generated_deepcopy.go +++ b/pkg/apis/helm.cattle.io/v1/zz_generated_deepcopy.go @@ -180,6 +180,11 @@ func (in *HelmChartSpec) DeepCopyInto(out *HelmChartSpec) { (*out)[key] = val } } + if in.BackOffLimit != nil { + in, out := &in.BackOffLimit, &out.BackOffLimit + *out = new(int32) + **out = **in + } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout *out = new(metav1.Duration) diff --git a/pkg/controllers/chart/chart.go b/pkg/controllers/chart/chart.go index 3c41eb99..8b078ee3 100644 --- a/pkg/controllers/chart/chart.go +++ b/pkg/controllers/chart/chart.go @@ -55,6 +55,7 @@ var ( deletePolicy = metav1.DeletePropagationForeground DefaultJobImage = "rancher/klipper-helm:v0.8.0-build20230510" DefaultFailurePolicy = FailurePolicyReinstall + defaultBackOffLimit = pointer.Int32(1000) ) type Controller struct { @@ -310,6 +311,12 @@ func (c *Controller) getJobAndRelatedResources(chart *v1.HelmChart) (*batch.Job, failurePolicy = chart.Spec.FailurePolicy } + // override default backOffLimit if specified + backOffLimit := defaultBackOffLimit + if chart.Spec.BackOffLimit != nil { + backOffLimit = chart.Spec.BackOffLimit + } + // get the default job and configmaps job, valuesSecret, contentConfigMap := job(chart, c.apiServerPort) @@ -332,6 +339,7 @@ func (c *Controller) getJobAndRelatedResources(chart *v1.HelmChart) (*batch.Job, // note: the purpose of the additional annotation is to cause the job to be destroyed // and recreated if the hash of the HelmChartConfig changes while it is being processed setFailurePolicy(job, failurePolicy) + setBackOffLimit(job, backOffLimit) hashObjects(job, contentConfigMap, valuesSecret) return job, []runtime.Object{ @@ -376,7 +384,6 @@ func job(chart *v1.HelmChart, apiServerPort string) (*batch.Job, *corev1.Secret, }, }, Spec: batch.JobSpec{ - BackoffLimit: pointer.Int32Ptr(1000), Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{}, @@ -814,3 +821,7 @@ func hashObjects(job *batch.Job, objs ...metav1.Object) { job.Spec.Template.ObjectMeta.Annotations[Annotation] = fmt.Sprintf("SHA256=%X", hash.Sum(nil)) } + +func setBackOffLimit(job *batch.Job, backOffLimit *int32) { + job.Spec.BackoffLimit = backOffLimit +} diff --git a/pkg/generated/controllers/helm.cattle.io/v1/helmchart.go b/pkg/generated/controllers/helm.cattle.io/v1/helmchart.go index 0adc7347..11075bf5 100644 --- a/pkg/generated/controllers/helm.cattle.io/v1/helmchart.go +++ b/pkg/generated/controllers/helm.cattle.io/v1/helmchart.go @@ -23,8 +23,6 @@ import ( "time" v1 "github.com/k3s-io/helm-controller/pkg/apis/helm.cattle.io/v1" - "github.com/rancher/lasso/pkg/client" - "github.com/rancher/lasso/pkg/controller" "github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/generic" @@ -36,237 +34,121 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/tools/cache" ) -type HelmChartHandler func(string, *v1.HelmChart) (*v1.HelmChart, error) - +// HelmChartController interface for managing HelmChart resources. type HelmChartController interface { generic.ControllerMeta HelmChartClient + // OnChange runs the given handler when the controller detects a resource was changed. OnChange(ctx context.Context, name string, sync HelmChartHandler) + + // OnRemove runs the given handler when the controller detects a resource was changed. OnRemove(ctx context.Context, name string, sync HelmChartHandler) + + // Enqueue adds the resource with the given name to the worker queue of the controller. Enqueue(namespace, name string) + + // EnqueueAfter runs Enqueue after the provided duration. EnqueueAfter(namespace, name string, duration time.Duration) + // Cache returns a cache for the resource type T. Cache() HelmChartCache } +// HelmChartClient interface for managing HelmChart resources in Kubernetes. type HelmChartClient interface { + // Create creates a new object and return the newly created Object or an error. Create(*v1.HelmChart) (*v1.HelmChart, error) + + // Update updates the object and return the newly updated Object or an error. Update(*v1.HelmChart) (*v1.HelmChart, error) + // UpdateStatus updates the Status field of a the object and return the newly updated Object or an error. + // Will always return an error if the object does not have a status field. UpdateStatus(*v1.HelmChart) (*v1.HelmChart, error) + + // Delete deletes the Object in the given name. Delete(namespace, name string, options *metav1.DeleteOptions) error + + // Get will attempt to retrieve the resource with the specified name. Get(namespace, name string, options metav1.GetOptions) (*v1.HelmChart, error) + + // List will attempt to find multiple resources. List(namespace string, opts metav1.ListOptions) (*v1.HelmChartList, error) + + // Watch will start watching resources. Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) + + // Patch will patch the resource with the matching name. Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.HelmChart, err error) } +// HelmChartCache interface for retrieving HelmChart resources in memory. type HelmChartCache interface { + // Get returns the resources with the specified name from the cache. Get(namespace, name string) (*v1.HelmChart, error) + + // List will attempt to find resources from the Cache. List(namespace string, selector labels.Selector) ([]*v1.HelmChart, error) + // AddIndexer adds a new Indexer to the cache with the provided name. + // If you call this after you already have data in the store, the results are undefined. AddIndexer(indexName string, indexer HelmChartIndexer) - GetByIndex(indexName, key string) ([]*v1.HelmChart, error) -} - -type HelmChartIndexer func(obj *v1.HelmChart) ([]string, error) - -type helmChartController struct { - controller controller.SharedController - client *client.Client - gvk schema.GroupVersionKind - groupResource schema.GroupResource -} - -func NewHelmChartController(gvk schema.GroupVersionKind, resource string, namespaced bool, controller controller.SharedControllerFactory) HelmChartController { - c := controller.ForResourceKind(gvk.GroupVersion().WithResource(resource), gvk.Kind, namespaced) - return &helmChartController{ - controller: c, - client: c.Client(), - gvk: gvk, - groupResource: schema.GroupResource{ - Group: gvk.Group, - Resource: resource, - }, - } -} - -func FromHelmChartHandlerToHandler(sync HelmChartHandler) generic.Handler { - return func(key string, obj runtime.Object) (ret runtime.Object, err error) { - var v *v1.HelmChart - if obj == nil { - v, err = sync(key, nil) - } else { - v, err = sync(key, obj.(*v1.HelmChart)) - } - if v == nil { - return nil, err - } - return v, err - } -} - -func (c *helmChartController) Updater() generic.Updater { - return func(obj runtime.Object) (runtime.Object, error) { - newObj, err := c.Update(obj.(*v1.HelmChart)) - if newObj == nil { - return nil, err - } - return newObj, err - } -} - -func UpdateHelmChartDeepCopyOnChange(client HelmChartClient, obj *v1.HelmChart, handler func(obj *v1.HelmChart) (*v1.HelmChart, error)) (*v1.HelmChart, error) { - if obj == nil { - return obj, nil - } - - copyObj := obj.DeepCopy() - newObj, err := handler(copyObj) - if newObj != nil { - copyObj = newObj - } - if obj.ResourceVersion == copyObj.ResourceVersion && !equality.Semantic.DeepEqual(obj, copyObj) { - return client.Update(copyObj) - } - - return copyObj, err -} - -func (c *helmChartController) AddGenericHandler(ctx context.Context, name string, handler generic.Handler) { - c.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(handler)) -} - -func (c *helmChartController) AddGenericRemoveHandler(ctx context.Context, name string, handler generic.Handler) { - c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), handler)) -} - -func (c *helmChartController) OnChange(ctx context.Context, name string, sync HelmChartHandler) { - c.AddGenericHandler(ctx, name, FromHelmChartHandlerToHandler(sync)) -} - -func (c *helmChartController) OnRemove(ctx context.Context, name string, sync HelmChartHandler) { - c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), FromHelmChartHandlerToHandler(sync))) -} - -func (c *helmChartController) Enqueue(namespace, name string) { - c.controller.Enqueue(namespace, name) -} - -func (c *helmChartController) EnqueueAfter(namespace, name string, duration time.Duration) { - c.controller.EnqueueAfter(namespace, name, duration) -} - -func (c *helmChartController) Informer() cache.SharedIndexInformer { - return c.controller.Informer() -} - -func (c *helmChartController) GroupVersionKind() schema.GroupVersionKind { - return c.gvk -} - -func (c *helmChartController) Cache() HelmChartCache { - return &helmChartCache{ - indexer: c.Informer().GetIndexer(), - resource: c.groupResource, - } -} - -func (c *helmChartController) Create(obj *v1.HelmChart) (*v1.HelmChart, error) { - result := &v1.HelmChart{} - return result, c.client.Create(context.TODO(), obj.Namespace, obj, result, metav1.CreateOptions{}) -} - -func (c *helmChartController) Update(obj *v1.HelmChart) (*v1.HelmChart, error) { - result := &v1.HelmChart{} - return result, c.client.Update(context.TODO(), obj.Namespace, obj, result, metav1.UpdateOptions{}) -} - -func (c *helmChartController) UpdateStatus(obj *v1.HelmChart) (*v1.HelmChart, error) { - result := &v1.HelmChart{} - return result, c.client.UpdateStatus(context.TODO(), obj.Namespace, obj, result, metav1.UpdateOptions{}) -} -func (c *helmChartController) Delete(namespace, name string, options *metav1.DeleteOptions) error { - if options == nil { - options = &metav1.DeleteOptions{} - } - return c.client.Delete(context.TODO(), namespace, name, *options) + // GetByIndex returns the stored objects whose set of indexed values + // for the named index includes the given indexed value. + GetByIndex(indexName, key string) ([]*v1.HelmChart, error) } -func (c *helmChartController) Get(namespace, name string, options metav1.GetOptions) (*v1.HelmChart, error) { - result := &v1.HelmChart{} - return result, c.client.Get(context.TODO(), namespace, name, result, options) -} +// HelmChartHandler is function for performing any potential modifications to a HelmChart resource. +type HelmChartHandler func(string, *v1.HelmChart) (*v1.HelmChart, error) -func (c *helmChartController) List(namespace string, opts metav1.ListOptions) (*v1.HelmChartList, error) { - result := &v1.HelmChartList{} - return result, c.client.List(context.TODO(), namespace, result, opts) -} +// HelmChartIndexer computes a set of indexed values for the provided object. +type HelmChartIndexer func(obj *v1.HelmChart) ([]string, error) -func (c *helmChartController) Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) { - return c.client.Watch(context.TODO(), namespace, opts) +// HelmChartGenericController wraps wrangler/pkg/generic.Controller so that the function definitions adhere to HelmChartController interface. +type HelmChartGenericController struct { + generic.ControllerInterface[*v1.HelmChart, *v1.HelmChartList] } -func (c *helmChartController) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (*v1.HelmChart, error) { - result := &v1.HelmChart{} - return result, c.client.Patch(context.TODO(), namespace, name, pt, data, result, metav1.PatchOptions{}, subresources...) +// OnChange runs the given resource handler when the controller detects a resource was changed. +func (c *HelmChartGenericController) OnChange(ctx context.Context, name string, sync HelmChartHandler) { + c.ControllerInterface.OnChange(ctx, name, generic.ObjectHandler[*v1.HelmChart](sync)) } -type helmChartCache struct { - indexer cache.Indexer - resource schema.GroupResource +// OnRemove runs the given object handler when the controller detects a resource was changed. +func (c *HelmChartGenericController) OnRemove(ctx context.Context, name string, sync HelmChartHandler) { + c.ControllerInterface.OnRemove(ctx, name, generic.ObjectHandler[*v1.HelmChart](sync)) } -func (c *helmChartCache) Get(namespace, name string) (*v1.HelmChart, error) { - obj, exists, err := c.indexer.GetByKey(namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(c.resource, name) +// Cache returns a cache of resources in memory. +func (c *HelmChartGenericController) Cache() HelmChartCache { + return &HelmChartGenericCache{ + c.ControllerInterface.Cache(), } - return obj.(*v1.HelmChart), nil } -func (c *helmChartCache) List(namespace string, selector labels.Selector) (ret []*v1.HelmChart, err error) { - - err = cache.ListAllByNamespace(c.indexer, namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.HelmChart)) - }) - - return ret, err +// HelmChartGenericCache wraps wrangler/pkg/generic.Cache so the function definitions adhere to HelmChartCache interface. +type HelmChartGenericCache struct { + generic.CacheInterface[*v1.HelmChart] } -func (c *helmChartCache) AddIndexer(indexName string, indexer HelmChartIndexer) { - utilruntime.Must(c.indexer.AddIndexers(map[string]cache.IndexFunc{ - indexName: func(obj interface{}) (strings []string, e error) { - return indexer(obj.(*v1.HelmChart)) - }, - })) -} - -func (c *helmChartCache) GetByIndex(indexName, key string) (result []*v1.HelmChart, err error) { - objs, err := c.indexer.ByIndex(indexName, key) - if err != nil { - return nil, err - } - result = make([]*v1.HelmChart, 0, len(objs)) - for _, obj := range objs { - result = append(result, obj.(*v1.HelmChart)) - } - return result, nil +// AddIndexer adds a new Indexer to the cache with the provided name. +// If you call this after you already have data in the store, the results are undefined. +func (c HelmChartGenericCache) AddIndexer(indexName string, indexer HelmChartIndexer) { + c.CacheInterface.AddIndexer(indexName, generic.Indexer[*v1.HelmChart](indexer)) } type HelmChartStatusHandler func(obj *v1.HelmChart, status v1.HelmChartStatus) (v1.HelmChartStatus, error) type HelmChartGeneratingHandler func(obj *v1.HelmChart, status v1.HelmChartStatus) ([]runtime.Object, v1.HelmChartStatus, error) +func FromHelmChartHandlerToHandler(sync HelmChartHandler) generic.Handler { + return generic.FromObjectHandlerToHandler(generic.ObjectHandler[*v1.HelmChart](sync)) +} + func RegisterHelmChartStatusHandler(ctx context.Context, controller HelmChartController, condition condition.Cond, name string, handler HelmChartStatusHandler) { statusHandler := &helmChartStatusHandler{ client: controller, diff --git a/pkg/generated/controllers/helm.cattle.io/v1/helmchartconfig.go b/pkg/generated/controllers/helm.cattle.io/v1/helmchartconfig.go index 73f1d97c..ae430ff4 100644 --- a/pkg/generated/controllers/helm.cattle.io/v1/helmchartconfig.go +++ b/pkg/generated/controllers/helm.cattle.io/v1/helmchartconfig.go @@ -23,234 +23,110 @@ import ( "time" v1 "github.com/k3s-io/helm-controller/pkg/apis/helm.cattle.io/v1" - "github.com/rancher/lasso/pkg/client" - "github.com/rancher/lasso/pkg/controller" "github.com/rancher/wrangler/pkg/generic" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/tools/cache" ) -type HelmChartConfigHandler func(string, *v1.HelmChartConfig) (*v1.HelmChartConfig, error) - +// HelmChartConfigController interface for managing HelmChartConfig resources. type HelmChartConfigController interface { generic.ControllerMeta HelmChartConfigClient + // OnChange runs the given handler when the controller detects a resource was changed. OnChange(ctx context.Context, name string, sync HelmChartConfigHandler) + + // OnRemove runs the given handler when the controller detects a resource was changed. OnRemove(ctx context.Context, name string, sync HelmChartConfigHandler) + + // Enqueue adds the resource with the given name to the worker queue of the controller. Enqueue(namespace, name string) + + // EnqueueAfter runs Enqueue after the provided duration. EnqueueAfter(namespace, name string, duration time.Duration) + // Cache returns a cache for the resource type T. Cache() HelmChartConfigCache } +// HelmChartConfigClient interface for managing HelmChartConfig resources in Kubernetes. type HelmChartConfigClient interface { + // Create creates a new object and return the newly created Object or an error. Create(*v1.HelmChartConfig) (*v1.HelmChartConfig, error) + + // Update updates the object and return the newly updated Object or an error. Update(*v1.HelmChartConfig) (*v1.HelmChartConfig, error) + // Delete deletes the Object in the given name. Delete(namespace, name string, options *metav1.DeleteOptions) error + + // Get will attempt to retrieve the resource with the specified name. Get(namespace, name string, options metav1.GetOptions) (*v1.HelmChartConfig, error) + + // List will attempt to find multiple resources. List(namespace string, opts metav1.ListOptions) (*v1.HelmChartConfigList, error) + + // Watch will start watching resources. Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) + + // Patch will patch the resource with the matching name. Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.HelmChartConfig, err error) } +// HelmChartConfigCache interface for retrieving HelmChartConfig resources in memory. type HelmChartConfigCache interface { + // Get returns the resources with the specified name from the cache. Get(namespace, name string) (*v1.HelmChartConfig, error) + + // List will attempt to find resources from the Cache. List(namespace string, selector labels.Selector) ([]*v1.HelmChartConfig, error) + // AddIndexer adds a new Indexer to the cache with the provided name. + // If you call this after you already have data in the store, the results are undefined. AddIndexer(indexName string, indexer HelmChartConfigIndexer) - GetByIndex(indexName, key string) ([]*v1.HelmChartConfig, error) -} - -type HelmChartConfigIndexer func(obj *v1.HelmChartConfig) ([]string, error) - -type helmChartConfigController struct { - controller controller.SharedController - client *client.Client - gvk schema.GroupVersionKind - groupResource schema.GroupResource -} - -func NewHelmChartConfigController(gvk schema.GroupVersionKind, resource string, namespaced bool, controller controller.SharedControllerFactory) HelmChartConfigController { - c := controller.ForResourceKind(gvk.GroupVersion().WithResource(resource), gvk.Kind, namespaced) - return &helmChartConfigController{ - controller: c, - client: c.Client(), - gvk: gvk, - groupResource: schema.GroupResource{ - Group: gvk.Group, - Resource: resource, - }, - } -} - -func FromHelmChartConfigHandlerToHandler(sync HelmChartConfigHandler) generic.Handler { - return func(key string, obj runtime.Object) (ret runtime.Object, err error) { - var v *v1.HelmChartConfig - if obj == nil { - v, err = sync(key, nil) - } else { - v, err = sync(key, obj.(*v1.HelmChartConfig)) - } - if v == nil { - return nil, err - } - return v, err - } -} - -func (c *helmChartConfigController) Updater() generic.Updater { - return func(obj runtime.Object) (runtime.Object, error) { - newObj, err := c.Update(obj.(*v1.HelmChartConfig)) - if newObj == nil { - return nil, err - } - return newObj, err - } -} - -func UpdateHelmChartConfigDeepCopyOnChange(client HelmChartConfigClient, obj *v1.HelmChartConfig, handler func(obj *v1.HelmChartConfig) (*v1.HelmChartConfig, error)) (*v1.HelmChartConfig, error) { - if obj == nil { - return obj, nil - } - - copyObj := obj.DeepCopy() - newObj, err := handler(copyObj) - if newObj != nil { - copyObj = newObj - } - if obj.ResourceVersion == copyObj.ResourceVersion && !equality.Semantic.DeepEqual(obj, copyObj) { - return client.Update(copyObj) - } - - return copyObj, err -} - -func (c *helmChartConfigController) AddGenericHandler(ctx context.Context, name string, handler generic.Handler) { - c.controller.RegisterHandler(ctx, name, controller.SharedControllerHandlerFunc(handler)) -} -func (c *helmChartConfigController) AddGenericRemoveHandler(ctx context.Context, name string, handler generic.Handler) { - c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), handler)) -} - -func (c *helmChartConfigController) OnChange(ctx context.Context, name string, sync HelmChartConfigHandler) { - c.AddGenericHandler(ctx, name, FromHelmChartConfigHandlerToHandler(sync)) -} - -func (c *helmChartConfigController) OnRemove(ctx context.Context, name string, sync HelmChartConfigHandler) { - c.AddGenericHandler(ctx, name, generic.NewRemoveHandler(name, c.Updater(), FromHelmChartConfigHandlerToHandler(sync))) -} - -func (c *helmChartConfigController) Enqueue(namespace, name string) { - c.controller.Enqueue(namespace, name) -} - -func (c *helmChartConfigController) EnqueueAfter(namespace, name string, duration time.Duration) { - c.controller.EnqueueAfter(namespace, name, duration) -} - -func (c *helmChartConfigController) Informer() cache.SharedIndexInformer { - return c.controller.Informer() -} - -func (c *helmChartConfigController) GroupVersionKind() schema.GroupVersionKind { - return c.gvk -} - -func (c *helmChartConfigController) Cache() HelmChartConfigCache { - return &helmChartConfigCache{ - indexer: c.Informer().GetIndexer(), - resource: c.groupResource, - } -} - -func (c *helmChartConfigController) Create(obj *v1.HelmChartConfig) (*v1.HelmChartConfig, error) { - result := &v1.HelmChartConfig{} - return result, c.client.Create(context.TODO(), obj.Namespace, obj, result, metav1.CreateOptions{}) -} - -func (c *helmChartConfigController) Update(obj *v1.HelmChartConfig) (*v1.HelmChartConfig, error) { - result := &v1.HelmChartConfig{} - return result, c.client.Update(context.TODO(), obj.Namespace, obj, result, metav1.UpdateOptions{}) -} - -func (c *helmChartConfigController) Delete(namespace, name string, options *metav1.DeleteOptions) error { - if options == nil { - options = &metav1.DeleteOptions{} - } - return c.client.Delete(context.TODO(), namespace, name, *options) + // GetByIndex returns the stored objects whose set of indexed values + // for the named index includes the given indexed value. + GetByIndex(indexName, key string) ([]*v1.HelmChartConfig, error) } -func (c *helmChartConfigController) Get(namespace, name string, options metav1.GetOptions) (*v1.HelmChartConfig, error) { - result := &v1.HelmChartConfig{} - return result, c.client.Get(context.TODO(), namespace, name, result, options) -} +// HelmChartConfigHandler is function for performing any potential modifications to a HelmChartConfig resource. +type HelmChartConfigHandler func(string, *v1.HelmChartConfig) (*v1.HelmChartConfig, error) -func (c *helmChartConfigController) List(namespace string, opts metav1.ListOptions) (*v1.HelmChartConfigList, error) { - result := &v1.HelmChartConfigList{} - return result, c.client.List(context.TODO(), namespace, result, opts) -} +// HelmChartConfigIndexer computes a set of indexed values for the provided object. +type HelmChartConfigIndexer func(obj *v1.HelmChartConfig) ([]string, error) -func (c *helmChartConfigController) Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) { - return c.client.Watch(context.TODO(), namespace, opts) +// HelmChartConfigGenericController wraps wrangler/pkg/generic.Controller so that the function definitions adhere to HelmChartConfigController interface. +type HelmChartConfigGenericController struct { + generic.ControllerInterface[*v1.HelmChartConfig, *v1.HelmChartConfigList] } -func (c *helmChartConfigController) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (*v1.HelmChartConfig, error) { - result := &v1.HelmChartConfig{} - return result, c.client.Patch(context.TODO(), namespace, name, pt, data, result, metav1.PatchOptions{}, subresources...) +// OnChange runs the given resource handler when the controller detects a resource was changed. +func (c *HelmChartConfigGenericController) OnChange(ctx context.Context, name string, sync HelmChartConfigHandler) { + c.ControllerInterface.OnChange(ctx, name, generic.ObjectHandler[*v1.HelmChartConfig](sync)) } -type helmChartConfigCache struct { - indexer cache.Indexer - resource schema.GroupResource +// OnRemove runs the given object handler when the controller detects a resource was changed. +func (c *HelmChartConfigGenericController) OnRemove(ctx context.Context, name string, sync HelmChartConfigHandler) { + c.ControllerInterface.OnRemove(ctx, name, generic.ObjectHandler[*v1.HelmChartConfig](sync)) } -func (c *helmChartConfigCache) Get(namespace, name string) (*v1.HelmChartConfig, error) { - obj, exists, err := c.indexer.GetByKey(namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(c.resource, name) +// Cache returns a cache of resources in memory. +func (c *HelmChartConfigGenericController) Cache() HelmChartConfigCache { + return &HelmChartConfigGenericCache{ + c.ControllerInterface.Cache(), } - return obj.(*v1.HelmChartConfig), nil -} - -func (c *helmChartConfigCache) List(namespace string, selector labels.Selector) (ret []*v1.HelmChartConfig, err error) { - - err = cache.ListAllByNamespace(c.indexer, namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.HelmChartConfig)) - }) - - return ret, err } -func (c *helmChartConfigCache) AddIndexer(indexName string, indexer HelmChartConfigIndexer) { - utilruntime.Must(c.indexer.AddIndexers(map[string]cache.IndexFunc{ - indexName: func(obj interface{}) (strings []string, e error) { - return indexer(obj.(*v1.HelmChartConfig)) - }, - })) +// HelmChartConfigGenericCache wraps wrangler/pkg/generic.Cache so the function definitions adhere to HelmChartConfigCache interface. +type HelmChartConfigGenericCache struct { + generic.CacheInterface[*v1.HelmChartConfig] } -func (c *helmChartConfigCache) GetByIndex(indexName, key string) (result []*v1.HelmChartConfig, err error) { - objs, err := c.indexer.ByIndex(indexName, key) - if err != nil { - return nil, err - } - result = make([]*v1.HelmChartConfig, 0, len(objs)) - for _, obj := range objs { - result = append(result, obj.(*v1.HelmChartConfig)) - } - return result, nil +// AddIndexer adds a new Indexer to the cache with the provided name. +// If you call this after you already have data in the store, the results are undefined. +func (c HelmChartConfigGenericCache) AddIndexer(indexName string, indexer HelmChartConfigIndexer) { + c.CacheInterface.AddIndexer(indexName, generic.Indexer[*v1.HelmChartConfig](indexer)) } diff --git a/pkg/generated/controllers/helm.cattle.io/v1/interface.go b/pkg/generated/controllers/helm.cattle.io/v1/interface.go index e1783f31..0726752f 100644 --- a/pkg/generated/controllers/helm.cattle.io/v1/interface.go +++ b/pkg/generated/controllers/helm.cattle.io/v1/interface.go @@ -21,6 +21,7 @@ package v1 import ( v1 "github.com/k3s-io/helm-controller/pkg/apis/helm.cattle.io/v1" "github.com/rancher/lasso/pkg/controller" + "github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/schemes" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -44,9 +45,14 @@ type version struct { controllerFactory controller.SharedControllerFactory } -func (c *version) HelmChart() HelmChartController { - return NewHelmChartController(schema.GroupVersionKind{Group: "helm.cattle.io", Version: "v1", Kind: "HelmChart"}, "helmcharts", true, c.controllerFactory) +func (v *version) HelmChart() HelmChartController { + return &HelmChartGenericController{ + generic.NewController[*v1.HelmChart, *v1.HelmChartList](schema.GroupVersionKind{Group: "helm.cattle.io", Version: "v1", Kind: "HelmChart"}, "helmcharts", true, v.controllerFactory), + } } -func (c *version) HelmChartConfig() HelmChartConfigController { - return NewHelmChartConfigController(schema.GroupVersionKind{Group: "helm.cattle.io", Version: "v1", Kind: "HelmChartConfig"}, "helmchartconfigs", true, c.controllerFactory) + +func (v *version) HelmChartConfig() HelmChartConfigController { + return &HelmChartConfigGenericController{ + generic.NewController[*v1.HelmChartConfig, *v1.HelmChartConfigList](schema.GroupVersionKind{Group: "helm.cattle.io", Version: "v1", Kind: "HelmChartConfig"}, "helmchartconfigs", true, v.controllerFactory), + } } diff --git a/test/framework/framework.go b/test/framework/framework.go index 7ae78e19..54095b71 100644 --- a/test/framework/framework.go +++ b/test/framework/framework.go @@ -203,3 +203,10 @@ func (f *Framework) WaitForChartApp(chart *v1.HelmChart, appName string, timeout return len(pods) >= count, nil }) } + +func (f *Framework) GetJob(chart *v1.HelmChart) (*batchv1.Job, error) { + if chart.Status.JobName == "" { + return nil, fmt.Errorf("waiting for job name to be populated") + } + return f.ClientSet.BatchV1().Jobs(chart.Namespace).Get(context.TODO(), chart.Status.JobName, metav1.GetOptions{}) +} diff --git a/test/suite/helm_test.go b/test/suite/helm_test.go index b034051a..411e961f 100644 --- a/test/suite/helm_test.go +++ b/test/suite/helm_test.go @@ -6,6 +6,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + batchv1 "k8s.io/api/batch/v1" v1 "github.com/k3s-io/helm-controller/pkg/apis/helm.cattle.io/v1" "github.com/k3s-io/helm-controller/test/framework" @@ -421,4 +422,112 @@ var _ = Describe("Helm Tests", Ordered, func() { }, 120*time.Second, 5*time.Second).Should(BeTrue()) }) }) + + Context("When a custom backoffLimit is specified", func() { + var ( + err error + chart *v1.HelmChart + job *batchv1.Job + backOffLimit int32 + ) + BeforeEach(func() { + backOffLimit = 10 + chart = framework.NewHelmChart("traefik-example-custom-backoff", + "stable/traefik", + "1.86.1", + "v3", + map[string]intstr.IntOrString{ + "rbac.enabled": { + Type: intstr.String, + StrVal: "true", + }, + "ssl.enabled": { + Type: intstr.String, + StrVal: "true", + }, + }) + chart.Spec.BackOffLimit = &backOffLimit + chart, err = framework.CreateHelmChart(chart, framework.Namespace) + Expect(err).ToNot(HaveOccurred()) + + labelSelector := labels.SelectorFromSet(labels.Set{ + "owner": "helm", + "name": chart.Name, + }) + _, err = framework.WaitForRelease(chart, labelSelector, 120*time.Second, 1) + Expect(err).ToNot(HaveOccurred()) + + chart, err = framework.GetHelmChart(chart.Name, chart.Namespace) + Expect(err).ToNot(HaveOccurred()) + job, err = framework.GetJob(chart) + Expect(err).ToNot(HaveOccurred()) + }) + It("Should have correct job backOff Limit", func() { + Expect(*job.Spec.BackoffLimit).To(Equal(backOffLimit)) + }) + AfterEach(func() { + err = framework.DeleteHelmChart(chart.Name, framework.Namespace) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() bool { + _, err := framework.GetHelmChart(chart.Name, framework.Namespace) + return err != nil && apierrors.IsNotFound(err) + }, 120*time.Second, 5*time.Second).Should(BeTrue()) + }) + + }) + + Context("When a no backoffLimit is specified", func() { + var ( + err error + chart *v1.HelmChart + job *batchv1.Job + ) + const ( + defaultBackOffLimit = int32(1000) + ) + BeforeEach(func() { + chart = framework.NewHelmChart("traefik-example-default-backoff", + "stable/traefik", + "1.86.1", + "v3", + map[string]intstr.IntOrString{ + "rbac.enabled": { + Type: intstr.String, + StrVal: "true", + }, + "ssl.enabled": { + Type: intstr.String, + StrVal: "true", + }, + }) + chart, err = framework.CreateHelmChart(chart, framework.Namespace) + Expect(err).ToNot(HaveOccurred()) + + labelSelector := labels.SelectorFromSet(labels.Set{ + "owner": "helm", + "name": chart.Name, + }) + _, err = framework.WaitForRelease(chart, labelSelector, 120*time.Second, 1) + Expect(err).ToNot(HaveOccurred()) + + chart, err = framework.GetHelmChart(chart.Name, chart.Namespace) + Expect(err).ToNot(HaveOccurred()) + job, err = framework.GetJob(chart) + Expect(err).ToNot(HaveOccurred()) + }) + It("Should have correct job backOff Limit", func() { + Expect(*job.Spec.BackoffLimit).To(Equal(defaultBackOffLimit)) + }) + AfterEach(func() { + err = framework.DeleteHelmChart(chart.Name, framework.Namespace) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() bool { + _, err := framework.GetHelmChart(chart.Name, framework.Namespace) + return err != nil && apierrors.IsNotFound(err) + }, 120*time.Second, 5*time.Second).Should(BeTrue()) + }) + + }) })