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

[release-5.6] LOG-4967: Backport PRs grafana/loki#11624 and grafana/loki#11592 #246

Closed
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
4 changes: 4 additions & 0 deletions operator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Main

## Release 5.6.16

- [11624](https://github.com/grafana/loki/pull/11624) **xperimental**: React to changes in ConfigMap used for storage CA

## Release 5.6.15

- [11448](https://github.com/grafana/loki/pull/11448) **periklis**: Update Loki operand to v2.9.3
Expand Down
43 changes: 36 additions & 7 deletions operator/controllers/loki/lokistack_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,7 @@ var (
})
createUpdateOrDeletePred = builder.WithPredicates(predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
if e.ObjectOld.GetGeneration() == 0 && len(e.ObjectOld.GetAnnotations()) == 0 {
return e.ObjectOld.GetResourceVersion() != e.ObjectNew.GetResourceVersion()
}

return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration() ||
cmp.Diff(e.ObjectOld.GetAnnotations(), e.ObjectNew.GetAnnotations()) != ""
return e.ObjectOld.GetResourceVersion() != e.ObjectNew.GetResourceVersion()
},
CreateFunc: func(e event.CreateEvent) bool { return true },
DeleteFunc: func(e event.DeleteEvent) bool { return true },
Expand Down Expand Up @@ -203,7 +198,8 @@ func (r *LokiStackReconciler) buildController(bld k8s.Builder) error {
Owns(&rbacv1.ClusterRoleBinding{}, updateOrDeleteOnlyPred).
Owns(&rbacv1.Role{}, updateOrDeleteOnlyPred).
Owns(&rbacv1.RoleBinding{}, updateOrDeleteOnlyPred).
Watches(&source.Kind{Type: &corev1.Secret{}}, r.enqueueForStorageSecret(), createUpdateOrDeletePred)
Watches(&source.Kind{Type: &corev1.Secret{}}, r.enqueueForStorageSecret(), createUpdateOrDeletePred).
Watches(&source.Kind{Type: &corev1.ConfigMap{}}, r.enqueueForStorageCA(), createUpdateOrDeletePred)

if r.FeatureGates.LokiStackAlerts {
bld = bld.Owns(&monitoringv1.PrometheusRule{}, updateOrDeleteOnlyPred)
Expand Down Expand Up @@ -290,3 +286,36 @@ func statusDifferent(e event.UpdateEvent) bool {
return false
}
}

func (r *LokiStackReconciler) enqueueForStorageCA() handler.EventHandler {
ctx := context.TODO()
return handler.EnqueueRequestsFromMapFunc(func(obj client.Object) []reconcile.Request {
lokiStacks := &lokiv1.LokiStackList{}
if err := r.Client.List(ctx, lokiStacks, client.InNamespace(obj.GetNamespace())); err != nil {
r.Log.Error(err, "Error listing LokiStack resources for storage CA update")
return nil
}

var requests []reconcile.Request
for _, stack := range lokiStacks.Items {
if stack.Spec.Storage.TLS == nil {
continue
}

storageTLS := stack.Spec.Storage.TLS
if obj.GetName() != storageTLS.CA {
continue
}

requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: stack.Namespace,
Name: stack.Name,
},
})
r.Log.Info("Enqueued request for LokiStack because of Storage CA resource change", "LokiStack", stack.Name, "ConfigMap", obj.GetName())
}

return requests
})
}
17 changes: 12 additions & 5 deletions operator/controllers/loki/lokistack_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@ func TestLokiStackController_RegisterWatchedResources(t *testing.T) {
table := []test{
{
src: &source.Kind{Type: &openshiftconfigv1.APIServer{}},
index: 1,
watchesCallsCount: 2,
index: 2,
watchesCallsCount: 3,
featureGates: configv1.FeatureGates{
OpenShift: configv1.OpenShiftFeatureGates{
ClusterTLSPolicy: true,
Expand All @@ -215,8 +215,8 @@ func TestLokiStackController_RegisterWatchedResources(t *testing.T) {
},
{
src: &source.Kind{Type: &openshiftconfigv1.Proxy{}},
index: 1,
watchesCallsCount: 2,
index: 2,
watchesCallsCount: 3,
featureGates: configv1.FeatureGates{
OpenShift: configv1.OpenShiftFeatureGates{
ClusterProxy: true,
Expand All @@ -227,7 +227,14 @@ func TestLokiStackController_RegisterWatchedResources(t *testing.T) {
{
src: &source.Kind{Type: &corev1.Secret{}},
index: 0,
watchesCallsCount: 1,
watchesCallsCount: 2,
featureGates: configv1.FeatureGates{},
pred: createUpdateOrDeletePred,
},
{
src: &source.Kind{Type: &corev1.ConfigMap{}},
index: 1,
watchesCallsCount: 2,
featureGates: configv1.FeatureGates{},
pred: createUpdateOrDeletePred,
},
Expand Down
5 changes: 2 additions & 3 deletions operator/internal/handlers/internal/gateway/base_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ import (
"github.com/ViaQ/logerr/v2/kverrors"
configv1 "github.com/openshift/api/config/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/internal/external/k8s"
"github.com/grafana/loki/operator/internal/status"
)

// GetOpenShiftBaseDomain returns the cluster DNS base domain on OpenShift
// getOpenShiftBaseDomain returns the cluster DNS base domain on OpenShift
// clusters to auto-create redirect URLs for OpenShift Auth or an error.
// If the config.openshift.io/DNS object is not found the whole lokistack
// resoure is set to a degraded state.
func GetOpenShiftBaseDomain(ctx context.Context, k k8s.Client, req ctrl.Request) (string, error) {
func getOpenShiftBaseDomain(ctx context.Context, k k8s.Client) (string, error) {
var cluster configv1.DNS
key := client.ObjectKey{Name: "cluster"}
if err := k.Get(ctx, key, &cluster); err != nil {
Expand Down
87 changes: 87 additions & 0 deletions operator/internal/handlers/internal/gateway/gateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package gateway

import (
"context"
"fmt"

"github.com/go-logr/logr"

configv1 "github.com/grafana/loki/operator/apis/config/v1"
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/internal/external/k8s"
"github.com/grafana/loki/operator/internal/handlers/internal/openshift"
"github.com/grafana/loki/operator/internal/manifests"
"github.com/grafana/loki/operator/internal/status"
)

// BuildOptions returns the options needed to generate Kubernetes resource
// manifests for the lokistack-gateway.
// The returned error can be a status.DegradedError in the following cases:
// - The tenants spec is missing.
// - The tenants spec is invalid.
func BuildOptions(ctx context.Context, log logr.Logger, k k8s.Client, stack *lokiv1.LokiStack, fg configv1.FeatureGates) (string, manifests.Tenants, error) {
var (
err error
baseDomain string
secrets []*manifests.TenantSecrets
configs map[string]manifests.TenantConfig
tenants manifests.Tenants
)

if !fg.LokiStackGateway {
return "", tenants, nil
}

if stack.Spec.Tenants == nil {
return "", tenants, &status.DegradedError{
Message: "Invalid tenants configuration: TenantsSpec cannot be nil when gateway flag is enabled",
Reason: lokiv1.ReasonInvalidTenantsConfiguration,
Requeue: false,
}
}

if err = validateModes(stack); err != nil {
return "", tenants, &status.DegradedError{
Message: fmt.Sprintf("Invalid tenants configuration: %s", err),
Reason: lokiv1.ReasonInvalidTenantsConfiguration,
Requeue: false,
}
}

switch stack.Spec.Tenants.Mode {
case lokiv1.OpenshiftLogging, lokiv1.OpenshiftNetwork:
baseDomain, err = getOpenShiftBaseDomain(ctx, k)
if err != nil {
return "", tenants, err
}

if stack.Spec.Proxy == nil {
// If the LokiStack has no proxy set but there is a cluster-wide proxy setting,
// set the LokiStack proxy to that.
ocpProxy, proxyErr := openshift.GetProxy(ctx, k)
if proxyErr != nil {
return "", tenants, proxyErr
}

stack.Spec.Proxy = ocpProxy
}
default:
secrets, err = getTenantSecrets(ctx, k, stack)
if err != nil {
return "", tenants, err
}
}

// extract the existing tenant's id, cookieSecret if exists, otherwise create new.
configs, err = getTenantConfigFromSecret(ctx, k, stack)
if err != nil {
log.Error(err, "error in getting tenant secret data")
}

tenants = manifests.Tenants{
Secrets: secrets,
Configs: configs,
}

return baseDomain, tenants, nil
}
Loading