Files
grafana/pkg/storage/unified/proto/resource.proto
2025-05-15 21:36:52 +02:00

634 lines
18 KiB
Protocol Buffer

syntax = "proto3";
package resource;
option go_package = "github.com/grafana/grafana/pkg/storage/unified/resourcepb";
message ResourceKey {
// Namespace (tenant)
string namespace = 2;
// Resource Group
string group = 1;
// The resource type
string resource = 3;
// Resource identifier (unique within namespace+group+resource)
string name = 4;
}
message ResourceWrapper {
// The resource version
int64 resource_version = 1;
// Full kubernetes json bytes (although the resource version may not be accurate)
bytes value = 2;
}
// Status structure is copied from:
// https://github.com/kubernetes/apimachinery/blob/v0.30.1/pkg/apis/meta/v1/generated.proto#L979
// However, this is only used for error handling, never for succesful results
message ErrorResult {
// A human-readable description of the status of this operation.
// +optional
string message = 1;
// 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
string reason = 2;
// Extended data associated with the reason. Each reason may define its
// own extended details. This field is optional and the data returned
// is not guaranteed to conform to any schema except that defined by
// the reason type.
// +optional
// +listType=atomic
ErrorDetails details = 3;
// Suggested HTTP return code for this status, 0 if not set.
// +optional
int32 code = 4;
}
// ErrorDetails is a set of additional properties that MAY be set by the
// server to provide additional information about a response. The Reason
// field of a Status object defines what attributes will be set. Clients
// must ignore fields that do not match the defined type of each attribute,
// and should assume that any attribute may be empty, invalid, or under
// defined.
message ErrorDetails {
// The name attribute of the resource associated with the status StatusReason
// (when there is a single name which can be described).
// +optional
string name = 1;
// The group attribute of the resource associated with the status StatusReason.
// +optional
string group = 2;
// The kind attribute of the resource associated with the status StatusReason.
// On some operations may differ from the requested resource Kind.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +optional
string kind = 3;
// UID of the resource.
// (when there is a single resource which can be described).
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids
// +optional
string uid = 6;
// The Causes array includes more details associated with the StatusReason
// failure. Not all StatusReasons may provide detailed causes.
// +optional
// +listType=atomic
repeated ErrorCause causes = 4;
// If specified, the time in seconds before the operation should be retried. Some errors may indicate
// the client must take an alternate action - for those errors this field may indicate how long to wait
// before taking the alternate action.
// +optional
int32 retryAfterSeconds = 5;
}
message ErrorCause {
// A machine-readable description of the cause of the error. If this value is
// empty there is no information available.
string reason = 1;
// A human-readable description of the cause of the error. This field may be
// presented as-is to a reader.
// +optional
string message = 2;
// The field of the resource that has caused this error, as named by its JSON
// serialization. May include dot and postfix notation for nested attributes.
// Arrays are zero-indexed. Fields may appear more than once in an array of
// causes due to fields having multiple errors.
// Optional.
//
// Examples:
// "name" - the field "name" on the current resource
// "items[0].name" - the field "name" on the first array entry in "items"
// +optional
string field = 3;
}
// ----------------------------------
// CRUD Objects
// ----------------------------------
message CreateRequest {
// Requires group+resource to be configuired
// If name is not set, a unique name will be generated
// The resourceVersion should not be set
ResourceKey key = 1;
// The resource JSON.
bytes value = 2;
}
message CreateResponse {
// Error details
ErrorResult error = 1;
// The updated resource version
int64 resource_version = 2;
}
message UpdateRequest {
// Full key must be set
ResourceKey key = 1;
// The current resource version
int64 resource_version = 2;
// The resource JSON.
bytes value = 3;
}
message UpdateResponse {
// Error details
ErrorResult error = 1;
// The updated resource version
int64 resource_version = 2;
}
message DeleteRequest {
ResourceKey key = 1;
// The current resource version
int64 resource_version = 2;
// Preconditions: make sure the uid matches the current saved value
// +optional
string uid = 3;
}
message DeleteResponse {
// Error details
ErrorResult error = 1;
// The resource version for the deletion marker
int64 resource_version = 2;
}
message ReadRequest {
ResourceKey key = 1;
// Optionally pick an explicit resource version
int64 resource_version = 2;
}
message ReadResponse {
// Error details
ErrorResult error = 1;
// The new resource version
int64 resource_version = 2;
// The properties
bytes value = 3;
}
// ----------------------------------
// List Request/Response
// ----------------------------------
// The label filtering requirements:
// https://github.com/kubernetes/kubernetes/blob/v1.30.1/staging/src/k8s.io/apimachinery/pkg/labels/selector.go#L141
message Requirement {
string key = 1;
string operator = 2; // See https://github.com/kubernetes/kubernetes/blob/v1.30.1/staging/src/k8s.io/apimachinery/pkg/selection/operator.go#L21
repeated string values = 3; // typically one value, but depends on the operator
}
message ListOptions {
// Group+Namespace+Resource (not name)
ResourceKey key = 1;
// (best effort) Match label
// Allowed to send more results than actually match because the filter will be applied
// to the results again in the client. That time with the full field selector
repeated Requirement labels = 2;
// (best effort) fields matcher
// Allowed to send more results than actually match because the filter will be applied
// to the results again in the client. That time with the full field selector
repeated Requirement fields = 3;
}
enum ResourceVersionMatch {
// Deprecated, use ResourceVersionMatch V2
DEPRECATED_NotOlderThan = 0;
DEPRECATED_Exact = 1;
}
enum ResourceVersionMatchV2 {
UNKNOWN = 0;
Unset = 1;
Exact = 2;
NotOlderThan = 3;
}
message ListRequest {
enum Source {
STORE = 0; // the standard place
HISTORY = 1;
TRASH = 2;
}
// Starting from the requested page (other query parameters must match!)
string next_page_token = 1;
// The resource version
int64 resource_version = 2;
// List options
// DEPRECATED - use version_match_v2
optional ResourceVersionMatch version_match = 3;
// Maximum number of items to return
// NOTE responses will also be limited by the response payload size
int64 limit = 4;
// Filtering
ListOptions options = 5;
// Select values from history or trash
Source source = 6;
ResourceVersionMatchV2 version_match_v2 = 7;
}
message ListResponse {
repeated ResourceWrapper items = 1;
// When more results exist, pass this in the next request
string next_page_token = 2;
// ResourceVersion of the list response
int64 resource_version = 3;
// remainingItemCount is the number of subsequent items in the list which are not included in this
// list response. If the list request contained label or field selectors, then the number of
// remaining items is unknown and the field will be left unset and omitted during serialization.
// If the list is complete (either because it is not chunking or because this is the last chunk),
// then there are no more remaining items and this field will be left unset and omitted during
// serialization.
//
// The intended use of the remainingItemCount is *estimating* the size of a collection. Clients
// should not rely on the remainingItemCount to be set or to be exact.
// +optional
int64 remaining_item_count = 4; // 0 won't be set either (no next page token)
// Error details
ErrorResult error = 5;
}
message WatchRequest {
// ResourceVersion of last changes. Empty will default to full history
int64 since = 1;
// Additional options
ListOptions options = 3;
// Return initial events
bool send_initial_events = 4;
// When done with initial events, send a bookmark event
bool allow_watch_bookmarks = 5;
}
message WatchEvent {
enum Type {
UNKNOWN = 0;
ADDED = 1;
MODIFIED = 2;
DELETED = 3;
BOOKMARK = 4;
ERROR = 5;
}
message Resource {
int64 version = 1;
bytes value = 2;
}
// Timestamp the event was sent
int64 timestamp = 1;
// The event type
Type type = 2;
// Resource version for the object
Resource resource = 3;
// Previous resource version (for update+delete)
Resource previous = 4;
}
message BulkRequest {
enum Action {
// will be an error
UNKNOWN = 0;
// Matches Watch event enum
ADDED = 1;
MODIFIED = 2;
DELETED = 3;
}
// NOTE everything in the same stream must share the same Namespace/Group/Resource
ResourceKey key = 1;
// Requested action
Action action = 2;
// The resource value
bytes value = 3;
// Hint that a new version will be written on-top of this
string folder = 4;
}
message BulkResponse {
message Summary {
string namespace = 1;
string group = 2;
string resource = 3;
int64 count = 4;
int64 history = 5;
int64 resource_version = 6; // The max saved RV
// The previous count
int64 previous_count = 7;
int64 previous_history = 8;
}
// Collect a few invalid messages
message Rejected {
ResourceKey key = 1;
BulkRequest.Action action = 2;
string error = 3;
}
// Error details
ErrorResult error = 1;
// Total events processed
int64 processed = 2;
// Summary status for the processed values
repeated Summary summary = 3;
// Rejected
repeated Rejected rejected = 4;
}
// List items within a resource type & repository name
// Access control is managed above this request
message ListManagedObjectsRequest {
// Starting from the requested page (other query parameters must match!)
string next_page_token = 1;
// Namespace (tenant)
string namespace = 2;
// The manager type (eg, terraform vs repo)
string kind = 3;
// The name of the manager
string id = 4;
}
message ListManagedObjectsResponse {
message Item {
// The resource object key
ResourceKey object = 1;
// Hash for the resource
string path = 2;
// Verification hash from the origin
string hash = 3;
// Change time from the origin
int64 time = 5;
// Title inside the payload
string title = 6;
// The name of the folder in metadata
string folder = 7;
}
// Item iterator
repeated Item items = 1;
// More results exist... pass this in the next request
string next_page_token = 2;
// Error details
ErrorResult error = 3;
}
// Count the items that exist with
message CountManagedObjectsRequest {
// Namespace (tenant)
string namespace = 1;
// Manager kind: terraform, plugin, kubectl, repo
string kind = 2;
// Name of the manager (meaningful inside kind)
string id = 3;
}
// Count the items that exist with
message CountManagedObjectsResponse {
message ResourceCount {
string kind = 1;
string id = 2;
string group = 3;
string resource = 4;
int64 count = 5;
}
// Resource counts
repeated ResourceCount items = 1;
// Error details
ErrorResult error = 2;
}
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}
// ResourceTable is a protobuf variation of the kubernetes Table object.
// This format allows specifying a flexible set of columns related to a given resource
message ResourceTable {
// Columns describes each column in the returned items array. The number of cells per row
// will always match the number of column definitions.
repeated ResourceTableColumnDefinition columns = 1;
// rows is the list of items in the table.
repeated ResourceTableRow rows = 2;
// When more results exist, pass this in the next request
string next_page_token = 3;
// ResourceVersion of the list response
// +optional
int64 resource_version = 4;
// remainingItemCount is the number of subsequent items in the list which are not included in this
// list response. If the list request contained label or field selectors, then the number of
// remaining items is unknown and the field will be left unset and omitted during serialization.
// If the list is complete (either because it is not chunking or because this is the last chunk),
// then there are no more remaining items and this field will be left unset and omitted during
// serialization.
//
// The intended use of the remainingItemCount is *estimating* the size of a collection. Clients
// should not rely on the remainingItemCount to be set or to be exact.
// +optional
int64 remaining_item_count = 5;
}
// TableColumnDefinition contains information about a column returned in the Table.
message ResourceTableColumnDefinition {
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.
// When converted to a k8s Table, this will become two fields: type and format
enum ColumnType {
UNKNOWN_TYPE = 0;
STRING = 1;
BOOLEAN = 2;
INT32 = 3;
INT64 = 4;
FLOAT = 5;
DOUBLE = 6;
DATE = 7;
DATE_TIME = 8;
BINARY = 9;
OBJECT = 10; // map[string]any
}
// These values are not part of standard k8s format
// however these are useful when indexing and analyzing results
message Properties {
// All values in this columns should be unique
bool unique_values = 1;
// The string value is free text; using text analyzers is appropriate
bool free_text = 2;
// The value(s) are reasonable to use for search refinement
// When indexing, these values would be good to add to an index
bool filterable = 3;
// When true, every value should exist
// not_null with a nil default_value should be an error
bool not_null = 4;
// When missing, this value can be used
bytes default_value = 5;
}
// name is a human readable name for the column.
string name = 1;
// Defines the column type. In k8s, this will resolve into both the type and format fields
ColumnType type = 2;
// The value is an array of given type
bool is_array = 3;
// description is a human readable description of this column.
string description = 4;
// Properties about this column (helpful for indexing and search)
Properties properties = 5;
// priority is an integer defining the relative importance of this column compared to others. Lower
// numbers are considered higher priority. Columns that may be omitted in limited space scenarios
// should be given a higher priority.
int32 priority = 6;
}
// TableRow is an individual row in a table.
message ResourceTableRow {
// The resource referenced by this row
ResourceKey key = 1;
// The resource version for the given values
int64 resource_version = 2;
// Cells will be as wide as the column definitions array
// Numeric values will be encoded using big endian bytes
// All arrays will be JSON encoded
repeated bytes cells = 3;
// This field may contains the additional information about each object based on the request.
// The value will be at least a partial object metadata, and perhaps the full object metadata.
// When this value exists, it should include both the key and the resource_version otherwise
// they may be lost in the conversion to k8s resource
// +optional
bytes object = 4;
}
// This provides the CRUD+List+Watch support needed for a k8s apiserver
// The semantics and behaviors of this service are constrained by kubernetes
// This does not understand the resource schemas, only deals with json bytes
// Clients should not use this interface directly; it is for use in API Servers
service ResourceStore {
rpc Read(ReadRequest) returns (ReadResponse);
rpc Create(CreateRequest) returns (CreateResponse);
rpc Update(UpdateRequest) returns (UpdateResponse);
rpc Delete(DeleteRequest) returns (DeleteResponse);
// The results *may* include values that should not be returned to the user
// This will perform best-effort filtering to increase performace.
// NOTE: storage.Interface is ultimatly responsible for the final filtering
rpc List(ListRequest) returns (ListResponse);
// The results *may* include values that should not be returned to the user
// This will perform best-effort filtering to increase performace.
// NOTE: storage.Interface is ultimatly responsible for the final filtering
rpc Watch(WatchRequest) returns (stream WatchEvent);
}
service BulkStore {
// Write multiple resources to the same Namespace/Group/Resource
// Events will not be sent until the stream is complete
// Only the *create* permissions is checked
rpc BulkProcess(stream BulkRequest) returns (BulkResponse);
}
// Query managed objects
// Results access control is based on access to the repository *not* the items
service ManagedObjectIndex {
// Describe how many resources of each type exist within a repository
rpc CountManagedObjects(CountManagedObjectsRequest) returns (CountManagedObjectsResponse);
// List the resources of a specific kind within a repository
rpc ListManagedObjects(ListManagedObjectsRequest) returns (ListManagedObjectsResponse);
}
// Clients can use this service directly
// NOTE: This is read only, and no read afer write guarantees
service Diagnostics {
// Check if the service is healthy
rpc IsHealthy(HealthCheckRequest) returns (HealthCheckResponse);
}