···11+/*
22+Copyright 2026.
33+44+Licensed under the Apache License, Version 2.0 (the "License");
55+you may not use this file except in compliance with the License.
66+You may obtain a copy of the License at
77+88+ http://www.apache.org/licenses/LICENSE-2.0
99+1010+Unless required by applicable law or agreed to in writing, software
1111+distributed under the License is distributed on an "AS IS" BASIS,
1212+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313+See the License for the specific language governing permissions and
1414+limitations under the License.
1515+*/
1616+1717+// Package v1alpha1 contains API Schema definitions for the autoscaling v1alpha1 API group.
1818+// +kubebuilder:object:generate=true
1919+// +groupName=autoscaling.kgz.sh
2020+package v1alpha1
2121+2222+import (
2323+ "k8s.io/apimachinery/pkg/runtime/schema"
2424+ "sigs.k8s.io/controller-runtime/pkg/scheme"
2525+)
2626+2727+var (
2828+ // GroupVersion is group version used to register these objects.
2929+ GroupVersion = schema.GroupVersion{Group: "autoscaling.kgz.sh", Version: "v1alpha1"}
3030+3131+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
3232+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
3333+3434+ // AddToScheme adds the types in this group-version to the given scheme.
3535+ AddToScheme = SchemeBuilder.AddToScheme
3636+)
···11+/*
22+Copyright 2026.
33+44+Licensed under the Apache License, Version 2.0 (the "License");
55+you may not use this file except in compliance with the License.
66+You may obtain a copy of the License at
77+88+ http://www.apache.org/licenses/LICENSE-2.0
99+1010+Unless required by applicable law or agreed to in writing, software
1111+distributed under the License is distributed on an "AS IS" BASIS,
1212+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313+See the License for the specific language governing permissions and
1414+limitations under the License.
1515+*/
1616+1717+package v1alpha1
1818+1919+import (
2020+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2121+)
2222+2323+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
2424+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
2525+2626+// PrometheusInformedScaleTargetSpec defines the desired state of PrometheusInformedScaleTarget
2727+type PrometheusInformedScaleTargetSpec struct {
2828+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
2929+ // Important: Run "make" to regenerate code after modifying this file
3030+ // The following markers will use OpenAPI v3 schema to validate the value
3131+ // More info: https://book.kubebuilder.io/reference/markers/crd-validation.html
3232+3333+ // foo is an example field of PrometheusInformedScaleTarget. Edit prometheusinformedscaletarget_types.go to remove/update
3434+ // +optional
3535+ Foo *string `json:"foo,omitempty"`
3636+}
3737+3838+// PrometheusInformedScaleTargetStatus defines the observed state of PrometheusInformedScaleTarget.
3939+type PrometheusInformedScaleTargetStatus struct {
4040+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
4141+ // Important: Run "make" to regenerate code after modifying this file
4242+}
4343+4444+// +kubebuilder:object:root=true
4545+// +kubebuilder:subresource:status
4646+4747+// PrometheusInformedScaleTarget is the Schema for the prometheusinformedscaletargets API
4848+type PrometheusInformedScaleTarget struct {
4949+ metav1.TypeMeta `json:",inline"`
5050+5151+ // metadata is a standard object metadata
5252+ // +optional
5353+ metav1.ObjectMeta `json:"metadata,omitempty,omitzero"`
5454+5555+ // spec defines the desired state of PrometheusInformedScaleTarget
5656+ // +required
5757+ Spec PrometheusInformedScaleTargetSpec `json:"spec"`
5858+5959+ // status defines the observed state of PrometheusInformedScaleTarget
6060+ // +optional
6161+ Status PrometheusInformedScaleTargetStatus `json:"status,omitempty,omitzero"`
6262+}
6363+6464+// +kubebuilder:object:root=true
6565+6666+// PrometheusInformedScaleTargetList contains a list of PrometheusInformedScaleTarget
6767+type PrometheusInformedScaleTargetList struct {
6868+ metav1.TypeMeta `json:",inline"`
6969+ metav1.ListMeta `json:"metadata,omitempty"`
7070+ Items []PrometheusInformedScaleTarget `json:"items"`
7171+}
7272+7373+func init() {
7474+ SchemeBuilder.Register(&PrometheusInformedScaleTarget{}, &PrometheusInformedScaleTargetList{})
7575+}
+119
api/v1alpha1/zz_generated.deepcopy.go
···11+//go:build !ignore_autogenerated
22+33+/*
44+Copyright 2026.
55+66+Licensed under the Apache License, Version 2.0 (the "License");
77+you may not use this file except in compliance with the License.
88+You may obtain a copy of the License at
99+1010+ http://www.apache.org/licenses/LICENSE-2.0
1111+1212+Unless required by applicable law or agreed to in writing, software
1313+distributed under the License is distributed on an "AS IS" BASIS,
1414+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+See the License for the specific language governing permissions and
1616+limitations under the License.
1717+*/
1818+1919+// Code generated by controller-gen. DO NOT EDIT.
2020+2121+package v1alpha1
2222+2323+import (
2424+ runtime "k8s.io/apimachinery/pkg/runtime"
2525+)
2626+2727+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
2828+func (in *PrometheusInformedScaleTarget) DeepCopyInto(out *PrometheusInformedScaleTarget) {
2929+ *out = *in
3030+ out.TypeMeta = in.TypeMeta
3131+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
3232+ in.Spec.DeepCopyInto(&out.Spec)
3333+ out.Status = in.Status
3434+}
3535+3636+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrometheusInformedScaleTarget.
3737+func (in *PrometheusInformedScaleTarget) DeepCopy() *PrometheusInformedScaleTarget {
3838+ if in == nil {
3939+ return nil
4040+ }
4141+ out := new(PrometheusInformedScaleTarget)
4242+ in.DeepCopyInto(out)
4343+ return out
4444+}
4545+4646+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
4747+func (in *PrometheusInformedScaleTarget) DeepCopyObject() runtime.Object {
4848+ if c := in.DeepCopy(); c != nil {
4949+ return c
5050+ }
5151+ return nil
5252+}
5353+5454+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
5555+func (in *PrometheusInformedScaleTargetList) DeepCopyInto(out *PrometheusInformedScaleTargetList) {
5656+ *out = *in
5757+ out.TypeMeta = in.TypeMeta
5858+ in.ListMeta.DeepCopyInto(&out.ListMeta)
5959+ if in.Items != nil {
6060+ in, out := &in.Items, &out.Items
6161+ *out = make([]PrometheusInformedScaleTarget, len(*in))
6262+ for i := range *in {
6363+ (*in)[i].DeepCopyInto(&(*out)[i])
6464+ }
6565+ }
6666+}
6767+6868+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrometheusInformedScaleTargetList.
6969+func (in *PrometheusInformedScaleTargetList) DeepCopy() *PrometheusInformedScaleTargetList {
7070+ if in == nil {
7171+ return nil
7272+ }
7373+ out := new(PrometheusInformedScaleTargetList)
7474+ in.DeepCopyInto(out)
7575+ return out
7676+}
7777+7878+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
7979+func (in *PrometheusInformedScaleTargetList) DeepCopyObject() runtime.Object {
8080+ if c := in.DeepCopy(); c != nil {
8181+ return c
8282+ }
8383+ return nil
8484+}
8585+8686+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
8787+func (in *PrometheusInformedScaleTargetSpec) DeepCopyInto(out *PrometheusInformedScaleTargetSpec) {
8888+ *out = *in
8989+ if in.Foo != nil {
9090+ in, out := &in.Foo, &out.Foo
9191+ *out = new(string)
9292+ **out = **in
9393+ }
9494+}
9595+9696+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrometheusInformedScaleTargetSpec.
9797+func (in *PrometheusInformedScaleTargetSpec) DeepCopy() *PrometheusInformedScaleTargetSpec {
9898+ if in == nil {
9999+ return nil
100100+ }
101101+ out := new(PrometheusInformedScaleTargetSpec)
102102+ in.DeepCopyInto(out)
103103+ return out
104104+}
105105+106106+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
107107+func (in *PrometheusInformedScaleTargetStatus) DeepCopyInto(out *PrometheusInformedScaleTargetStatus) {
108108+ *out = *in
109109+}
110110+111111+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrometheusInformedScaleTargetStatus.
112112+func (in *PrometheusInformedScaleTargetStatus) DeepCopy() *PrometheusInformedScaleTargetStatus {
113113+ if in == nil {
114114+ return nil
115115+ }
116116+ out := new(PrometheusInformedScaleTargetStatus)
117117+ in.DeepCopyInto(out)
118118+ return out
119119+}
···11+---
22+apiVersion: apiextensions.k8s.io/v1
33+kind: CustomResourceDefinition
44+metadata:
55+ annotations:
66+ controller-gen.kubebuilder.io/version: v0.18.0
77+ name: prometheusinformedscaletargets.autoscaling.kgz.sh
88+spec:
99+ group: autoscaling.kgz.sh
1010+ names:
1111+ kind: PrometheusInformedScaleTarget
1212+ listKind: PrometheusInformedScaleTargetList
1313+ plural: prometheusinformedscaletargets
1414+ singular: prometheusinformedscaletarget
1515+ scope: Namespaced
1616+ versions:
1717+ - name: v1alpha1
1818+ schema:
1919+ openAPIV3Schema:
2020+ description: PrometheusInformedScaleTarget is the Schema for the prometheusinformedscaletargets
2121+ API
2222+ properties:
2323+ apiVersion:
2424+ description: |-
2525+ APIVersion defines the versioned schema of this representation of an object.
2626+ Servers should convert recognized schemas to the latest internal value, and
2727+ may reject unrecognized values.
2828+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
2929+ type: string
3030+ kind:
3131+ description: |-
3232+ Kind is a string value representing the REST resource this object represents.
3333+ Servers may infer this from the endpoint the client submits requests to.
3434+ Cannot be updated.
3535+ In CamelCase.
3636+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
3737+ type: string
3838+ metadata:
3939+ type: object
4040+ spec:
4141+ description: spec defines the desired state of PrometheusInformedScaleTarget
4242+ properties:
4343+ foo:
4444+ description: foo is an example field of PrometheusInformedScaleTarget.
4545+ Edit prometheusinformedscaletarget_types.go to remove/update
4646+ type: string
4747+ type: object
4848+ status:
4949+ description: status defines the observed state of PrometheusInformedScaleTarget
5050+ type: object
5151+ required:
5252+ - spec
5353+ type: object
5454+ served: true
5555+ storage: true
5656+ subresources:
5757+ status: {}
+16
config/crd/kustomization.yaml
···11+# This kustomization.yaml is not intended to be run by itself,
22+# since it depends on service name and namespace that are out of this kustomize package.
33+# It should be run by config/default
44+resources:
55+- bases/autoscaling.kgz.sh_prometheusinformedscaletargets.yaml
66+# +kubebuilder:scaffold:crdkustomizeresource
77+88+patches:
99+# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
1010+# patches here are for enabling the conversion webhook for each CRD
1111+# +kubebuilder:scaffold:crdkustomizewebhookpatch
1212+1313+# [WEBHOOK] To enable webhook, uncomment the following section
1414+# the following config is for teaching kustomize how to do kustomization for CRDs.
1515+#configurations:
1616+#- kustomizeconfig.yaml
+19
config/crd/kustomizeconfig.yaml
···11+# This file is for teaching kustomize how to substitute name and namespace reference in CRD
22+nameReference:
33+- kind: Service
44+ version: v1
55+ fieldSpecs:
66+ - kind: CustomResourceDefinition
77+ version: v1
88+ group: apiextensions.k8s.io
99+ path: spec/conversion/webhook/clientConfig/service/name
1010+1111+namespace:
1212+- kind: CustomResourceDefinition
1313+ version: v1
1414+ group: apiextensions.k8s.io
1515+ path: spec/conversion/webhook/clientConfig/service/namespace
1616+ create: false
1717+1818+varReference:
1919+- path: metadata/annotations
+1-1
config/default/kustomization.yaml
···1515# someName: someValue
16161717resources:
1818-#- ../crd
1818+- ../crd
1919- ../rbac
2020- ../manager
2121# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
+8
config/rbac/kustomization.yaml
···1818- metrics_auth_role.yaml
1919- metrics_auth_role_binding.yaml
2020- metrics_reader_role.yaml
2121+# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by
2222+# default, aiding admins in cluster management. Those roles are
2323+# not used by the pist itself. You can comment the following lines
2424+# if you do not want those helpers be installed with your Project.
2525+- prometheusinformedscaletarget_admin_role.yaml
2626+- prometheusinformedscaletarget_editor_role.yaml
2727+- prometheusinformedscaletarget_viewer_role.yaml
2828+
···11+# This rule is not used by the project pist itself.
22+# It is provided to allow the cluster admin to help manage permissions for users.
33+#
44+# Grants full permissions ('*') over autoscaling.kgz.sh.
55+# This role is intended for users authorized to modify roles and bindings within the cluster,
66+# enabling them to delegate specific permissions to other users or groups as needed.
77+88+apiVersion: rbac.authorization.k8s.io/v1
99+kind: ClusterRole
1010+metadata:
1111+ labels:
1212+ app.kubernetes.io/name: pist
1313+ app.kubernetes.io/managed-by: kustomize
1414+ name: prometheusinformedscaletarget-admin-role
1515+rules:
1616+- apiGroups:
1717+ - autoscaling.kgz.sh
1818+ resources:
1919+ - prometheusinformedscaletargets
2020+ verbs:
2121+ - '*'
2222+- apiGroups:
2323+ - autoscaling.kgz.sh
2424+ resources:
2525+ - prometheusinformedscaletargets/status
2626+ verbs:
2727+ - get
···11+# This rule is not used by the project pist itself.
22+# It is provided to allow the cluster admin to help manage permissions for users.
33+#
44+# Grants permissions to create, update, and delete resources within the autoscaling.kgz.sh.
55+# This role is intended for users who need to manage these resources
66+# but should not control RBAC or manage permissions for others.
77+88+apiVersion: rbac.authorization.k8s.io/v1
99+kind: ClusterRole
1010+metadata:
1111+ labels:
1212+ app.kubernetes.io/name: pist
1313+ app.kubernetes.io/managed-by: kustomize
1414+ name: prometheusinformedscaletarget-editor-role
1515+rules:
1616+- apiGroups:
1717+ - autoscaling.kgz.sh
1818+ resources:
1919+ - prometheusinformedscaletargets
2020+ verbs:
2121+ - create
2222+ - delete
2323+ - get
2424+ - list
2525+ - patch
2626+ - update
2727+ - watch
2828+- apiGroups:
2929+ - autoscaling.kgz.sh
3030+ resources:
3131+ - prometheusinformedscaletargets/status
3232+ verbs:
3333+ - get
···11+# This rule is not used by the project pist itself.
22+# It is provided to allow the cluster admin to help manage permissions for users.
33+#
44+# Grants read-only access to autoscaling.kgz.sh resources.
55+# This role is intended for users who need visibility into these resources
66+# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing.
77+88+apiVersion: rbac.authorization.k8s.io/v1
99+kind: ClusterRole
1010+metadata:
1111+ labels:
1212+ app.kubernetes.io/name: pist
1313+ app.kubernetes.io/managed-by: kustomize
1414+ name: prometheusinformedscaletarget-viewer-role
1515+rules:
1616+- apiGroups:
1717+ - autoscaling.kgz.sh
1818+ resources:
1919+ - prometheusinformedscaletargets
2020+ verbs:
2121+ - get
2222+ - list
2323+ - watch
2424+- apiGroups:
2525+ - autoscaling.kgz.sh
2626+ resources:
2727+ - prometheusinformedscaletargets/status
2828+ verbs:
2929+ - get
···11+/*
22+Copyright 2026.
33+44+Licensed under the Apache License, Version 2.0 (the "License");
55+you may not use this file except in compliance with the License.
66+You may obtain a copy of the License at
77+88+ http://www.apache.org/licenses/LICENSE-2.0
99+1010+Unless required by applicable law or agreed to in writing, software
1111+distributed under the License is distributed on an "AS IS" BASIS,
1212+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313+See the License for the specific language governing permissions and
1414+limitations under the License.
1515+*/
1616+1717+package controller
1818+1919+import (
2020+ "context"
2121+2222+ "k8s.io/apimachinery/pkg/runtime"
2323+ ctrl "sigs.k8s.io/controller-runtime"
2424+ "sigs.k8s.io/controller-runtime/pkg/client"
2525+ logf "sigs.k8s.io/controller-runtime/pkg/log"
2626+2727+ autoscalingv1alpha1 "github.com/kragniz/pist/api/v1alpha1"
2828+)
2929+3030+// PrometheusInformedScaleTargetReconciler reconciles a PrometheusInformedScaleTarget object
3131+type PrometheusInformedScaleTargetReconciler struct {
3232+ client.Client
3333+ Scheme *runtime.Scheme
3434+}
3535+3636+// +kubebuilder:rbac:groups=autoscaling.kgz.sh,resources=prometheusinformedscaletargets,verbs=get;list;watch;create;update;patch;delete
3737+// +kubebuilder:rbac:groups=autoscaling.kgz.sh,resources=prometheusinformedscaletargets/status,verbs=get;update;patch
3838+// +kubebuilder:rbac:groups=autoscaling.kgz.sh,resources=prometheusinformedscaletargets/finalizers,verbs=update
3939+4040+// Reconcile is part of the main kubernetes reconciliation loop which aims to
4141+// move the current state of the cluster closer to the desired state.
4242+// TODO(user): Modify the Reconcile function to compare the state specified by
4343+// the PrometheusInformedScaleTarget object against the actual cluster state, and then
4444+// perform operations to make the cluster state reflect the state specified by
4545+// the user.
4646+//
4747+// For more details, check Reconcile and its Result here:
4848+// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.21.0/pkg/reconcile
4949+func (r *PrometheusInformedScaleTargetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
5050+ _ = logf.FromContext(ctx)
5151+5252+ // TODO(user): your logic here
5353+5454+ return ctrl.Result{}, nil
5555+}
5656+5757+// SetupWithManager sets up the controller with the Manager.
5858+func (r *PrometheusInformedScaleTargetReconciler) SetupWithManager(mgr ctrl.Manager) error {
5959+ return ctrl.NewControllerManagedBy(mgr).
6060+ For(&autoscalingv1alpha1.PrometheusInformedScaleTarget{}).
6161+ Named("prometheusinformedscaletarget").
6262+ Complete(r)
6363+}
···11+/*
22+Copyright 2026.
33+44+Licensed under the Apache License, Version 2.0 (the "License");
55+you may not use this file except in compliance with the License.
66+You may obtain a copy of the License at
77+88+ http://www.apache.org/licenses/LICENSE-2.0
99+1010+Unless required by applicable law or agreed to in writing, software
1111+distributed under the License is distributed on an "AS IS" BASIS,
1212+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313+See the License for the specific language governing permissions and
1414+limitations under the License.
1515+*/
1616+1717+package controller
1818+1919+import (
2020+ "context"
2121+2222+ . "github.com/onsi/ginkgo/v2"
2323+ . "github.com/onsi/gomega"
2424+ "k8s.io/apimachinery/pkg/api/errors"
2525+ "k8s.io/apimachinery/pkg/types"
2626+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
2727+2828+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2929+3030+ autoscalingv1alpha1 "github.com/kragniz/pist/api/v1alpha1"
3131+)
3232+3333+var _ = Describe("PrometheusInformedScaleTarget Controller", func() {
3434+ Context("When reconciling a resource", func() {
3535+ const resourceName = "test-resource"
3636+3737+ ctx := context.Background()
3838+3939+ typeNamespacedName := types.NamespacedName{
4040+ Name: resourceName,
4141+ Namespace: "default", // TODO(user):Modify as needed
4242+ }
4343+ prometheusinformedscaletarget := &autoscalingv1alpha1.PrometheusInformedScaleTarget{}
4444+4545+ BeforeEach(func() {
4646+ By("creating the custom resource for the Kind PrometheusInformedScaleTarget")
4747+ err := k8sClient.Get(ctx, typeNamespacedName, prometheusinformedscaletarget)
4848+ if err != nil && errors.IsNotFound(err) {
4949+ resource := &autoscalingv1alpha1.PrometheusInformedScaleTarget{
5050+ ObjectMeta: metav1.ObjectMeta{
5151+ Name: resourceName,
5252+ Namespace: "default",
5353+ },
5454+ // TODO(user): Specify other spec details if needed.
5555+ }
5656+ Expect(k8sClient.Create(ctx, resource)).To(Succeed())
5757+ }
5858+ })
5959+6060+ AfterEach(func() {
6161+ // TODO(user): Cleanup logic after each test, like removing the resource instance.
6262+ resource := &autoscalingv1alpha1.PrometheusInformedScaleTarget{}
6363+ err := k8sClient.Get(ctx, typeNamespacedName, resource)
6464+ Expect(err).NotTo(HaveOccurred())
6565+6666+ By("Cleanup the specific resource instance PrometheusInformedScaleTarget")
6767+ Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
6868+ })
6969+ It("should successfully reconcile the resource", func() {
7070+ By("Reconciling the created resource")
7171+ controllerReconciler := &PrometheusInformedScaleTargetReconciler{
7272+ Client: k8sClient,
7373+ Scheme: k8sClient.Scheme(),
7474+ }
7575+7676+ _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
7777+ NamespacedName: typeNamespacedName,
7878+ })
7979+ Expect(err).NotTo(HaveOccurred())
8080+ // TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
8181+ // Example: If you expect a certain status condition after reconciliation, verify it here.
8282+ })
8383+ })
8484+})
+116
internal/controller/suite_test.go
···11+/*
22+Copyright 2026.
33+44+Licensed under the Apache License, Version 2.0 (the "License");
55+you may not use this file except in compliance with the License.
66+You may obtain a copy of the License at
77+88+ http://www.apache.org/licenses/LICENSE-2.0
99+1010+Unless required by applicable law or agreed to in writing, software
1111+distributed under the License is distributed on an "AS IS" BASIS,
1212+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313+See the License for the specific language governing permissions and
1414+limitations under the License.
1515+*/
1616+1717+package controller
1818+1919+import (
2020+ "context"
2121+ "os"
2222+ "path/filepath"
2323+ "testing"
2424+2525+ . "github.com/onsi/ginkgo/v2"
2626+ . "github.com/onsi/gomega"
2727+2828+ "k8s.io/client-go/kubernetes/scheme"
2929+ "k8s.io/client-go/rest"
3030+ "sigs.k8s.io/controller-runtime/pkg/client"
3131+ "sigs.k8s.io/controller-runtime/pkg/envtest"
3232+ logf "sigs.k8s.io/controller-runtime/pkg/log"
3333+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
3434+3535+ autoscalingv1alpha1 "github.com/kragniz/pist/api/v1alpha1"
3636+ // +kubebuilder:scaffold:imports
3737+)
3838+3939+// These tests use Ginkgo (BDD-style Go testing framework). Refer to
4040+// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
4141+4242+var (
4343+ ctx context.Context
4444+ cancel context.CancelFunc
4545+ testEnv *envtest.Environment
4646+ cfg *rest.Config
4747+ k8sClient client.Client
4848+)
4949+5050+func TestControllers(t *testing.T) {
5151+ RegisterFailHandler(Fail)
5252+5353+ RunSpecs(t, "Controller Suite")
5454+}
5555+5656+var _ = BeforeSuite(func() {
5757+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
5858+5959+ ctx, cancel = context.WithCancel(context.TODO())
6060+6161+ var err error
6262+ err = autoscalingv1alpha1.AddToScheme(scheme.Scheme)
6363+ Expect(err).NotTo(HaveOccurred())
6464+6565+ // +kubebuilder:scaffold:scheme
6666+6767+ By("bootstrapping test environment")
6868+ testEnv = &envtest.Environment{
6969+ CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
7070+ ErrorIfCRDPathMissing: true,
7171+ }
7272+7373+ // Retrieve the first found binary directory to allow running tests from IDEs
7474+ if getFirstFoundEnvTestBinaryDir() != "" {
7575+ testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
7676+ }
7777+7878+ // cfg is defined in this file globally.
7979+ cfg, err = testEnv.Start()
8080+ Expect(err).NotTo(HaveOccurred())
8181+ Expect(cfg).NotTo(BeNil())
8282+8383+ k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
8484+ Expect(err).NotTo(HaveOccurred())
8585+ Expect(k8sClient).NotTo(BeNil())
8686+})
8787+8888+var _ = AfterSuite(func() {
8989+ By("tearing down the test environment")
9090+ cancel()
9191+ err := testEnv.Stop()
9292+ Expect(err).NotTo(HaveOccurred())
9393+})
9494+9595+// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path.
9696+// ENVTEST-based tests depend on specific binaries, usually located in paths set by
9797+// controller-runtime. When running tests directly (e.g., via an IDE) without using
9898+// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
9999+//
100100+// This function streamlines the process by finding the required binaries, similar to
101101+// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are
102102+// properly set up, run 'make setup-envtest' beforehand.
103103+func getFirstFoundEnvTestBinaryDir() string {
104104+ basePath := filepath.Join("..", "..", "bin", "k8s")
105105+ entries, err := os.ReadDir(basePath)
106106+ if err != nil {
107107+ logf.Log.Error(err, "Failed to read directory", "path", basePath)
108108+ return ""
109109+ }
110110+ for _, entry := range entries {
111111+ if entry.IsDir() {
112112+ return filepath.Join(basePath, entry.Name())
113113+ }
114114+ }
115115+ return ""
116116+}