Files
grafana/pkg/services/store/entity/entity.proto
T
Dan Cech c4c9bfaf2e Storage: Unified Storage based on Entity API (#71977)
* first round of entityapi updates

- quote column names and clean up insert/update queries
- replace grn with guid
- streamline table structure

fixes

streamline entity history

move EntitySummary into proto

remove EntitySummary

add guid to json

fix tests

change DB_Uuid to DB_NVarchar

fix folder test

convert interface to any

more cleanup

start entity store under grafana-apiserver dskit target

CRUD working, kind of

rough cut of wiring entity api to kube-apiserver

fake grafana user in context

add key to entity

list working

revert unnecessary changes

move entity storage files to their own package, clean up

use accessor to read/write grafana annotations

implement separate Create and Update functions

* go mod tidy

* switch from Kind to resource

* basic grpc storage server

* basic support for grpc entity store

* don't connect to database unless it's needed, pass user identity over grpc

* support getting user from k8s context, fix some mysql issues

* assign owner to snowflake dependency

* switch from ulid to uuid for guids

* cleanup, rename Search to List

* remove entityListResult

* EntityAPI: remove extra user abstraction (#79033)

* remove extra user abstraction

* add test stub (but

* move grpc context setup into client wrapper, fix lint issue

* remove unused constants

* remove custom json stuff

* basic list filtering, add todo

* change target to storage-server, allow entityStore flag in prod mode

* fix issue with Update

* EntityAPI: make test work, need to resolve expected differences (#79123)

* make test work, need to resolve expected differences

* remove the fields not supported by legacy

* sanitize out the bits legacy does not support

* sanitize out the bits legacy does not support

---------

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>

* update feature toggle generated files

* remove unused http headers

* update feature flag strategy

* devmode

* update readme

* spelling

* readme

---------

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2023-12-06 15:21:21 -05:00

485 lines
12 KiB
Protocol Buffer

syntax = "proto3";
package entity;
option go_package = "github.com/grafana/grafana/pkg/services/store/entity";
import "pkg/infra/grn/grn.proto";
// The canonical entity/document data -- this represents the raw bytes and storage level metadata
message Entity {
// Globally unique ID set by the system. This can not be set explicitly
string guid = 1;
// The resourceVersion -- it will change whenever anythign on the object is saved
string version = 2;
// Entity identifier -- tenant_id, kind, uid
grn.GRN GRN = 3;
// group version of the entity
string group_version = 23;
// k8s key value
string key = 22;
// The folder UID
string folder = 4;
// Raw meta from k8s
bytes meta = 5;
// Raw bytes of the storage entity. The kind will determine what is a valid payload
bytes body = 6;
// k8s style status (ignored for now)
bytes status = 7;
// the friendly name of the entity
string name = 8;
// Content Length
int64 size = 9;
// MD5 digest of the body
string ETag = 10;
// Time in epoch milliseconds that the entity was created
int64 created_at = 11;
// Who created the entity
string created_by = 12;
// Time in epoch milliseconds that the entity was updated
int64 updated_at = 13;
// Who updated the entity
string updated_by = 14;
// External location info
EntityOriginInfo origin = 15;
// human-readable description of the entity
string description = 16;
// URL safe version of the name. It will be unique within the folder
string slug = 17;
// Commit message (optional)
string message = 18;
// Key value pairs. Tags are are represented as keys with empty values
map<string,string> labels = 19;
// Optional field values. The schema will define and document possible values for a given kind
map<string, string> fields = 20;
// When errors exist
repeated EntityErrorInfo errors = 21;
}
// This stores additional metadata for items entities that were synced from external systmes
message EntityOriginInfo {
// identify the external source (plugin, git instance, etc)
string source = 1;
// Key in the upstream system (git hash, file path, etc)
string key = 2;
// Time in epoch milliseconds that the entity was last synced with an external system (provisioning/git)
int64 time = 3;
}
// Report error while working with entitys
// NOTE: real systems at scale will contain errors.
message EntityErrorInfo {
// Match an error code registry?
int64 code = 1;
// Simple error display
string message = 2;
// Details encoded in JSON
bytes details_json = 3;
}
//-----------------------------------------------
// Get request/response
//-----------------------------------------------
message ReadEntityRequest {
// Entity identifier
grn.GRN GRN = 1;
string key = 7;
// Fetch an explicit version (default is latest)
string version = 2;
// Include the full meta bytes
bool with_meta = 3;
// Include the full body bytes
bool with_body = 4;
// Include the status bytes (ignored for now)
bool with_status = 5;
// Include derived summary metadata
bool with_summary = 6;
}
//------------------------------------------------------
// Make many read requests at once (by Kind+ID+version)
//------------------------------------------------------
message BatchReadEntityRequest {
repeated ReadEntityRequest batch = 1;
}
message BatchReadEntityResponse {
repeated Entity results = 1;
}
//-----------------------------------------------
// Write request/response
//-----------------------------------------------
message WriteEntityRequest {
// Entity details
Entity entity = 1;
// Used for optimistic locking. If missing, the previous version will be replaced regardless
string previous_version = 2;
}
// This operation is useful when syncing a resource from external sources
// that have more accurate metadata information (git, or an archive).
// This process can bypass the forced checks that
message AdminWriteEntityRequest {
// Entity details
Entity entity = 1;
// Used for optimistic locking. If missing, the previous version will be replaced regardless
// This may not be used along with an explicit version in the request
string previous_version = 2;
// Request that all previous versions are removed from the history
// This will make sense for systems that manage history explicitly externallay
bool clear_history = 3;
}
message WriteEntityResponse {
// Error info -- if exists, the save did not happen
EntityErrorInfo error = 1;
// Entity details
Entity entity = 2;
// Status code
Status status = 3;
// Status enumeration
enum Status {
ERROR = 0;
CREATED = 1;
UPDATED = 2;
UNCHANGED = 3;
}
}
//-----------------------------------------------
// Create request/response
//-----------------------------------------------
message CreateEntityRequest {
// Entity details
Entity entity = 1;
}
message CreateEntityResponse {
// Error info -- if exists, the save did not happen
EntityErrorInfo error = 1;
// Entity details
Entity entity = 2;
// Status code
Status status = 3;
// Status enumeration
enum Status {
ERROR = 0;
CREATED = 1;
}
}
//-----------------------------------------------
// Update request/response
//-----------------------------------------------
message UpdateEntityRequest {
// Entity details
Entity entity = 1;
// Used for optimistic locking. If missing, the previous version will be replaced regardless
string previous_version = 2;
}
message UpdateEntityResponse {
// Error info -- if exists, the save did not happen
EntityErrorInfo error = 1;
// Entity details
Entity entity = 2;
// Status code
Status status = 3;
// Status enumeration
enum Status {
ERROR = 0;
UPDATED = 1;
UNCHANGED = 2;
}
}
//-----------------------------------------------
// Delete request/response
//-----------------------------------------------
message DeleteEntityRequest {
// Entity identifier
grn.GRN GRN = 1;
string key = 3;
// Used for optimistic locking. If missing, the current version will be deleted regardless
string previous_version = 2;
}
message DeleteEntityResponse {
// Error info -- if exists, the delete did not happen
EntityErrorInfo error = 1;
// Entity details
Entity entity = 2;
// Status code
Status status = 3;
// Status enumeration
enum Status {
ERROR = 0;
DELETED = 1;
NOTFOUND = 2;
}
}
//-----------------------------------------------
// History request/response
//-----------------------------------------------
message EntityHistoryRequest {
// Entity identifier
grn.GRN GRN = 1;
// Maximum number of items to return
int64 limit = 3;
// Starting from the requested page
string next_page_token = 5;
}
message EntityHistoryResponse {
// Entity identifier
grn.GRN GRN = 1;
// Entity metadata without the raw bytes
repeated Entity versions = 2;
// More results exist... pass this in the next request
string next_page_token = 3;
}
//-----------------------------------------------
// List request/response
//-----------------------------------------------
message EntityListRequest {
// Starting from the requested page (other query parameters must match!)
string next_page_token = 1;
// Maximum number of items to return
int64 limit = 2;
// Free text query string -- mileage may vary :)
string query = 3;
// limit to a specific kind (empty is all)
repeated string kind = 4;
// limit to a specific key
repeated string key = 11;
// Limit results to items in a specific folder
string folder = 5;
// Must match all labels
map<string,string> labels = 6;
// Sorting instructions `field ASC/DESC`
repeated string sort = 7;
// Return the full body in each payload
bool with_body = 8;
// Return the full body in each payload
bool with_labels = 9;
// Return the full body in each payload
bool with_fields = 10;
}
message ReferenceRequest {
// Starting from the requested page (other query parameters must match!)
string next_page_token = 1;
// Maximum number of items to return
int64 limit = 2;
// Free text query string -- mileage may vary :)
string kind = 3;
// Free text query string -- mileage may vary :)
string uid = 4;
}
message EntityListResponse {
repeated Entity results = 1;
// More results exist... pass this in the next request
string next_page_token = 2;
}
//-----------------------------------------------
// Watch request/response
//-----------------------------------------------
message EntityWatchRequest {
// Timestamp of last changes. Empty will default to
int64 since = 1;
// Watch sppecific entities
repeated grn.GRN GRN = 2;
// limit to a specific kind (empty is all)
repeated string kind = 3;
// Limit results to items in a specific folder
string folder = 4;
// Must match all labels
map<string,string> labels = 5;
// Return the full body in each payload
bool with_body = 6;
// Return the full body in each payload
bool with_labels = 7;
// Return the full body in each payload
bool with_fields = 8;
}
message EntityWatchResponse {
// Timestamp the event was sent
int64 timestamp = 1;
// List of entities with the same action
repeated Entity entity = 2;
// Action code
Action action = 3;
// Status enumeration
enum Action {
UNKNOWN = 0;
UPDATED = 1;
DELETED = 2;
}
}
message EntitySummary {
string UID = 1;
string kind = 2;
string name = 3;
string description = 4;
// Key value pairs. Tags are are represented as keys with empty values
map<string,string> labels = 5;
// Parent folder UID
string folder = 6;
// URL safe version of the name. It will be unique within the folder
string slug = 7;
// When errors exist
EntityErrorInfo error = 8;
// Optional field values. The schema will define and document possible values for a given kind
map<string, string> fields = 9;
// eg: panels within dashboard
repeated EntitySummary nested = 10;
// Optional references to external things
repeated EntityExternalReference references = 11;
}
message EntityExternalReference {
// Category of dependency
// eg: datasource, plugin, runtime
string family = 1;
// datasource > prometheus|influx|...
// plugin > panel | datasource
// runtime > transformer
string type = 2;
// datasource > UID
// plugin > plugin identifier
// runtime > name lookup
string identifier = 3;
}
//-----------------------------------------------
// Storage interface
//-----------------------------------------------
// The entity store provides a basic CRUD (+watch eventually) interface for generic entitys
service EntityStore {
rpc Read(ReadEntityRequest) returns (Entity);
rpc BatchRead(BatchReadEntityRequest) returns (BatchReadEntityResponse);
rpc Write(WriteEntityRequest) returns (WriteEntityResponse);
rpc Create(CreateEntityRequest) returns (CreateEntityResponse);
rpc Update(UpdateEntityRequest) returns (UpdateEntityResponse);
rpc Delete(DeleteEntityRequest) returns (DeleteEntityResponse);
rpc History(EntityHistoryRequest) returns (EntityHistoryResponse);
rpc List(EntityListRequest) returns (EntityListResponse);
rpc Watch(EntityWatchRequest) returns (stream EntityWatchResponse);
// TEMPORARY... while we split this into a new service (see below)
rpc AdminWrite(AdminWriteEntityRequest) returns (WriteEntityResponse);
}
// The admin service extends the basic entity store interface, but provides
// more explicit control that can support bulk operations like efficient git sync
service EntityStoreAdmin {
rpc AdminWrite(AdminWriteEntityRequest) returns (WriteEntityResponse);
}