Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apis/v1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ var (
)

func init() {
SchemeBuilder.Register(&ObjectBucket{}, &XObjectBucket{})
SchemeBuilder.Register(&ObjectBucket{}, &XObjectBucket{}, &VPA{}, &VPAList{})
}
45 changes: 45 additions & 0 deletions apis/v1/vpa_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package v1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.spec.selector
// +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".spec.replicas"
// +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.replicas"

// VPA is a simple Custom Resource Definition with scale subresource support
type VPA struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec VPASpec `json:"spec"`
Status VPAStatus `json:"status,omitempty"`
}

// VPASpec defines the desired state of VPA
type VPASpec struct {
// Replicas is the desired number of replicas
// +kubebuilder:default=1
Replicas int32 `json:"replicas,omitempty"`
// Selector is the label selector for pods (used by scale subresource)
// +optional
Selector string `json:"selector,omitempty"`
}

// VPAStatus reflects the observed state of VPA
type VPAStatus struct {
// Replicas is the actual number of replicas
Replicas int32 `json:"replicas,omitempty"`
}

// +kubebuilder:object:root=true

// VPAList contains a list of VPA
type VPAList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []VPA `json:"items"`
}
89 changes: 89 additions & 0 deletions apis/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 0 additions & 9 deletions config/controller/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,9 @@ rules:
- xvshnpostgresqls/status
- xvshnredis
- xvshnredis/status
- xobjectbuckets
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- apiextensions.crossplane.io
resources:
- compositeresourcedefinitions
verbs:
- get
- list
- watch
78 changes: 78 additions & 0 deletions crds/appcat.vshn.io_vpas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.5
name: vpas.appcat.vshn.io
spec:
group: appcat.vshn.io
names:
kind: VPA
listKind: VPAList
plural: vpas
singular: vpa
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.replicas
name: Replicas
type: integer
- jsonPath: .status.replicas
name: Ready
type: integer
name: v1
schema:
openAPIV3Schema:
description: VPA is a simple Custom Resource Definition with scale subresource
support
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: VPASpec defines the desired state of VPA
properties:
replicas:
default: 1
description: Replicas is the desired number of replicas
format: int32
type: integer
selector:
description: Selector is the label selector for pods (used by scale
subresource)
type: string
type: object
status:
description: VPAStatus reflects the observed state of VPA
properties:
replicas:
description: Replicas is the actual number of replicas
format: int32
type: integer
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
scale:
labelSelectorPath: .spec.selector
specReplicasPath: .spec.replicas
statusReplicasPath: .status.replicas
status: {}
77 changes: 77 additions & 0 deletions pkg/comp-functions/functions/common/vpa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package common

import (
"context"
"fmt"

fnproto "github.com/crossplane/function-sdk-go/proto/v1"
appcatv1 "github.com/vshn/appcat/v4/apis/v1"
"github.com/vshn/appcat/v4/pkg/comp-functions/runtime"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// AddVPAConfig creates a VPA CR and a VerticalPodAutoscaler that references it
func AddVPAConfig[T client.Object](ctx context.Context, obj T, svc *runtime.ServiceRuntime) *fnproto.Result {
log := svc.Log

err := svc.GetObservedComposite(obj)
if err != nil {
return runtime.NewFatalResult(fmt.Errorf("can't get composite: %w", err))
}

comp := obj.DeepCopyObject().(Composite)

log.Info("Creating VPA configuration", "service", comp.GetName())

// Create the VPA CR
vpaCR := &appcatv1.VPA{
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName() + "-vpa",
Namespace: comp.GetInstanceNamespace(),
Labels: comp.GetLabels(),
},
Spec: appcatv1.VPASpec{
Replicas: int32(comp.GetInstances()),
Selector: fmt.Sprintf("cnpg.io/cluster=%s-cluster", comp.GetName()),
},
}

err = svc.SetDesiredKubeObject(vpaCR, comp.GetName()+"-vpa-cr", runtime.KubeOptionAllowDeletion)
if err != nil {
return runtime.NewFatalResult(fmt.Errorf("could not set desired VPA CR: %w", err))
}

// Create the VerticalPodAutoscaler using unstructured
vpaAutoscaler := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "autoscaling.k8s.io/v1",
"kind": "VerticalPodAutoscaler",
"metadata": map[string]interface{}{
"name": comp.GetName() + "-vpa-autoscaler",
"namespace": comp.GetInstanceNamespace(),
"labels": comp.GetLabels(),
},
"spec": map[string]interface{}{
"targetRef": map[string]interface{}{
"apiVersion": "appcat.vshn.io/v1",
"kind": "VPA",
"name": comp.GetName() + "-vpa",
},
"updatePolicy": map[string]interface{}{
"updateMode": "Auto",
},
},
},
}

err = svc.SetDesiredKubeObject(vpaAutoscaler, comp.GetName()+"-vpa-autoscaler", runtime.KubeOptionAllowDeletion)
if err != nil {
return runtime.NewFatalResult(fmt.Errorf("could not set desired VPA autoscaler: %w", err))
}

log.Info("VPA configuration created", "vpaCR", vpaCR.Name, "vpaAutoscaler", vpaAutoscaler.GetName())

return runtime.NewNormalResult("VPA and VerticalPodAutoscaler created")
}
4 changes: 4 additions & 0 deletions pkg/comp-functions/functions/vshnpostgrescnpg/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ func init() {
Name: "billing",
Execute: AddBilling,
},
{
Name: "vpa",
Execute: common.AddVPAConfig[*vshnv1.VSHNPostgreSQL],
},
},
})
}
Loading