-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
API: Add new AdmissionControl service (experimental for now) (#983)
Co-authored-by: Andres Martinez Gotor <[email protected]> Co-authored-by: Marcus Efraimsson <[email protected]>
- Loading branch information
1 parent
ee05993
commit 94941f4
Showing
17 changed files
with
1,888 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package backend | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2" | ||
) | ||
|
||
// AdmissionHandler is an EXPERIMENTAL service that allows checking objects before they are saved | ||
// This is modeled after the kubernetes model for admission controllers | ||
// Since grafana 11.1, this feature is under active development and will continue to evolve in 2024 | ||
// This may also be replaced with a more native kubernetes solution that does not work with existing tooling | ||
type AdmissionHandler interface { | ||
// ValidateAdmission is a simple yes|no check if an object can be saved | ||
ValidateAdmission(context.Context, *AdmissionRequest) (*ValidationResponse, error) | ||
// MutateAdmission converts the input into an object that can be saved, or rejects the request | ||
MutateAdmission(context.Context, *AdmissionRequest) (*MutationResponse, error) | ||
// ConvertObject is called to covert objects between different versions | ||
ConvertObject(context.Context, *ConversionRequest) (*ConversionResponse, error) | ||
} | ||
|
||
type ValidateAdmissionFunc func(context.Context, *AdmissionRequest) (*ValidationResponse, error) | ||
type MutateAdmissionFunc func(context.Context, *AdmissionRequest) (*MutationResponse, error) | ||
type ConvertObjectFunc func(context.Context, *ConversionRequest) (*ConversionResponse, error) | ||
|
||
// Operation is the type of resource operation being checked for admission control | ||
// https://github.com/kubernetes/kubernetes/blob/v1.30.0/pkg/apis/admission/types.go#L158 | ||
type AdmissionRequestOperation int32 | ||
|
||
const ( | ||
AdmissionRequestCreate AdmissionRequestOperation = 0 | ||
AdmissionRequestUpdate AdmissionRequestOperation = 1 | ||
AdmissionRequestDelete AdmissionRequestOperation = 2 | ||
) | ||
|
||
// String textual representation of the operation. | ||
func (o AdmissionRequestOperation) String() string { | ||
return pluginv2.AdmissionRequest_Operation(o).String() | ||
} | ||
|
||
// Identify the Object properties | ||
type GroupVersionKind struct { | ||
Group string `json:"group,omitempty"` | ||
Version string `json:"version,omitempty"` | ||
Kind string `json:"kind,omitempty"` | ||
} | ||
|
||
type AdmissionRequest struct { | ||
// NOTE: this may not include populated instance settings depending on the request | ||
PluginContext PluginContext `json:"pluginContext,omitempty"` | ||
// The requested operation | ||
Operation AdmissionRequestOperation `json:"operation,omitempty"` | ||
// The object kind | ||
Kind GroupVersionKind `json:"kind,omitempty"` | ||
// Object is the object in the request. This includes the full metadata envelope. | ||
ObjectBytes []byte `json:"object_bytes,omitempty"` | ||
// OldObject is the object as it currently exists in storage. This includes the full metadata envelope. | ||
OldObjectBytes []byte `json:"old_object_bytes,omitempty"` | ||
} | ||
|
||
// ConversionRequest supports converting an object from on version to another | ||
type ConversionRequest struct { | ||
// NOTE: this may not include app or datasource instance settings depending on the request | ||
PluginContext PluginContext `json:"pluginContext,omitempty"` | ||
// The object kind | ||
Kind GroupVersionKind `json:"kind,omitempty"` | ||
// Object is the object in the request. This includes the full metadata envelope. | ||
ObjectBytes []byte `json:"object_bytes,omitempty"` | ||
// Target converted version | ||
TargetVersion string `json:"target_version,omitempty"` | ||
} | ||
|
||
// Basic request to say if the validation was successful or not | ||
type ValidationResponse struct { | ||
// Allowed indicates whether or not the admission request was permitted. | ||
Allowed bool `json:"allowed,omitempty"` | ||
// Result contains extra details into why an admission request was denied. | ||
// This field IS NOT consulted in any way if "Allowed" is "true". | ||
// +optional | ||
Result *StatusResult `json:"result,omitempty"` | ||
// warnings is a list of warning messages to return to the requesting API client. | ||
// Warning messages describe a problem the client making the API request should correct or be aware of. | ||
// Limit warnings to 120 characters if possible. | ||
// Warnings over 256 characters and large numbers of warnings may be truncated. | ||
// +optional | ||
Warnings []string `json:"warnings,omitempty"` | ||
} | ||
|
||
type MutationResponse struct { | ||
// Allowed indicates whether or not the admission request was permitted. | ||
Allowed bool `json:"allowed,omitempty"` | ||
// Result contains extra details into why an admission request was denied. | ||
// This field IS NOT consulted in any way if "Allowed" is "true". | ||
// +optional | ||
Result *StatusResult `json:"result,omitempty"` | ||
// warnings is a list of warning messages to return to the requesting API client. | ||
// Warning messages describe a problem the client making the API request should correct or be aware of. | ||
// Limit warnings to 120 characters if possible. | ||
// Warnings over 256 characters and large numbers of warnings may be truncated. | ||
// +optional | ||
Warnings []string `json:"warnings,omitempty"` | ||
// Mutated object bytes (when requested) | ||
// +optional | ||
ObjectBytes []byte `json:"object_bytes,omitempty"` | ||
} | ||
|
||
type ConversionResponse struct { | ||
// Allowed indicates whether or not the admission request was permitted. | ||
Allowed bool `json:"allowed,omitempty"` | ||
// Result contains extra details into why an admission request was denied. | ||
// This field IS NOT consulted in any way if "Allowed" is "true". | ||
// +optional | ||
Result *StatusResult `json:"result,omitempty"` | ||
// Converted object bytes | ||
ObjectBytes []byte `json:"object_bytes,omitempty"` | ||
} | ||
|
||
type StatusResult struct { | ||
// Status of the operation. | ||
// One of: "Success" or "Failure". | ||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status | ||
// +optional | ||
Status string `json:"status,omitempty"` | ||
// A human-readable description of the status of this operation. | ||
// +optional | ||
Message string `json:"message,omitempty"` | ||
// A machine-readable description of why this operation is in the | ||
// "Failure" status. If this value is empty there | ||
// is no information available. A Reason clarifies an HTTP status | ||
// code but does not override it. | ||
// +optional | ||
Reason string `json:"reason,omitempty"` | ||
// Suggested HTTP return code for this status, 0 if not set. | ||
// +optional | ||
Code int32 `json:"code,omitempty"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package backend | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2" | ||
) | ||
|
||
// admissionSDKAdapter adapter between low level plugin protocol and SDK interfaces. | ||
type admissionSDKAdapter struct { | ||
handler AdmissionHandler | ||
} | ||
|
||
func newAdmissionSDKAdapter(handler AdmissionHandler) *admissionSDKAdapter { | ||
return &admissionSDKAdapter{ | ||
handler: handler, | ||
} | ||
} | ||
|
||
func (a *admissionSDKAdapter) ValidateAdmission(ctx context.Context, req *pluginv2.AdmissionRequest) (*pluginv2.ValidationResponse, error) { | ||
ctx = propagateTenantIDIfPresent(ctx) | ||
parsedReq := FromProto().AdmissionRequest(req) | ||
resp, err := a.handler.ValidateAdmission(ctx, parsedReq) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return ToProto().ValidationResponse(resp), nil | ||
} | ||
|
||
func (a *admissionSDKAdapter) MutateAdmission(ctx context.Context, req *pluginv2.AdmissionRequest) (*pluginv2.MutationResponse, error) { | ||
ctx = propagateTenantIDIfPresent(ctx) | ||
parsedReq := FromProto().AdmissionRequest(req) | ||
resp, err := a.handler.MutateAdmission(ctx, parsedReq) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return ToProto().MutationResponse(resp), nil | ||
} | ||
|
||
func (a *admissionSDKAdapter) ConvertObject(ctx context.Context, req *pluginv2.ConversionRequest) (*pluginv2.ConversionResponse, error) { | ||
ctx = propagateTenantIDIfPresent(ctx) | ||
parsedReq := FromProto().ConversionRequest(req) | ||
resp, err := a.handler.ConvertObject(ctx, parsedReq) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return ToProto().ConversionResponse(resp), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.