Skip to content

Commit

Permalink
extract webhooks to seperate package to avoid import cycle (#766)
Browse files Browse the repository at this point in the history
* extract webhooks to seperate package to avoid import cycle

Signed-off-by: Andreas Gerstmayr <[email protected]>

* move defaults tests

Signed-off-by: Andreas Gerstmayr <[email protected]>

---------

Signed-off-by: Andreas Gerstmayr <[email protected]>
  • Loading branch information
andreasgerstmayr authored Jan 30, 2024
1 parent de70152 commit 37ac629
Show file tree
Hide file tree
Showing 12 changed files with 605 additions and 632 deletions.
49 changes: 49 additions & 0 deletions apis/tempo/v1alpha1/tempomonolithic_defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package v1alpha1

import "k8s.io/apimachinery/pkg/api/resource"

var (
tenGBQuantity = resource.MustParse("10Gi")
)

// Default sets all default values in a central place, instead of setting it at every place where the value is accessed.
// NOTE: This function is called inside the Reconcile loop, NOT in the webhook.
// We want to keep the CR as minimal as the user configures it, and not modify it in any way (except for upgrades).
func (r *TempoMonolithic) Default() {
if r.Spec.Storage == nil {
r.Spec.Storage = &MonolithicStorageSpec{}
}

if r.Spec.Storage.Traces.Backend == "" {
r.Spec.Storage.Traces.Backend = MonolithicTracesStorageBackendMemory
}

if r.Spec.Storage.Traces.Backend != MonolithicTracesStorageBackendMemory && r.Spec.Storage.Traces.WAL == nil {
r.Spec.Storage.Traces.WAL = &MonolithicTracesStorageWALSpec{
Size: tenGBQuantity,
}
}

if r.Spec.Storage.Traces.Backend == MonolithicTracesStorageBackendPV && r.Spec.Storage.Traces.PV == nil {
r.Spec.Storage.Traces.PV = &MonolithicTracesStoragePVSpec{
Size: tenGBQuantity,
}
}

if r.Spec.Ingestion == nil {
r.Spec.Ingestion = &MonolithicIngestionSpec{}
}
if r.Spec.Ingestion.OTLP == nil {
r.Spec.Ingestion.OTLP = &MonolithicIngestionOTLPSpec{}
}
if r.Spec.Ingestion.OTLP.GRPC == nil {
r.Spec.Ingestion.OTLP.GRPC = &MonolithicIngestionOTLPProtocolsGRPCSpec{
Enabled: true,
}
}
if r.Spec.Ingestion.OTLP.HTTP == nil {
r.Spec.Ingestion.OTLP.HTTP = &MonolithicIngestionOTLPProtocolsHTTPSpec{
Enabled: true,
}
}
}
96 changes: 0 additions & 96 deletions apis/tempo/v1alpha1/tempomonolithic_webhook.go

This file was deleted.

18 changes: 1 addition & 17 deletions apis/tempo/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cmd/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
controllers "github.com/grafana/tempo-operator/controllers/tempo"
"github.com/grafana/tempo-operator/internal/manifests"
"github.com/grafana/tempo-operator/internal/manifests/manifestutils"
"github.com/grafana/tempo-operator/internal/webhooks"
)

// yamlOrJsonDecoderBufferSize determines how far into the stream
Expand All @@ -42,7 +43,7 @@ func loadSpec(r io.Reader) (v1alpha1.TempoStack, error) {

func build(params manifestutils.Params) ([]client.Object, error) {
// apply default values from Defaulter webhook
defaulterWebhook := v1alpha1.NewDefaulter(params.CtrlConfig)
defaulterWebhook := webhooks.NewDefaulter(params.CtrlConfig)
err := defaulterWebhook.Default(context.Background(), &params.Tempo)
if err != nil {
return nil, err
Expand Down
6 changes: 3 additions & 3 deletions cmd/start/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/manager"

configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
tempov1alpha1 "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
"github.com/grafana/tempo-operator/cmd"
controllers "github.com/grafana/tempo-operator/controllers/tempo"
"github.com/grafana/tempo-operator/internal/upgrade"
"github.com/grafana/tempo-operator/internal/version"
"github.com/grafana/tempo-operator/internal/webhooks"
//+kubebuilder:scaffold:imports
)

Expand Down Expand Up @@ -78,11 +78,11 @@ func start(c *cobra.Command, args []string) {

enableWebhooks := os.Getenv("ENABLE_WEBHOOKS") != "false"
if enableWebhooks {
if err = (&tempov1alpha1.TempoStack{}).SetupWebhookWithManager(mgr, ctrlConfig); err != nil {
if err = (&webhooks.TempoStackWebhook{}).SetupWebhookWithManager(mgr, ctrlConfig); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "TempoStack")
os.Exit(1)
}
if err = (&tempov1alpha1.TempoMonolithic{}).SetupWebhookWithManager(mgr); err != nil {
if err = (&webhooks.TempoMonolithicWebhook{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "TempoMonolithic")
os.Exit(1)
}
Expand Down
3 changes: 2 additions & 1 deletion controllers/tempo/tempostack_create_or_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/grafana/tempo-operator/internal/manifests/manifestutils"
"github.com/grafana/tempo-operator/internal/status"
"github.com/grafana/tempo-operator/internal/tlsprofile"
"github.com/grafana/tempo-operator/internal/webhooks"
)

func listErrors(fieldErrs field.ErrorList) string {
Expand Down Expand Up @@ -81,7 +82,7 @@ func (r *TempoStackReconciler) createOrUpdate(ctx context.Context, log logr.Logg
}
}

if err = v1alpha1.ValidateTenantConfigs(tempo); err != nil {
if err = webhooks.ValidateTenantConfigs(tempo); err != nil {
return &status.ConfigurationError{
Message: fmt.Sprintf("Invalid tenants configuration: %s", err),
Reason: v1alpha1.ReasonInvalidTenantsConfiguration,
Expand Down
58 changes: 0 additions & 58 deletions docs/operator/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,56 +518,6 @@ PodStatusMap
</tr></tbody>
</table>

## Defaulter { #tempo-grafana-com-v1alpha1-Defaulter }

<div>

<p>Defaulter implements the CustomDefaulter interface.</p>

</div>

<table>

<thead>

<tr>

<th>Field</th>

<th>Description</th>

</tr>

</thead>

<tbody>

<tr>

<td>

<code>ctrlConfig</code><br/>

<em>

<a href="../v1/feature-gates.md#tempo-grafana-com-v1alpha1-ProjectConfig">

Feature Gates.ProjectConfig

</a>

</em>

</td>

<td>

</td>
</tr>

</tbody>
</table>

## ExtraConfigSpec { #tempo-grafana-com-v1alpha1-ExtraConfigSpec }

<p>
Expand Down Expand Up @@ -4308,14 +4258,6 @@ responsible for decrypting traffic.</p>
and re-encrypt using a new certificate.</p>
</td>

</tr><tr><td><p>&#34;passthrough&#34;</p></td>

<td></td>

</tr><tr><td><p>&#34;edge&#34;</p></td>

<td></td>

</tr></tbody>
</table>

Expand Down
84 changes: 84 additions & 0 deletions internal/webhooks/tempomonolithic_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package webhooks

import (
"context"
"fmt"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

tempov1alpha1 "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
)

// TempoMonolithicWebhook provides webhooks for TempoMonolithic CR.
type TempoMonolithicWebhook struct {
}

// SetupWebhookWithManager will setup the manager to manage the webhooks.
func (w *TempoMonolithicWebhook) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(&tempov1alpha1.TempoMonolithic{}).
WithValidator(&monolithicValidator{client: mgr.GetClient()}).
Complete()
}

//+kubebuilder:webhook:path=/validate-tempo-grafana-com-v1alpha1-tempomonolithic,mutating=false,failurePolicy=fail,sideEffects=None,groups=tempo.grafana.com,resources=tempomonolithics,verbs=create;update,versions=v1alpha1,name=vtempomonolithic.kb.io,admissionReviewVersions=v1

type monolithicValidator struct {
client client.Client
}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (v *monolithicValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
return v.validate(ctx, obj)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (v *monolithicValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
return v.validate(ctx, newObj)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
func (v *monolithicValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
return nil, nil
}

func (v *monolithicValidator) validate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
tempo, ok := obj.(*tempov1alpha1.TempoMonolithic)
if !ok {
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a TempoMonolithic object but got %T", obj))
}

log := ctrl.LoggerFrom(ctx).WithName("tempomonolithic-webhook")
log.V(1).Info("running validating webhook", "name", tempo.Name)

// We do not modify the Kubernetes object in the defaulter webhook,
// but still apply some default values in-memory.
tempo.Default()

allWarnings := admission.Warnings{}
allErrors := field.ErrorList{}
addValidation := func(warnings admission.Warnings, errors field.ErrorList) {
allWarnings = append(allWarnings, warnings...)
allErrors = append(allErrors, errors...)
}

addValidation(v.validateExtraConfig(*tempo))

if len(allErrors) == 0 {
return allWarnings, nil
}
return allWarnings, apierrors.NewInvalid(tempo.GroupVersionKind().GroupKind(), tempo.Name, allErrors)
}

func (v *monolithicValidator) validateExtraConfig(tempo tempov1alpha1.TempoMonolithic) (admission.Warnings, field.ErrorList) { //nolint:unparam
if tempo.Spec.ExtraConfig != nil && len(tempo.Spec.ExtraConfig.Tempo.Raw) > 0 {
return admission.Warnings{"overriding Tempo configuration could potentially break the deployment, use it carefully"}, nil
}
return nil, nil
}
Loading

0 comments on commit 37ac629

Please sign in to comment.