Skip to content

Commit cac4460

Browse files
committed
feat: implement mvp controller
Signed-off-by: Bence Csati <[email protected]>
1 parent 4b0d848 commit cac4460

File tree

9 files changed

+440
-15
lines changed

9 files changed

+440
-15
lines changed

charts/logging-operator/charts/logging-operator-crds/templates/logging.banzaicloud.io_axosyslogs.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ spec:
3636
type: object
3737
spec:
3838
properties:
39+
configReloadImage:
40+
properties:
41+
repository:
42+
type: string
43+
tag:
44+
type: string
45+
type: object
3946
destinations:
4047
items:
4148
properties:
@@ -45,6 +52,13 @@ spec:
4552
type: string
4653
type: object
4754
type: array
55+
image:
56+
properties:
57+
repository:
58+
type: string
59+
tag:
60+
type: string
61+
type: object
4862
logPaths:
4963
items:
5064
properties:

charts/logging-operator/crds/logging.banzaicloud.io_axosyslogs.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ spec:
3333
type: object
3434
spec:
3535
properties:
36+
configReloadImage:
37+
properties:
38+
repository:
39+
type: string
40+
tag:
41+
type: string
42+
type: object
3643
destinations:
3744
items:
3845
properties:
@@ -42,6 +49,13 @@ spec:
4249
type: string
4350
type: object
4451
type: array
52+
image:
53+
properties:
54+
repository:
55+
type: string
56+
tag:
57+
type: string
58+
type: object
4559
logPaths:
4660
items:
4761
properties:

config/crd/bases/logging.banzaicloud.io_axosyslogs.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ spec:
3333
type: object
3434
spec:
3535
properties:
36+
configReloadImage:
37+
properties:
38+
repository:
39+
type: string
40+
tag:
41+
type: string
42+
type: object
3643
destinations:
3744
items:
3845
properties:
@@ -42,6 +49,13 @@ spec:
4249
type: string
4350
type: object
4451
type: array
52+
image:
53+
properties:
54+
repository:
55+
type: string
56+
tag:
57+
type: string
58+
type: object
4559
logPaths:
4660
items:
4761
properties:

controllers/logging/axosyslog_controller.go

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,55 +16,124 @@ package controllers
1616

1717
import (
1818
"context"
19+
"fmt"
20+
"reflect"
21+
"runtime"
1922

23+
"emperror.dev/errors"
24+
"github.com/cisco-open/operator-tools/pkg/reconciler"
2025
"github.com/go-logr/logr"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2127
ctrl "sigs.k8s.io/controller-runtime"
2228
"sigs.k8s.io/controller-runtime/pkg/client"
2329

24-
"github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1"
30+
"github.com/kube-logging/logging-operator/pkg/resources"
31+
axosyslogresources "github.com/kube-logging/logging-operator/pkg/resources/axosyslog"
32+
v1beta1 "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1"
2533
)
2634

2735
// NewAxoSyslogReconciler creates a new AxoSyslogReconciler instance
28-
func NewAxoSyslogReconciler(client client.Client, log logr.Logger) *AxoSyslogReconciler {
36+
func NewAxoSyslogReconciler(client client.Client, log logr.Logger, opts reconciler.ReconcilerOpts) *AxoSyslogReconciler {
2937
return &AxoSyslogReconciler{
30-
Client: client,
31-
Log: log,
38+
Client: client,
39+
GenericResourceReconciler: reconciler.NewGenericReconciler(client, log, opts),
40+
Log: log,
3241
}
3342
}
3443

3544
type AxoSyslogReconciler struct {
3645
client.Client
46+
*reconciler.GenericResourceReconciler
3747
Log logr.Logger
3848
}
3949

4050
// +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=axosyslogs,verbs=get;list;watch;create;update;patch;delete
4151
// +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=axosyslogs/status,verbs=get;update;patch
42-
// +kubebuilder:rbac:groups="",resources=configmaps;secrets,verbs=get;list;watch;create;update;patch;delete
4352
// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete
4453
// +kubebuilder:rbac:groups="",resources=services;persistentvolumeclaims;serviceaccounts;pods,verbs=get;list;watch;create;update;patch;delete
45-
// +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles;clusterrolebindings;roles;rolebindings,verbs=get;list;watch;create;update;patch;delete
54+
// +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles;rolebindings,verbs=get;list;watch;create;update;patch;delete
4655

47-
// Reconciles axosyslog resource
56+
// Reconcile implements the reconciliation logic for AxoSyslog resources
4857
func (r *AxoSyslogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
49-
log := r.Log.WithValues("axosyslog", req.NamespacedName)
58+
r.Log.V(1).Info("Reconciling AxoSyslog")
5059

51-
log.V(1).Info("Reconciling AxoSyslog")
52-
53-
var axosyslog v1beta1.AxoSyslog
54-
if err := r.Get(ctx, req.NamespacedName, &axosyslog); err != nil {
60+
var axoSyslog v1beta1.AxoSyslog
61+
if err := r.Get(ctx, req.NamespacedName, &axoSyslog); err != nil {
5562
return ctrl.Result{}, client.IgnoreNotFound(err)
5663
}
5764

58-
if err := axosyslog.SetDefaults(); err != nil {
65+
log := r.Log.WithValues("axosyslog", fmt.Sprintf("%s/%s", axoSyslog.Namespace, axoSyslog.Name))
66+
67+
if err := axoSyslog.SetDefaults(); err != nil {
68+
return ctrl.Result{}, errors.WrapIf(err, "failed to set defaults")
69+
}
70+
71+
// TODO: config-check ?
72+
73+
if result, err := r.reconcileWorkloadResources(log, &axoSyslog); err != nil {
5974
return ctrl.Result{}, err
75+
} else if result != nil {
76+
return *result, nil
6077
}
6178

6279
return ctrl.Result{}, nil
6380
}
6481

82+
// reconcileWorkloadResources handles resources related to AxoSyslog and requires it's spec
83+
func (r *AxoSyslogReconciler) reconcileWorkloadResources(log logr.Logger, axoSyslog *v1beta1.AxoSyslog) (*ctrl.Result, error) {
84+
resourceBuilders := []resources.ResourceWithSpec{
85+
axosyslogresources.StatefulSet,
86+
axosyslogresources.Service,
87+
axosyslogresources.HeadlessService,
88+
// TODO: service-metrics & buffer-metrics ?
89+
// axosyslogresources.ServiceMetrics,
90+
// axosyslogresources.ServiceBufferMetrics,
91+
}
92+
93+
for _, buildObject := range resourceBuilders {
94+
builderName := getFunctionName(buildObject)
95+
log.V(2).Info("Processing resource", "builder", builderName)
96+
97+
o, state, err := buildObject(axoSyslog)
98+
if err != nil {
99+
return nil, errors.WrapIff(err, "failed to build object with %s", builderName)
100+
}
101+
if o == nil {
102+
return nil, errors.Errorf("reconcile error: %s returned nil object", builderName)
103+
}
104+
105+
metaObj, ok := o.(metav1.Object)
106+
if !ok {
107+
return nil, errors.Errorf("reconcile error: %s returned non-metav1.Object", builderName)
108+
}
109+
110+
if metaObj.GetNamespace() == "" {
111+
return nil, errors.Errorf("reconcile error: %s returned resource without namespace set", builderName)
112+
}
113+
114+
if err := ctrl.SetControllerReference(axoSyslog, metaObj, r.Scheme()); err != nil {
115+
return nil, errors.WrapIff(err, "failed to set controller reference for %s", metaObj.GetName())
116+
}
117+
118+
result, err := r.ReconcileResource(o, state)
119+
if err != nil {
120+
return nil, errors.WrapIff(err, "failed to reconcile resource %s/%s", metaObj.GetNamespace(), metaObj.GetName())
121+
}
122+
if result != nil {
123+
return result, nil
124+
}
125+
}
126+
127+
return nil, nil
128+
}
129+
65130
func SetupAxoSyslogWithManager(mgr ctrl.Manager, logger logr.Logger) error {
66131
return ctrl.NewControllerManagedBy(mgr).
67132
For(&v1beta1.AxoSyslog{}).
68-
Named("AxoSyslogController").
69-
Complete(NewAxoSyslogReconciler(mgr.GetClient(), logger))
133+
Named("axosyslog").
134+
Complete(NewAxoSyslogReconciler(mgr.GetClient(), logger, reconciler.ReconcilerOpts{}))
135+
}
136+
137+
func getFunctionName(i any) string {
138+
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
70139
}

docs/configuration/crds/v1beta1/axosyslog_types.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,21 @@ AxoSyslog is the Schema for the AxoSyslogs API
1919

2020
AxoSyslogSpec defines the desired state of AxoSyslog
2121

22+
### configReloadImage (*BasicImageSpec, optional) {#axosyslogspec-configreloadimage}
23+
24+
ConfigReloadImage is the image specification for the config reload
25+
26+
2227
### destinations ([]Destination, optional) {#axosyslogspec-destinations}
2328

2429
Destinations is a list of destinations to be rendered in the AxoSyslog configuration
2530

2631

32+
### image (*BasicImageSpec, optional) {#axosyslogspec-image}
33+
34+
Image is the image specification for AxoSyslog
35+
36+
2737
### logPaths ([]LogPath, optional) {#axosyslogspec-logpaths}
2838

2939
LogPaths is a list of log paths to be rendered in the AxoSyslog configuration

pkg/resources/axosyslog/service.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright © 2025 Kube logging authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package axosyslog
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/cisco-open/operator-tools/pkg/reconciler"
21+
corev1 "k8s.io/api/core/v1"
22+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
"k8s.io/apimachinery/pkg/runtime"
24+
"k8s.io/apimachinery/pkg/util/intstr"
25+
26+
"github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1"
27+
)
28+
29+
func Service(object any) (runtime.Object, reconciler.DesiredState, error) {
30+
axoSyslog, ok := object.(*v1beta1.AxoSyslog)
31+
if !ok {
32+
return nil, reconciler.StateAbsent, fmt.Errorf("expected *v1beta1.AxoSyslog, got %T", axoSyslog)
33+
}
34+
35+
service := &corev1.Service{
36+
ObjectMeta: metav1.ObjectMeta{
37+
Name: commonAxoSyslogObjectValue,
38+
Namespace: axoSyslog.Namespace,
39+
Labels: map[string]string{
40+
LabelAppName: commonAxoSyslogObjectValue,
41+
LabelAppComponent: commonAxoSyslogObjectValue,
42+
},
43+
},
44+
Spec: corev1.ServiceSpec{
45+
Ports: []corev1.ServicePort{
46+
{
47+
Name: "tcp-axosyslog",
48+
Protocol: corev1.ProtocolTCP,
49+
Port: 601,
50+
TargetPort: intstr.IntOrString{IntVal: 601},
51+
},
52+
{
53+
Name: "udp-axosyslog",
54+
Protocol: corev1.ProtocolUDP,
55+
Port: 514,
56+
TargetPort: intstr.IntOrString{IntVal: 514},
57+
},
58+
},
59+
Selector: map[string]string{
60+
LabelAppName: commonAxoSyslogObjectValue,
61+
LabelAppComponent: commonAxoSyslogObjectValue,
62+
},
63+
Type: corev1.ServiceTypeClusterIP,
64+
},
65+
}
66+
67+
beforeUpdateHook := reconciler.DesiredStateHook(func(current runtime.Object) error {
68+
if s, ok := current.(*corev1.Service); ok {
69+
service.Spec.ClusterIP = s.Spec.ClusterIP
70+
} else {
71+
return fmt.Errorf("failed to cast service object %+v", current)
72+
}
73+
return nil
74+
})
75+
76+
return service, beforeUpdateHook, nil
77+
}
78+
79+
func HeadlessService(object any) (runtime.Object, reconciler.DesiredState, error) {
80+
axoSyslog, ok := object.(*v1beta1.AxoSyslog)
81+
if !ok {
82+
return nil, reconciler.StateAbsent, fmt.Errorf("expected *v1beta1.AxoSyslog, got %T", axoSyslog)
83+
}
84+
85+
return &corev1.Service{
86+
ObjectMeta: metav1.ObjectMeta{
87+
Name: commonAxoSyslogObjectValue + "-headless",
88+
Namespace: axoSyslog.Namespace,
89+
Labels: map[string]string{
90+
LabelAppName: commonAxoSyslogObjectValue,
91+
LabelAppComponent: commonAxoSyslogObjectValue,
92+
},
93+
},
94+
Spec: corev1.ServiceSpec{
95+
Ports: []corev1.ServicePort{
96+
{
97+
Name: "tcp-axosyslog",
98+
Protocol: corev1.ProtocolTCP,
99+
Port: 601,
100+
TargetPort: intstr.IntOrString{IntVal: 601},
101+
},
102+
{
103+
Name: "udp-axosyslog",
104+
Protocol: corev1.ProtocolUDP,
105+
Port: 514,
106+
TargetPort: intstr.IntOrString{IntVal: 514},
107+
},
108+
},
109+
Selector: map[string]string{
110+
LabelAppName: commonAxoSyslogObjectValue,
111+
LabelAppComponent: commonAxoSyslogObjectValue,
112+
},
113+
Type: corev1.ServiceTypeClusterIP,
114+
ClusterIP: corev1.ClusterIPNone,
115+
},
116+
}, reconciler.StatePresent, nil
117+
}
118+
119+
func ServiceMetrics(object any) (runtime.Object, reconciler.DesiredState, error) {
120+
// TODO: Implement metrics service
121+
return &corev1.Service{}, reconciler.StateAbsent, nil
122+
}
123+
124+
func ServiceBufferMetrics(object any) (runtime.Object, reconciler.DesiredState, error) {
125+
// TODO: Implement buffer metrics service
126+
return &corev1.Service{}, reconciler.StateAbsent, nil
127+
}

0 commit comments

Comments
 (0)