Skip to content

Commit

Permalink
Refactor CredentialsRequest reconciliation
Browse files Browse the repository at this point in the history
  • Loading branch information
periklis committed Jan 15, 2024
1 parent 0617963 commit b9e86ab
Show file tree
Hide file tree
Showing 20 changed files with 452 additions and 93 deletions.
3 changes: 3 additions & 0 deletions operator/apis/config/v1/projectconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type OpenShiftFeatureGates struct {

// Dashboards enables the loki-mixin dashboards into the OpenShift Console
Dashboards bool `json:"dashboards,omitempty"`

// ManagedAuthEnv enabled when the operator installation is on OpenShift STS clusters.
ManagedAuthEnv bool
}

// FeatureGates is the supported set of all operator feature gates.
Expand Down
3 changes: 3 additions & 0 deletions operator/apis/loki/v1/lokistack_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,9 @@ const (
ReasonMissingObjectStorageSecret LokiStackConditionReason = "MissingObjectStorageSecret"
// ReasonInvalidObjectStorageSecret when the format of the secret is invalid.
ReasonInvalidObjectStorageSecret LokiStackConditionReason = "InvalidObjectStorageSecret"
// ReasonMissingCredentialsRequest when the required request for managed auth credentials to object
// storage is missing.
ReasonMissingCredentialsRequest LokiStackConditionReason = "MissingCredentialsRequest"
// ReasonMissingManagedAuthSecret when the required secret for managed auth credentials to object
// storage is missing.
ReasonMissingManagedAuthSecret LokiStackConditionReason = "MissingManagedAuthenticationSecret"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: docker.io/grafana/loki-operator:0.5.0
createdAt: "2024-01-11T10:11:56Z"
createdAt: "2024-01-15T16:48:42Z"
description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components.
features.operators.openshift.io/disconnected: "true"
Expand Down Expand Up @@ -1470,11 +1470,6 @@ spec:
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: docker.io/grafana/loki-operator:0.5.0
createdAt: "2024-01-11T10:11:54Z"
createdAt: "2024-01-15T16:48:40Z"
description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components.
operators.operatorframework.io/builder: operator-sdk-unknown
Expand Down Expand Up @@ -1450,11 +1450,6 @@ spec:
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: quay.io/openshift-logging/loki-operator:0.1.0
createdAt: "2024-01-11T10:11:58Z"
createdAt: "2024-01-15T16:48:44Z"
description: |
The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging.
## Prerequisites and Requirements
Expand Down Expand Up @@ -1455,11 +1455,6 @@ spec:
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
5 changes: 0 additions & 5 deletions operator/config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ rules:
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
61 changes: 61 additions & 0 deletions operator/controllers/loki/credentialsrequests_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package controllers

import (
"context"

"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/controllers/loki/internal/lokistack"
"github.com/grafana/loki/operator/controllers/loki/internal/management/state"
"github.com/grafana/loki/operator/internal/handlers"
)

type CredentialsRequestsReconciler struct {
client.Client
Scheme *runtime.Scheme
Log logr.Logger
}

func (r *CredentialsRequestsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
managed, err := state.IsManaged(ctx, req, r.Client)
if err != nil {
return ctrl.Result{}, err
}
if !managed {
r.Log.Info("Skipping reconciliation for unmanaged LokiStack resource", "name", req.String())
// Stop requeueing for unmanaged LokiStack custom resources
return ctrl.Result{}, nil
}

var stack *lokiv1.LokiStack
if err = r.Client.Get(ctx, req.NamespacedName, stack); err != nil {
if errors.IsNotFound(err) {
return ctrl.Result{}, handlers.DeleteCredentialsRequest(ctx, r.Client, req.NamespacedName)
}
return ctrl.Result{}, err
}

secretRef, err := handlers.CreateCredentialsRequest(ctx, r.Client, req.NamespacedName)
if err != nil {
return ctrl.Result{}, err
}

if err := lokistack.AnnotateForCredentialsRequest(ctx, r.Client, req.NamespacedName, secretRef); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager to only call this controller on create/delete/generic events.
func (r *CredentialsRequestsReconciler) SetupWithManager(mgr manager.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&lokiv1.LokiStack{}, createOrDeletesPred).
Complete(r)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package lokistack

import (
"context"
"errors"

"github.com/ViaQ/logerr/v2/kverrors"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/grafana/loki/operator/internal/external/k8s"
"github.com/grafana/loki/operator/internal/manifests/storage"
)

var ErrAnnotationAlreadyExists = errors.New("credentialsRequestsSecretRef annotation already exists")

// AnnotateForCredentialsRequest adds/updates the `loki.grafana.com/credentials-request-secret-ref` annotation
// to the named Lokistack. If no LokiStack is found, then skip reconciliation.
func AnnotateForCredentialsRequest(ctx context.Context, k k8s.Client, key client.ObjectKey, secretRef string) error {
stack, err := getLokiStack(ctx, k, key)
if stack == nil || err != nil {
return err
}

if val, ok := stack.Annotations[storage.AnnotationCredentialsRequestsSecretRef]; ok && val == secretRef {
return ErrAnnotationAlreadyExists
}

if err := updateAnnotation(ctx, k, stack, storage.AnnotationCredentialsRequestsSecretRef, secretRef); err != nil {
return kverrors.Wrap(err, "failed to update lokistack `credentialsRequestSecretRef` annotation", "key", key)
}

return nil
}
2 changes: 1 addition & 1 deletion operator/controllers/loki/lokistack_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ type LokiStackReconciler struct {
// +kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=get;list;watch;create;update
// +kubebuilder:rbac:groups=config.openshift.io,resources=dnses;apiservers;proxies,verbs=get;list;watch
// +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=get;list;watch;create;update;delete
// +kubebuilder:rbac:groups=cloudcredential.openshift.io,resources=credentialsrequests,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cloudcredential.openshift.io,resources=credentialsrequests,verbs=create;delete

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
Expand Down
11 changes: 11 additions & 0 deletions operator/docs/operator/feature-gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,17 @@ bool
<p>Dashboards enables the loki-mixin dashboards into the OpenShift Console</p>
</td>
</tr>
<tr>
<td>
<code>ManagedAuthEnv</code><br/>
<em>
bool
</em>
</td>
<td>
<p>ManagedAuthEnv enabled when the operator installation is on OpenShift STS clusters.</p>
</td>
</tr>
</tbody>
</table>

Expand Down
40 changes: 40 additions & 0 deletions operator/internal/handlers/credentialsrequest_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package handlers

import (
"context"

"github.com/ViaQ/logerr/v2/kverrors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/grafana/loki/operator/internal/external/k8s"
"github.com/grafana/loki/operator/internal/manifests/openshift"
)

func CreateCredentialsRequest(ctx context.Context, k k8s.Client, stack client.ObjectKey) (string, error) {
managedAuthEnv := openshift.DiscoverManagedAuthEnv()
if managedAuthEnv == nil {
return "", nil
}

opts := openshift.Options{
BuildOpts: openshift.BuildOptions{
LokiStackName: stack.Name,
LokiStackNamespace: stack.Namespace,
},
ManagedAuthEnv: managedAuthEnv,
}

credReq, err := openshift.BuildCredentialsRequest(opts)
if err != nil {
return "", err
}

if err := k.Create(ctx, credReq); err != nil {
if !apierrors.IsAlreadyExists(err) {
return "", kverrors.Wrap(err, "failed to create credentialsrequest", "key", client.ObjectKeyFromObject(credReq))
}
}

return credReq.Spec.SecretRef.Name, nil
}
37 changes: 37 additions & 0 deletions operator/internal/handlers/credentialsrequest_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package handlers

import (
"context"

"github.com/ViaQ/logerr/v2/kverrors"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/grafana/loki/operator/internal/external/k8s"
"github.com/grafana/loki/operator/internal/manifests/openshift"
)

func DeleteCredentialsRequest(ctx context.Context, k k8s.Client, stack client.ObjectKey) error {
managedAuthEnv := openshift.DiscoverManagedAuthEnv()
if managedAuthEnv == nil {
return nil
}

opts := openshift.Options{
BuildOpts: openshift.BuildOptions{
LokiStackName: stack.Name,
LokiStackNamespace: stack.Namespace,
},
ManagedAuthEnv: managedAuthEnv,
}

credReq, err := openshift.BuildCredentialsRequest(opts)
if err != nil {
return kverrors.Wrap(err, "failed to build credentialsrequest", "key", stack)
}

if err := k.Delete(ctx, credReq); err != nil {
return kverrors.Wrap(err, "failed to delete credentialsrequest", "key", client.ObjectKeyFromObject(credReq))
}

return nil
}
29 changes: 0 additions & 29 deletions operator/internal/handlers/internal/openshift/discover.go

This file was deleted.

20 changes: 9 additions & 11 deletions operator/internal/handlers/internal/storage/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
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/storage"
"github.com/grafana/loki/operator/internal/status"
)
Expand All @@ -25,7 +24,6 @@ func getSecrets(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg c
var (
storageSecret corev1.Secret
managedAuthSecret corev1.Secret
stackKey = client.ObjectKeyFromObject(stack)
)

key := client.ObjectKey{Name: stack.Spec.Storage.Secret.Name, Namespace: stack.Namespace}
Expand All @@ -40,17 +38,17 @@ func getSecrets(ctx context.Context, k k8s.Client, stack *lokiv1.LokiStack, fg c
return nil, nil, kverrors.Wrap(err, "failed to lookup lokistack storage secret", "name", key)
}

if fg.OpenShift.Enabled {
managedAuthEnv := openshift.DiscoverManagedAuthEnv()
if managedAuthEnv == nil {
return &storageSecret, nil, nil
}

managedAuthCredsKey, err := openshift.CreateCredentialsRequest(ctx, k, stackKey, managedAuthEnv)
if err != nil {
return nil, nil, kverrors.Wrap(err, "failed creating OpenShift CCO CredentialsRequest", "name", stackKey)
if fg.OpenShift.ManagedAuthEnv {
secretName, ok := stack.Annotations[storage.AnnotationCredentialsRequestsSecretRef]
if !ok {
return nil, nil, &status.DegradedError{
Message: "Missing OpenShift cloud credentials request",
Reason: lokiv1.ReasonMissingCredentialsRequest,
Requeue: true,
}
}

managedAuthCredsKey := client.ObjectKey{Name: secretName, Namespace: stack.Namespace}
if err := k.Get(ctx, managedAuthCredsKey, &managedAuthSecret); err != nil {
if apierrors.IsNotFound(err) {
return nil, nil, &status.DegradedError{
Expand Down
Loading

0 comments on commit b9e86ab

Please sign in to comment.