Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add k8s events logging to alloy #263

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b276673
add k8s events logging to alloy
QuantumEnigmaa Nov 12, 2024
d1ecc0e
changelog
QuantumEnigmaa Nov 12, 2024
73c3a71
create the events-logger resource : either alloy or grafana-agent
QuantumEnigmaa Nov 14, 2024
c39115a
handle secret for authentication
QuantumEnigmaa Nov 14, 2024
3cfb909
merge with main and resolve conflicts
QuantumEnigmaa Nov 14, 2024
33cce97
fix alloy config property name
QuantumEnigmaa Nov 14, 2024
dedd9ad
merge with main
QuantumEnigmaa Nov 18, 2024
f49f6f3
merge with main
QuantumEnigmaa Nov 18, 2024
2e6c67f
merge with main
QuantumEnigmaa Nov 18, 2024
f09f504
fix build errors
QuantumEnigmaa Nov 18, 2024
9a8454c
rename k8s-events-config package to events-logger-config
QuantumEnigmaa Nov 19, 2024
a62b968
Apply suggestions from code review
QuantumEnigmaa Nov 19, 2024
8e78389
fix error log
QuantumEnigmaa Nov 19, 2024
6776f50
return correct configmap name depending on the events logger
QuantumEnigmaa Nov 19, 2024
27f1aef
return correct secret name depending on the events logger
QuantumEnigmaa Nov 19, 2024
83c572b
add scrapedNamespaces to alloy config create related function in common
QuantumEnigmaa Nov 19, 2024
ab44bc4
add tls config for alloy
QuantumEnigmaa Nov 19, 2024
ad0e906
fix formating in grafana-agent template
QuantumEnigmaa Nov 19, 2024
1469dff
hardcode controller.type and controller.replicas in alloyEvents template
QuantumEnigmaa Nov 19, 2024
25c8cb4
remove unused observabilityBundleVersion parameters and variable in e…
QuantumEnigmaa Nov 19, 2024
e0cb4a7
remove grafanaAgentSecretName and eventsLoggerSecretName from securit…
QuantumEnigmaa Nov 19, 2024
aa6917a
rename variables in events-logger-config's reconciler to a neutral name
QuantumEnigmaa Nov 19, 2024
049d2cc
make several functions private
QuantumEnigmaa Nov 19, 2024
ec83211
hardcode several fields in grafana-agent config template
QuantumEnigmaa Nov 19, 2024
ad971d0
rename comments and logs in agents-toggle's reconciler
QuantumEnigmaa Nov 19, 2024
194d1cc
enable events logger in main.go
QuantumEnigmaa Nov 20, 2024
b3e196e
fix formating in events-logger templates
QuantumEnigmaa Nov 20, 2024
cdc361c
remove unused field in alloy generateAlloyConfig
QuantumEnigmaa Nov 20, 2024
df3a66e
fix alloy-events secret name
QuantumEnigmaa Nov 20, 2024
5d04402
merge with main
QuantumEnigmaa Nov 20, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add kubernetes events logging in Alloy.
- Add support for Private CAs in alloy logs.

### Changed
Expand Down
1 change: 1 addition & 0 deletions helm/logging-operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ spec:
- -insecure-ca={{ .Values.managementCluster.insecureCA }}
- -installation-name={{ .Values.managementCluster.name }}
- -logging-agent={{ .Values.loggingOperator.loggingAgent }}
- -events-logger={{ .Values.loggingOperator.eventsLogger }}
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
- -default-namespaces={{ .Values.loggingOperator.defaultNamespaces }}
livenessProbe:
httpGet:
Expand Down
1 change: 1 addition & 0 deletions helm/logging-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ loggingOperator:
vintageMode: true
loggingEnabled: true
loggingAgent: alloy
eventsLogger: alloy

managementCluster:
name: unknown
Expand Down
17 changes: 10 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ import (
loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
loggingreconciler "github.com/giantswarm/logging-operator/pkg/logging-reconciler"
"github.com/giantswarm/logging-operator/pkg/reconciler"
grafanaagentconfig "github.com/giantswarm/logging-operator/pkg/resource/grafana-agent-config"
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
grafanaagentsecret "github.com/giantswarm/logging-operator/pkg/resource/grafana-agent-secret"
eventsloggersecret "github.com/giantswarm/logging-operator/pkg/resource/events-logger-secret"
grafanadatasource "github.com/giantswarm/logging-operator/pkg/resource/grafana-datasource"
k8seventsconfig "github.com/giantswarm/logging-operator/pkg/resource/k8s-events-config"
loggingagentstoggle "github.com/giantswarm/logging-operator/pkg/resource/logging-agents-toggle"
loggingconfig "github.com/giantswarm/logging-operator/pkg/resource/logging-config"
loggingcredentials "github.com/giantswarm/logging-operator/pkg/resource/logging-credentials"
Expand Down Expand Up @@ -82,6 +82,7 @@ func main() {
var enableLeaderElection bool
var enableLogging bool
var loggingAgent string
var eventsLogger string
var installationName string
var insecureCA bool
var metricsAddr string
Expand All @@ -94,6 +95,7 @@ func main() {
"Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&enableLogging, "enable-logging", true, "enable/disable logging for the whole installation")
flag.StringVar(&loggingAgent, "logging-agent", common.LoggingAgentAlloy, fmt.Sprintf("select logging agent to use (%s or %s)", common.LoggingAgentPromtail, common.LoggingAgentAlloy))
flag.StringVar(&eventsLogger, "events-logger", common.EventsLoggerAlloy, fmt.Sprintf("select events logger to use (%s or %s)", common.EventsLoggerAlloy, common.EventsLoggerGrafanaAgent))
flag.StringVar(&installationName, "installation-name", "unknown", "Name of the installation")
flag.BoolVar(&insecureCA, "insecure-ca", false, "Is the management cluter CA insecure?")
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
Expand Down Expand Up @@ -165,11 +167,12 @@ func main() {
DefaultWorkloadClusterNamespaces: defaultNamespaces,
}

grafanaAgentSecret := grafanaagentsecret.Reconciler{
Client: mgr.GetClient(),
eventsLoggerConfig := k8seventsconfig.Reconciler{
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
Client: mgr.GetClient(),
DefaultWorkloadClusterNamespaces: defaultNamespaces,
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
}

grafanaAgentConfig := grafanaagentconfig.Reconciler{
eventsLoggerSecret := eventsloggersecret.Reconciler{
Client: mgr.GetClient(),
}

Expand All @@ -190,8 +193,8 @@ func main() {
&proxyAuth,
&loggingSecret,
&loggingConfig,
&grafanaAgentSecret,
&grafanaAgentConfig,
&eventsLoggerConfig,
&eventsLoggerSecret,
},
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const (
LoggingAgentPromtail = "promtail"
LoggingAgentAlloy = "alloy"

// Possible values for --events-logger flag.
EventsLoggerAlloy = "alloy"
EventsLoggerGrafanaAgent = "grafana-agent"

// App name keys in the observability bundle
AlloyObservabilityBundleAppName = "alloyLogs"
PromtailObservabilityBundleAppName = "promtail"
Expand Down
8 changes: 8 additions & 0 deletions pkg/logged-cluster/capicluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ func (o *Object) SetLoggingAgent(loggingAgent string) {
o.Options.LoggingAgent = loggingAgent
}

func (o *Object) GetEventsLogger() string {
return o.Options.EventsLogger
}

func (o *Object) SetEventsLogger(eventsLogger string) {
o.Options.EventsLogger = eventsLogger
}

func (o Object) IsInsecureCA() bool {
return o.Options.InsecureCA
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/logged-cluster/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type Interface interface {
HasLoggingEnabled() bool
GetLoggingAgent() string
SetLoggingAgent(string)
GetEventsLogger() string
SetEventsLogger(string)
IsInsecureCA() bool
GetAppsNamespace() string
GetEnableLoggingFlag() bool
Expand Down
1 change: 1 addition & 0 deletions pkg/logged-cluster/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package loggedcluster
type Options struct {
EnableLoggingFlag bool
LoggingAgent string
EventsLogger string
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
InstallationName string
InsecureCA bool
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/logged-cluster/vintagemc/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ func (o *Object) SetLoggingAgent(loggingAgent string) {
o.Options.LoggingAgent = loggingAgent
}

func (o *Object) GetEventsLogger() string {
return o.Options.EventsLogger
}

func (o *Object) SetEventsLogger(eventsLogger string) {
o.Options.EventsLogger = eventsLogger
}

func (o Object) IsInsecureCA() bool {
return o.Options.InsecureCA
}
Expand Down
60 changes: 60 additions & 0 deletions pkg/resource/events-logger-secret/events-logger-secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package eventsloggersecret

import (
"fmt"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/pkg/errors"

"github.com/giantswarm/logging-operator/pkg/common"
loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
loggingsecret "github.com/giantswarm/logging-operator/pkg/resource/logging-secret"
)

const eventsLoggerSecretName = "events-logger-secret"

func GenerateEventsLoggerSecret(lc loggedcluster.Interface, loggingCredentialsSecret *v1.Secret, lokiURL string) (v1.Secret, error) {
var data map[string][]byte
var err error

switch lc.GetEventsLogger() {
case common.EventsLoggerGrafanaAgent:
data, err = GenerateGrafanaAgentSecret(lc, loggingCredentialsSecret, lokiURL)
if err != nil {
return v1.Secret{}, err
}
case common.EventsLoggerAlloy:
// In the case of Alloy being the events logger, we reuse the secret generation from the logging-secret package
data, err = loggingsecret.GenerateAlloyLoggingSecret(lc, loggingCredentialsSecret, lokiURL)
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return v1.Secret{}, err
}
default:
return v1.Secret{}, errors.Errorf("unsupported logging agent %q", lc.GetLoggingAgent())
}

secret := v1.Secret{
ObjectMeta: SecretMeta(lc),
Data: data,
}

return secret, nil
}

// SecretMeta returns metadata for the events-logger-secret
func SecretMeta(lc loggedcluster.Interface) metav1.ObjectMeta {
metadata := metav1.ObjectMeta{
Name: GetEventsLoggerSecretName(lc),
Namespace: lc.GetAppsNamespace(),
Labels: map[string]string{},
}

common.AddCommonLabels(metadata.Labels)
return metadata
}

func GetEventsLoggerSecretName(lc loggedcluster.Interface) string {
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Sprintf("%s-%s", lc.GetClusterName(), eventsLoggerSecretName)
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package grafanaagentsecret
package eventsloggersecret

import (
"fmt"

"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"

"github.com/giantswarm/logging-operator/pkg/common"
Expand All @@ -22,26 +21,14 @@ type extraSecret struct {
Data map[string]string `yaml:"data" json:"data"`
}

// SecretMeta returns metadata for the grafana-agent-secret
func SecretMeta(lc loggedcluster.Interface) metav1.ObjectMeta {
metadata := metav1.ObjectMeta{
Name: getGrafanaAgentSecretName(lc),
Namespace: lc.GetAppsNamespace(),
Labels: map[string]string{},
}

common.AddCommonLabels(metadata.Labels)
return metadata
}

// GenerateGrafanaAgentSecret returns a secret for
// the Loki-multi-tenant-proxy config
func GenerateGrafanaAgentSecret(lc loggedcluster.Interface, credentialsSecret *v1.Secret, lokiURL string) (v1.Secret, error) {
func GenerateGrafanaAgentSecret(lc loggedcluster.Interface, credentialsSecret *v1.Secret, lokiURL string) (map[string][]byte, error) {
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
clusterName := lc.GetClusterName()
writeUser := clusterName
writePassword, err := loggingcredentials.GetPassword(lc, credentialsSecret, clusterName)
if err != nil {
return v1.Secret{}, errors.WithStack(err)
return nil, errors.WithStack(err)
}

values := values{
Expand All @@ -58,19 +45,11 @@ func GenerateGrafanaAgentSecret(lc loggedcluster.Interface, credentialsSecret *v

v, err := yaml.Marshal(values)
if err != nil {
return v1.Secret{}, errors.WithStack(err)
return nil, errors.WithStack(err)
}

secret := v1.Secret{
ObjectMeta: SecretMeta(lc),
Data: map[string][]byte{
"values": []byte(v),
},
}

return secret, nil
}
data := make(map[string][]byte)
data["values"] = []byte(v)

func getGrafanaAgentSecretName(lc loggedcluster.Interface) string {
return fmt.Sprintf("%s-%s", lc.GetClusterName(), common.GrafanaAgentExtraSecretName())
return data, nil
}
120 changes: 120 additions & 0 deletions pkg/resource/events-logger-secret/reconciler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package eventsloggersecret

import (
"context"
"reflect"

"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
apimachineryerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"

"github.com/giantswarm/logging-operator/pkg/common"
loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
loggingcredentials "github.com/giantswarm/logging-operator/pkg/resource/logging-credentials"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
)

// Reconciler implements a reconciler.Interface to handle
// Events-logger secret: extra events-logger secret about where and how to send logs (in this case : k8S events)
type Reconciler struct {
client.Client
}

// ReconcileCreate ensures events-logger-secret is created with the right credentials
func (r *Reconciler) ReconcileCreate(ctx context.Context, lc loggedcluster.Interface) (ctrl.Result, error) {
logger := log.FromContext(ctx)
logger.Info("events-logger-secret create")

// Retrieve secret containing credentials
var eventsLoggerCredentialsSecret v1.Secret
err := r.Client.Get(ctx, types.NamespacedName{Name: loggingcredentials.LoggingCredentialsSecretMeta(lc).Name, Namespace: loggingcredentials.LoggingCredentialsSecretMeta(lc).Namespace},
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
&eventsLoggerCredentialsSecret)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}

// Retrieve Loki ingress name
lokiURL, err := common.ReadProxyIngressURL(ctx, lc, r.Client)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}

// Get desired secret
desiredEventsLoggerSecret, err := GenerateEventsLoggerSecret(lc, &eventsLoggerCredentialsSecret, lokiURL)
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
logger.Info("logging-secret - failed generating auth config!", "error", err)
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
return ctrl.Result{}, errors.WithStack(err)
}

// Check if secret already exists.
logger.Info("events-logger-secret - getting", "namespace", desiredEventsLoggerSecret.GetNamespace(), "name", desiredEventsLoggerSecret.GetName())
var currentEventsLoggerSecret v1.Secret
err = r.Client.Get(ctx, types.NamespacedName{Name: desiredEventsLoggerSecret.GetName(), Namespace: desiredEventsLoggerSecret.GetNamespace()}, &currentEventsLoggerSecret)
if err != nil {
if apimachineryerrors.IsNotFound(err) {
logger.Info("events-logger-secret not found, creating")
err = r.Client.Create(ctx, &desiredEventsLoggerSecret)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}
} else {
return ctrl.Result{}, errors.WithStack(err)
}
}

if !needUpdate(currentEventsLoggerSecret, desiredEventsLoggerSecret) {
logger.Info("events-logger-secret up to date")
return ctrl.Result{}, nil
}

logger.Info("events-logger-secret - updating")
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
err = r.Client.Update(ctx, &desiredEventsLoggerSecret)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}

logger.Info("events-logger-secret - done")
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
return ctrl.Result{}, nil
}

// ReconcileDelete - Not much to do here when a cluster is deleted
func (r *Reconciler) ReconcileDelete(ctx context.Context, lc loggedcluster.Interface) (ctrl.Result, error) {
logger := log.FromContext(ctx)
logger.Info("events-logger-secret delete")

// Get expected secret.
var currentEventsLoggerSecret v1.Secret
err := r.Client.Get(ctx, types.NamespacedName{Name: GetEventsLoggerSecretName(lc), Namespace: lc.GetAppsNamespace()}, &currentEventsLoggerSecret)
if err != nil {
if apimachineryerrors.IsNotFound(err) {
logger.Info("events-logger-secret not found, stop here")
return ctrl.Result{}, nil
}
return ctrl.Result{}, errors.WithStack(err)
}

// Delete secret.
logger.Info("events-logger-secret deleting", "namespace", currentEventsLoggerSecret.GetNamespace(), "name", currentEventsLoggerSecret.GetName())
err = r.Client.Delete(ctx, &currentEventsLoggerSecret)
if err != nil {
if apimachineryerrors.IsNotFound(err) {
// Do no throw error in case it was not found, as this means
// it was already deleted.
logger.Info("events-logger-secret already deleted")
return ctrl.Result{}, nil
}
return ctrl.Result{}, errors.WithStack(err)
}
logger.Info("events-logger-secret deleted")

return ctrl.Result{}, nil
}

// needUpdate return true if current.Data and desired.Data do not match.
func needUpdate(current, desired v1.Secret) bool {
return !reflect.DeepEqual(current.Data, desired.Data)
}
Loading