Skip to content

Commit 2bf28de

Browse files
authored
Add scaling support (#28)
1 parent 6dae435 commit 2bf28de

37 files changed

Lines changed: 555 additions & 74 deletions

api/v1alpha1/asset_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,15 @@ type AssetStatus struct {
3333
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
3434
// Important: Run "make" to regenerate code after modifying this file
3535
Conditions []metav1.Condition `json:"conditions,omitempty"`
36+
// Replicas is the number of actual replicas of the asset deployment
37+
Replicas int32 `json:"replicas,omitempty"`
38+
// Selector is the label selector for pods corresponding to this asset deployment
39+
Selector string `json:"selector,omitempty"`
3640
}
3741

3842
//+kubebuilder:object:root=true
3943
//+kubebuilder:subresource:status
44+
//+kubebuilder:subresource:scale:specpath=.spec.deploymentOverrides.replicas,statuspath=.status.replicas,selectorpath=.status.selector
4045

4146
// Asset is the Schema for the assets API
4247
type Asset struct {

api/v1alpha1/propagation_types.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,19 @@ type PropagationSpec struct {
3434
// PropagationStatus defines the observed state of Propagation
3535
type PropagationStatus struct {
3636
Conditions []metav1.Condition `json:"conditions,omitempty"`
37+
// Replicas is the number of actual replicas of the propagation deployment
38+
Replicas int32 `json:"replicas,omitempty"`
39+
// Selector is the label selector for pods corresponding to this propagation deployment
40+
Selector string `json:"selector,omitempty"`
3741
}
3842

3943
//+kubebuilder:object:root=true
4044
//+kubebuilder:subresource:status
45+
//+kubebuilder:subresource:scale:specpath=.spec.deploymentOverrides.replicas,statuspath=.status.replicas,selectorpath=.status.selector
46+
//+kubebuilder:printcolumn:name="Desired",type=integer,JSONPath=`.spec.deploymentOverrides.replicas`,description="Desired number of replicas"
47+
//+kubebuilder:printcolumn:name="Current",type=integer,JSONPath=`.status.replicas`,description="Current number of replicas"
48+
//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Reconciled")].status`,description="Ready status"
49+
//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
4150

4251
// Propagation is the Schema for the propagations API
4352
type Propagation struct {

api/v1alpha1/subtreevalidator_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@ type SubtreeValidatorStatus struct {
3131
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
3232
// Important: Run "make" to regenerate code after modifying this file
3333
Conditions []metav1.Condition `json:"conditions,omitempty"`
34+
// Replicas is the number of actual replicas of the subtreevalidator deployment
35+
Replicas int32 `json:"replicas,omitempty"`
36+
// Selector is the label selector for pods corresponding to this subtreevalidator deployment
37+
Selector string `json:"selector,omitempty"`
3438
}
3539

3640
//+kubebuilder:object:root=true
3741
//+kubebuilder:subresource:status
42+
//+kubebuilder:subresource:scale:specpath=.spec.deploymentOverrides.replicas,statuspath=.status.replicas,selectorpath=.status.selector
3843

3944
// SubtreeValidator is the Schema for the subtreevalidators API
4045
type SubtreeValidator struct {

cmd/main.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ import (
2525
"sort"
2626
"strings"
2727

28+
teranodev1alpha1 "github.com/bsv-blockchain/teranode-operator/api/v1alpha1"
29+
appsv1 "k8s.io/api/apps/v1"
30+
scalev1 "k8s.io/api/autoscaling/v1"
31+
corev1 "k8s.io/api/core/v1"
32+
networkingv1 "k8s.io/api/networking/v1"
2833
"k8s.io/apimachinery/pkg/runtime"
29-
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
30-
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3134

3235
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
3336
// to ensure that exec-entrypoint and run can make use of them.
@@ -39,7 +42,6 @@ import (
3942
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4043
"sigs.k8s.io/controller-runtime/pkg/webhook"
4144

42-
teranodev1alpha1 "github.com/bsv-blockchain/teranode-operator/api/v1alpha1"
4345
"github.com/bsv-blockchain/teranode-operator/internal/controller"
4446
)
4547

@@ -55,13 +57,6 @@ const (
5557
CreateControllerError = "unable to create controller"
5658
)
5759

58-
func init() {
59-
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
60-
61-
utilruntime.Must(teranodev1alpha1.AddToScheme(scheme))
62-
//+kubebuilder:scaffold:scheme
63-
}
64-
6560
//nolint:gocognit,gocyclo // Main function complexity is acceptable for initialization
6661
func main() {
6762
var metricsAddr string
@@ -70,7 +65,7 @@ func main() {
7065
var secureMetrics bool
7166
var enableHTTP2 bool
7267
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
73-
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
68+
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8181", "The address the probe endpoint binds to.")
7469
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
7570
"Enable leader election for controller manager. "+
7671
"Enabling this will ensure there is only one active controller manager.")
@@ -84,6 +79,33 @@ func main() {
8479
opts.BindFlags(flag.CommandLine)
8580
flag.Parse()
8681

82+
if err := scalev1.AddToScheme(scheme); err != nil {
83+
setupLog.Error(err, "unable to add autoscaling/v1 scheme")
84+
os.Exit(1)
85+
}
86+
87+
if err := teranodev1alpha1.AddToScheme(scheme); err != nil {
88+
setupLog.Error(err, "unable to add v1alpha1 scheme")
89+
os.Exit(1)
90+
}
91+
92+
if err := appsv1.AddToScheme(scheme); err != nil {
93+
setupLog.Error(err, "unable to add apps/v1 scheme")
94+
os.Exit(1)
95+
}
96+
97+
if err := corev1.AddToScheme(scheme); err != nil {
98+
setupLog.Error(err, "unable to add core/v1 scheme")
99+
os.Exit(1)
100+
}
101+
102+
if err := networkingv1.AddToScheme(scheme); err != nil {
103+
setupLog.Error(err, "unable to add networking/v1 scheme")
104+
os.Exit(1)
105+
}
106+
107+
//+kubebuilder:scaffold:scheme
108+
87109
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
88110

89111
// if the enable-http2 flag is false (the default), http/2 should be disabled

config/crd/bases/teranode.bsvblockchain.org_assets.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3820,9 +3820,22 @@ spec:
38203820
- type
38213821
type: object
38223822
type: array
3823+
replicas:
3824+
description: Replicas is the number of actual replicas of the asset
3825+
deployment
3826+
format: int32
3827+
type: integer
3828+
selector:
3829+
description: Selector is the label selector for pods corresponding
3830+
to this asset deployment
3831+
type: string
38233832
type: object
38243833
type: object
38253834
served: true
38263835
storage: true
38273836
subresources:
3837+
scale:
3838+
labelSelectorPath: .status.selector
3839+
specReplicasPath: .spec.deploymentOverrides.replicas
3840+
statusReplicasPath: .status.replicas
38283841
status: {}

config/crd/bases/teranode.bsvblockchain.org_propagations.yaml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,23 @@ spec:
1414
singular: propagation
1515
scope: Namespaced
1616
versions:
17-
- name: v1alpha1
17+
- additionalPrinterColumns:
18+
- description: Desired number of replicas
19+
jsonPath: .spec.deploymentOverrides.replicas
20+
name: Desired
21+
type: integer
22+
- description: Current number of replicas
23+
jsonPath: .status.replicas
24+
name: Current
25+
type: integer
26+
- description: Ready status
27+
jsonPath: .status.conditions[?(@.type=="Reconciled")].status
28+
name: Ready
29+
type: string
30+
- jsonPath: .metadata.creationTimestamp
31+
name: Age
32+
type: date
33+
name: v1alpha1
1834
schema:
1935
openAPIV3Schema:
2036
description: Propagation is the Schema for the propagations API
@@ -3849,9 +3865,22 @@ spec:
38493865
- type
38503866
type: object
38513867
type: array
3868+
replicas:
3869+
description: Replicas is the number of actual replicas of the propagation
3870+
deployment
3871+
format: int32
3872+
type: integer
3873+
selector:
3874+
description: Selector is the label selector for pods corresponding
3875+
to this propagation deployment
3876+
type: string
38523877
type: object
38533878
type: object
38543879
served: true
38553880
storage: true
38563881
subresources:
3882+
scale:
3883+
labelSelectorPath: .status.selector
3884+
specReplicasPath: .spec.deploymentOverrides.replicas
3885+
statusReplicasPath: .status.replicas
38573886
status: {}

config/crd/bases/teranode.bsvblockchain.org_subtreevalidators.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3782,9 +3782,22 @@ spec:
37823782
- type
37833783
type: object
37843784
type: array
3785+
replicas:
3786+
description: Replicas is the number of actual replicas of the subtreevalidator
3787+
deployment
3788+
format: int32
3789+
type: integer
3790+
selector:
3791+
description: Selector is the label selector for pods corresponding
3792+
to this subtreevalidator deployment
3793+
type: string
37853794
type: object
37863795
type: object
37873796
served: true
37883797
storage: true
37893798
subresources:
3799+
scale:
3800+
labelSelectorPath: .status.selector
3801+
specReplicasPath: .spec.deploymentOverrides.replicas
3802+
statusReplicasPath: .status.replicas
37903803
status: {}

config/rbac/teranode_service_runner_service_account.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ apiVersion: v1
22
kind: ServiceAccount
33
metadata:
44
name: service-runner
5-
namespace: system
5+
namespace: system

config/samples/teranode_v1alpha1_propagation.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@ metadata:
99
app.kubernetes.io/created-by: teranode-operator
1010
name: propagation-sample
1111
spec:
12-
# TODO(user): Add fields here
1312
resources:
1413
requests:
1514
cpu: 1
1615
memory: 1Gi
1716
limits:
1817
memory: 2Gi
1918
imagePullPolicy: Always
19+
replicas: 1
20+
deploymentOverrides:
21+
replicas: 1
22+
resources:
23+
requests:
24+
cpu: 1
25+
memory: 1Gi
26+
limits:
27+
memory: 2Gi
28+
imagePullPolicy: Always

internal/controller/asset_controller.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
networkingv1 "k8s.io/api/networking/v1"
2727
apimeta "k8s.io/apimachinery/pkg/api/meta"
2828
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
"sigs.k8s.io/controller-runtime/pkg/predicate"
30+
2931
"k8s.io/apimachinery/pkg/runtime"
3032
"k8s.io/apimachinery/pkg/types"
3133
ctrl "sigs.k8s.io/controller-runtime"
@@ -77,6 +79,17 @@ func (r *AssetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
7779
r.ReconcileHTTPSIngress,
7880
)
7981

82+
// Update scale status (replicas and selector) from deployment
83+
deployment := &appsv1.Deployment{}
84+
if err := r.Get(ctx, types.NamespacedName{
85+
Name: AssetDeploymentName,
86+
Namespace: asset.Namespace,
87+
}, deployment); err == nil {
88+
replicas, selector := utils.GetScaleStatusFromDeployment(deployment)
89+
asset.Status.Replicas = replicas
90+
asset.Status.Selector = selector
91+
}
92+
8093
if err != nil {
8194
apimeta.SetStatusCondition(&asset.Status.Conditions,
8295
metav1.Condition{
@@ -103,6 +116,14 @@ func (r *AssetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
103116
}
104117

105118
err = r.Client.Status().Update(ctx, &asset)
119+
120+
if asset.Spec.DeploymentOverrides != nil && asset.Spec.DeploymentOverrides.Replicas != nil {
121+
if asset.Status.Replicas != *asset.Spec.DeploymentOverrides.Replicas {
122+
r.Log.Info("requeuing to monitor replica status", "status", asset.Status.Replicas, "spec", asset.Spec.DeploymentOverrides.Replicas)
123+
return ctrl.Result{RequeueAfter: time.Second}, nil
124+
}
125+
}
126+
106127
return ctrl.Result{Requeue: false, RequeueAfter: 0}, err
107128
}
108129

@@ -113,5 +134,6 @@ func (r *AssetReconciler) SetupWithManager(mgr ctrl.Manager) error {
113134
Owns(&appsv1.Deployment{}).
114135
Owns(&networkingv1.Ingress{}).
115136
Owns(&corev1.Service{}).
137+
WithEventFilter(predicate.GenerationChangedPredicate{}).
116138
Complete(r)
117139
}

0 commit comments

Comments
 (0)