Advisor: Expose endpoint to register checktypes (#113750)

This commit is contained in:
Andres Martinez Gotor
2025-11-17 12:48:53 +01:00
committed by GitHub
parent aa26cc4254
commit 151d9ec1cc
8 changed files with 286 additions and 44 deletions
+44 -8
View File
@@ -2,7 +2,9 @@ package app
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/k8s"
@@ -16,6 +18,7 @@ import (
"github.com/grafana/grafana/apps/advisor/pkg/app/checkscheduler"
"github.com/grafana/grafana/apps/advisor/pkg/app/checktyperegisterer"
"github.com/grafana/grafana/pkg/apimachinery/identity"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
@@ -49,6 +52,16 @@ func New(cfg app.Config) (app.App, error) {
checkMap[c.ID()] = c
}
ctr, err := checktyperegisterer.New(cfg, log)
if err != nil {
return nil, err
}
csch, err := checkscheduler.New(cfg, log)
if err != nil {
return nil, err
}
simpleConfig := simple.AppConfig{
Name: "advisor",
KubeConfig: cfg.KubeConfig,
@@ -110,6 +123,37 @@ func New(cfg app.Config) (app.App, error) {
Kind: advisorv0alpha1.CheckTypeKind(),
},
},
VersionedCustomRoutes: map[string]simple.AppVersionRouteHandlers{
"v0alpha1": {
{
Namespaced: true,
Path: "register",
Method: "POST",
}: func(ctx context.Context, w app.CustomRouteResponseWriter, req *app.CustomRouteRequest) error {
logger := log.WithContext(ctx)
namespace := req.ResourceIdentifier.Namespace
// Register check types for the namespace
err := ctr.RegisterCheckTypesInNamespace(ctx, logger, namespace)
if err != nil {
logger.Error("Failed to register check types", "namespace", namespace, "error", err)
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
return err
}
// Return typed response matching the manifest
return json.NewEncoder(w).Encode(advisorv0alpha1.CreateRegister{
TypeMeta: metav1.TypeMeta{
APIVersion: fmt.Sprintf("%s/%s", advisorv0alpha1.APIGroup, advisorv0alpha1.APIVersion),
},
CreateRegisterBody: advisorv0alpha1.CreateRegisterBody{
Message: "Check types registered successfully",
},
})
},
},
},
}
a, err := simple.NewApp(simpleConfig)
@@ -123,17 +167,9 @@ func New(cfg app.Config) (app.App, error) {
}
// Save check types as resources
ctr, err := checktyperegisterer.New(cfg, log)
if err != nil {
return nil, err
}
a.AddRunnable(ctr)
// Start scheduler
csch, err := checkscheduler.New(cfg, log)
if err != nil {
return nil, err
}
a.AddRunnable(csch)
return a, nil
@@ -34,8 +34,10 @@ type Runner struct {
retryDelay time.Duration
}
var _ app.Runnable = (*Runner)(nil)
// NewRunner creates a new Runner.
func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
func New(cfg app.Config, log logging.Logger) (*Runner, error) {
// Read config
specificConfig, ok := cfg.SpecificConfig.(checkregistry.AdvisorAppConfig)
if !ok {
@@ -79,37 +81,9 @@ func (r *Runner) Run(ctx context.Context) error {
// Register check types in each namespace
for _, namespace := range namespaces {
for _, t := range r.checkRegistry.Checks() {
steps := t.Steps()
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
for i, s := range steps {
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
Title: s.Title(),
Description: s.Description(),
StepID: s.ID(),
Resolution: s.Resolution(),
}
}
obj := &advisorv0alpha1.CheckType{
ObjectMeta: metav1.ObjectMeta{
Name: t.ID(),
Namespace: namespace,
Annotations: map[string]string{
checks.NameAnnotation: t.Name(),
// Flag to indicate feature availability
checks.RetryAnnotation: "1",
checks.IgnoreStepsAnnotation: "1",
},
},
Spec: advisorv0alpha1.CheckTypeSpec{
Name: t.ID(),
Steps: stepTypes,
},
}
err := r.registerCheckType(ctx, logger, t.ID(), obj)
if err != nil {
return err
}
err := r.RegisterCheckTypesInNamespace(ctx, logger, namespace)
if err != nil {
return fmt.Errorf("failed to register check types in namespace %s: %w", namespace, err)
}
}
return nil
@@ -243,3 +217,38 @@ func isAPIServerShuttingDown(err error, logger logging.Logger) bool {
}
return false
}
func (r *Runner) RegisterCheckTypesInNamespace(ctx context.Context, logger logging.Logger, namespace string) error {
for _, t := range r.checkRegistry.Checks() {
steps := t.Steps()
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
for i, s := range steps {
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
Title: s.Title(),
Description: s.Description(),
StepID: s.ID(),
Resolution: s.Resolution(),
}
}
obj := &advisorv0alpha1.CheckType{
ObjectMeta: metav1.ObjectMeta{
Name: t.ID(),
Namespace: namespace,
Annotations: map[string]string{
checks.NameAnnotation: t.Name(),
// Flag to indicate feature availability
checks.RetryAnnotation: "1",
checks.IgnoreStepsAnnotation: "1",
},
},
Spec: advisorv0alpha1.CheckTypeSpec{
Name: t.ID(),
Steps: stepTypes,
},
}
if err := r.registerCheckType(ctx, logger, t.ID(), obj); err != nil {
return fmt.Errorf("failed to register check type %s: %w", t.ID(), err)
}
}
return nil
}