The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/storage/unified/resource/resource.proto

865 lines
24 KiB

syntax = "proto3";
package resource;
option go_package = "github.com/grafana/grafana/pkg/storage/unified/resource";
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;
// Optionally decide to return the latest RV if deleted
bool include_deleted = 3;
}
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 {
NotOlderThan = 0;
Exact = 1;
}
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
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;
}
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 BatchRequest {
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 BatchResponse {
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;
BatchRequest.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;
}
// Get statistics across multiple resources
// For these queries, we do not need authorization to see the actual values
message ResourceStatsRequest {
// Namespace (tenant)
string namespace = 1;
// An optional list of group/resource identifiers
// when empty, we assume searching across everything
// NOTE, this query may need to federate across a few storage instances
repeated string kinds = 2;
// Limit the stats within a folder (not recursive!)
string folder = 3;
}
message ResourceStatsResponse {
message Stats {
// Resource group
string group = 1;
// Resource name
string resource = 2;
// Number of items
int64 count = 3;
}
// Error details
ErrorResult error = 1;
// All results exist within this key
repeated Stats stats = 2;
}
// Search within a single resource
message ResourceSearchRequest {
message Sort {
string field = 1;
bool desc = 2; // defaults to ascending
}
message Facet {
string field = 1;
int64 limit = 2;
// For now, only term queries, eventually?
// numeric queries
// date queries
}
// The key must include namespace + group + resource
ListOptions options = 1;
// To search additional resource types, add additional keys to this list
// NOTE: queries will only support federation across kinds with common fields
repeated ResourceKey federated = 2;
// When a query exists, it is parsed and used to influence
// query string for chosen implementation (currently just bleve)
// The score is only relevant when a query exists
string query = 3;
// max results
int64 limit = 4;
// where to start the query (eg, From)
int64 offset = 5;
// sorting
repeated Sort sortBy = 6;
// calculate field statistics
map<string,Facet> facet = 7;
// the return fields (empty will return everything)
repeated string fields = 8;
// explain each result (added to the each row)
bool explain = 9;
bool is_deleted = 10;
int64 page = 11;
int64 permission = 12;
}
message ResourceSearchResponse {
message Facet {
string field = 1;
// The distinct terms
int64 total = 2;
// The number of documents that do *not* have this field
int64 missing = 3;
// Top term stats
repeated TermFacet terms = 4;
// numeric range
// date range facets
}
message TermFacet {
string term = 1;
int64 count = 2;
}
// Error details
ErrorResult error = 1;
// All results exist within this key
ResourceKey key = 2;
// Query results
ResourceTable results = 3;
// The total hit count
int64 total_hits = 4;
// indicates how expensive was the query with respect to bytes read
double query_cost = 5;
// maximum score across all fields
double max_score = 6;
// Facet results
map<string,Facet> facet = 7;
}
// List items within a resource type & repository name
// Access control is managed above this request
message ListRepositoryObjectsRequest {
// Starting from the requested page (other query parameters must match!)
string next_page_token = 1;
// Namespace (tenant)
string namespace = 2;
// The name of the repository
string name = 3;
}
message ListRepositoryObjectsResponse {
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 CountRepositoryObjectsRequest {
// Namespace (tenant)
string namespace = 1;
// The name of the repository
// empty to count across all repositories
string name = 2;
}
// Count the items that exist with
message CountRepositoryObjectsResponse {
message ResourceCount {
string repository = 1;
string group = 2;
string resource = 3;
int64 count = 4;
}
// 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;
}
//----------------------------
// Restore Support
//----------------------------
message RestoreRequest {
// Full key must be set
ResourceKey key = 1;
// The resource version to restore
int64 resource_version = 2;
}
message RestoreResponse {
// Error details
ErrorResult error = 1;
// The updated resource version
int64 resource_version = 2;
}
//----------------------------
// Blob Support
//----------------------------
message PutBlobRequest {
enum Method {
// Use the inline raw []byte
GRPC = 0;
// Get a signed URL and PUT the value
HTTP = 1;
}
// The resource that will use this blob
// NOTE: the name may not yet exist, but group+resource are required
ResourceKey resource = 1;
// How to upload
Method method = 2;
// Content type header
string content_type = 3;
// Raw value to write
// Not valid when method == HTTP
bytes value = 4;
}
message PutBlobResponse {
// Error details
ErrorResult error = 1;
// The blob uid. This must be saved into the resource to support access
string uid = 2;
// The URL where this value can be PUT
string url = 3;
// Size of the uploaded blob
int64 size = 4;
// Content hash used for an etag
string hash = 5;
// Validated mimetype (from content_type)
string mime_type = 6;
// Validated charset (from content_type)
string charset = 7;
}
message GetBlobRequest {
ResourceKey resource = 1;
// The new resource version
int64 resource_version = 2;
// Do not return a pre-signed URL (when possible)
bool must_proxy_bytes = 3;
// The blob UID -- when empty, the value is loaded from annotations in the matching resource
string uid = 4;
}
message GetBlobResponse {
// Error details
ErrorResult error = 1;
// (optional) When possible, the system will return a presigned URL
// that can be used to actually read the full blob+metadata
// When this is set, neither info nor value will be set
string url = 2;
// Content type
string content_type = 3;
// The raw object value
bytes value = 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);
rpc Restore(RestoreRequest) returns (RestoreResponse);
// 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 BatchStore {
// 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 BatchProcess(stream BatchRequest) returns (BatchResponse);
}
// Unlike the ResourceStore, this service can be exposed to clients directly
// It should be implemented with efficient indexes and does not need read-after-write semantics
service ResourceIndex {
rpc Search(ResourceSearchRequest) returns (ResourceSearchResponse);
// Get the resource stats
rpc GetStats(ResourceStatsRequest) returns (ResourceStatsResponse);
}
// Query repository info from the search index.
// Results access control is based on access to the repository *not* the items
service RepositoryIndex {
// Describe how many resources of each type exist within a repository
rpc CountRepositoryObjects(CountRepositoryObjectsRequest) returns (CountRepositoryObjectsResponse);
// List the resources of a specific kind within a repository
rpc ListRepositoryObjects(ListRepositoryObjectsRequest) returns (ListRepositoryObjectsResponse);
}
service BlobStore {
// Upload a blob that will be saved in a resource
rpc PutBlob(PutBlobRequest) returns (PutBlobResponse);
// Get blob contents. When possible, this will return a signed URL
// For large payloads, signed URLs are required to avoid protobuf message size limits
rpc GetBlob(GetBlobRequest) returns (GetBlobResponse);
// NOTE: there is no direct access to delete blobs
// >> cleanup will be managed via garbage collection or direct access to the underlying storage
}
// 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);
}