c4c9bfaf2e
* 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>
485 lines
12 KiB
Protocol Buffer
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);
|
|
}
|