Admission Control

作者 grafana1ccacf29049fApache-2.0279 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫今天更新

Use when the user asks to "write a validator", "add validation", "implement admission control", "write a mutating webhook", "add a mutation handler", "validate incoming resources", "implement admission logic", "add admission webhooks", "write ingress validation", or asks how to validate or mutate resources before they are persisted in a grafana-app-sdk app. Provides guidance on implementing validation and mutation admission handlers for grafana-app-sdk apps.

AI 產生的概覽

指導為 grafana-app-sdk 應用程式實作驗證與變更准入處理器。

功能
此技能為在 grafana-app-sdk 應用程式中撰寫准入控制處理器提供指引與程式碼模式。內容涵蓋 Validator 與 Mutator 介面、範例實作、在應用程式建構器中註冊處理器、准入請求欄位,以及不可變性與跨欄位驗證等常見驗證模式。它也說明獨立 operator 與 grafana/apps 部署方式下准入執行方式的差異。
適用情境
當使用者要求撰寫驗證器、加入驗證、實作准入控制、撰寫變更 webhook,或在 grafana-app-sdk 應用程式中於資源持久化前驗證或變更資源時使用。它面向使用 grafana-app-sdk 類型與准入邏輯的開發者。
執行需求
需要一個 grafana-app-sdk Go 專案;此技能僅為說明文件,不附帶指令碼。它引用 grafana-app-sdk 的 Go 套件以及用於產生 operator 骨架的 grafana-app-sdk 命令列工具,並提及 Kubernetes 准入 webhook 與 CUE 類型定義。

Admission Control

Admission control intercepts resource create/update requests before they are persisted. In grafana-app-sdk there are two types:

  • Validation — accept or reject a request; cannot modify the resource
  • Mutation — modify the resource before it is persisted (e.g. set defaults, normalize fields)

The app business logic for admission is identical whether the app runs as a standalone operator or inside grafana/apps. The only difference is the runtime: standalone apps stand up their own webhook server; grafana/apps apps have admission auto-registered as a Kubernetes plugin.

Getting Stubs

For standalone apps, if pkg/app/app.go does not yet exist, a stub App can be generated with:

bash
grafana-app-sdk project component add operator

This creates scaffolded simple.App which admission handlers can be added to for each kind in ManagedKinds.

Validator Interface

go
// Implement this interface for each kind you want to validatetype Validator interface {    Validate(ctx context.Context, request *app.AdmissionRequest) error}
  • Return nil to admit the request
  • Return an error to reject it (the error message is returned to the API caller)
  • app.AdmissionRequest provides access to the incoming object and operation type
  • You can use k8s.NewAdmissionError(err error, statusCode int, reason string) (from "github.com/grafana/grafana-app-sdk/k8s") to better control the returned error information

Validator Example

go
type MyKindValidator struct{}
func (v *MyKindValidator) Validate(ctx context.Context, req *app.AdmissionRequest) error {    obj, ok := req.Object.(*v1.MyKind)    if !ok {        return fmt.Errorf("admission request object was of invalid type %T (expected *v1.MyKind)", req.Object)    }
    // Validate spec fields    if obj.Spec.Title == "" {        return fmt.Errorf("spec.title is required")    }
    if obj.Spec.Count < 0 {        return fmt.Errorf("spec.count must be non-negative, got %d", obj.Spec.Count)    }
    // Distinguish create vs update    if req.Action == resource.AdmissionActionUpdate && req.OldObject != nil {        old, ok := req.OldObject.(*v1.MyKind)        if !ok {            return fmt.Errorf("admission request old object was of invalid type %T (expected *v1.MyKind)", req.OldObject)        }        if old.Spec.Title != obj.Spec.Title {            return fmt.Errorf("spec.title is immutable after creation")        }    }
    return nil}

Mutating Admission (Mutator)

go
// Implement this interface to mutate resources before persistencetype Mutator interface {    Mutate(ctx context.Context, request *app.AdmissionRequest) (*app.MutatingResponse, error)}
  • Return a MutatingResponse containing the (optionally modified) object
  • Return an error to reject the request entirely
  • Best practice is to reject requests from validators, not mutators

Mutating Handler Example

go
type MyKindMutator struct{}
func (m *MyKindMutator) Mutate(    ctx context.Context,    req *app.AdmissionRequest,) (*app.MutatingResponse, error) {    obj, ok := req.Object.(*v1.MyKind)    if !ok {        return nil, fmt.Errorf("admission request object was of invalid type %T (expected *v1.MyKind)", req.Object)    }
    // Set defaults on create    if req.Action == resource.AdmissionActionCreate {        if obj.Spec.Description == "" {            obj.Spec.Description = "No description provided"        }    }
    return &app.MutatingResponse{UpdatedObject: obj}, nil}

Registering Admission Handlers

Register validators and mutators when building the app in pkg/app/app.go:

go
func New(cfg app.Config) (app.App, error) {    cfg.KubeConfig.APIPath = "/apis"    a, err := simple.NewApp(simple.AppConfig{        ManagedKinds: []simple.AppManagedKind{            {                Kind:      v1.MyKindKind(),                Validator: &MyKindValidator{},                Mutator:   &MyKindMutator{},            },        },    })    if err != nil {      return nil, fmt.Errorf("error creating app: %w", err)    }    if err = a.ValidateManifest(cfg.ManifestData); err != nil {        return nil, fmt.Errorf("app manifest validation failed: %w", err)    }    return a, nil}

Note that mutation and validation must also be enabled in the kind's CUE definition (mutation.operations and validation.operations fields) — see the cue-kind-definition skill for details.

Admission Request Fields

Key fields available on app.AdmissionRequest:

FieldTypeDescription
Objectresource.ObjectThe incoming resource (after decoding)
OldObjectresource.ObjectPrevious state (only on UPDATE operations)
Actionresource.AdmissionActionAdmissionActionCreate, AdmissionActionUpdate, AdmissionActionDelete, AdmissionActionConnect
UserInforesource.AdmissionUserInfoThe user making the request
KindstringThe Object kind
GroupstringThe Object API Group
VersionstringThe Object API Version

Validation Patterns

Common patterns to implement:

go
// Immutability checkif req.Action == resource.AdmissionActionUpdate && old.Spec.ImmutableField != obj.Spec.ImmutableField {    return fmt.Errorf("spec.immutableField cannot be changed after creation")}
// Cross-field validationif obj.Spec.StartTime.After(obj.Spec.EndTime) {    return fmt.Errorf("spec.startTime must be before spec.endTime")}
// Referential validation (e.g. check referenced resource exists)if _, err := v.client.Get(ctx, resource.Identifier{Name: obj.Spec.RefName, Namespace: obj.Namespace}); err != nil {    return fmt.Errorf("referenced resource %q not found", obj.Spec.RefName)}

Deployment Difference

ModeAdmission runtime
Standalone operatorApp starts a webhook server; Kubernetes routes admission requests to it
grafana/appsAdmission handlers are auto-registered as a Kubernetes in-process plugin — no separate server required

The handler code itself is identical in both cases.

Resources

來源與署名

來源:grafana/skills位於skills/grafana-app-sdk/admission-control提交1ccacf2

授權條款: Apache-2.0

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 grafana/skills 的技能

React 19 Plugin Migration

grafana

指導將 Grafana 外掛遷移至 React 19 相容,依序完成建置、相依性與原始碼修改步驟。

Software Development279今天更新

Plugin Bundle Size

grafana

指導使用 React.lazy、Suspense 與 webpack 程式碼分割來最佳化 Grafana 應用程式外掛的打包體積。

Software Development279今天更新

Grafana Scenes

grafana

使用 @grafana/scenes 框架建置 Grafana 外掛頁面,涵蓋場景、面板、變數與下鑽導覽。

Software Development279今天更新

Check Npm

grafana

對 JS/TS 儲存庫的 npm、yarn 或 pnpm 設定進行唯讀供應鏈強化稽核。

Security279今天更新

Mimir

grafana

指導架設與維運 Grafana Mimir,用於可擴充、多租戶、長期的 Prometheus 與 OTLP 指標儲存。

DevOps & Cloud279今天更新

K6 Trend Analysis

grafana

Analyze Grafana Cloud k6 test run trends over time. Detects slow metric drift (e.g., P95 latency creeping up while still passing thresholds), computes headroom to thresholds, flags anomalies, and recommends threshold tightening. Use when the user asks about test performance trends, wants to know if metrics are degrading, asks whether thresholds should be tightened, or wants a health check across recent runs for a specific test. Trigger on phrases like "how is my test trending", "is P95 getting worse", "check for performance regression", "should I tighten thresholds", "are my tests degrading", "show me trends for test X", "analyze my k6 test runs", or "is my test getting slower". Also trigger when a user asks to check all tests in a project -- run this skill once per test and synthesize.

待分類279今天更新