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

Merged
merged 46 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 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
0cc0a9f
Apply suggestions from code review
QuantumEnigmaa Nov 20, 2024
fadf34e
Merge branch 'main' into alloy-log-events
QuentinBisson Nov 20, 2024
1c550c5
update test files
QuantumEnigmaa Nov 21, 2024
bc645a4
Merge branch 'main' of github.com:giantswarm/logging-operator into al…
QuantumEnigmaa Nov 21, 2024
82b6f31
handle specific case of observability-bundle version < 0.9.0
QuantumEnigmaa Nov 21, 2024
1b70c2e
remove secret namespace field
QuantumEnigmaa Nov 21, 2024
d2befbf
remove extra line in alloy and grafana-agent config
QuantumEnigmaa Nov 21, 2024
e508983
fix variable name in reconcileDelete method from event-logger-config …
QuantumEnigmaa Nov 21, 2024
a9731db
fix UTs for grafana-agent template
QuantumEnigmaa Nov 21, 2024
65d4941
disable crds creation in alloy-events template
QuantumEnigmaa Nov 21, 2024
a8ab45f
fixed grafana-agent tests in events-logger-config
QuantumEnigmaa Nov 25, 2024
5d5d87b
fix enabling of events logger depending on observability-bundle version
QuantumEnigmaa Nov 25, 2024
b41c7b8
minor fixes
QuantumEnigmaa Nov 25, 2024
fa22e3e
Merge branch 'main' of github.com:giantswarm/logging-operator into al…
QuantumEnigmaa Nov 25, 2024
44084d8
add tests for alloy-events in events-logger-config (#277)
QuantumEnigmaa Nov 25, 2024
49036f0
Merge branch 'main' of github.com:giantswarm/logging-operator into al…
QuantumEnigmaa Nov 25, 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ 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.
- Add KubeEventsLogger option and related methods in loggedCLuster package.
- Add `events-logger` flag in the operator.
- Add toggle for `events-logger` in observability-bundle configmap.
- Add tests for `alloy-events` in events-logger-config.

### Changed

Expand Down
8 changes: 4 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@ func main() {
DefaultWorkloadClusterNamespaces: defaultNamespaces,
}

eventsLoggerSecret := eventsloggersecret.Reconciler{
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
Client: mgr.GetClient(),
}

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

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

loggedcluster.O.EnableLoggingFlag = enableLogging
loggedcluster.O.LoggingAgent = loggingAgent
loggedcluster.O.KubeEventsLogger = eventsLogger
Expand Down
4 changes: 4 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const (
AlloyLogAgentAppName = "alloy-logs"
AlloyLogAgentAppNamespace = "kube-system"

// Alloy app name and namespace when using Alloy as events logger.
AlloyEventsLoggerAppName = "alloy-events"
AlloyEventsLoggerAppNamespace = "kube-system"

MaxBackoffPeriod = "10m"
LokiURLFormat = "https://%s/loki/api/v1/push"
)
Expand Down
47 changes: 25 additions & 22 deletions pkg/resource/agents-toggle/observability_bundle_configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,30 +59,33 @@ func GenerateObservabilityBundleConfigMap(ctx context.Context, lc loggedcluster.
return v1.ConfigMap{}, errors.Errorf("unsupported logging agent %q", lc.GetLoggingAgent())
}

// Enforce grafana-agent as events logger when observability-bundle version < 1.9.0 because this needs alloy 0.7.0.
if observabilityBundleVersion.LT(semver.MustParse("1.9.0")) && lc.GetKubeEventsLogger() == common.EventsLoggerAlloy {
logger := log.FromContext(ctx)
logger.Info("Alloy events logger is not supported by observability bundle, using grafana-agent instead.", "observability-bundle-version", observabilityBundleVersion, "events-logger", lc.GetKubeEventsLogger())
lc.SetKubeEventsLogger(common.EventsLoggerGrafanaAgent)
}

switch lc.GetKubeEventsLogger() {
case common.EventsLoggerGrafanaAgent:
appsToEnable["grafanaAgent"] = app{
Enabled: true,
}
appsToEnable["alloyEvents"] = app{
Enabled: false,
// If observability-bundle version >= 0.9.0, events loggers can be enabled.
if observabilityBundleVersion.GT(semver.MustParse("0.9.0")) {
// Enforce grafana-agent as events logger when observability-bundle version < 1.9.0 because this needs alloy 0.7.0.
if observabilityBundleVersion.LT(semver.MustParse("1.9.0")) && lc.GetKubeEventsLogger() == common.EventsLoggerAlloy {
logger := log.FromContext(ctx)
logger.Info("Alloy events logger is not supported by observability bundle, using grafana-agent instead.", "observability-bundle-version", observabilityBundleVersion, "events-logger", lc.GetKubeEventsLogger())
lc.SetKubeEventsLogger(common.EventsLoggerGrafanaAgent)
}
case common.EventsLoggerAlloy:
appsToEnable["grafanaAgent"] = app{
Enabled: false,
}
appsToEnable["alloyEvents"] = app{
Enabled: true,

switch lc.GetKubeEventsLogger() {
case common.EventsLoggerGrafanaAgent:
appsToEnable["grafanaAgent"] = app{
Enabled: true,
}
appsToEnable["alloyEvents"] = app{
Enabled: false,
}
case common.EventsLoggerAlloy:
appsToEnable["grafanaAgent"] = app{
Enabled: false,
}
appsToEnable["alloyEvents"] = app{
Enabled: true,
}
default:
return v1.ConfigMap{}, errors.Errorf("unsupported events logger %q", lc.GetKubeEventsLogger())
}
default:
return v1.ConfigMap{}, errors.Errorf("unsupported events logger %q", lc.GetKubeEventsLogger())
}

values := Values{
Expand Down
33 changes: 19 additions & 14 deletions pkg/resource/agents-toggle/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,36 +28,36 @@ type Reconciler struct {
Scheme *runtime.Scheme
}

// ReconcileCreate ensure logging agents are enabled in the given cluster.
// ReconcileCreate ensure logging agents and events loggers are enabled in the given cluster.
func (r *Reconciler) ReconcileCreate(ctx context.Context, lc loggedcluster.Interface) (ctrl.Result, error) {
logger := log.FromContext(ctx)
logger.Info("Logging agents toggle create")
logger.Info("agents toggle create")

observabilityBundleVersion, err := common.GetObservabilityBundleAppVersion(lc, r.Client, ctx)
if err != nil {
// Handle case where the app is not found.
if apimachineryerrors.IsNotFound(err) {
logger.Info("logging-agents-toggle - observability bundle app not found, requeueing")
logger.Info("agents-toggle - observability bundle app not found, requeueing")
// If the app is not found we should requeue and try again later (5 minutes is the app platform default reconciliation time)
return ctrl.Result{RequeueAfter: time.Duration(5 * time.Minute)}, nil
}
return ctrl.Result{}, errors.WithStack(err)
}

// Get desired configmap to enable logging agents.
// Get desired configmap to enable logging agents and events loggers.
desiredConfigMap, err := GenerateObservabilityBundleConfigMap(ctx, lc, observabilityBundleVersion)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}

// Check if configmap is already installed.
logger.Info("Logging agents toggle checking", "namespace", desiredConfigMap.GetNamespace(), "name", desiredConfigMap.GetName())
logger.Info("agents toggle checking", "namespace", desiredConfigMap.GetNamespace(), "name", desiredConfigMap.GetName())
var currentConfigMap v1.ConfigMap
err = r.Client.Get(ctx, types.NamespacedName{Name: desiredConfigMap.GetName(), Namespace: desiredConfigMap.GetNamespace()}, &currentConfigMap)
if err != nil {
if apimachineryerrors.IsNotFound(err) {
// Install configmap.
logger.Info("Logging agents toggle not found, creating")
logger.Info("agents toggle not found, creating")
err = r.Client.Create(ctx, &desiredConfigMap)
}
if err != nil {
Expand All @@ -66,24 +66,24 @@ func (r *Reconciler) ReconcileCreate(ctx context.Context, lc loggedcluster.Inter
}

if needUpdate(currentConfigMap, desiredConfigMap) {
logger.Info("Logging agents toggle updating")
logger.Info("agents toggle updating")
// Update configmap
// Configmap is installed and need to be updated.
err := r.Client.Update(ctx, &desiredConfigMap)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}
} else {
logger.Info("Logging agents toggle up to date")
logger.Info("agents toggle up to date")
}

return ctrl.Result{}, nil
}

// ReconcileDelete ensure logging agents are disabled for the given cluster.
// ReconcileDelete ensure logging agents and events loggers are disabled for the given cluster.
func (r *Reconciler) ReconcileDelete(ctx context.Context, lc loggedcluster.Interface) (ctrl.Result, error) {
logger := log.FromContext(ctx)
logger.Info("Logging agents toggle delete")
logger.Info("agents toggle delete")

// Get observability bundle app metadata.
appMeta := common.ObservabilityBundleAppMeta(lc)
Expand All @@ -93,7 +93,7 @@ func (r *Reconciler) ReconcileDelete(ctx context.Context, lc loggedcluster.Inter
if err != nil {
// Handle case where the app is not found.
if apimachineryerrors.IsNotFound(err) {
logger.Info("logging-agents-toggle - observability bundle app not found, skipping deletion")
logger.Info("agents-toggle - observability bundle app not found, skipping deletion")
// If the app is not found we ignore the error and return, as this means the app was already deleted.
return ctrl.Result{}, nil
}
Expand All @@ -105,25 +105,30 @@ func (r *Reconciler) ReconcileDelete(ctx context.Context, lc loggedcluster.Inter
return ctrl.Result{}, errors.WithStack(err)
}

// If the observability-bundle version is too old, we don't need to do anything.
if observabilityBundleVersion.LT(semver.MustParse("0.9.0")) {
return ctrl.Result{}, nil
}

// Get expected configmap.
desiredConfigMap, err := GenerateObservabilityBundleConfigMap(ctx, lc, observabilityBundleVersion)
if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}

// Delete configmap.
logger.Info("Logging agents toggle deleting", "namespace", desiredConfigMap.GetNamespace(), "name", desiredConfigMap.GetName())
logger.Info("agents toggle deleting", "namespace", desiredConfigMap.GetNamespace(), "name", desiredConfigMap.GetName())
err = r.Client.Delete(ctx, &desiredConfigMap)
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("Logging agents toggle already deleted")
logger.Info("agents toggle already deleted")
} else if err != nil {
return ctrl.Result{}, errors.WithStack(err)
}
} else {
logger.Info("Logging agents toggle deleted")
logger.Info("agents toggle deleted")
}

return ctrl.Result{}, nil
Expand Down
86 changes: 86 additions & 0 deletions pkg/resource/events-logger-config/alloy-events-config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package eventsloggerconfig

import (
"bytes"
_ "embed"
"fmt"
"text/template"

"github.com/Masterminds/sprig/v3"

"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"
)

var (
//go:embed alloy/events-logger.alloy.template
alloyEvents string
alloyEventsTemplate *template.Template

//go:embed alloy/events-logger-config.alloy.yaml.template
alloyEventsConfig string
alloyEventsConfigTemplate *template.Template
)

func init() {
alloyEventsTemplate = template.Must(template.New("events-logger.alloy").Funcs(sprig.FuncMap()).Parse(alloyEvents))
alloyEventsConfigTemplate = template.Must(template.New("events-logger-config.alloy.yaml").Funcs(sprig.FuncMap()).Parse(alloyEventsConfig))
}

func generateAlloyEventsConfig(lc loggedcluster.Interface, defaultNamespaces []string) (string, error) {
var values bytes.Buffer

alloyConfig, err := generateAlloyConfig(lc, defaultNamespaces)
if err != nil {
return "", err
}

data := struct {
AlloyConfig string
SecretName string
}{
AlloyConfig: alloyConfig,
SecretName: common.AlloyEventsLoggerAppName,
}

err = alloyEventsConfigTemplate.Execute(&values, data)
if err != nil {
return "", err
}

return values.String(), nil
}

func generateAlloyConfig(lc loggedcluster.Interface, defaultNamespaces []string) (string, error) {
var values bytes.Buffer

data := struct {
ClusterID string
Installation string
InsecureSkipVerify string
MaxBackoffPeriod string
LokiURLEnvVarName string
TenantIDEnvVarName string
BasicAuthUsernameEnvVarName string
BasicAuthPasswordEnvVarName string
ScrapedNamespaces string
}{
ClusterID: lc.GetClusterName(),
Installation: lc.GetInstallationName(),
InsecureSkipVerify: fmt.Sprintf("%t", lc.IsInsecureCA()),
MaxBackoffPeriod: common.MaxBackoffPeriod,
LokiURLEnvVarName: loggingsecret.AlloyLokiURLEnvVarName,
TenantIDEnvVarName: loggingsecret.AlloyTenantIDEnvVarName,
BasicAuthUsernameEnvVarName: loggingsecret.AlloyBasicAuthUsernameEnvVarName,
BasicAuthPasswordEnvVarName: loggingsecret.AlloyBasicAuthPasswordEnvVarName,
ScrapedNamespaces: common.FormatScrapedNamespaces(lc, defaultNamespaces),
}

err := alloyEventsTemplate.Execute(&values, data)
if err != nil {
return "", err
}

return values.String(), nil
}
73 changes: 73 additions & 0 deletions pkg/resource/events-logger-config/alloy-events-config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package eventsloggerconfig

import (
_ "embed"
"os"
"path/filepath"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
capi "sigs.k8s.io/cluster-api/api/v1beta1"

"github.com/google/go-cmp/cmp"

loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
"github.com/giantswarm/logging-operator/pkg/logged-cluster/capicluster"
)

func TestGenerateAlloyEventsConfig(t *testing.T) {
testCases := []struct {
goldenFile string
defaultNamespaces []string
installationName string
clusterName string
}{
{
goldenFile: "alloy/test/events-logger-config.alloy.MC.yaml",
installationName: "test-installation",
clusterName: "test-installation",
},
{
goldenFile: "alloy/test/events-logger-config.alloy.WC.yaml",
installationName: "test-installation",
clusterName: "test-cluster",
},
}

for _, tc := range testCases {
t.Run(filepath.Base(tc.goldenFile), func(t *testing.T) {
golden, err := os.ReadFile(tc.goldenFile)
if err != nil {
t.Fatalf("Failed to read golden file: %v", err)
}

loggedCluster := &capicluster.Object{
Object: &capi.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: tc.clusterName,
},
},
Options: loggedcluster.Options{
InstallationName: tc.installationName,
KubeEventsLogger: "alloy",
},
}

config, err := generateAlloyEventsConfig(loggedCluster, []string{"kube-system", "giantswarm"})
if err != nil {
t.Fatalf("Failed to generate alloy config: %v", err)
}

if string(golden) != config {
t.Logf("Generated config differs from %s, diff:\n%s", tc.goldenFile, cmp.Diff(string(golden), config))
t.Fail()
if *update {
//nolint:gosec
if err := os.WriteFile(tc.goldenFile, []byte(config), 0644); err != nil {
t.Fatalf("Failed to update golden file: %v", err)
}
}
}
})
}
}
Loading