this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Start crd + querying

+181 -22
+26 -10
api/v1alpha1/prometheusinformedscaletarget_types.go
··· 20 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 21 ) 22 22 23 - // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! 24 - // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 23 + // CrossVersionObjectReference contains enough information to let you identify the referred resource. 24 + // borrowed from https://github.com/kubernetes/kubernetes/blob/0e71d2d28f29514e4e55e5a4f3d0e57436fe1f0b/pkg/apis/autoscaling/types.go#L63-L74 25 + type CrossVersionObjectReference struct { 26 + // kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 27 + Kind string `json:"kind"` 28 + 29 + // name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names 30 + Name string `json:"name"` 31 + 32 + // apiVersion is the API version of the referent 33 + // +optional 34 + APIVersion string `json:"apiVersion,omitempty"` 35 + } 25 36 26 37 // PrometheusInformedScaleTargetSpec defines the desired state of PrometheusInformedScaleTarget 27 38 type PrometheusInformedScaleTargetSpec struct { 28 - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster 29 - // Important: Run "make" to regenerate code after modifying this file 30 - // The following markers will use OpenAPI v3 schema to validate the value 31 - // More info: https://book.kubebuilder.io/reference/markers/crd-validation.html 39 + Query string `json:"query"` 40 + ScaleTargetRef CrossVersionObjectReference `json:"scaleTargetRef"` 32 41 33 - // foo is an example field of PrometheusInformedScaleTarget. Edit prometheusinformedscaletarget_types.go to remove/update 42 + // minReplicas is the lower limit for the number of replicas to which the autoscaler 43 + // can scale down. It defaults to 1 pod. minReplicas is allowed to be 0 if the 44 + // alpha feature gate HPAScaleToZero is enabled and at least one Object or External 45 + // metric is configured. Scaling is active as long as at least one metric value is 46 + // available. 34 47 // +optional 35 - Foo *string `json:"foo,omitempty"` 48 + MinReplicas *int32 `json:"minReplicas,omitempty"` 49 + 50 + // maxReplicas is the upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas. 51 + // +required 52 + MaxReplicas int32 `json:"maxReplicas"` 36 53 } 37 54 38 55 // PrometheusInformedScaleTargetStatus defines the observed state of PrometheusInformedScaleTarget. 39 56 type PrometheusInformedScaleTargetStatus struct { 40 - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster 41 - // Important: Run "make" to regenerate code after modifying this file 42 57 } 43 58 44 59 // +kubebuilder:object:root=true 45 60 // +kubebuilder:subresource:status 61 + // +kubebuilder:resource:shortName=pist 46 62 47 63 // PrometheusInformedScaleTarget is the Schema for the prometheusinformedscaletargets API 48 64 type PrometheusInformedScaleTarget struct {
+19 -3
api/v1alpha1/zz_generated.deepcopy.go
··· 25 25 ) 26 26 27 27 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 28 + func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { 29 + *out = *in 30 + } 31 + 32 + // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossVersionObjectReference. 33 + func (in *CrossVersionObjectReference) DeepCopy() *CrossVersionObjectReference { 34 + if in == nil { 35 + return nil 36 + } 37 + out := new(CrossVersionObjectReference) 38 + in.DeepCopyInto(out) 39 + return out 40 + } 41 + 42 + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 28 43 func (in *PrometheusInformedScaleTarget) DeepCopyInto(out *PrometheusInformedScaleTarget) { 29 44 *out = *in 30 45 out.TypeMeta = in.TypeMeta ··· 86 101 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 87 102 func (in *PrometheusInformedScaleTargetSpec) DeepCopyInto(out *PrometheusInformedScaleTargetSpec) { 88 103 *out = *in 89 - if in.Foo != nil { 90 - in, out := &in.Foo, &out.Foo 91 - *out = new(string) 104 + out.ScaleTargetRef = in.ScaleTargetRef 105 + if in.MinReplicas != nil { 106 + in, out := &in.MinReplicas, &out.MinReplicas 107 + *out = new(int32) 92 108 **out = **in 93 109 } 94 110 }
+39 -3
config/crd/bases/autoscaling.kgz.sh_prometheusinformedscaletargets.yaml
··· 11 11 kind: PrometheusInformedScaleTarget 12 12 listKind: PrometheusInformedScaleTargetList 13 13 plural: prometheusinformedscaletargets 14 + shortNames: 15 + - pist 14 16 singular: prometheusinformedscaletarget 15 17 scope: Namespaced 16 18 versions: ··· 40 42 spec: 41 43 description: spec defines the desired state of PrometheusInformedScaleTarget 42 44 properties: 43 - foo: 44 - description: foo is an example field of PrometheusInformedScaleTarget. 45 - Edit prometheusinformedscaletarget_types.go to remove/update 45 + maxReplicas: 46 + description: maxReplicas is the upper limit for the number of pods 47 + that can be set by the autoscaler; cannot be smaller than MinReplicas. 48 + format: int32 49 + type: integer 50 + minReplicas: 51 + description: |- 52 + minReplicas is the lower limit for the number of replicas to which the autoscaler 53 + can scale down. It defaults to 1 pod. minReplicas is allowed to be 0 if the 54 + alpha feature gate HPAScaleToZero is enabled and at least one Object or External 55 + metric is configured. Scaling is active as long as at least one metric value is 56 + available. 57 + format: int32 58 + type: integer 59 + query: 46 60 type: string 61 + scaleTargetRef: 62 + description: |- 63 + CrossVersionObjectReference contains enough information to let you identify the referred resource. 64 + borrowed from https://github.com/kubernetes/kubernetes/blob/0e71d2d28f29514e4e55e5a4f3d0e57436fe1f0b/pkg/apis/autoscaling/types.go#L63-L74 65 + properties: 66 + apiVersion: 67 + description: apiVersion is the API version of the referent 68 + type: string 69 + kind: 70 + description: 'kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 71 + type: string 72 + name: 73 + description: 'name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' 74 + type: string 75 + required: 76 + - kind 77 + - name 78 + type: object 79 + required: 80 + - maxReplicas 81 + - query 82 + - scaleTargetRef 47 83 type: object 48 84 status: 49 85 description: status defines the observed state of PrometheusInformedScaleTarget
+6
config/manager/kustomization.yaml
··· 1 1 resources: 2 2 - manager.yaml 3 + apiVersion: kustomize.config.k8s.io/v1beta1 4 + kind: Kustomization 5 + images: 6 + - name: controller 7 + newName: controller 8 + newTag: latest
+9 -4
config/samples/autoscaling_v1alpha1_prometheusinformedscaletarget.yaml
··· 1 1 apiVersion: autoscaling.kgz.sh/v1alpha1 2 2 kind: PrometheusInformedScaleTarget 3 3 metadata: 4 - labels: 5 - app.kubernetes.io/name: pist 6 - app.kubernetes.io/managed-by: kustomize 7 4 name: prometheusinformedscaletarget-sample 8 5 spec: 9 - # TODO(user): Add fields here 6 + maxReplicas: 128 7 + minReplicas: 2 8 + query: sin(vector(time() * 0.01)) * 100 + 100 9 + # query: prometheus_http_requests_total 10 + # query: '1.4' 11 + scaleTargetRef: 12 + apiVersion: apps/v1 13 + kind: Deployment 14 + name: sleep
+24 -2
internal/controller/prometheusinformedscaletarget_controller.go
··· 18 18 19 19 import ( 20 20 "context" 21 + "fmt" 21 22 23 + apierrors "k8s.io/apimachinery/pkg/api/errors" 22 24 "k8s.io/apimachinery/pkg/runtime" 23 25 ctrl "sigs.k8s.io/controller-runtime" 24 26 "sigs.k8s.io/controller-runtime/pkg/client" 25 27 logf "sigs.k8s.io/controller-runtime/pkg/log" 26 28 27 29 autoscalingv1alpha1 "github.com/kragniz/pist/api/v1alpha1" 30 + "github.com/kragniz/pist/internal/prom" 28 31 ) 29 32 30 33 // PrometheusInformedScaleTargetReconciler reconciles a PrometheusInformedScaleTarget object ··· 47 50 // For more details, check Reconcile and its Result here: 48 51 // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.21.0/pkg/reconcile 49 52 func (r *PrometheusInformedScaleTargetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 50 - _ = logf.FromContext(ctx) 53 + log := logf.FromContext(ctx) 51 54 52 - // TODO(user): your logic here 55 + p := &autoscalingv1alpha1.PrometheusInformedScaleTarget{} 56 + err := r.Get(ctx, req.NamespacedName, p) 57 + if err != nil { 58 + if apierrors.IsNotFound(err) { 59 + // Probably already deleted 60 + return ctrl.Result{}, nil 61 + } 62 + 63 + log.Error(err, "failed to get PrometheusInformedScaleTarget") 64 + return ctrl.Result{}, err 65 + } 66 + 67 + fmt.Printf("Reconciling PrometheusInformedScaleTarget: %s\n", p.Spec.Query) 68 + 69 + result, err := prom.InstantQuery(ctx, p.Spec.Query, 0) 70 + if err != nil { 71 + log.Error(err, "failed to execute prometheus query") 72 + return ctrl.Result{}, err 73 + } 74 + fmt.Printf("query: %v\n", result) 53 75 54 76 return ctrl.Result{}, nil 55 77 }
+58
internal/prom/prom.go
··· 1 + package prom 2 + 3 + // Package prom contains functions to perform simple prometheus queries 4 + 5 + import ( 6 + "context" 7 + "fmt" 8 + "math" 9 + "time" 10 + 11 + "github.com/prometheus/client_golang/api" 12 + v1 "github.com/prometheus/client_golang/api/prometheus/v1" 13 + "github.com/prometheus/common/model" 14 + ) 15 + 16 + func InstantQuery(ctx context.Context, query string, timeout time.Duration) (int, error) { 17 + if timeout == 0 { 18 + timeout = 60 * time.Second 19 + } 20 + 21 + client, err := api.NewClient(api.Config{ 22 + Address: "http://localhost:9090", 23 + }) 24 + if err != nil { 25 + return 0, fmt.Errorf("failed to create prometheus client: %w", err) 26 + } 27 + 28 + promAPI := v1.NewAPI(client) 29 + ctx, cancel := context.WithTimeout(ctx, timeout) 30 + defer cancel() 31 + 32 + result, warnings, err := promAPI.Query(ctx, query, time.Now()) 33 + if err != nil { 34 + return 0, fmt.Errorf("failed to execute prometheus query: %w", err) 35 + } 36 + if len(warnings) > 0 { 37 + fmt.Printf("prometheus query warnings: %v\n", warnings) 38 + } 39 + 40 + value := 0 41 + 42 + switch result.Type() { 43 + case model.ValVector: 44 + // take the avg for now, TODO add option for min max etc 45 + s := 0.0 46 + for _, sample := range result.(model.Vector) { 47 + s += float64(sample.Value) 48 + } 49 + n := len(result.(model.Vector)) 50 + value = int(math.Round(s / float64(n))) 51 + case model.ValScalar: 52 + value = int(math.Round(float64(result.(*model.Scalar).Value))) 53 + default: 54 + return 0, fmt.Errorf("wrong return result from query: %v", result.Type()) 55 + } 56 + 57 + return value, nil 58 + }