Chore: Replace entity GRN with infra/grn GRN (#74198)
replace entity GRN with infra/grn GRN
This commit is contained in:
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
# To compile all protobuf files in this repository, run
|
||||
# "make protobuf" at the top-level.
|
||||
|
||||
set -eu
|
||||
|
||||
DST_DIR=./
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
cd "$DIR"
|
||||
|
||||
protoc \
|
||||
-I ./ \
|
||||
-I ../../../ \
|
||||
--go_out=${DST_DIR} \
|
||||
--go_opt=paths=source_relative \
|
||||
--go-grpc_out=${DST_DIR} \
|
||||
--go-grpc_opt=paths=source_relative \
|
||||
--go-grpc_opt=require_unimplemented_servers=false \
|
||||
*.proto
|
||||
+16
-27
@@ -6,32 +6,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Grafana resource name. See also:
|
||||
// https://github.com/grafana/grafana/blob/main/pkg/services/store/entity/entity.proto#L6
|
||||
// NOTE: This structure/format is still under active development and is subject to change
|
||||
type GRN struct {
|
||||
// TenantID contains the ID of the tenant (in hosted grafana) or
|
||||
// organization (in other environments) the resource belongs to. This field
|
||||
// may be omitted for global Grafana resources which are not associated with
|
||||
// an organization.
|
||||
TenantID int64
|
||||
|
||||
// The kind of resource being identified, for e.g. "dashboard" or "user".
|
||||
// The caller is responsible for validating the value.
|
||||
ResourceKind string
|
||||
|
||||
// ResourceIdentifier is used by the underlying service to identify the
|
||||
// resource.
|
||||
ResourceIdentifier string
|
||||
|
||||
// GRN can not be extended
|
||||
_ any
|
||||
}
|
||||
|
||||
// ParseStr attempts to parse a string into a GRN. It returns an error if the
|
||||
// given string does not match the GRN format, but does not validate the values.
|
||||
func ParseStr(str string) (GRN, error) {
|
||||
ret := GRN{}
|
||||
func ParseStr(str string) (*GRN, error) {
|
||||
ret := &GRN{}
|
||||
parts := strings.Split(str, ":")
|
||||
|
||||
if len(parts) != 3 {
|
||||
@@ -65,7 +43,7 @@ func ParseStr(str string) (GRN, error) {
|
||||
|
||||
// MustParseStr is a wrapper around ParseStr that panics if the given input is
|
||||
// not a valid GRN. This is intended for use in tests.
|
||||
func MustParseStr(str string) GRN {
|
||||
func MustParseStr(str string) *GRN {
|
||||
grn, err := ParseStr(str)
|
||||
if err != nil {
|
||||
panic("bad grn!")
|
||||
@@ -73,8 +51,19 @@ func MustParseStr(str string) GRN {
|
||||
return grn
|
||||
}
|
||||
|
||||
// String returns a string representation of a grn in the format
|
||||
// ToGRNString returns a string representation of a grn in the format
|
||||
// grn:tenantID:kind/resourceIdentifier
|
||||
func (g *GRN) String() string {
|
||||
func (g *GRN) ToGRNString() string {
|
||||
return fmt.Sprintf("grn:%d:%s/%s", g.TenantID, g.ResourceKind, g.ResourceIdentifier)
|
||||
}
|
||||
|
||||
// Check if the two GRNs reference to the same object
|
||||
// we can not use simple `*x == *b` because of the internal settings
|
||||
func (g *GRN) Equal(b *GRN) bool {
|
||||
if b == nil {
|
||||
return false
|
||||
}
|
||||
return g == b || (g.TenantID == b.TenantID &&
|
||||
g.ResourceKind == b.ResourceKind &&
|
||||
g.ResourceIdentifier == b.ResourceIdentifier)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v4.23.4
|
||||
// source: grn.proto
|
||||
|
||||
package grn
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GRN struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// TenantID contains the ID of the tenant (in hosted grafana) or
|
||||
// organization (in other environments) the resource belongs to. This field
|
||||
// may be omitted for global Grafana resources which are not associated with
|
||||
// an organization.
|
||||
TenantID int64 `protobuf:"varint,1,opt,name=TenantID,proto3" json:"TenantID,omitempty"`
|
||||
// The kind of resource being identified, for e.g. "dashboard" or "user".
|
||||
// The caller is responsible for validating the value.
|
||||
ResourceKind string `protobuf:"bytes,3,opt,name=ResourceKind,proto3" json:"ResourceKind,omitempty"`
|
||||
// ResourceIdentifier is used by the underlying service to identify the
|
||||
// resource.
|
||||
ResourceIdentifier string `protobuf:"bytes,4,opt,name=ResourceIdentifier,proto3" json:"ResourceIdentifier,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GRN) Reset() {
|
||||
*x = GRN{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_grn_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GRN) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GRN) ProtoMessage() {}
|
||||
|
||||
func (x *GRN) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_grn_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GRN.ProtoReflect.Descriptor instead.
|
||||
func (*GRN) Descriptor() ([]byte, []int) {
|
||||
return file_grn_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *GRN) GetTenantID() int64 {
|
||||
if x != nil {
|
||||
return x.TenantID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GRN) GetResourceKind() string {
|
||||
if x != nil {
|
||||
return x.ResourceKind
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GRN) GetResourceIdentifier() string {
|
||||
if x != nil {
|
||||
return x.ResourceIdentifier
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_grn_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_grn_proto_rawDesc = []byte{
|
||||
0x0a, 0x09, 0x67, 0x72, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x67, 0x72, 0x6e,
|
||||
0x22, 0x75, 0x0a, 0x03, 0x47, 0x52, 0x4e, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x54, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b,
|
||||
0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72,
|
||||
0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x69, 0x6e, 0x66, 0x72, 0x61, 0x2f,
|
||||
0x67, 0x72, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_grn_proto_rawDescOnce sync.Once
|
||||
file_grn_proto_rawDescData = file_grn_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_grn_proto_rawDescGZIP() []byte {
|
||||
file_grn_proto_rawDescOnce.Do(func() {
|
||||
file_grn_proto_rawDescData = protoimpl.X.CompressGZIP(file_grn_proto_rawDescData)
|
||||
})
|
||||
return file_grn_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_grn_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_grn_proto_goTypes = []interface{}{
|
||||
(*GRN)(nil), // 0: grn.GRN
|
||||
}
|
||||
var file_grn_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_grn_proto_init() }
|
||||
func file_grn_proto_init() {
|
||||
if File_grn_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_grn_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GRN); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_grn_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_grn_proto_goTypes,
|
||||
DependencyIndexes: file_grn_proto_depIdxs,
|
||||
MessageInfos: file_grn_proto_msgTypes,
|
||||
}.Build()
|
||||
File_grn_proto = out.File
|
||||
file_grn_proto_rawDesc = nil
|
||||
file_grn_proto_goTypes = nil
|
||||
file_grn_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
syntax = "proto3";
|
||||
package grn;
|
||||
|
||||
option go_package = "github.com/grafana/grafana/pkg/infra/grn";
|
||||
|
||||
message GRN {
|
||||
// TenantID contains the ID of the tenant (in hosted grafana) or
|
||||
// organization (in other environments) the resource belongs to. This field
|
||||
// may be omitted for global Grafana resources which are not associated with
|
||||
// an organization.
|
||||
int64 TenantID = 1;
|
||||
|
||||
// The kind of resource being identified, for e.g. "dashboard" or "user".
|
||||
// The caller is responsible for validating the value.
|
||||
string ResourceKind = 3;
|
||||
|
||||
// ResourceIdentifier is used by the underlying service to identify the
|
||||
// resource.
|
||||
string ResourceIdentifier = 4;
|
||||
}
|
||||
+13
-11
@@ -3,57 +3,59 @@ package grn
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestParseGRNStr(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expect GRN
|
||||
expect *GRN
|
||||
expectErr bool
|
||||
}{
|
||||
{ // empty
|
||||
"",
|
||||
GRN{},
|
||||
&GRN{},
|
||||
true,
|
||||
},
|
||||
{ // too few parts
|
||||
"grn:dashboards",
|
||||
GRN{},
|
||||
&GRN{},
|
||||
true,
|
||||
},
|
||||
{ // too many parts
|
||||
"grn::dashboards:user:orgs:otherthings:hello:stillgoing",
|
||||
GRN{},
|
||||
&GRN{},
|
||||
true,
|
||||
},
|
||||
{ // Does not look like a GRN
|
||||
"hrn:grafana::123:dashboards/foo",
|
||||
GRN{},
|
||||
&GRN{},
|
||||
true,
|
||||
},
|
||||
{ // Missing Kind
|
||||
"grn::foo",
|
||||
GRN{},
|
||||
&GRN{},
|
||||
true,
|
||||
},
|
||||
{ // good!
|
||||
"grn::roles/Admin",
|
||||
GRN{TenantID: 0, ResourceKind: "roles", ResourceIdentifier: "Admin"},
|
||||
&GRN{TenantID: 0, ResourceKind: "roles", ResourceIdentifier: "Admin"},
|
||||
false,
|
||||
},
|
||||
{ // good!
|
||||
"grn::roles/Admin/with/some/slashes",
|
||||
GRN{TenantID: 0, ResourceKind: "roles", ResourceIdentifier: "Admin/with/some/slashes"},
|
||||
&GRN{TenantID: 0, ResourceKind: "roles", ResourceIdentifier: "Admin/with/some/slashes"},
|
||||
false,
|
||||
},
|
||||
{ // good!
|
||||
"grn:123456789:roles/Admin/with/some/slashes",
|
||||
GRN{TenantID: 123456789, ResourceKind: "roles", ResourceIdentifier: "Admin/with/some/slashes"},
|
||||
&GRN{TenantID: 123456789, ResourceKind: "roles", ResourceIdentifier: "Admin/with/some/slashes"},
|
||||
false,
|
||||
},
|
||||
{ // Weird, but valid.
|
||||
"grn::roles///Admin/with/leading/slashes",
|
||||
GRN{TenantID: 0, ResourceKind: "roles", ResourceIdentifier: "//Admin/with/leading/slashes"},
|
||||
&GRN{TenantID: 0, ResourceKind: "roles", ResourceIdentifier: "//Admin/with/leading/slashes"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
@@ -69,7 +71,7 @@ func TestParseGRNStr(t *testing.T) {
|
||||
t.Fatalf("wrong result. Expected success, got error %s", err.Error())
|
||||
}
|
||||
|
||||
if got != test.expect {
|
||||
if !cmp.Equal(test.expect, got) {
|
||||
t.Fatalf("wrong result. Wanted %s, got %s\n", test.expect.String(), got.String())
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user