diff --git a/Dockerfile b/Dockerfile index 1fa8e663612..efa061be39f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -77,6 +77,7 @@ COPY pkg/build pkg/build COPY pkg/build/wire pkg/build/wire COPY pkg/promlib pkg/promlib COPY pkg/storage/unified/resource pkg/storage/unified/resource +COPY pkg/storage/unified/resourcepb pkg/storage/unified/resourcepb COPY pkg/storage/unified/apistore pkg/storage/unified/apistore COPY pkg/semconv pkg/semconv COPY pkg/aggregator pkg/aggregator diff --git a/Makefile b/Makefile index 062bdd3036a..1f4dcb47525 100644 --- a/Makefile +++ b/Makefile @@ -452,11 +452,11 @@ devenv-mysql: .PHONY: protobuf protobuf: ## Compile protobuf definitions bash scripts/protobuf-check.sh - go install google.golang.org/protobuf/cmd/protoc-gen-go + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.5 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.4.0 buf generate pkg/plugins/backendplugin/pluginextensionv2 --template pkg/plugins/backendplugin/pluginextensionv2/buf.gen.yaml buf generate pkg/apis/secret/v0alpha1/decrypt --template pkg/apis/secret/v0alpha1/decrypt/buf.gen.yaml - buf generate pkg/storage/unified/resource --template pkg/storage/unified/resource/buf.gen.yaml + buf generate pkg/storage/unified/proto --template pkg/storage/unified/proto/buf.gen.yaml buf generate pkg/services/authz/proto/v1 --template pkg/services/authz/proto/v1/buf.gen.yaml buf generate pkg/services/ngalert/store/proto/v1 --template pkg/services/ngalert/store/proto/v1/buf.gen.yaml diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index 97fccf16741..0e6ce6cafd2 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -98,7 +98,7 @@ require ( google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/apps/alerting/notifications/go.sum b/apps/alerting/notifications/go.sum index f3cef9ad6fa..7eeb9649133 100644 --- a/apps/alerting/notifications/go.sum +++ b/apps/alerting/notifications/go.sum @@ -335,8 +335,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/apps/dashboard/go.mod b/apps/dashboard/go.mod index c9f0fa7889d..e2edb1c2d33 100644 --- a/apps/dashboard/go.mod +++ b/apps/dashboard/go.mod @@ -115,7 +115,7 @@ require ( golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/apps/dashboard/go.sum b/apps/dashboard/go.sum index c5a9ae8a435..e87c9bd9bb8 100644 --- a/apps/dashboard/go.sum +++ b/apps/dashboard/go.sum @@ -359,8 +359,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/apps/playlist/go.mod b/apps/playlist/go.mod index 84d7b761baa..34b5175c432 100644 --- a/apps/playlist/go.mod +++ b/apps/playlist/go.mod @@ -76,7 +76,7 @@ require ( gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/apps/playlist/go.sum b/apps/playlist/go.sum index 13918e2ec69..8e90e0233d9 100644 --- a/apps/playlist/go.sum +++ b/apps/playlist/go.sum @@ -193,8 +193,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go.mod b/go.mod index 81dd22b8e23..71135fb4886 100644 --- a/go.mod +++ b/go.mod @@ -187,7 +187,7 @@ require ( golang.org/x/tools v0.33.0 // indirect; @grafana/grafana-as-code gonum.org/v1/gonum v0.15.1 // @grafana/oss-big-tent google.golang.org/api v0.223.0 // @grafana/grafana-backend-group - google.golang.org/grpc v1.72.0 // @grafana/plugins-platform-backend + google.golang.org/grpc v1.72.1 // @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.6 // @grafana/plugins-platform-backend gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend gopkg.in/mail.v2 v2.3.1 // @grafana/grafana-backend-group diff --git a/go.sum b/go.sum index 8d1bf535d33..c9f077ba251 100644 --- a/go.sum +++ b/go.sum @@ -3401,8 +3401,7 @@ google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwS google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/go.work b/go.work index 9ec2b4a78d8..535f6cd6b86 100644 --- a/go.work +++ b/go.work @@ -30,6 +30,7 @@ use ( ./pkg/semconv ./pkg/storage/unified/apistore ./pkg/storage/unified/resource + ./pkg/storage/unified/resourcepb ) replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975 diff --git a/go.work.sum b/go.work.sum index 0045e12a04d..6ea3500e007 100644 --- a/go.work.sum +++ b/go.work.sum @@ -2129,6 +2129,7 @@ google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFN google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index 459cb40f3a0..98da3be3177 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -152,7 +152,7 @@ require ( google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index e99349270ff..a1f1f9d231c 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -494,8 +494,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index 331b1b13068..4a0f5674706 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -43,7 +43,7 @@ require ( golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.25.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index f592b41e72a..14b2947f0ff 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -151,8 +151,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/apis/secret/go.mod b/pkg/apis/secret/go.mod index 63e579ca8c3..914fcf0c08c 100644 --- a/pkg/apis/secret/go.mod +++ b/pkg/apis/secret/go.mod @@ -5,7 +5,7 @@ go 1.24.3 require ( github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250422074709-7c8433fbb2c2 github.com/stretchr/testify v1.10.0 - google.golang.org/grpc v1.72.0 + google.golang.org/grpc v1.72.1 google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.32.3 diff --git a/pkg/apis/secret/go.sum b/pkg/apis/secret/go.sum index 30fcc2c9686..cc793315196 100644 --- a/pkg/apis/secret/go.sum +++ b/pkg/apis/secret/go.sum @@ -304,8 +304,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index 073d09f5575..c62e87478b4 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -97,7 +97,7 @@ require ( google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index 969b11a7420..a9f48603307 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -347,8 +347,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index 1ac3f7caa4c..fedc99897da 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -33,7 +33,7 @@ require ( golang.org/x/text v0.25.0 // indirect; @grafana/grafana-backend-group golang.org/x/time v0.11.0 // indirect; @grafana/grafana-backend-group google.golang.org/api v0.223.0 // @grafana/grafana-backend-group - google.golang.org/grpc v1.72.0 // indirect; @grafana/plugins-platform-backend + google.golang.org/grpc v1.72.1 // indirect; @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.6 // indirect; @grafana/plugins-platform-backend gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend ) diff --git a/pkg/build/go.sum b/pkg/build/go.sum index c6243e781c3..4b297f89121 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -382,8 +382,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go index 293ec5d16fc..79901c746d2 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" authlib "github.com/grafana/authlib/types" + dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/identity" @@ -26,6 +27,7 @@ import ( "github.com/grafana/grafana/pkg/storage/unified" "github.com/grafana/grafana/pkg/storage/unified/parquet" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // ToUnifiedStorage converts dashboards+folders into unified storage @@ -148,7 +150,7 @@ func ToUnifiedStorage(c utils.CommandLine, cfg *setting.Cfg, sqlStore db.DB) err } // Check the stats (eventually compare) - req := &resource.ResourceStatsRequest{ + req := &resourcepb.ResourceStatsRequest{ Namespace: opts.Namespace, } for _, r := range opts.Resources { @@ -218,7 +220,7 @@ func newUnifiedClient(cfg *setting.Cfg, sqlStore db.DB) (resource.ResourceClient }, nil, nil) } -func newParquetClient(file *os.File) (resource.BulkStoreClient, error) { +func newParquetClient(file *os.File) (resourcepb.BulkStoreClient, error) { writer, err := parquet.NewParquetWriter(file) if err != nil { return nil, err diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index d3d95fe43b8..b6deb185546 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -124,7 +124,7 @@ require ( google.golang.org/api v0.223.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect - google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc v1.72.1 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index 6c1cc85f52a..e9162df8800 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -409,8 +409,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/registry/apis/dashboard/legacy/client.go b/pkg/registry/apis/dashboard/legacy/client.go index d85c66047c9..1eeebd7b689 100644 --- a/pkg/registry/apis/dashboard/legacy/client.go +++ b/pkg/registry/apis/dashboard/legacy/client.go @@ -7,6 +7,7 @@ import ( "google.golang.org/grpc" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var ( @@ -23,69 +24,69 @@ type directResourceClient struct { } // Create implements ResourceClient. -func (d *directResourceClient) Create(ctx context.Context, in *resource.CreateRequest, opts ...grpc.CallOption) (*resource.CreateResponse, error) { +func (d *directResourceClient) Create(ctx context.Context, in *resourcepb.CreateRequest, opts ...grpc.CallOption) (*resourcepb.CreateResponse, error) { return d.server.Create(ctx, in) } // Delete implements ResourceClient. -func (d *directResourceClient) Delete(ctx context.Context, in *resource.DeleteRequest, opts ...grpc.CallOption) (*resource.DeleteResponse, error) { +func (d *directResourceClient) Delete(ctx context.Context, in *resourcepb.DeleteRequest, opts ...grpc.CallOption) (*resourcepb.DeleteResponse, error) { return d.server.Delete(ctx, in) } // GetBlob implements ResourceClient. -func (d *directResourceClient) GetBlob(ctx context.Context, in *resource.GetBlobRequest, opts ...grpc.CallOption) (*resource.GetBlobResponse, error) { +func (d *directResourceClient) GetBlob(ctx context.Context, in *resourcepb.GetBlobRequest, opts ...grpc.CallOption) (*resourcepb.GetBlobResponse, error) { return d.server.GetBlob(ctx, in) } // GetStats implements ResourceClient. -func (d *directResourceClient) GetStats(ctx context.Context, in *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) { +func (d *directResourceClient) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { return d.server.GetStats(ctx, in) } // IsHealthy implements ResourceClient. -func (d *directResourceClient) IsHealthy(ctx context.Context, in *resource.HealthCheckRequest, opts ...grpc.CallOption) (*resource.HealthCheckResponse, error) { +func (d *directResourceClient) IsHealthy(ctx context.Context, in *resourcepb.HealthCheckRequest, opts ...grpc.CallOption) (*resourcepb.HealthCheckResponse, error) { return d.server.IsHealthy(ctx, in) } // List implements ResourceClient. -func (d *directResourceClient) List(ctx context.Context, in *resource.ListRequest, opts ...grpc.CallOption) (*resource.ListResponse, error) { +func (d *directResourceClient) List(ctx context.Context, in *resourcepb.ListRequest, opts ...grpc.CallOption) (*resourcepb.ListResponse, error) { return d.server.List(ctx, in) } -func (d *directResourceClient) ListManagedObjects(ctx context.Context, in *resource.ListManagedObjectsRequest, opts ...grpc.CallOption) (*resource.ListManagedObjectsResponse, error) { +func (d *directResourceClient) ListManagedObjects(ctx context.Context, in *resourcepb.ListManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.ListManagedObjectsResponse, error) { return d.server.ListManagedObjects(ctx, in) } -func (d *directResourceClient) CountManagedObjects(ctx context.Context, in *resource.CountManagedObjectsRequest, opts ...grpc.CallOption) (*resource.CountManagedObjectsResponse, error) { +func (d *directResourceClient) CountManagedObjects(ctx context.Context, in *resourcepb.CountManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.CountManagedObjectsResponse, error) { return d.server.CountManagedObjects(ctx, in) } // PutBlob implements ResourceClient. -func (d *directResourceClient) PutBlob(ctx context.Context, in *resource.PutBlobRequest, opts ...grpc.CallOption) (*resource.PutBlobResponse, error) { +func (d *directResourceClient) PutBlob(ctx context.Context, in *resourcepb.PutBlobRequest, opts ...grpc.CallOption) (*resourcepb.PutBlobResponse, error) { return d.server.PutBlob(ctx, in) } // Read implements ResourceClient. -func (d *directResourceClient) Read(ctx context.Context, in *resource.ReadRequest, opts ...grpc.CallOption) (*resource.ReadResponse, error) { +func (d *directResourceClient) Read(ctx context.Context, in *resourcepb.ReadRequest, opts ...grpc.CallOption) (*resourcepb.ReadResponse, error) { return d.server.Read(ctx, in) } // Search implements ResourceClient. -func (d *directResourceClient) Search(ctx context.Context, in *resource.ResourceSearchRequest, opts ...grpc.CallOption) (*resource.ResourceSearchResponse, error) { +func (d *directResourceClient) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { return d.server.Search(ctx, in) } // Update implements ResourceClient. -func (d *directResourceClient) Update(ctx context.Context, in *resource.UpdateRequest, opts ...grpc.CallOption) (*resource.UpdateResponse, error) { +func (d *directResourceClient) Update(ctx context.Context, in *resourcepb.UpdateRequest, opts ...grpc.CallOption) (*resourcepb.UpdateResponse, error) { return d.server.Update(ctx, in) } // Watch implements ResourceClient. -func (d *directResourceClient) Watch(ctx context.Context, in *resource.WatchRequest, opts ...grpc.CallOption) (resource.ResourceStore_WatchClient, error) { +func (d *directResourceClient) Watch(ctx context.Context, in *resourcepb.WatchRequest, opts ...grpc.CallOption) (resourcepb.ResourceStore_WatchClient, error) { return nil, fmt.Errorf("watch not supported with direct resource client") } // BulkProcess implements resource.ResourceClient. -func (d *directResourceClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { +func (d *directResourceClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) { return nil, fmt.Errorf("BulkProcess not supported with direct resource client") } diff --git a/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go b/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go index d576d333d43..18796640c96 100644 --- a/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go +++ b/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go @@ -5,7 +5,8 @@ package legacy import ( context "context" - resource "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + mock "github.com/stretchr/testify/mock" ) @@ -23,23 +24,23 @@ func (_m *MockLegacyMigrator) EXPECT() *MockLegacyMigrator_Expecter { } // Migrate provides a mock function with given fields: ctx, opts -func (_m *MockLegacyMigrator) Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) { +func (_m *MockLegacyMigrator) Migrate(ctx context.Context, opts MigrateOptions) (*resourcepb.BulkResponse, error) { ret := _m.Called(ctx, opts) if len(ret) == 0 { panic("no return value specified for Migrate") } - var r0 *resource.BulkResponse + var r0 *resourcepb.BulkResponse var r1 error - if rf, ok := ret.Get(0).(func(context.Context, MigrateOptions) (*resource.BulkResponse, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, MigrateOptions) (*resourcepb.BulkResponse, error)); ok { return rf(ctx, opts) } - if rf, ok := ret.Get(0).(func(context.Context, MigrateOptions) *resource.BulkResponse); ok { + if rf, ok := ret.Get(0).(func(context.Context, MigrateOptions) *resourcepb.BulkResponse); ok { r0 = rf(ctx, opts) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*resource.BulkResponse) + r0 = ret.Get(0).(*resourcepb.BulkResponse) } } @@ -71,12 +72,12 @@ func (_c *MockLegacyMigrator_Migrate_Call) Run(run func(ctx context.Context, opt return _c } -func (_c *MockLegacyMigrator_Migrate_Call) Return(_a0 *resource.BulkResponse, _a1 error) *MockLegacyMigrator_Migrate_Call { +func (_c *MockLegacyMigrator_Migrate_Call) Return(_a0 *resourcepb.BulkResponse, _a1 error) *MockLegacyMigrator_Migrate_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockLegacyMigrator_Migrate_Call) RunAndReturn(run func(context.Context, MigrateOptions) (*resource.BulkResponse, error)) *MockLegacyMigrator_Migrate_Call { +func (_c *MockLegacyMigrator_Migrate_Call) RunAndReturn(run func(context.Context, MigrateOptions) (*resourcepb.BulkResponse, error)) *MockLegacyMigrator_Migrate_Call { _c.Call.Return(run) return _c } diff --git a/pkg/registry/apis/dashboard/legacy/migrate.go b/pkg/registry/apis/dashboard/legacy/migrate.go index 48db5f23930..82b504f4c30 100644 --- a/pkg/registry/apis/dashboard/legacy/migrate.go +++ b/pkg/registry/apis/dashboard/legacy/migrate.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" authlib "github.com/grafana/authlib/types" + dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/utils" @@ -21,13 +22,14 @@ import ( "github.com/grafana/grafana/pkg/storage/legacysql" "github.com/grafana/grafana/pkg/storage/unified/apistore" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type MigrateOptions struct { Namespace string - Store resource.BulkStoreClient + Store resourcepb.BulkStoreClient LargeObjects apistore.LargeObjectSupport - BlobStore resource.BlobStoreClient + BlobStore resourcepb.BlobStoreClient Resources []schema.GroupResource WithHistory bool // only applies to dashboards OnlyCount bool // just count the values @@ -38,7 +40,7 @@ type MigrateOptions struct { // //go:generate mockery --name LegacyMigrator --structname MockLegacyMigrator --inpackage --filename legacy_migrator_mock.go --with-expecter type LegacyMigrator interface { - Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) + Migrate(ctx context.Context, opts MigrateOptions) (*resourcepb.BulkResponse, error) } // This can migrate Folders, Dashboards and LibraryPanels @@ -56,9 +58,9 @@ type BlobStoreInfo struct { } // migrate function -- works for a single kind -type migrator = func(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) +type migrator = func(ctx context.Context, orgId int64, opts MigrateOptions, stream resourcepb.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) -func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) { +func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) (*resourcepb.BulkResponse, error) { info, err := authlib.ParseNamespace(opts.Namespace) if err != nil { return nil, err @@ -82,7 +84,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( switch fmt.Sprintf("%s/%s", res.Group, res.Resource) { case "folder.grafana.app/folders": migrators = append(migrators, a.migrateFolders) - settings.Collection = append(settings.Collection, &resource.ResourceKey{ + settings.Collection = append(settings.Collection, &resourcepb.ResourceKey{ Namespace: opts.Namespace, Group: folders.GROUP, Resource: folders.RESOURCE, @@ -90,7 +92,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( case "dashboard.grafana.app/librarypanels": migrators = append(migrators, a.migratePanels) - settings.Collection = append(settings.Collection, &resource.ResourceKey{ + settings.Collection = append(settings.Collection, &resourcepb.ResourceKey{ Namespace: opts.Namespace, Group: dashboard.GROUP, Resource: dashboard.LIBRARY_PANEL_RESOURCE, @@ -98,7 +100,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( case "dashboard.grafana.app/dashboards": migrators = append(migrators, a.migrateDashboards) - settings.Collection = append(settings.Collection, &resource.ResourceKey{ + settings.Collection = append(settings.Collection, &resourcepb.ResourceKey{ Namespace: opts.Namespace, Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -134,7 +136,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( return stream.CloseAndRecv() } -func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) { +func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOptions) (*resourcepb.BulkResponse, error) { sql, err := a.sql(ctx) if err != nil { return nil, err @@ -144,12 +146,12 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption return nil, err } orgId := ns.OrgID - rsp := &resource.BulkResponse{} + rsp := &resourcepb.BulkResponse{} err = sql.DB.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { for _, res := range opts.Resources { switch fmt.Sprintf("%s/%s", res.Group, res.Resource) { case "folder.grafana.app/folders": - summary := &resource.BulkResponse_Summary{} + summary := &resourcepb.BulkResponse_Summary{} summary.Group = folders.GROUP summary.Group = folders.RESOURCE _, err = sess.SQL("SELECT COUNT(*) FROM "+sql.Table("dashboard")+ @@ -157,7 +159,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption rsp.Summary = append(rsp.Summary, summary) case "dashboard.grafana.app/librarypanels": - summary := &resource.BulkResponse_Summary{} + summary := &resourcepb.BulkResponse_Summary{} summary.Group = dashboard.GROUP summary.Resource = dashboard.LIBRARY_PANEL_RESOURCE _, err = sess.SQL("SELECT COUNT(*) FROM "+sql.Table("library_element")+ @@ -165,7 +167,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption rsp.Summary = append(rsp.Summary, summary) case "dashboard.grafana.app/dashboards": - summary := &resource.BulkResponse_Summary{} + summary := &resourcepb.BulkResponse_Summary{} summary.Group = dashboard.GROUP summary.Resource = dashboard.DASHBOARD_RESOURCE rsp.Summary = append(rsp.Summary, summary) @@ -177,7 +179,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption } // Also count history - _, err = sess.SQL(`SELECT COUNT(*) + _, err = sess.SQL(`SELECT COUNT(*) FROM `+sql.Table("dashboard_version")+` as dv JOIN `+sql.Table("dashboard")+` as dd ON dd.id = dv.dashboard_id @@ -192,7 +194,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption return rsp, nil } -func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { +func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, opts MigrateOptions, stream resourcepb.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { query := &DashboardQuery{ OrgID: orgId, Limit: 100000000, @@ -234,8 +236,8 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, return blobs, err } - req := &resource.BulkRequest{ - Key: &resource.ResourceKey{ + req := &resourcepb.BulkRequest{ + Key: &resourcepb.ResourceKey{ Namespace: opts.Namespace, Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -243,12 +245,12 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, }, Value: body, Folder: rows.row.FolderUID, - Action: resource.BulkRequest_ADDED, + Action: resourcepb.BulkRequest_ADDED, } if dash.Generation > 1 { - req.Action = resource.BulkRequest_MODIFIED + req.Action = resourcepb.BulkRequest_MODIFIED } else if dash.Generation < 0 { - req.Action = resource.BulkRequest_DELETED + req.Action = resourcepb.BulkRequest_DELETED } // With large object support @@ -301,7 +303,7 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, return blobs, err } -func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { +func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, opts MigrateOptions, stream resourcepb.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { query := &DashboardQuery{ OrgID: orgId, Limit: 100000000, @@ -347,8 +349,8 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op return nil, err } - req := &resource.BulkRequest{ - Key: &resource.ResourceKey{ + req := &resourcepb.BulkRequest{ + Key: &resourcepb.ResourceKey{ Namespace: opts.Namespace, Group: "folder.grafana.app", Resource: "folders", @@ -356,12 +358,12 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op }, Value: body, Folder: rows.row.FolderUID, - Action: resource.BulkRequest_ADDED, + Action: resourcepb.BulkRequest_ADDED, } if dash.Generation > 1 { - req.Action = resource.BulkRequest_MODIFIED + req.Action = resourcepb.BulkRequest_MODIFIED } else if dash.Generation < 0 { - req.Action = resource.BulkRequest_DELETED + req.Action = resourcepb.BulkRequest_DELETED } opts.Progress(i, fmt.Sprintf("[v:%d] %s (%d)", dash.Generation, dash.Name, len(req.Value))) @@ -383,7 +385,7 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op return nil, err } -func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { +func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opts MigrateOptions, stream resourcepb.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { opts.Progress(-1, "migrating library panels...") panels, err := a.GetLibraryPanels(ctx, LibraryPanelQuery{ OrgID: orgId, @@ -402,8 +404,8 @@ func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opt return nil, err } - req := &resource.BulkRequest{ - Key: &resource.ResourceKey{ + req := &resourcepb.BulkRequest{ + Key: &resourcepb.ResourceKey{ Namespace: opts.Namespace, Group: dashboard.GROUP, Resource: dashboard.LIBRARY_PANEL_RESOURCE, @@ -411,10 +413,10 @@ func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opt }, Value: body, Folder: meta.GetFolder(), - Action: resource.BulkRequest_ADDED, + Action: resourcepb.BulkRequest_ADDED, } if panel.Generation > 1 { - req.Action = resource.BulkRequest_MODIFIED + req.Action = resourcepb.BulkRequest_MODIFIED } opts.Progress(i, fmt.Sprintf("[v:%d] %s (%d)", i, meta.GetName(), len(req.Value))) diff --git a/pkg/registry/apis/dashboard/legacy/storage.go b/pkg/registry/apis/dashboard/legacy/storage.go index 42af196f49b..5c9e392a862 100644 --- a/pkg/registry/apis/dashboard/legacy/storage.go +++ b/pkg/registry/apis/dashboard/legacy/storage.go @@ -13,6 +13,8 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + apierrors "k8s.io/apimachinery/pkg/api/errors" ) @@ -59,7 +61,7 @@ func getProvisioningDataFromEvent(event resource.WriteEvent) (*dashboards.Dashbo return provisioning, nil } -func isDashboardKey(key *resource.ResourceKey, requireName bool) error { +func isDashboardKey(key *resourcepb.ResourceKey, requireName bool) error { gr := dashboard.DashboardResourceInfo.GroupResource() if key.Group != gr.Group { return fmt.Errorf("expecting dashboard group (%s != %s)", key.Group, gr.Group) @@ -83,13 +85,13 @@ func (a *dashboardSqlAccess) WriteEvent(ctx context.Context, event resource.Writ } switch event.Type { - case resource.WatchEvent_DELETED: + case resourcepb.WatchEvent_DELETED: { _, _, err = a.DeleteDashboard(ctx, info.OrgID, event.Key.Name) //rv = ??? } // The difference depends on embedded internal ID - case resource.WatchEvent_ADDED, resource.WatchEvent_MODIFIED: + case resourcepb.WatchEvent_ADDED, resourcepb.WatchEvent_MODIFIED: { dash, err := getDashboardFromEvent(event) if err != nil { @@ -119,7 +121,7 @@ func (a *dashboardSqlAccess) WriteEvent(ctx context.Context, event resource.Writ rv = int64(after.Version) } } else { - failOnExisting := event.Type == resource.WatchEvent_ADDED + failOnExisting := event.Type == resourcepb.WatchEvent_ADDED after, _, err := a.SaveDashboard(ctx, info.OrgID, dash, failOnExisting) if err != nil { return 0, err @@ -187,7 +189,7 @@ func (a *dashboardSqlAccess) GetDashboard(ctx context.Context, orgId int64, uid } // Read implements ResourceStoreServer. -func (a *dashboardSqlAccess) ReadResource(ctx context.Context, req *resource.ReadRequest) *resource.BackendReadResponse { +func (a *dashboardSqlAccess) ReadResource(ctx context.Context, req *resourcepb.ReadRequest) *resource.BackendReadResponse { rsp := &resource.BackendReadResponse{} info, err := claims.ParseNamespace(req.Key.Namespace) if err == nil { @@ -208,7 +210,7 @@ func (a *dashboardSqlAccess) ReadResource(ctx context.Context, req *resource.Rea return rsp } if dash == nil { - rsp.Error = &resource.ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Code: http.StatusNotFound, } } else { @@ -228,7 +230,7 @@ func (a *dashboardSqlAccess) ReadResource(ctx context.Context, req *resource.Rea } // List implements AppendingStore. -func (a *dashboardSqlAccess) ListIterator(ctx context.Context, req *resource.ListRequest, cb func(resource.ListIterator) error) (int64, error) { +func (a *dashboardSqlAccess) ListIterator(ctx context.Context, req *resourcepb.ListRequest, cb func(resource.ListIterator) error) (int64, error) { if req.ResourceVersion != 0 { return 0, apierrors.NewBadRequest("List with explicit resourceVersion is not supported with this storage backend") } @@ -262,12 +264,12 @@ func (a *dashboardSqlAccess) ListIterator(ctx context.Context, req *resource.Lis } switch req.Source { - case resource.ListRequest_HISTORY: + case resourcepb.ListRequest_HISTORY: query.GetHistory = true query.UID = req.Options.Key.Name - case resource.ListRequest_TRASH: + case resourcepb.ListRequest_TRASH: query.GetTrash = true - case resource.ListRequest_STORE: + case resourcepb.ListRequest_STORE: // normal } @@ -321,23 +323,23 @@ func (a *dashboardSqlAccess) WatchWriteEvents(ctx context.Context) (<-chan *reso } // Simple wrapper for index implementation -func (a *dashboardSqlAccess) Read(ctx context.Context, req *resource.ReadRequest) (*resource.BackendReadResponse, error) { +func (a *dashboardSqlAccess) Read(ctx context.Context, req *resourcepb.ReadRequest) (*resource.BackendReadResponse, error) { return a.ReadResource(ctx, req), nil } -func (a *dashboardSqlAccess) Search(ctx context.Context, req *resource.ResourceSearchRequest) (*resource.ResourceSearchResponse, error) { +func (a *dashboardSqlAccess) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { return a.dashboardSearchClient.Search(ctx, req) } -func (a *dashboardSqlAccess) ListManagedObjects(ctx context.Context, req *resource.ListManagedObjectsRequest) (*resource.ListManagedObjectsResponse, error) { +func (a *dashboardSqlAccess) ListManagedObjects(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { return nil, fmt.Errorf("not implemented") } -func (a *dashboardSqlAccess) CountManagedObjects(context.Context, *resource.CountManagedObjectsRequest) (*resource.CountManagedObjectsResponse, error) { +func (a *dashboardSqlAccess) CountManagedObjects(context.Context, *resourcepb.CountManagedObjectsRequest) (*resourcepb.CountManagedObjectsResponse, error) { return nil, fmt.Errorf("not implemented") } // GetStats implements ResourceServer. -func (a *dashboardSqlAccess) GetStats(ctx context.Context, req *resource.ResourceStatsRequest) (*resource.ResourceStatsResponse, error) { +func (a *dashboardSqlAccess) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest) (*resourcepb.ResourceStatsResponse, error) { return a.dashboardSearchClient.GetStats(ctx, req) } diff --git a/pkg/registry/apis/dashboard/legacy/storage_test.go b/pkg/registry/apis/dashboard/legacy/storage_test.go index 1251d45ef2c..00168d2eee2 100644 --- a/pkg/registry/apis/dashboard/legacy/storage_test.go +++ b/pkg/registry/apis/dashboard/legacy/storage_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestGetProvisioningDataFromEvent(t *testing.T) { @@ -86,7 +87,7 @@ func TestWriteProvisioningEvent(t *testing.T) { dashBytes, err := json.Marshal(dashData) require.NoError(t, err) - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: dashboard.DashboardResourceInfo.GroupResource().Group, Resource: dashboard.DashboardResourceInfo.GroupResource().Resource, Name: "test-dashboard", @@ -109,7 +110,7 @@ func TestWriteProvisioningEvent(t *testing.T) { }) event := resource.WriteEvent{ - Type: resource.WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Key: key, Object: meta, Value: dashBytes, diff --git a/pkg/registry/apis/dashboard/legacy/types.go b/pkg/registry/apis/dashboard/legacy/types.go index 435103cac93..f20f9232afb 100644 --- a/pkg/registry/apis/dashboard/legacy/types.go +++ b/pkg/registry/apis/dashboard/legacy/types.go @@ -6,6 +6,7 @@ import ( dashboardV0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // This does not check if you have permissions! @@ -30,7 +31,7 @@ type DashboardQuery struct { GetFolders bool // The label requirements - Labels []*resource.Requirement + Labels []*resourcepb.Requirement // DESC|ASC, how to order the IDs Order string // asc required to use lastID, desc required for export with history @@ -52,7 +53,7 @@ type LibraryPanelQuery struct { type DashboardAccess interface { resource.StorageBackend - resource.ResourceIndexServer + resourcepb.ResourceIndexServer LegacyMigrator GetDashboard(ctx context.Context, orgId int64, uid string, version int64) (*dashboardV1.Dashboard, int64, error) diff --git a/pkg/registry/apis/dashboard/legacysearcher/search_client.go b/pkg/registry/apis/dashboard/legacysearcher/search_client.go index ef667736684..014ee911db6 100644 --- a/pkg/registry/apis/dashboard/legacysearcher/search_client.go +++ b/pkg/registry/apis/dashboard/legacysearcher/search_client.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/selection" claims "github.com/grafana/authlib/types" + dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/identity" @@ -20,11 +21,12 @@ import ( "github.com/grafana/grafana/pkg/services/search/sort" "github.com/grafana/grafana/pkg/services/sqlstore/searchstore" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" unisearch "github.com/grafana/grafana/pkg/storage/unified/search" ) type DashboardSearchClient struct { - resource.ResourceIndexClient + resourcepb.ResourceIndexClient dashboardStore dashboards.Store sorter sort.Service } @@ -64,7 +66,7 @@ func ParseSortName(sortName string) (string, bool, error) { } // nolint:gocyclo -func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.ResourceSearchRequest, opts ...grpc.CallOption) (*resource.ResourceSearchResponse, error) { +func (c *DashboardSearchClient) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest, _ ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { user, err := identity.GetRequester(ctx) if err != nil { return nil, err @@ -147,17 +149,17 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.Resour if err != nil { return nil, err } - list := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{}, - Facet: map[string]*resource.ResourceSearchResponse_Facet{ + list := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{}, + Facet: map[string]*resourcepb.ResourceSearchResponse_Facet{ "tags": { - Terms: []*resource.ResourceSearchResponse_TermFacet{}, + Terms: []*resourcepb.ResourceSearchResponse_TermFacet{}, }, }, } for _, tag := range tags { - list.Facet["tags"].Terms = append(list.Facet["tags"].Terms, &resource.ResourceSearchResponse_TermFacet{ + list.Facet["tags"].Terms = append(list.Facet["tags"].Terms, &resourcepb.ResourceSearchResponse_TermFacet{ Term: tag.Term, Count: int64(tag.Count), }) @@ -230,7 +232,7 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.Resour } } searchFields := resource.StandardSearchFields() - columns := []*resource.ResourceTableColumnDefinition{ + columns := []*resourcepb.ResourceTableColumnDefinition{ searchFields.Field(resource.SEARCH_FIELD_TITLE), searchFields.Field(resource.SEARCH_FIELD_FOLDER), searchFields.Field(resource.SEARCH_FIELD_TAGS), @@ -238,14 +240,14 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.Resour } if sortByField != "" { - columns = append(columns, &resource.ResourceTableColumnDefinition{ + columns = append(columns, &resourcepb.ResourceTableColumnDefinition{ Name: sortByField, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }) } - list := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ + list := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ Columns: columns, }, } @@ -284,7 +286,7 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.Resour cells = append(cells, []byte("0")) } - list.Results.Rows = append(list.Results.Rows, &resource.ResourceTableRow{ + list.Results.Rows = append(list.Results.Rows, &resourcepb.ResourceTableRow{ Key: getResourceKey(&dashboards.DashboardSearchProjection{ UID: dashboard.UID, }, req.Options.Key.Namespace), @@ -321,7 +323,7 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.Resour cells = append(cells, []byte(strconv.FormatInt(dashboard.SortMeta, 10))) } - list.Results.Rows = append(list.Results.Rows, &resource.ResourceTableRow{ + list.Results.Rows = append(list.Results.Rows, &resourcepb.ResourceTableRow{ Key: getResourceKey(dashboard, req.Options.Key.Namespace), Cells: cells, }) @@ -332,9 +334,9 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resource.Resour return list, nil } -func getResourceKey(item *dashboards.DashboardSearchProjection, namespace string) *resource.ResourceKey { +func getResourceKey(item *dashboards.DashboardSearchProjection, namespace string) *resourcepb.ResourceKey { if item.IsFolder { - return &resource.ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: namespace, Group: folders.GROUP, Resource: folders.RESOURCE, @@ -342,7 +344,7 @@ func getResourceKey(item *dashboards.DashboardSearchProjection, namespace string } } - return &resource.ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: namespace, Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -379,7 +381,7 @@ func formatQueryResult(res []dashboards.DashboardSearchProjection) []*dashboards return hitList } -func (c *DashboardSearchClient) GetStats(ctx context.Context, req *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) { +func (c *DashboardSearchClient) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest, _ ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { info, err := claims.ParseNamespace(req.Namespace) if err != nil { return nil, fmt.Errorf("unable to read namespace") @@ -410,8 +412,8 @@ func (c *DashboardSearchClient) GetStats(ctx context.Context, req *resource.Reso return nil, err } - return &resource.ResourceStatsResponse{ - Stats: []*resource.ResourceStatsResponse_Stats{ + return &resourcepb.ResourceStatsResponse{ + Stats: []*resourcepb.ResourceStatsResponse_Stats{ { Group: parts[0], Resource: parts[1], diff --git a/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go b/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go index cc3cd3c6869..9161e16a68e 100644 --- a/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go +++ b/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/search/sort" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" unisearch "github.com/grafana/grafana/pkg/storage/unified/search" ) @@ -31,7 +32,7 @@ func TestDashboardSearchClient_Search(t *testing.T) { emptyTags, err := json.Marshal([]string{}) require.NoError(t, err) - dashboardKey := &resource.ResourceKey{ + dashboardKey := &resourcepb.ResourceKey{ Name: "uid", Resource: dashboard.DASHBOARD_RESOURCE, } @@ -47,11 +48,11 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 2, UID: "uid2", Title: "Test Dashboard2", FolderUID: "folder2"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ { Field: resource.SEARCH_FIELD_TITLE, }, @@ -65,18 +66,18 @@ func TestDashboardSearchClient_Search(t *testing.T) { require.NotNil(t, resp) searchFields := resource.StandardSearchFields() - require.Equal(t, &resource.ResourceSearchResponse{ + require.Equal(t, &resourcepb.ResourceSearchResponse{ TotalHits: 2, - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ searchFields.Field(resource.SEARCH_FIELD_TITLE), searchFields.Field(resource.SEARCH_FIELD_FOLDER), searchFields.Field(resource.SEARCH_FIELD_TAGS), searchFields.Field(resource.SEARCH_FIELD_LEGACY_ID), }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -89,7 +90,7 @@ func TestDashboardSearchClient_Search(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -123,11 +124,11 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(50)}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ { Field: resource.SEARCH_FIELD_PREFIX + unisearch.DASHBOARD_VIEWS_TOTAL, // "fields." prefix should be removed Desc: false, @@ -138,22 +139,22 @@ func TestDashboardSearchClient_Search(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) searchFields := resource.StandardSearchFields() - require.Equal(t, &resource.ResourceSearchResponse{ + require.Equal(t, &resourcepb.ResourceSearchResponse{ TotalHits: 1, - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ searchFields.Field(resource.SEARCH_FIELD_TITLE), searchFields.Field(resource.SEARCH_FIELD_FOLDER), searchFields.Field(resource.SEARCH_FIELD_TAGS), searchFields.Field(resource.SEARCH_FIELD_LEGACY_ID), { Name: "views_total", - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -188,11 +189,11 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(2)}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ { Field: unisearch.DASHBOARD_ERRORS_LAST_30_DAYS, Desc: true, @@ -203,22 +204,22 @@ func TestDashboardSearchClient_Search(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) searchFields := resource.StandardSearchFields() - require.Equal(t, &resource.ResourceSearchResponse{ + require.Equal(t, &resourcepb.ResourceSearchResponse{ TotalHits: 1, - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ searchFields.Field(resource.SEARCH_FIELD_TITLE), searchFields.Field(resource.SEARCH_FIELD_FOLDER), searchFields.Field(resource.SEARCH_FIELD_TAGS), searchFields.Field(resource.SEARCH_FIELD_LEGACY_ID), { Name: "errors_last_30_days", - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, @@ -246,13 +247,13 @@ func TestDashboardSearchClient_Search(t *testing.T) { {Term: "tag2", Count: 5}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + req := &resourcepb.ResourceSearchRequest{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "tags": { Field: "tags", }, }, - Options: &resource.ListOptions{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, } @@ -260,11 +261,11 @@ func TestDashboardSearchClient_Search(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) - require.Equal(t, &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{}, - Facet: map[string]*resource.ResourceSearchResponse_Facet{ + require.Equal(t, &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{}, + Facet: map[string]*resourcepb.ResourceSearchResponse_Facet{ "tags": { - Terms: []*resource.ResourceSearchResponse_TermFacet{ + Terms: []*resourcepb.ResourceSearchResponse_TermFacet{ { Term: "tag1", Count: 1, @@ -292,8 +293,8 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, Query: "*test*", @@ -317,10 +318,10 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, - Labels: []*resource.Requirement{ + Labels: []*resourcepb.Requirement{ { Key: utils.LabelKeyDeprecatedInternalID, Operator: "in", @@ -350,10 +351,10 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, - Fields: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_TAGS, Operator: "in", @@ -390,10 +391,10 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, - Fields: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_MANAGER_ID, Operator: "in", @@ -423,10 +424,10 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, - Fields: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_MANAGER_KIND, Operator: "=", @@ -456,10 +457,10 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, - Fields: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_MANAGER_KIND, Operator: "=", @@ -493,11 +494,11 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ { Field: resource.SEARCH_FIELD_TITLE, }, @@ -515,11 +516,11 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1", SortMeta: 100}, }, nil).Once() - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardKey, }, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ { Field: resource.SEARCH_FIELD_PREFIX + unisearch.DASHBOARD_VIEWS_TOTAL, }, diff --git a/pkg/registry/apis/dashboard/search.go b/pkg/registry/apis/dashboard/search.go index ca61ca5eb27..17643ce2743 100644 --- a/pkg/registry/apis/dashboard/search.go +++ b/pkg/registry/apis/dashboard/search.go @@ -29,6 +29,7 @@ import ( foldermodel "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" "github.com/grafana/grafana/pkg/util/errhttp" ) @@ -36,12 +37,12 @@ import ( // The DTO returns everything the UI needs in a single request type SearchHandler struct { log log.Logger - client resource.ResourceIndexClient + client resourcepb.ResourceIndexClient tracer trace.Tracer features featuremgmt.FeatureToggles } -func NewSearchHandler(tracer trace.Tracer, dual dualwrite.Service, legacyDashboardSearcher resource.ResourceIndexClient, resourceClient resource.ResourceClient, features featuremgmt.FeatureToggles) *SearchHandler { +func NewSearchHandler(tracer trace.Tracer, dual dualwrite.Service, legacyDashboardSearcher resourcepb.ResourceIndexClient, resourceClient resource.ResourceClient, features featuremgmt.FeatureToggles) *SearchHandler { searchClient := resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), dashboardv0alpha1.DashboardResourceInfo.GroupResource(), resourceClient, legacyDashboardSearcher) return &SearchHandler{ client: searchClient, @@ -237,8 +238,8 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { page, _ = strconv.Atoi(queryParams.Get("page")) } - searchRequest := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{}, + searchRequest := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{}, Query: queryParams.Get("query"), Limit: int64(limit), Offset: int64(offset), @@ -257,7 +258,7 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { searchRequest.Fields = fields types := queryParams["type"] - var federate *resource.ResourceKey + var federate *resourcepb.ResourceKey switch len(types) { case 0: // When no type specified, search for dashboards @@ -281,7 +282,7 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { return } if federate != nil { - searchRequest.Federated = []*resource.ResourceKey{federate} + searchRequest.Federated = []*resourcepb.ResourceKey{federate} } // Add sorting @@ -290,7 +291,7 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { if slices.Contains(search.DashboardFields(), sort) { sort = resource.SEARCH_FIELD_PREFIX + sort } - s := &resource.ResourceSearchRequest_Sort{Field: sort} + s := &resourcepb.ResourceSearchRequest_Sort{Field: sort} if strings.HasPrefix(sort, "-") { s.Desc = true s.Field = s.Field[1:] @@ -301,9 +302,9 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { // The facet term fields if facets, ok := queryParams["facet"]; ok { - searchRequest.Facet = make(map[string]*resource.ResourceSearchRequest_Facet) + searchRequest.Facet = make(map[string]*resourcepb.ResourceSearchRequest_Facet) for _, v := range facets { - searchRequest.Facet[v] = &resource.ResourceSearchRequest_Facet{ + searchRequest.Facet[v] = &resourcepb.ResourceSearchRequest_Facet{ Field: v, Limit: 50, } @@ -312,7 +313,7 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { // The tags filter if tags, ok := queryParams["tag"]; ok { - searchRequest.Options.Fields = []*resource.Requirement{{ + searchRequest.Options.Fields = []*resourcepb.Requirement{{ Key: "tags", Operator: "=", Values: tags, @@ -343,7 +344,7 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { if folder == rootFolder { folder = "" // root folder is empty in the search index } - searchRequest.Options.Fields = []*resource.Requirement{{ + searchRequest.Options.Fields = []*resourcepb.Requirement{{ Key: "folder", Operator: "=", Values: []string{folder}, @@ -352,9 +353,9 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { if len(names) > 0 { if searchRequest.Options.Fields == nil { - searchRequest.Options.Fields = []*resource.Requirement{} + searchRequest.Options.Fields = []*resourcepb.Requirement{} } - namesFilter := []*resource.Requirement{{ + namesFilter := []*resourcepb.Requirement{{ Key: "name", Operator: "in", Values: names, @@ -395,7 +396,7 @@ func (s *SearchHandler) write(w http.ResponseWriter, obj any) { } // Given a namespace and type convert it to a search key -func asResourceKey(ns string, k string) (*resource.ResourceKey, error) { +func asResourceKey(ns string, k string) (*resourcepb.ResourceKey, error) { key, err := resource.AsResourceKey(ns, k) if err != nil { return nil, apierrors.NewBadRequest(err.Error()) @@ -433,12 +434,12 @@ func (s *SearchHandler) getDashboardsUIDsSharedWithUser(ctx context.Context, use return sharedDashboards, err } - dashboardSearchRequest := &resource.ResourceSearchRequest{ + dashboardSearchRequest := &resourcepb.ResourceSearchRequest{ Fields: []string{"folder"}, Limit: int64(len(dashboardUids)), - Options: &resource.ListOptions{ + Options: &resourcepb.ListOptions{ Key: key, - Fields: []*resource.Requirement{{ + Fields: []*resourcepb.Requirement{{ Key: "name", Operator: "in", Values: dashboardUids, @@ -477,12 +478,12 @@ func (s *SearchHandler) getDashboardsUIDsSharedWithUser(ctx context.Context, use return sharedDashboards, err } - folderSearchRequest := &resource.ResourceSearchRequest{ + folderSearchRequest := &resourcepb.ResourceSearchRequest{ Fields: []string{"folder"}, Limit: int64(len(allFolders)), - Options: &resource.ListOptions{ + Options: &resourcepb.ListOptions{ Key: folderKey, - Fields: []*resource.Requirement{{ + Fields: []*resourcepb.Requirement{{ Key: "name", Operator: "in", Values: allFolders, diff --git a/pkg/registry/apis/dashboard/search_test.go b/pkg/registry/apis/dashboard/search_test.go index 90411b3cbbf..f6dfdb03892 100644 --- a/pkg/registry/apis/dashboard/search_test.go +++ b/pkg/registry/apis/dashboard/search_test.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestSearchFallback(t *testing.T) { @@ -277,10 +278,10 @@ func TestSearchHandler(t *testing.T) { }) t.Run("Sort - default sort by resource", func(t *testing.T) { - rows := make([]*resource.ResourceTableRow, len(mockResults)) + rows := make([]*resourcepb.ResourceTableRow, len(mockResults)) for i, r := range mockResults { - rows[i] = &resource.ResourceTableRow{ - Key: &resource.ResourceKey{ + rows[i] = &resourcepb.ResourceTableRow{ + Key: &resourcepb.ResourceKey{ Name: r.Name, Resource: r.Resource, }, @@ -290,9 +291,9 @@ func TestSearchHandler(t *testing.T) { } } - mockResponse := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + mockResponse := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ {Name: resource.SEARCH_FIELD_TITLE}, }, Rows: rows, @@ -300,7 +301,7 @@ func TestSearchHandler(t *testing.T) { } // Create a mock client mockClient := &MockClient{ - MockResponses: []*resource.ResourceSearchResponse{mockResponse}, + MockResponses: []*resourcepb.ResourceSearchResponse{mockResponse}, } features := featuremgmt.WithFeatures() @@ -396,23 +397,23 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { t.Run("should return empty result if user has access to folder of all shared dashboards", func(t *testing.T) { // dashboardSearchRequest - mockResponse1 := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + mockResponse1 := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "folder", }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "dashboardinroot", Resource: "dashboard", }, Cells: [][]byte{[]byte("")}, // root folder doesn't have uid }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "dashboardinpublicfolder", Resource: "dashboard", }, @@ -425,16 +426,16 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { } // folderSearchRequest - mockResponse2 := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + mockResponse2 := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "folder", }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "publicfolder", Resource: "folder", }, @@ -447,7 +448,7 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { } mockClient := &MockClient{ - MockResponses: []*resource.ResourceSearchResponse{mockResponse1, mockResponse2}, + MockResponses: []*resourcepb.ResourceSearchResponse{mockResponse1, mockResponse2}, } features := featuremgmt.WithFeatures(featuremgmt.FlagUnifiedStorageSearchPermissionFiltering) @@ -486,23 +487,23 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { t.Run("should return the dashboards shared with the user", func(t *testing.T) { // dashboardSearchRequest - mockResponse1 := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + mockResponse1 := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "folder", }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "dashboardinroot", Resource: "dashboard", }, Cells: [][]byte{[]byte("")}, // root folder doesn't have uid }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "dashboardinprivatefolder", Resource: "dashboard", }, @@ -511,7 +512,7 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "dashboardinpublicfolder", Resource: "dashboard", }, @@ -524,16 +525,16 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { } // folderSearchRequest - mockResponse2 := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + mockResponse2 := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "folder", }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "publicfolder", Resource: "folder", }, @@ -545,16 +546,16 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { }, } - mockResponse3 := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + mockResponse3 := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "folder", }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "dashboardinprivatefolder", Resource: "dashboard", }, @@ -567,7 +568,7 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { } mockClient := &MockClient{ - MockResponses: []*resource.ResourceSearchResponse{mockResponse1, mockResponse2, mockResponse3}, + MockResponses: []*resourcepb.ResourceSearchResponse{mockResponse1, mockResponse2, mockResponse3}, } features := featuremgmt.WithFeatures(featuremgmt.FlagUnifiedStorageSearchPermissionFiltering) @@ -618,14 +619,14 @@ func TestSearchHandlerSharedDashboards(t *testing.T) { // MockClient implements the ResourceIndexClient interface for testing type MockClient struct { - resource.ResourceIndexClient + resourcepb.ResourceIndexClient resource.ResourceIndex // Capture the last SearchRequest for assertions - LastSearchRequest *resource.ResourceSearchRequest + LastSearchRequest *resourcepb.ResourceSearchRequest - MockResponses []*resource.ResourceSearchResponse - MockCalls []*resource.ResourceSearchRequest + MockResponses []*resourcepb.ResourceSearchResponse + MockCalls []*resourcepb.ResourceSearchRequest CallCount int } @@ -658,11 +659,11 @@ var mockResults = []MockResult{ }, } -func (m *MockClient) Search(ctx context.Context, in *resource.ResourceSearchRequest, opts ...grpc.CallOption) (*resource.ResourceSearchResponse, error) { +func (m *MockClient) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { m.LastSearchRequest = in m.MockCalls = append(m.MockCalls, in) - var response *resource.ResourceSearchResponse + var response *resourcepb.ResourceSearchResponse if m.CallCount < len(m.MockResponses) { response = m.MockResponses[m.CallCount] } @@ -671,42 +672,42 @@ func (m *MockClient) Search(ctx context.Context, in *resource.ResourceSearchRequ return response, nil } -func (m *MockClient) GetStats(ctx context.Context, in *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) { +func (m *MockClient) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { return nil, nil } -func (m *MockClient) CountManagedObjects(ctx context.Context, in *resource.CountManagedObjectsRequest, opts ...grpc.CallOption) (*resource.CountManagedObjectsResponse, error) { +func (m *MockClient) CountManagedObjects(ctx context.Context, in *resourcepb.CountManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.CountManagedObjectsResponse, error) { return nil, nil } -func (m *MockClient) Watch(ctx context.Context, in *resource.WatchRequest, opts ...grpc.CallOption) (resource.ResourceStore_WatchClient, error) { +func (m *MockClient) Watch(ctx context.Context, in *resourcepb.WatchRequest, opts ...grpc.CallOption) (resourcepb.ResourceStore_WatchClient, error) { return nil, nil } -func (m *MockClient) Delete(ctx context.Context, in *resource.DeleteRequest, opts ...grpc.CallOption) (*resource.DeleteResponse, error) { +func (m *MockClient) Delete(ctx context.Context, in *resourcepb.DeleteRequest, opts ...grpc.CallOption) (*resourcepb.DeleteResponse, error) { return nil, nil } -func (m *MockClient) Create(ctx context.Context, in *resource.CreateRequest, opts ...grpc.CallOption) (*resource.CreateResponse, error) { +func (m *MockClient) Create(ctx context.Context, in *resourcepb.CreateRequest, opts ...grpc.CallOption) (*resourcepb.CreateResponse, error) { return nil, nil } -func (m *MockClient) Update(ctx context.Context, in *resource.UpdateRequest, opts ...grpc.CallOption) (*resource.UpdateResponse, error) { +func (m *MockClient) Update(ctx context.Context, in *resourcepb.UpdateRequest, opts ...grpc.CallOption) (*resourcepb.UpdateResponse, error) { return nil, nil } -func (m *MockClient) Read(ctx context.Context, in *resource.ReadRequest, opts ...grpc.CallOption) (*resource.ReadResponse, error) { +func (m *MockClient) Read(ctx context.Context, in *resourcepb.ReadRequest, opts ...grpc.CallOption) (*resourcepb.ReadResponse, error) { return nil, nil } -func (m *MockClient) GetBlob(ctx context.Context, in *resource.GetBlobRequest, opts ...grpc.CallOption) (*resource.GetBlobResponse, error) { +func (m *MockClient) GetBlob(ctx context.Context, in *resourcepb.GetBlobRequest, opts ...grpc.CallOption) (*resourcepb.GetBlobResponse, error) { return nil, nil } -func (m *MockClient) PutBlob(ctx context.Context, in *resource.PutBlobRequest, opts ...grpc.CallOption) (*resource.PutBlobResponse, error) { +func (m *MockClient) PutBlob(ctx context.Context, in *resourcepb.PutBlobRequest, opts ...grpc.CallOption) (*resourcepb.PutBlobResponse, error) { return nil, nil } -func (m *MockClient) List(ctx context.Context, in *resource.ListRequest, opts ...grpc.CallOption) (*resource.ListResponse, error) { +func (m *MockClient) List(ctx context.Context, in *resourcepb.ListRequest, opts ...grpc.CallOption) (*resourcepb.ListResponse, error) { return nil, nil } -func (m *MockClient) ListManagedObjects(ctx context.Context, in *resource.ListManagedObjectsRequest, opts ...grpc.CallOption) (*resource.ListManagedObjectsResponse, error) { +func (m *MockClient) ListManagedObjects(ctx context.Context, in *resourcepb.ListManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.ListManagedObjectsResponse, error) { return nil, nil } -func (m *MockClient) IsHealthy(ctx context.Context, in *resource.HealthCheckRequest, opts ...grpc.CallOption) (*resource.HealthCheckResponse, error) { +func (m *MockClient) IsHealthy(ctx context.Context, in *resourcepb.HealthCheckRequest, opts ...grpc.CallOption) (*resourcepb.HealthCheckResponse, error) { return nil, nil } -func (m *MockClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { +func (m *MockClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) { return nil, nil } diff --git a/pkg/registry/apis/dashboard/sub_dto.go b/pkg/registry/apis/dashboard/sub_dto.go index 32f0b787ee8..80ec5c8f12c 100644 --- a/pkg/registry/apis/dashboard/sub_dto.go +++ b/pkg/registry/apis/dashboard/sub_dto.go @@ -11,6 +11,7 @@ import ( claims "github.com/grafana/authlib/types" "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" @@ -21,6 +22,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/storage/unified/apistore" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type dtoBuilder = func(dashboard runtime.Object, access *dashboard.DashboardAccess) (runtime.Object, error) @@ -109,7 +111,7 @@ func (r *DTOConnector) Connect(ctx context.Context, name string, opts runtime.Ob blobInfo := obj.GetBlob() if blobInfo != nil && r.largeObjects != nil { gr := r.largeObjects.GroupResource() - err = r.largeObjects.Reconstruct(ctx, &resource.ResourceKey{ + err = r.largeObjects.Reconstruct(ctx, &resourcepb.ResourceKey{ Group: gr.Group, Resource: gr.Resource, Namespace: obj.GetNamespace(), diff --git a/pkg/registry/apis/folders/mocks.go b/pkg/registry/apis/folders/mocks.go index ee722574aab..b053ba875ba 100644 --- a/pkg/registry/apis/folders/mocks.go +++ b/pkg/registry/apis/folders/mocks.go @@ -3,7 +3,8 @@ package folders import ( "context" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/mock" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/apis/meta/internalversion" @@ -19,7 +20,7 @@ type storageMock struct { type searcherMock struct { *mock.Mock - resource.ResourceIndexClient + resourcepb.ResourceIndexClient } func (m storageMock) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { @@ -75,7 +76,7 @@ func (m storageMock) Update(ctx context.Context, name string, objInfo rest.Updat return args.Get(0).(runtime.Object), args.Bool(1), args.Error(2) } -func (s searcherMock) GetStats(ctx context.Context, req *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) { +func (s searcherMock) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest, _ ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { args := s.Called(ctx, req) - return args.Get(0).(*resource.ResourceStatsResponse), args.Error(1) + return args.Get(0).(*resourcepb.ResourceStatsResponse), args.Error(1) } diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index 6c28909f63b..cee02f5f8a9 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -14,10 +14,11 @@ import ( "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" - common "k8s.io/kube-openapi/pkg/common" + "k8s.io/kube-openapi/pkg/common" "k8s.io/kube-openapi/pkg/spec3" authtypes "github.com/grafana/authlib/types" + folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" @@ -32,6 +33,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified/apistore" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var _ builder.APIGroupBuilder = (*FolderAPIBuilder)(nil) @@ -54,7 +56,7 @@ type FolderAPIBuilder struct { authorizer authorizer.Authorizer - searcher resource.ResourceIndexClient + searcher resourcepb.ResourceIndexClient cfg *setting.Cfg ignoreLegacy bool // skip legacy storage and only use unified storage } @@ -260,7 +262,7 @@ func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes, } func (b *FolderAPIBuilder) validateOnDelete(ctx context.Context, f *folders.Folder) error { - resp, err := b.searcher.GetStats(ctx, &resource.ResourceStatsRequest{Namespace: f.Namespace, Folder: f.Name}) + resp, err := b.searcher.GetStats(ctx, &resourcepb.ResourceStatsRequest{Namespace: f.Namespace, Folder: f.Name}) if err != nil { return err } diff --git a/pkg/registry/apis/folders/register_test.go b/pkg/registry/apis/folders/register_test.go index 960d128395f..d693bd53106 100644 --- a/pkg/registry/apis/folders/register_test.go +++ b/pkg/registry/apis/folders/register_test.go @@ -17,7 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestFolderAPIBuilder_Validate_Create(t *testing.T) { @@ -169,16 +169,16 @@ func TestFolderAPIBuilder_Validate_Create(t *testing.T) { func TestFolderAPIBuilder_Validate_Delete(t *testing.T) { tests := []struct { name string - statsResponse *resource.ResourceStatsResponse_Stats + statsResponse *resourcepb.ResourceStatsResponse_Stats wantErr bool }{ { name: "should allow deletion when folder is empty", - statsResponse: &resource.ResourceStatsResponse_Stats{Count: 0}, + statsResponse: &resourcepb.ResourceStatsResponse_Stats{Count: 0}, }, { name: "should return folder not empty when the folder is not empty", - statsResponse: &resource.ResourceStatsResponse_Stats{Count: 2}, + statsResponse: &resourcepb.ResourceStatsResponse_Stats{Count: 2}, wantErr: true, }, } @@ -200,9 +200,9 @@ func TestFolderAPIBuilder_Validate_Delete(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var setupFn = func(m *mock.Mock, stats *resource.ResourceStatsResponse_Stats) { - m.On("GetStats", mock.Anything, &resource.ResourceStatsRequest{Namespace: obj.Namespace, Folder: obj.Name}).Return( - &resource.ResourceStatsResponse{Stats: []*resource.ResourceStatsResponse_Stats{stats}}, + var setupFn = func(m *mock.Mock, stats *resourcepb.ResourceStatsResponse_Stats) { + m.On("GetStats", mock.Anything, &resourcepb.ResourceStatsRequest{Namespace: obj.Namespace, Folder: obj.Name}).Return( + &resourcepb.ResourceStatsResponse{Stats: []*resourcepb.ResourceStatsResponse_Stats{stats}}, nil, ).Once() } diff --git a/pkg/registry/apis/folders/sub_count.go b/pkg/registry/apis/folders/sub_count.go index 34515818f0f..ebaeb590a50 100644 --- a/pkg/registry/apis/folders/sub_count.go +++ b/pkg/registry/apis/folders/sub_count.go @@ -9,11 +9,11 @@ import ( folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type subCountREST struct { - searcher resource.ResourceIndexClient + searcher resourcepb.ResourceIndexClient } var ( @@ -44,7 +44,7 @@ func (r *subCountREST) NewConnectOptions() (runtime.Object, bool, string) { return nil, false, "" // true means you can use the trailing path as a variable } -func (r *subCountREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) { +func (r *subCountREST) Connect(ctx context.Context, name string, _ runtime.Object, responder rest.Responder) (http.Handler, error) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { @@ -52,7 +52,7 @@ func (r *subCountREST) Connect(ctx context.Context, name string, opts runtime.Ob return } - stats, err := r.searcher.GetStats(ctx, &resource.ResourceStatsRequest{ + stats, err := r.searcher.GetStats(ctx, &resourcepb.ResourceStatsRequest{ Namespace: ns.Value, Folder: name, }) diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go index 810d03a245b..34391f3e56f 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources/signature" "github.com/grafana/grafana/pkg/storage/unified/parquet" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var _ resource.BulkResourceWriter = (*legacyResourceResourceMigrator)(nil) @@ -159,12 +160,12 @@ func (r *legacyResourceResourceMigrator) Close() error { } // CloseWithResults implements resource.BulkResourceWriter. -func (r *legacyResourceResourceMigrator) CloseWithResults() (*resource.BulkResponse, error) { - return &resource.BulkResponse{}, nil +func (r *legacyResourceResourceMigrator) CloseWithResults() (*resourcepb.BulkResponse, error) { + return &resourcepb.BulkResponse{}, nil } // Write implements resource.BulkResourceWriter. -func (r *legacyResourceResourceMigrator) Write(ctx context.Context, key *resource.ResourceKey, value []byte) error { +func (r *legacyResourceResourceMigrator) Write(ctx context.Context, key *resourcepb.ResourceKey, value []byte) error { // Reuse the same parse+cleanup logic parsed, err := r.parser.Parse(ctx, &repository.FileInfo{ Path: "", // empty path to ignore file system diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go index 50032583024..aff308a4a9b 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go @@ -21,7 +21,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources/signature" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestLegacyResourcesMigrator_Migrate(t *testing.T) { @@ -96,7 +96,7 @@ func TestLegacyResourcesMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, errors.New("legacy migrator error")) + })).Return(&resourcepb.BulkResponse{}, errors.New("legacy migrator error")) progress := jobs.NewMockJobProgressRecorder(t) progress.On("SetMessage", mock.Anything, mock.Anything).Return() @@ -311,11 +311,11 @@ func TestLegacyResourcesMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, nil).Once() // Count phase + })).Return(&resourcepb.BulkResponse{}, nil).Once() // Count phase mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return !opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{ - Summary: []*resource.BulkResponse_Summary{ + })).Return(&resourcepb.BulkResponse{ + Summary: []*resourcepb.BulkResponse_Summary{ { Group: "test.grafana.app", Resource: "tests", @@ -390,7 +390,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { signature.NewGrafanaSigner(), ) - err := migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("test")) + err := migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) require.Error(t, err) require.Contains(t, err.Error(), "unmarshal unstructured") @@ -440,7 +440,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { signature.NewGrafanaSigner(), ) - err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("test")) + err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) require.NoError(t, err) // Error is recorded but not returned mockParser.AssertExpectations(t) @@ -483,7 +483,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { mockSigner, ) - err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("test")) + err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) require.Error(t, err) require.EqualError(t, err, "add author signature: signing error") @@ -543,7 +543,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { mockSigner, ) - err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("test")) + err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) require.NoError(t, err) mockParser.AssertExpectations(t) @@ -592,7 +592,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { ) writeResourceFileFromObject.Return("aaaa.json", nil) - err := migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("")) + err := migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("")) require.NoError(t, err) require.Equal(t, "aaaa.json", migrator.history["test"], "kept track of the old files") @@ -601,7 +601,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { mockRepo.On("Delete", mock.Anything, "aaaa.json", "", "moved to: bbbb.json"). Return(nil).Once() - err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("")) + err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("")) require.NoError(t, err) require.Equal(t, "bbbb.json", migrator.history["test"], "kept track of the old files") @@ -685,7 +685,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { signature.NewGrafanaSigner(), ) - err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("test")) + err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) require.NoError(t, err) mockParser.AssertExpectations(t) @@ -731,7 +731,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { signature.NewGrafanaSigner(), ) - err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte("test")) + err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) require.EqualError(t, err, "too many errors") mockParser.AssertExpectations(t) @@ -745,7 +745,7 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, errors.New("count error")) + })).Return(&resourcepb.BulkResponse{}, errors.New("count error")) progress := jobs.NewMockJobProgressRecorder(t) progress.On("SetMessage", mock.Anything, mock.Anything).Return() @@ -774,10 +774,10 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, nil).Once() // Count phase + })).Return(&resourcepb.BulkResponse{}, nil).Once() // Count phase mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return !opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, errors.New("write error")).Once() // Write phase + })).Return(&resourcepb.BulkResponse{}, errors.New("write error")).Once() // Write phase progress := jobs.NewMockJobProgressRecorder(t) progress.On("SetMessage", mock.Anything, mock.Anything).Return() @@ -806,10 +806,10 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, nil).Once() // Count phase + })).Return(&resourcepb.BulkResponse{}, nil).Once() // Count phase mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return !opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, nil).Once() // Write phase + })).Return(&resourcepb.BulkResponse{}, nil).Once() // Write phase progress := jobs.NewMockJobProgressRecorder(t) progress.On("SetMessage", mock.Anything, mock.Anything).Return() @@ -836,8 +836,8 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{ - Summary: []*resource.BulkResponse_Summary{ + })).Return(&resourcepb.BulkResponse{ + Summary: []*resourcepb.BulkResponse_Summary{ { Group: "test.grafana.app", Resource: "tests", @@ -848,7 +848,7 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { }, nil).Once() // Count phase mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return !opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, nil).Once() // Write phase + })).Return(&resourcepb.BulkResponse{}, nil).Once() // Write phase progress := jobs.NewMockJobProgressRecorder(t) progress.On("SetMessage", mock.Anything, mock.Anything).Return() @@ -876,8 +876,8 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { mockLegacyMigrator := legacy.NewMockLegacyMigrator(t) mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{ - Summary: []*resource.BulkResponse_Summary{ + })).Return(&resourcepb.BulkResponse{ + Summary: []*resourcepb.BulkResponse_Summary{ { Group: "test.grafana.app", Resource: "tests", @@ -888,7 +888,7 @@ func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { }, nil).Once() // Count phase mockLegacyMigrator.On("Migrate", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { return !opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resource.BulkResponse{}, nil).Once() // Write phase + })).Return(&resourcepb.BulkResponse{}, nil).Once() // Write phase progress := jobs.NewMockJobProgressRecorder(t) progress.On("SetMessage", mock.Anything, mock.Anything).Return() @@ -930,7 +930,7 @@ func TestLegacyResourceResourceMigrator_CloseWithResults(t *testing.T) { require.NoError(t, err) require.NotNil(t, response) - require.IsType(t, &resource.BulkResponse{}, response) + require.IsType(t, &resourcepb.BulkResponse{}, response) require.Empty(t, response.Summary) }) } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go index f29f05347c2..15051cd430e 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go @@ -7,8 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" metadata "google.golang.org/grpc/metadata" - - resource "github.com/grafana/grafana/pkg/storage/unified/resource" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // BulkStore_BulkProcessClient is an autogenerated mock type for the BulkStore_BulkProcessClient type @@ -25,23 +25,23 @@ func (_m *BulkStore_BulkProcessClient) EXPECT() *BulkStore_BulkProcessClient_Exp } // CloseAndRecv provides a mock function with no fields -func (_m *BulkStore_BulkProcessClient) CloseAndRecv() (*resource.BulkResponse, error) { +func (_m *BulkStore_BulkProcessClient) CloseAndRecv() (*resourcepb.BulkResponse, error) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for CloseAndRecv") } - var r0 *resource.BulkResponse + var r0 *resourcepb.BulkResponse var r1 error - if rf, ok := ret.Get(0).(func() (*resource.BulkResponse, error)); ok { + if rf, ok := ret.Get(0).(func() (*resourcepb.BulkResponse, error)); ok { return rf() } - if rf, ok := ret.Get(0).(func() *resource.BulkResponse); ok { + if rf, ok := ret.Get(0).(func() *resourcepb.BulkResponse); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*resource.BulkResponse) + r0 = ret.Get(0).(*resourcepb.BulkResponse) } } @@ -71,12 +71,12 @@ func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) Run(run func()) *BulkSt return _c } -func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) Return(_a0 *resource.BulkResponse, _a1 error) *BulkStore_BulkProcessClient_CloseAndRecv_Call { +func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) Return(_a0 *resourcepb.BulkResponse, _a1 error) *BulkStore_BulkProcessClient_CloseAndRecv_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) RunAndReturn(run func() (*resource.BulkResponse, error)) *BulkStore_BulkProcessClient_CloseAndRecv_Call { +func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) RunAndReturn(run func() (*resourcepb.BulkResponse, error)) *BulkStore_BulkProcessClient_CloseAndRecv_Call { _c.Call.Return(run) return _c } @@ -277,7 +277,7 @@ func (_c *BulkStore_BulkProcessClient_RecvMsg_Call) RunAndReturn(run func(interf } // Send provides a mock function with given fields: _a0 -func (_m *BulkStore_BulkProcessClient) Send(_a0 *resource.BulkRequest) error { +func (_m *BulkStore_BulkProcessClient) Send(_a0 *resourcepb.BulkRequest) error { ret := _m.Called(_a0) if len(ret) == 0 { @@ -285,7 +285,7 @@ func (_m *BulkStore_BulkProcessClient) Send(_a0 *resource.BulkRequest) error { } var r0 error - if rf, ok := ret.Get(0).(func(*resource.BulkRequest) error); ok { + if rf, ok := ret.Get(0).(func(*resourcepb.BulkRequest) error); ok { r0 = rf(_a0) } else { r0 = ret.Error(0) @@ -305,9 +305,9 @@ func (_e *BulkStore_BulkProcessClient_Expecter) Send(_a0 interface{}) *BulkStore return &BulkStore_BulkProcessClient_Send_Call{Call: _e.mock.On("Send", _a0)} } -func (_c *BulkStore_BulkProcessClient_Send_Call) Run(run func(_a0 *resource.BulkRequest)) *BulkStore_BulkProcessClient_Send_Call { +func (_c *BulkStore_BulkProcessClient_Send_Call) Run(run func(_a0 *resourcepb.BulkRequest)) *BulkStore_BulkProcessClient_Send_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*resource.BulkRequest)) + run(args[0].(*resourcepb.BulkRequest)) }) return _c } @@ -317,7 +317,7 @@ func (_c *BulkStore_BulkProcessClient_Send_Call) Return(_a0 error) *BulkStore_Bu return _c } -func (_c *BulkStore_BulkProcessClient_Send_Call) RunAndReturn(run func(*resource.BulkRequest) error) *BulkStore_BulkProcessClient_Send_Call { +func (_c *BulkStore_BulkProcessClient_Send_Call) RunAndReturn(run func(*resourcepb.BulkRequest) error) *BulkStore_BulkProcessClient_Send_Call { _c.Call.Return(run) return _c } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go index 4ca9b8e5e72..ff6a0cd0cf7 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go @@ -9,7 +9,7 @@ import ( mock "github.com/stretchr/testify/mock" - resource "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // MockBulkStoreClient is an autogenerated mock type for the BulkStoreClient type @@ -26,7 +26,7 @@ func (_m *MockBulkStoreClient) EXPECT() *MockBulkStoreClient_Expecter { } // BulkProcess provides a mock function with given fields: ctx, opts -func (_m *MockBulkStoreClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { +func (_m *MockBulkStoreClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -40,16 +40,16 @@ func (_m *MockBulkStoreClient) BulkProcess(ctx context.Context, opts ...grpc.Cal panic("no return value specified for BulkProcess") } - var r0 resource.BulkStore_BulkProcessClient + var r0 resourcepb.BulkStore_BulkProcessClient var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error)); ok { return rf(ctx, opts...) } - if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) resource.BulkStore_BulkProcessClient); ok { + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) resourcepb.BulkStore_BulkProcessClient); ok { r0 = rf(ctx, opts...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(resource.BulkStore_BulkProcessClient) + r0 = ret.Get(0).(resourcepb.BulkStore_BulkProcessClient) } } @@ -88,12 +88,12 @@ func (_c *MockBulkStoreClient_BulkProcess_Call) Run(run func(ctx context.Context return _c } -func (_c *MockBulkStoreClient_BulkProcess_Call) Return(_a0 resource.BulkStore_BulkProcessClient, _a1 error) *MockBulkStoreClient_BulkProcess_Call { +func (_c *MockBulkStoreClient_BulkProcess_Call) Return(_a0 resourcepb.BulkStore_BulkProcessClient, _a1 error) *MockBulkStoreClient_BulkProcess_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockBulkStoreClient_BulkProcess_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error)) *MockBulkStoreClient_BulkProcess_Call { +func (_c *MockBulkStoreClient_BulkProcess_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error)) *MockBulkStoreClient_BulkProcess_Call { _c.Call.Return(run) return _c } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/storage.go b/pkg/registry/apis/provisioning/jobs/migrate/storage.go index 3b59776836f..6d04eaa8c88 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/storage.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/storage.go @@ -9,15 +9,17 @@ import ( "google.golang.org/grpc/metadata" "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) //go:generate mockery --name BulkStoreClient --structname MockBulkStoreClient --inpackage --filename mock_bulk_store_client.go --with-expecter //go:generate mockery --name=BulkStore_BulkProcessClient --srcpkg=github.com/grafana/grafana/pkg/storage/unified/resource --output=. --outpkg=migrate --filename=mock_bulk_process_client.go --with-expecter type BulkStoreClient interface { - BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) + BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) } //go:generate mockery --name StorageSwapper --structname MockStorageSwapper --inpackage --filename mock_storage_swapper.go --with-expecter @@ -69,7 +71,7 @@ func (s *storageSwapper) WipeUnifiedAndSetMigratedFlag(ctx context.Context, name } settings := resource.BulkSettings{ RebuildCollection: true, // wipes everything in the collection - Collection: []*resource.ResourceKey{{ + Collection: []*resourcepb.ResourceKey{{ Namespace: namespace, Group: gr.Group, Resource: gr.Resource, diff --git a/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go b/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go index 7c636f73174..5e1adadcc2d 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go @@ -12,6 +12,8 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "google.golang.org/grpc/metadata" ) @@ -115,7 +117,7 @@ func TestStorageSwapper_WipeUnifiedAndSetMigratedFlag(t *testing.T) { dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) mockStream := NewBulkStore_BulkProcessClient(t) - mockStream.On("CloseAndRecv").Return(&resource.BulkResponse{}, nil) + mockStream.On("CloseAndRecv").Return(&resourcepb.BulkResponse{}, nil) bulk.On("BulkProcess", mock.Anything, mock.Anything).Return(mockStream, nil) dual.On("Update", mock.Anything, mock.MatchedBy(func(status dualwrite.StorageStatus) bool { @@ -143,7 +145,7 @@ func TestStorageSwapper_WipeUnifiedAndSetMigratedFlag(t *testing.T) { dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) mockStream := NewBulkStore_BulkProcessClient(t) - mockStream.On("CloseAndRecv").Return(&resource.BulkResponse{}, nil) + mockStream.On("CloseAndRecv").Return(&resourcepb.BulkResponse{}, nil) bulk.On("BulkProcess", mock.MatchedBy(func(ctx context.Context) bool { md, ok := metadata.FromOutgoingContext(ctx) if !ok { diff --git a/pkg/registry/apis/provisioning/resources/object.go b/pkg/registry/apis/provisioning/resources/object.go index 3553056dd0a..9faa4412fce 100644 --- a/pkg/registry/apis/provisioning/resources/object.go +++ b/pkg/registry/apis/provisioning/resources/object.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // Get repository stats @@ -24,15 +25,15 @@ type ResourceLister interface { } type ResourceListerFromSearch struct { - managed resource.ManagedObjectIndexClient - index resource.ResourceIndexClient + managed resourcepb.ManagedObjectIndexClient + index resourcepb.ResourceIndexClient legacyMigrator legacy.LegacyMigrator storageStatus dualwrite.Service } func NewResourceLister( - managed resource.ManagedObjectIndexClient, - index resource.ResourceIndexClient, + managed resourcepb.ManagedObjectIndexClient, + index resourcepb.ResourceIndexClient, legacyMigrator legacy.LegacyMigrator, storageStatus dualwrite.Service, ) ResourceLister { @@ -46,7 +47,7 @@ func NewResourceLister( // List implements ResourceLister. func (o *ResourceListerFromSearch) List(ctx context.Context, namespace, repository string) (*provisioning.ResourceList, error) { - objects, err := o.managed.ListManagedObjects(ctx, &resource.ListManagedObjectsRequest{ + objects, err := o.managed.ListManagedObjects(ctx, &resourcepb.ListManagedObjectsRequest{ Namespace: namespace, Kind: string(utils.ManagerKindRepo), Id: repository, @@ -76,7 +77,7 @@ func (o *ResourceListerFromSearch) List(ctx context.Context, namespace, reposito // Stats implements ResourceLister. func (o *ResourceListerFromSearch) Stats(ctx context.Context, namespace, repository string) (*provisioning.ResourceStats, error) { - req := &resource.CountManagedObjectsRequest{ + req := &resourcepb.CountManagedObjectsRequest{ Namespace: namespace, } if repository != "" { @@ -150,7 +151,7 @@ func (o *ResourceListerFromSearch) Stats(ctx context.Context, namespace, reposit } // Get full instance stats - info, err := o.index.GetStats(ctx, &resource.ResourceStatsRequest{ + info, err := o.index.GetStats(ctx, &resourcepb.ResourceStatsRequest{ Namespace: namespace, }) if err != nil { diff --git a/pkg/registry/apis/provisioning/usage.go b/pkg/registry/apis/provisioning/usage.go index b0fef85e468..fa45de200dd 100644 --- a/pkg/registry/apis/provisioning/usage.go +++ b/pkg/registry/apis/provisioning/usage.go @@ -6,7 +6,7 @@ import ( "k8s.io/apimachinery/pkg/labels" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func (b *APIBuilder) collectProvisioningStats(ctx context.Context) (map[string]any, error) { @@ -22,7 +22,7 @@ func (b *APIBuilder) collectProvisioningStats(ctx context.Context) (map[string]a // We could get namespaces from the list of repos below, but that could be zero // while we still have resources managed by terraform, etc ns := "default" - count, err := b.unified.CountManagedObjects(ctx, &resource.CountManagedObjectsRequest{ + count, err := b.unified.CountManagedObjects(ctx, &resourcepb.CountManagedObjectsRequest{ Namespace: ns, }) if err != nil { diff --git a/pkg/registry/apis/provisioning/webhooks/pullrequest/blobstore_client_mock.go b/pkg/registry/apis/provisioning/webhooks/pullrequest/blobstore_client_mock.go index ad69c8c9b57..cddf0ada660 100644 --- a/pkg/registry/apis/provisioning/webhooks/pullrequest/blobstore_client_mock.go +++ b/pkg/registry/apis/provisioning/webhooks/pullrequest/blobstore_client_mock.go @@ -9,7 +9,7 @@ import ( mock "github.com/stretchr/testify/mock" - resource "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // MockBlobStoreClient is an autogenerated mock type for the BlobStoreClient type @@ -26,7 +26,7 @@ func (_m *MockBlobStoreClient) EXPECT() *MockBlobStoreClient_Expecter { } // PutBlob provides a mock function with given fields: ctx, in, opts -func (_m *MockBlobStoreClient) PutBlob(ctx context.Context, in *resource.PutBlobRequest, opts ...grpc.CallOption) (*resource.PutBlobResponse, error) { +func (_m *MockBlobStoreClient) PutBlob(ctx context.Context, in *resourcepb.PutBlobRequest, opts ...grpc.CallOption) (*resourcepb.PutBlobResponse, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -40,20 +40,20 @@ func (_m *MockBlobStoreClient) PutBlob(ctx context.Context, in *resource.PutBlob panic("no return value specified for PutBlob") } - var r0 *resource.PutBlobResponse + var r0 *resourcepb.PutBlobResponse var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *resource.PutBlobRequest, ...grpc.CallOption) (*resource.PutBlobResponse, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *resourcepb.PutBlobRequest, ...grpc.CallOption) (*resourcepb.PutBlobResponse, error)); ok { return rf(ctx, in, opts...) } - if rf, ok := ret.Get(0).(func(context.Context, *resource.PutBlobRequest, ...grpc.CallOption) *resource.PutBlobResponse); ok { + if rf, ok := ret.Get(0).(func(context.Context, *resourcepb.PutBlobRequest, ...grpc.CallOption) *resourcepb.PutBlobResponse); ok { r0 = rf(ctx, in, opts...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*resource.PutBlobResponse) + r0 = ret.Get(0).(*resourcepb.PutBlobResponse) } } - if rf, ok := ret.Get(1).(func(context.Context, *resource.PutBlobRequest, ...grpc.CallOption) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *resourcepb.PutBlobRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { r1 = ret.Error(1) @@ -76,7 +76,7 @@ func (_e *MockBlobStoreClient_Expecter) PutBlob(ctx interface{}, in interface{}, append([]interface{}{ctx, in}, opts...)...)} } -func (_c *MockBlobStoreClient_PutBlob_Call) Run(run func(ctx context.Context, in *resource.PutBlobRequest, opts ...grpc.CallOption)) *MockBlobStoreClient_PutBlob_Call { +func (_c *MockBlobStoreClient_PutBlob_Call) Run(run func(ctx context.Context, in *resourcepb.PutBlobRequest, opts ...grpc.CallOption)) *MockBlobStoreClient_PutBlob_Call { _c.Call.Run(func(args mock.Arguments) { variadicArgs := make([]grpc.CallOption, len(args)-2) for i, a := range args[2:] { @@ -84,17 +84,17 @@ func (_c *MockBlobStoreClient_PutBlob_Call) Run(run func(ctx context.Context, in variadicArgs[i] = a.(grpc.CallOption) } } - run(args[0].(context.Context), args[1].(*resource.PutBlobRequest), variadicArgs...) + run(args[0].(context.Context), args[1].(*resourcepb.PutBlobRequest), variadicArgs...) }) return _c } -func (_c *MockBlobStoreClient_PutBlob_Call) Return(_a0 *resource.PutBlobResponse, _a1 error) *MockBlobStoreClient_PutBlob_Call { +func (_c *MockBlobStoreClient_PutBlob_Call) Return(_a0 *resourcepb.PutBlobResponse, _a1 error) *MockBlobStoreClient_PutBlob_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockBlobStoreClient_PutBlob_Call) RunAndReturn(run func(context.Context, *resource.PutBlobRequest, ...grpc.CallOption) (*resource.PutBlobResponse, error)) *MockBlobStoreClient_PutBlob_Call { +func (_c *MockBlobStoreClient_PutBlob_Call) RunAndReturn(run func(context.Context, *resourcepb.PutBlobRequest, ...grpc.CallOption) (*resourcepb.PutBlobResponse, error)) *MockBlobStoreClient_PutBlob_Call { _c.Call.Return(run) return _c } diff --git a/pkg/registry/apis/provisioning/webhooks/pullrequest/render.go b/pkg/registry/apis/provisioning/webhooks/pullrequest/render.go index 31e35b86673..897f73a2e74 100644 --- a/pkg/registry/apis/provisioning/webhooks/pullrequest/render.go +++ b/pkg/registry/apis/provisioning/webhooks/pullrequest/render.go @@ -14,13 +14,14 @@ import ( provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/rendering" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "google.golang.org/grpc" ) //go:generate mockery --name BlobStoreClient --structname MockBlobStoreClient --inpackage --filename blobstore_client_mock.go --with-expecter type BlobStoreClient interface { - PutBlob(ctx context.Context, in *resource.PutBlobRequest, opts ...grpc.CallOption) (*resource.PutBlobResponse, error) + PutBlob(ctx context.Context, in *resourcepb.PutBlobRequest, opts ...grpc.CallOption) (*resourcepb.PutBlobResponse, error) } // ScreenshotRenderer is an interface for rendering a preview of a file @@ -85,14 +86,14 @@ func (r *screenshotRenderer) RenderScreenshot(ctx context.Context, repo provisio return "", err } - rsp, err := r.blobstore.PutBlob(ctx, &resource.PutBlobRequest{ - Resource: &resource.ResourceKey{ + rsp, err := r.blobstore.PutBlob(ctx, &resourcepb.PutBlobRequest{ + Resource: &resourcepb.ResourceKey{ Namespace: repo.Namespace, Group: provisioning.GROUP, Resource: provisioning.RepositoryResourceInfo.GroupResource().Resource, Name: repo.Name, }, - Method: resource.PutBlobRequest_GRPC, + Method: resourcepb.PutBlobRequest_GRPC, ContentType: mime.TypeByExtension(ext), // image/png Value: body, }) diff --git a/pkg/registry/apis/provisioning/webhooks/pullrequest/render_test.go b/pkg/registry/apis/provisioning/webhooks/pullrequest/render_test.go index f21be8d1c18..3cb2ac1c3c8 100644 --- a/pkg/registry/apis/provisioning/webhooks/pullrequest/render_test.go +++ b/pkg/registry/apis/provisioning/webhooks/pullrequest/render_test.go @@ -15,7 +15,7 @@ import ( provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/rendering" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func setupTempFile(t *testing.T) (string, func()) { @@ -170,10 +170,10 @@ func TestScreenshotRenderer_RenderScreenshot(t *testing.T) { }, setupBlobstore: func(t *testing.T) BlobStoreClient { blobstore := NewMockBlobStoreClient(t) - blobstore.On("PutBlob", mock.Anything, mock.MatchedBy(func(req *resource.PutBlobRequest) bool { + blobstore.On("PutBlob", mock.Anything, mock.MatchedBy(func(req *resourcepb.PutBlobRequest) bool { return req.Resource.Group == provisioning.GROUP && req.Resource.Resource == provisioning.RepositoryResourceInfo.GroupResource().Resource && - req.Method == resource.PutBlobRequest_GRPC && + req.Method == resourcepb.PutBlobRequest_GRPC && req.ContentType == "image/png" })).Return(nil, errors.New("blobstore error")) return blobstore @@ -200,7 +200,7 @@ func TestScreenshotRenderer_RenderScreenshot(t *testing.T) { setupBlobstore: func(t *testing.T) BlobStoreClient { blobstore := NewMockBlobStoreClient(t) blobstore.On("PutBlob", mock.Anything, mock.Anything). - Return(&resource.PutBlobResponse{ + Return(&resourcepb.PutBlobResponse{ Url: "https://example.com/test.png", }, nil) return blobstore @@ -227,7 +227,7 @@ func TestScreenshotRenderer_RenderScreenshot(t *testing.T) { setupBlobstore: func(t *testing.T) BlobStoreClient { blobstore := NewMockBlobStoreClient(t) blobstore.On("PutBlob", mock.Anything, mock.Anything). - Return(&resource.PutBlobResponse{ + Return(&resourcepb.PutBlobResponse{ Uid: "test-uid", }, nil) return blobstore @@ -257,7 +257,7 @@ func TestScreenshotRenderer_RenderScreenshot(t *testing.T) { setupBlobstore: func(t *testing.T) BlobStoreClient { blobstore := NewMockBlobStoreClient(t) blobstore.On("PutBlob", mock.Anything, mock.Anything). - Return(&resource.PutBlobResponse{ + Return(&resourcepb.PutBlobResponse{ Uid: "test-uid", }, nil) return blobstore diff --git a/pkg/registry/apis/provisioning/webhooks/render.go b/pkg/registry/apis/provisioning/webhooks/render.go index d0863a7d77e..06a19923a8c 100644 --- a/pkg/registry/apis/provisioning/webhooks/render.go +++ b/pkg/registry/apis/provisioning/webhooks/render.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" provisioningapis "github.com/grafana/grafana/pkg/registry/apis/provisioning" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type renderConnector struct { @@ -132,8 +133,8 @@ func (c *renderConnector) Connect( return } - rsp, err := c.unified.GetBlob(ctx, &resource.GetBlobRequest{ - Resource: &resource.ResourceKey{ + rsp, err := c.unified.GetBlob(ctx, &resourcepb.GetBlobRequest{ + Resource: &resourcepb.ResourceKey{ Namespace: namespace, Group: provisioning.GROUP, Resource: provisioning.RepositoryResourceInfo.GroupResource().Resource, diff --git a/pkg/services/apiserver/client/client.go b/pkg/services/apiserver/client/client.go index d4d9ca9a255..8aa75c22416 100644 --- a/pkg/services/apiserver/client/client.go +++ b/pkg/services/apiserver/client/client.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type K8sHandler interface { @@ -29,8 +30,8 @@ type K8sHandler interface { Delete(ctx context.Context, name string, orgID int64, options v1.DeleteOptions) error DeleteCollection(ctx context.Context, orgID int64) error List(ctx context.Context, orgID int64, options v1.ListOptions) (*unstructured.UnstructuredList, error) - Search(ctx context.Context, orgID int64, in *resource.ResourceSearchRequest) (*resource.ResourceSearchResponse, error) - GetStats(ctx context.Context, orgID int64) (*resource.ResourceStatsResponse, error) + Search(ctx context.Context, orgID int64, in *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) + GetStats(ctx context.Context, orgID int64) (*resourcepb.ResourceStatsResponse, error) GetUsersFromMeta(ctx context.Context, userMeta []string) (map[string]*user.User, error) } @@ -40,7 +41,7 @@ type k8sHandler struct { namespacer request.NamespaceMapper gvr schema.GroupVersionResource restConfig func(context.Context) (*rest.Config, error) - searcher resource.ResourceIndexClient + searcher resourcepb.ResourceIndexClient userService user.Service } @@ -116,14 +117,14 @@ func (h *k8sHandler) List(ctx context.Context, orgID int64, options v1.ListOptio return client.List(ctx, options) } -func (h *k8sHandler) Search(ctx context.Context, orgID int64, in *resource.ResourceSearchRequest) (*resource.ResourceSearchResponse, error) { +func (h *k8sHandler) Search(ctx context.Context, orgID int64, in *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { // goes directly through grpc, so doesn't need the new context if in.Options == nil { - in.Options = &resource.ListOptions{} + in.Options = &resourcepb.ListOptions{} } if in.Options.Key == nil { - in.Options.Key = &resource.ResourceKey{ + in.Options.Key = &resourcepb.ResourceKey{ Namespace: h.GetNamespace(orgID), Group: h.gvr.Group, Resource: h.gvr.Resource, @@ -133,9 +134,9 @@ func (h *k8sHandler) Search(ctx context.Context, orgID int64, in *resource.Resou return h.searcher.Search(ctx, in) } -func (h *k8sHandler) GetStats(ctx context.Context, orgID int64) (*resource.ResourceStatsResponse, error) { +func (h *k8sHandler) GetStats(ctx context.Context, orgID int64) (*resourcepb.ResourceStatsResponse, error) { // goes directly through grpc, so doesn't need the new context - return h.searcher.GetStats(ctx, &resource.ResourceStatsRequest{ + return h.searcher.GetStats(ctx, &resourcepb.ResourceStatsRequest{ Namespace: h.GetNamespace(orgID), Kinds: []string{ h.gvr.Group + "/" + h.gvr.Resource, diff --git a/pkg/services/apiserver/client/client_mock.go b/pkg/services/apiserver/client/client_mock.go index 2cc34b89d95..0d32d8de1b9 100644 --- a/pkg/services/apiserver/client/client_mock.go +++ b/pkg/services/apiserver/client/client_mock.go @@ -6,7 +6,8 @@ import ( "github.com/stretchr/testify/mock" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/rest" @@ -66,20 +67,20 @@ func (m *MockK8sHandler) List(ctx context.Context, orgID int64, options v1.ListO return args.Get(0).(*unstructured.UnstructuredList), args.Error(1) } -func (m *MockK8sHandler) Search(ctx context.Context, orgID int64, in *resource.ResourceSearchRequest) (*resource.ResourceSearchResponse, error) { +func (m *MockK8sHandler) Search(ctx context.Context, orgID int64, in *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { args := m.Called(ctx, orgID, in) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*resource.ResourceSearchResponse), args.Error(1) + return args.Get(0).(*resourcepb.ResourceSearchResponse), args.Error(1) } -func (m *MockK8sHandler) GetStats(ctx context.Context, orgID int64) (*resource.ResourceStatsResponse, error) { +func (m *MockK8sHandler) GetStats(ctx context.Context, orgID int64) (*resourcepb.ResourceStatsResponse, error) { args := m.Called(ctx, orgID) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*resource.ResourceStatsResponse), args.Error(1) + return args.Get(0).(*resourcepb.ResourceStatsResponse), args.Error(1) } func (m *MockK8sHandler) GetUsersFromMeta(ctx context.Context, usersMeta []string) (map[string]*user.User, error) { diff --git a/pkg/services/dashboards/dashboard.go b/pkg/services/dashboards/dashboard.go index c0cc9cf2d23..cbea5a09ada 100644 --- a/pkg/services/dashboards/dashboard.go +++ b/pkg/services/dashboards/dashboard.go @@ -4,13 +4,15 @@ import ( "context" authtypes "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/search/model" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) @@ -47,7 +49,7 @@ type PermissionsRegistrationService interface { RegisterDashboardPermissions(service accesscontrol.DashboardPermissionsService) // Used to apply default permissions in unified storage after create - SetDefaultPermissionsAfterCreate(ctx context.Context, key *resource.ResourceKey, id authtypes.AuthInfo, obj utils.GrafanaMetaAccessor) error + SetDefaultPermissionsAfterCreate(ctx context.Context, key *resourcepb.ResourceKey, id authtypes.AuthInfo, obj utils.GrafanaMetaAccessor) error } // PluginService is a service for operating on plugin dashboards. diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index cb0e8352b2e..116521bc414 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -25,6 +25,7 @@ import ( claims "github.com/grafana/authlib/types" "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard" dashboardv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" @@ -60,6 +61,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util/retryer" ) @@ -1204,7 +1206,7 @@ func (dr *DashboardServiceImpl) GetDashboardsByPluginID(ctx context.Context, que } // (sometimes) called by the k8s storage engine after creating an object -func (dr *DashboardServiceImpl) SetDefaultPermissionsAfterCreate(ctx context.Context, key *resource.ResourceKey, id claims.AuthInfo, obj utils.GrafanaMetaAccessor) error { +func (dr *DashboardServiceImpl) SetDefaultPermissionsAfterCreate(ctx context.Context, key *resourcepb.ResourceKey, id claims.AuthInfo, obj utils.GrafanaMetaAccessor) error { ctx, span := tracer.Start(ctx, "dashboards.service.SetDefaultPermissionsAfterCreate") defer span.End() @@ -1714,8 +1716,8 @@ func makeQueryResult(query *dashboards.FindPersistedDashboardsQuery, res []dashb func (dr *DashboardServiceImpl) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) ([]*dashboards.DashboardTagCloudItem, error) { if dr.features.IsEnabled(ctx, featuremgmt.FlagKubernetesClientDashboardsFolders) { - res, err := dr.k8sclient.Search(ctx, query.OrgID, &resource.ResourceSearchRequest{ - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + res, err := dr.k8sclient.Search(ctx, query.OrgID, &resourcepb.ResourceSearchRequest{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "tags": { Field: "tags", Limit: 100000, @@ -1959,15 +1961,15 @@ func (dr *DashboardServiceImpl) listDashboardsThroughK8s(ctx context.Context, or } func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) (dashboardv0.SearchResults, error) { - request := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{}, + request := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{}, }, Limit: 100000} if len(query.DashboardUIDs) > 0 { - request.Options.Fields = []*resource.Requirement{{ + request.Options.Fields = []*resourcepb.Requirement{{ Key: resource.SEARCH_FIELD_NAME, Operator: string(selection.In), Values: query.DashboardUIDs, @@ -1978,7 +1980,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex values[i] = strconv.FormatInt(id, 10) } - request.Options.Labels = append(request.Options.Labels, &resource.Requirement{ + request.Options.Labels = append(request.Options.Labels, &resourcepb.Requirement{ Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck Operator: string(selection.In), Values: values, @@ -1996,7 +1998,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex } } - req := []*resource.Requirement{{ + req := []*resourcepb.Requirement{{ Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), Values: query.FolderUIDs, @@ -2008,7 +2010,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex values[i] = strconv.FormatInt(id, 10) } - request.Options.Labels = append(request.Options.Labels, &resource.Requirement{ + request.Options.Labels = append(request.Options.Labels, &resourcepb.Requirement{ Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck Operator: string(selection.In), Values: values, @@ -2016,7 +2018,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex } if query.ManagedBy != "" { - request.Options.Fields = append(request.Options.Fields, &resource.Requirement{ + request.Options.Fields = append(request.Options.Fields, &resourcepb.Requirement{ Key: resource.SEARCH_FIELD_MANAGER_KIND, Operator: string(selection.Equals), Values: []string{string(query.ManagedBy)}, @@ -2024,7 +2026,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex } if query.ManagerIdentity != "" { - request.Options.Fields = append(request.Options.Fields, &resource.Requirement{ + request.Options.Fields = append(request.Options.Fields, &resourcepb.Requirement{ Key: resource.SEARCH_FIELD_MANAGER_ID, Operator: string(selection.In), Values: []string{query.ManagerIdentity}, @@ -2032,14 +2034,14 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex } if len(query.ManagerIdentityNotIn) > 0 { - request.Options.Fields = append(request.Options.Fields, &resource.Requirement{ + request.Options.Fields = append(request.Options.Fields, &resourcepb.Requirement{ Key: resource.SEARCH_FIELD_MANAGER_ID, Operator: string(selection.NotIn), Values: query.ManagerIdentityNotIn, }) } if query.SourcePath != "" { - request.Options.Fields = append(request.Options.Fields, &resource.Requirement{ + request.Options.Fields = append(request.Options.Fields, &resourcepb.Requirement{ Key: resource.SEARCH_FIELD_SOURCE_PATH, Operator: string(selection.In), Values: []string{query.SourcePath}, @@ -2054,7 +2056,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex } if len(query.Tags) > 0 { - req := []*resource.Requirement{{ + req := []*resourcepb.Requirement{{ Key: resource.SEARCH_FIELD_TAGS, Operator: string(selection.In), Values: query.Tags, @@ -2084,7 +2086,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex namespace := dr.k8sclient.GetNamespace(query.OrgId) var err error - var federate *resource.ResourceKey + var federate *resourcepb.ResourceKey switch query.Type { case "": // When no type specified, search for dashboards @@ -2106,7 +2108,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex } if federate != nil { - request.Federated = []*resource.ResourceKey{federate} + request.Federated = []*resourcepb.ResourceKey{federate} } if query.Sort.Name != "" { @@ -2114,7 +2116,7 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex if err != nil { return dashboardv0.SearchResults{}, err } - request.SortBy = append(request.SortBy, &resource.ResourceSearchRequest_Sort{Field: sortName, Desc: isDesc}) + request.SortBy = append(request.SortBy, &resourcepb.ResourceSearchRequest_Sort{Field: sortName, Desc: isDesc}) } res, err := dr.k8sclient.Search(ctx, query.OrgId, request) diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index ce9d97e650e..6fda3537cf6 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -45,6 +45,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestDashboardService(t *testing.T) { @@ -355,21 +356,21 @@ func TestGetDashboard(t *testing.T) { } k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&dashboardUnstructured, nil).Once() k8sCliMock.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{}, nil) - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -567,36 +568,36 @@ func TestGetProvisionedDashboardData(t *testing.T) { }, nil).Once() repo := "test" k8sCliMock.On("Search", mock.Anything, int64(1), - mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { // make sure the kind is added to the query return req.Options.Fields[0].Values[0] == string(utils.ManagerKindClassicFP) && // nolint:staticcheck req.Options.Fields[1].Values[0] == repo - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{}, - Rows: []*resource.ResourceTableRow{}, + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{}, + Rows: []*resourcepb.ResourceTableRow{}, }, TotalHits: 0, }, nil).Once() - k8sCliMock.On("Search", mock.Anything, int64(2), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(2), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { // make sure the kind is added to the query return req.Options.Fields[0].Values[0] == string(utils.ManagerKindClassicFP) && // nolint:staticcheck req.Options.Fields[1].Values[0] == repo - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -670,28 +671,28 @@ func TestGetProvisionedDashboardDataByDashboardID(t *testing.T) { "title": "testing slugify", }, }}, nil) - k8sCliMock.On("Search", mock.Anything, int64(1), mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{}, - Rows: []*resource.ResourceTableRow{}, + k8sCliMock.On("Search", mock.Anything, int64(1), mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{}, + Rows: []*resourcepb.ResourceTableRow{}, }, TotalHits: 0, }, nil) - k8sCliMock.On("Search", mock.Anything, int64(2), mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, int64(2), mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -764,21 +765,21 @@ func TestGetProvisionedDashboardDataByDashboardUID(t *testing.T) { "title": "testing slugify", }, }}, nil).Once() - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -873,24 +874,24 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { }, "spec": map[string]any{}, }}, nil).Once() - k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { // nolint:staticcheck return req.Options.Fields[0].Key == "manager.kind" && req.Options.Fields[0].Values[0] == string(utils.ManagerKindClassicFP) && req.Options.Fields[1].Key == "manager.id" && req.Options.Fields[1].Values[0] == "test" && req.Options.Fields[1].Operator == "notin" - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -904,24 +905,24 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { TotalHits: 1, }, nil).Once() - k8sCliMock.On("Search", mock.Anything, int64(2), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(2), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { // nolint:staticcheck return req.Options.Fields[0].Key == "manager.kind" && req.Options.Fields[0].Values[0] == string(utils.ManagerKindClassicFP) && req.Options.Fields[1].Key == "manager.id" && req.Options.Fields[1].Values[0] == "test" && req.Options.Fields[1].Operator == "notin" - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Resource: "dashboard", }, @@ -931,7 +932,7 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid3", Resource: "dashboard", }, @@ -946,8 +947,8 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { }, nil).Once() // mock call to waitForSearchQuery() - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{}, + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{}, TotalHits: 0, }, nil).Twice() @@ -998,25 +999,25 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { }, }, }, nil).Once() - k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { // make sure the kind is added to the query return req.Options.Fields[0].Values[0] == string(utils.ManagerKindClassicFP) && // nolint:staticcheck req.Options.Fields[1].Values[0] == repo - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -1035,14 +1036,14 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { // Mock WaitForSearchQuery() // First call returns 1 hit - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{}, + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{}, TotalHits: 1, }, nil).Once() // Second call returns 0 hits - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{}, + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{}, TotalHits: 0, }, nil).Once() @@ -1068,12 +1069,12 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) { // Call to searchProvisionedDashboardsThroughK8s() k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { // make sure the kind is added to the query return req.Options.Fields[0].Values[0] == string(utils.ManagerKindClassicFP) && // nolint:staticcheck req.Options.Fields[1].Values[0] == repo - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{}, + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{}, TotalHits: 0, }, nil) @@ -1140,21 +1141,21 @@ func TestUnprovisionDashboard(t *testing.T) { }).Return(dashWithoutAnnotations, nil) k8sCliMock.On("GetNamespace", mock.Anything).Return("default") k8sCliMock.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{}, nil) - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -1208,25 +1209,25 @@ func TestGetDashboardsByPluginID(t *testing.T) { k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") k8sCliMock.On("Get", mock.Anything, "uid", mock.Anything, mock.Anything, mock.Anything).Return(uidUnstructured, nil) k8sCliMock.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{}, nil) - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { return ( // gofmt comment helper req.Options.Fields[0].Key == "manager.kind" && req.Options.Fields[0].Values[0] == string(utils.ManagerKindPlugin) && req.Options.Fields[1].Key == "manager.id" && req.Options.Fields[1].Values[0] == "testing") - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -1496,21 +1497,21 @@ func TestDeleteDashboard(t *testing.T) { ctx, k8sCliMock := setupK8sDashboardTests(service) k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") k8sCliMock.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -1648,25 +1649,25 @@ func TestSearchDashboards(t *testing.T) { } fakeFolders.ExpectedHitList = expectedFolders k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "tags", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid1", Resource: "dashboard", }, @@ -1677,7 +1678,7 @@ func TestSearchDashboards(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Resource: "dashboard", }, @@ -1702,7 +1703,7 @@ func TestSearchDashboards(t *testing.T) { ctx, k8sCliMock := setupK8sDashboardTests(service) service.features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders, featuremgmt.FlagKubernetesClientDashboardsFolders) k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { if len(req.Options.Fields) == 0 { return false } @@ -1713,25 +1714,25 @@ func TestSearchDashboards(t *testing.T) { } } return false - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "tags", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "shared-uid1", Resource: "dashboard", }, @@ -1745,7 +1746,7 @@ func TestSearchDashboards(t *testing.T) { }, TotalHits: 1, }, nil).Once() - k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, int64(1), mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { if len(req.Options.Fields) == 0 { return false } @@ -1755,25 +1756,25 @@ func TestSearchDashboards(t *testing.T) { } } return false - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "tags", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "shared-uid1", Resource: "dashboard", }, @@ -1878,21 +1879,21 @@ func TestGetDashboards(t *testing.T) { k8sCliMock.On("Get", mock.Anything, "uid1", mock.Anything, mock.Anything, mock.Anything).Return(uid1Unstructured, nil) k8sCliMock.On("Get", mock.Anything, "uid2", mock.Anything, mock.Anything, mock.Anything).Return(uid2Unstructured, nil) k8sCliMock.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{}, nil) - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid1", Resource: "dashboard", }, @@ -1902,7 +1903,7 @@ func TestGetDashboards(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Resource: "dashboard", }, @@ -1959,21 +1960,21 @@ func TestGetDashboardUIDByID(t *testing.T) { t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) { ctx, k8sCliMock := setupK8sDashboardTests(service) k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid1", Resource: "dashboard", }, @@ -2078,10 +2079,10 @@ func TestGetDashboardTags(t *testing.T) { t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) { ctx, k8sCliMock := setupK8sDashboardTests(service) - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Facet: map[string]*resource.ResourceSearchResponse_Facet{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Facet: map[string]*resourcepb.ResourceSearchResponse_Facet{ "tags": { - Terms: []*resource.ResourceSearchResponse_TermFacet{ + Terms: []*resourcepb.ResourceSearchResponse_TermFacet{ { Term: "tag1", Count: 1, @@ -2119,15 +2120,15 @@ func TestQuotaCount(t *testing.T) { }, } - countOrg1 := resource.ResourceStatsResponse{ - Stats: []*resource.ResourceStatsResponse_Stats{ + countOrg1 := resourcepb.ResourceStatsResponse{ + Stats: []*resourcepb.ResourceStatsResponse_Stats{ { Count: 1, }, }, } - countOrg2 := resource.ResourceStatsResponse{ - Stats: []*resource.ResourceStatsResponse_Stats{ + countOrg2 := resourcepb.ResourceStatsResponse{ + Stats: []*resourcepb.ResourceStatsResponse_Stats{ { Count: 2, }, @@ -2176,8 +2177,8 @@ func TestCountDashboardsInOrg(t *testing.T) { cfg: setting.NewCfg(), dashboardStore: &fakeStore, } - count := resource.ResourceStatsResponse{ - Stats: []*resource.ResourceStatsResponse_Stats{ + count := resourcepb.ResourceStatsResponse{ + Stats: []*resourcepb.ResourceStatsResponse_Stats{ { Count: 3, }, @@ -2208,21 +2209,21 @@ func TestCountInFolders(t *testing.T) { cfg: setting.NewCfg(), dashboardStore: &fakeStore, } - dashs := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + dashs := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -2232,7 +2233,7 @@ func TestCountInFolders(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Resource: "dashboard", }, @@ -2273,26 +2274,26 @@ func TestSearchDashboardsThroughK8sRaw(t *testing.T) { Sort: sort.SortAlphaAsc, } k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.MatchedBy(func(req *resource.ResourceSearchRequest) bool { + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.MatchedBy(func(req *resourcepb.ResourceSearchRequest) bool { return len(req.SortBy) == 1 && // should be converted to "title" due to ParseSortName req.SortBy[0].Field == "title" && !req.SortBy[0].Desc - })).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + })).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -2347,21 +2348,21 @@ func TestSearchProvisionedDashboardsThroughK8sRaw(t *testing.T) { "spec": map[string]any{}, }} k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -2371,7 +2372,7 @@ func TestSearchProvisionedDashboardsThroughK8sRaw(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Resource: "dashboard", }, @@ -2514,7 +2515,7 @@ func TestSetDefaultPermissionsAfterCreate(t *testing.T) { service.RegisterDashboardPermissions(permService) // Create test object - key := &resource.ResourceKey{Group: "dashboard.grafana.app", Resource: "dashboards", Name: "test", Namespace: "default"} + key := &resourcepb.ResourceKey{Group: "dashboard.grafana.app", Resource: "dashboards", Name: "test", Namespace: "default"} obj := &dashboardv0.Dashboard{ TypeMeta: metav1.TypeMeta{ APIVersion: "dashboard.grafana.app/v0alpha1", diff --git a/pkg/services/dashboards/service/search/search.go b/pkg/services/dashboards/service/search/search.go index ed53dc73407..18c00ccacef 100644 --- a/pkg/services/dashboards/service/search/search.go +++ b/pkg/services/dashboards/service/search/search.go @@ -6,6 +6,7 @@ import ( "fmt" common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" "github.com/grafana/grafana/pkg/storage/unified/resource" @@ -37,7 +38,7 @@ var ( } ) -func ParseResults(result *resource.ResourceSearchResponse, offset int64) (v0alpha1.SearchResults, error) { +func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0alpha1.SearchResults, error) { if result == nil { return v0alpha1.SearchResults{}, nil } else if result.Error != nil { diff --git a/pkg/services/dashboards/service/search/search_test.go b/pkg/services/dashboards/service/search/search_test.go index 405eaf240a6..69b76de472e 100644 --- a/pkg/services/dashboards/service/search/search_test.go +++ b/pkg/services/dashboards/service/search/search_test.go @@ -3,37 +3,39 @@ package dashboardsearch import ( "testing" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" - "github.com/stretchr/testify/require" ) // regression test - parsing int32 values from search results was causing a panic func TestParseResults(t *testing.T) { t.Run("should parse results", func(t *testing.T) { - resSearchResp := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + resSearchResp := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: search.DASHBOARD_ERRORS_LAST_1_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, { Name: search.DASHBOARD_LINK_COUNT, - Type: resource.ResourceTableColumnDefinition_INT32, + Type: resourcepb.ResourceTableColumnDefinition_INT32, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, @@ -54,33 +56,33 @@ func TestParseResults(t *testing.T) { }) t.Run("should return error when trying to parse results with mismatch length between Columns and row Cells", func(t *testing.T) { - resSearchResp := &resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + resSearchResp := &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: search.DASHBOARD_ERRORS_LAST_1_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, { Name: search.DASHBOARD_LINK_COUNT, - Type: resource.ResourceTableColumnDefinition_INT32, + Type: resourcepb.ResourceTableColumnDefinition_INT32, }, { Name: resource.SEARCH_FIELD_LEGACY_ID, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "dashboard", }, diff --git a/pkg/services/folder/folderimpl/folder_unifiedstorage.go b/pkg/services/folder/folderimpl/folder_unifiedstorage.go index 09f0605cef1..256daf18825 100644 --- a/pkg/services/folder/folderimpl/folder_unifiedstorage.go +++ b/pkg/services/folder/folderimpl/folder_unifiedstorage.go @@ -30,6 +30,7 @@ import ( "github.com/grafana/grafana/pkg/services/search/model" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/util" ) @@ -175,20 +176,20 @@ func (s *Service) searchFoldersFromApiServer(ctx context.Context, query folder.S query.OrgID = requester.GetOrgID() } - request := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + request := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: s.k8sclient.GetNamespace(query.OrgID), Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, }, - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{}, + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{}, }, Limit: folderSearchLimit} if len(query.UIDs) > 0 { - request.Options.Fields = []*resource.Requirement{{ + request.Options.Fields = []*resourcepb.Requirement{{ Key: resource.SEARCH_FIELD_NAME, Operator: string(selection.In), Values: query.UIDs, @@ -199,7 +200,7 @@ func (s *Service) searchFoldersFromApiServer(ctx context.Context, query folder.S values[i] = strconv.FormatInt(id, 10) } - request.Options.Labels = append(request.Options.Labels, &resource.Requirement{ + request.Options.Labels = append(request.Options.Labels, &resourcepb.Requirement{ Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck Operator: string(selection.In), Values: values, @@ -253,17 +254,17 @@ func (s *Service) getFolderByIDFromApiServer(ctx context.Context, id int64, orgI return &folder.GeneralFolder, nil } - folderkey := &resource.ResourceKey{ + folderkey := &resourcepb.ResourceKey{ Namespace: s.k8sclient.GetNamespace(orgID), Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, } - request := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + request := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: folderkey, - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{ { Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck Operator: string(selection.In), @@ -309,23 +310,23 @@ func (s *Service) getFolderByTitleFromApiServer(ctx context.Context, orgID int64 return nil, dashboards.ErrFolderTitleEmpty } - folderkey := &resource.ResourceKey{ + folderkey := &resourcepb.ResourceKey{ Namespace: s.k8sclient.GetNamespace(orgID), Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, } - request := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + request := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: folderkey, - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{}, + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{}, }, Query: title, Limit: folderSearchLimit} if parentUID != nil { - req := []*resource.Requirement{{ + req := []*resourcepb.Requirement{{ Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), Values: []string{*parentUID}, @@ -670,10 +671,10 @@ func (s *Service) deleteFromApiServer(ctx context.Context, cmd *folder.DeleteFol // We need a list of dashboard uids inside the folder to delete related dashboards & public dashboards - // we cannot use the dashboard service directly due to circular dependencies, so use the search client to get the dashboards - request := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Labels: []*resource.Requirement{}, - Fields: []*resource.Requirement{ + request := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Labels: []*resourcepb.Requirement{}, + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), diff --git a/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go b/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go index cdb42e38ce7..ee6e1928af5 100644 --- a/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go +++ b/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go @@ -42,6 +42,7 @@ import ( "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type rcp struct { @@ -368,7 +369,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { }) t.Run("When deleting folder by uid should not return access denied error - ForceDeleteRules false", func(t *testing.T) { - fakeK8sClient.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{Results: &resource.ResourceTable{}}, nil).Once() + fakeK8sClient.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{Results: &resourcepb.ResourceTable{}}, nil).Once() publicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil) err := folderService.Delete(ctx, &folder.DeleteFolderCommand{ @@ -381,7 +382,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { }) t.Run("When deleting folder by uid, expectedForceDeleteRules as false,should not return access denied error", func(t *testing.T) { - fakeK8sClient.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{Results: &resource.ResourceTable{}}, nil).Once() + fakeK8sClient.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{Results: &resourcepb.ResourceTable{}}, nil).Once() expectedForceDeleteRules := false err := folderService.Delete(ctx, &folder.DeleteFolderCommand{ @@ -394,7 +395,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { }) t.Run("When deleting folder by uid, expectedForceDeleteRules as true, should not return access denied error", func(t *testing.T) { - fakeK8sClient.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{Results: &resource.ResourceTable{}}, nil).Once() + fakeK8sClient.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resourcepb.ResourceSearchResponse{Results: &resourcepb.ResourceTable{}}, nil).Once() expectedForceDeleteRules := true err := folderService.Delete(ctx, &folder.DeleteFolderCommand{ @@ -555,37 +556,37 @@ func TestSearchFoldersFromApiServer(t *testing.T) { fakeK8sClient.On("GetNamespace", mock.Anything, mock.Anything).Return("default") t.Run("Should call search with uids, if provided", func(t *testing.T) { - fakeK8sClient.On("Search", mock.Anything, int64(1), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + fakeK8sClient.On("Search", mock.Anything, int64(1), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, }, - Fields: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_NAME, Operator: string(selection.In), Values: []string{"uid1", "uid2"}, // should only search by uid since it is provided }, }, - Labels: []*resource.Requirement{}, + Labels: []*resourcepb.Requirement{}, }, - Limit: folderSearchLimit}).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Limit: folderSearchLimit}).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid1", Resource: "folder", }, @@ -595,7 +596,7 @@ func TestSearchFoldersFromApiServer(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid2", Resource: "folder", }, @@ -645,15 +646,15 @@ func TestSearchFoldersFromApiServer(t *testing.T) { IDs: []int64{123}, SignedInUser: user, } - fakeK8sClient.On("Search", mock.Anything, int64(1), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + fakeK8sClient.On("Search", mock.Anything, int64(1), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, }, - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{ + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{ { Key: utils.LabelKeyDeprecatedInternalID, Operator: string(selection.In), @@ -661,21 +662,21 @@ func TestSearchFoldersFromApiServer(t *testing.T) { }, }, }, - Limit: folderSearchLimit}).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Limit: folderSearchLimit}).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "foo", Resource: "folder", }, @@ -714,33 +715,33 @@ func TestSearchFoldersFromApiServer(t *testing.T) { Title: "parent title", } service.unifiedStore = fakeFolderStore - fakeK8sClient.On("Search", mock.Anything, int64(1), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + fakeK8sClient.On("Search", mock.Anything, int64(1), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, }, - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{}, + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{}, }, Query: "*test*", Fields: dashboardsearch.IncludeFields, - Limit: folderSearchLimit}).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Limit: folderSearchLimit}).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "folder", }, @@ -798,7 +799,7 @@ func TestGetFoldersFromApiServer(t *testing.T) { user := &user.SignedInUser{OrgID: 1} ctx := identity.WithRequester(context.Background(), user) fakeK8sClient.On("GetNamespace", mock.Anything, mock.Anything).Return("default") - folderkey := &resource.ResourceKey{ + folderkey := &resourcepb.ResourceKey{ Namespace: "default", Group: folderv1.FolderResourceInfo.GroupVersionResource().Group, Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource, @@ -816,29 +817,29 @@ func TestGetFoldersFromApiServer(t *testing.T) { URL: "/dashboards/f/foouid/foo-title", } service.unifiedStore = fakeFolderStore - fakeK8sClient.On("Search", mock.Anything, int64(1), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + fakeK8sClient.On("Search", mock.Anything, int64(1), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: folderkey, - Fields: []*resource.Requirement{}, - Labels: []*resource.Requirement{}, + Fields: []*resourcepb.Requirement{}, + Labels: []*resourcepb.Requirement{}, }, Query: "foo title", Limit: folderSearchLimit}). - Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "uid", Resource: "folder", }, @@ -903,7 +904,7 @@ func TestDeleteFoldersFromApiServer(t *testing.T) { t.Run("Should delete folder", func(t *testing.T) { publicDashboardFakeService.On("DeleteByDashboardUIDs", mock.Anything, int64(1), []string{}).Return(nil).Once() - dashboardK8sclient.On("Search", mock.Anything, int64(1), mock.Anything).Return(&resource.ResourceSearchResponse{Results: &resource.ResourceTable{}}, nil).Once() + dashboardK8sclient.On("Search", mock.Anything, int64(1), mock.Anything).Return(&resourcepb.ResourceSearchResponse{Results: &resourcepb.ResourceTable{}}, nil).Once() err := service.deleteFromApiServer(ctx, &folder.DeleteFolderCommand{ UID: "uid1", OrgID: 1, @@ -918,10 +919,10 @@ func TestDeleteFoldersFromApiServer(t *testing.T) { fakeFolderStore.ExpectedFolders = []*folder.Folder{{UID: "uid2", ID: 2}} dashboardK8sclient.On("Delete", mock.Anything, "test", int64(1), mock.Anything).Return(nil).Once() dashboardK8sclient.On("Delete", mock.Anything, "test2", int64(1), mock.Anything).Return(nil).Once() - dashboardK8sclient.On("Search", mock.Anything, int64(1), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Labels: []*resource.Requirement{}, - Fields: []*resource.Requirement{ + dashboardK8sclient.On("Search", mock.Anything, int64(1), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Labels: []*resourcepb.Requirement{}, + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), @@ -929,21 +930,21 @@ func TestDeleteFoldersFromApiServer(t *testing.T) { }, }, }, - Limit: folderSearchLimit}).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ + Limit: folderSearchLimit}).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "folder", - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "test", Resource: "dashboard", }, @@ -953,7 +954,7 @@ func TestDeleteFoldersFromApiServer(t *testing.T) { }, }, { - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "test2", Resource: "dashboard", }, diff --git a/pkg/services/folder/folderimpl/unifiedstore.go b/pkg/services/folder/folderimpl/unifiedstore.go index 97a8944cbd7..2d2a79cb638 100644 --- a/pkg/services/folder/folderimpl/unifiedstore.go +++ b/pkg/services/folder/folderimpl/unifiedstore.go @@ -11,8 +11,10 @@ import ( "k8s.io/apimachinery/pkg/selection" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/infra/log" @@ -195,9 +197,9 @@ func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetC } } - req := &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Fields: []*resource.Requirement{ + req := &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), @@ -214,7 +216,7 @@ func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetC // only filter the folder UIDs if they are provided in the query if len(q.FolderUIDs) > 0 { - req.Options.Fields = append(req.Options.Fields, &resource.Requirement{ + req.Options.Fields = append(req.Options.Fields, &resourcepb.Requirement{ Key: resource.SEARCH_FIELD_NAME, Operator: string(selection.In), Values: q.FolderUIDs, diff --git a/pkg/services/folder/folderimpl/unifiedstore_test.go b/pkg/services/folder/folderimpl/unifiedstore_test.go index 147c03a04de..82154881a97 100644 --- a/pkg/services/folder/folderimpl/unifiedstore_test.go +++ b/pkg/services/folder/folderimpl/unifiedstore_test.go @@ -6,6 +6,7 @@ import ( "testing" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/apiserver/client" @@ -13,6 +14,8 @@ import ( "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -198,9 +201,9 @@ func TestGetChildren(t *testing.T) { orgID := int64(2) t.Run("should be able to find children folders, and set defaults for pages", func(t *testing.T) { - mockCli.On("Search", mock.Anything, orgID, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Fields: []*resource.Requirement{ + mockCli.On("Search", mock.Anything, orgID, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), @@ -211,18 +214,18 @@ func TestGetChildren(t *testing.T) { Limit: folderSearchLimit, // should default to folderSearchLimit Offset: 0, // should be set as limit * (page - 1) Page: 1, // should be set to 1 by default - }).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ - {Name: "folder", Type: resource.ResourceTableColumnDefinition_STRING}, + }).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ + {Name: "folder", Type: resourcepb.ResourceTableColumnDefinition_STRING}, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{Name: "folder2", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder2", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, { - Key: &resource.ResourceKey{Name: "folder3", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder3", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, }, @@ -257,9 +260,9 @@ func TestGetChildren(t *testing.T) { }) t.Run("should return an error if the folder is not found", func(t *testing.T) { - mockCli.On("Search", mock.Anything, orgID, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Fields: []*resource.Requirement{ + mockCli.On("Search", mock.Anything, orgID, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), @@ -270,18 +273,18 @@ func TestGetChildren(t *testing.T) { Limit: folderSearchLimit, // should default to folderSearchLimit Offset: 0, // should be set as limit * (page - 1) Page: 1, // should be set to 1 by default - }).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ - {Name: "folder", Type: resource.ResourceTableColumnDefinition_STRING}, + }).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ + {Name: "folder", Type: resourcepb.ResourceTableColumnDefinition_STRING}, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{Name: "folder2", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder2", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, { - Key: &resource.ResourceKey{Name: "folder3", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder3", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, }, @@ -298,9 +301,9 @@ func TestGetChildren(t *testing.T) { }) t.Run("pages should be able to be set, general folder should be turned to empty string, and folder uids should be passed in", func(t *testing.T) { - mockCli.On("Search", mock.Anything, orgID, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Fields: []*resource.Requirement{ + mockCli.On("Search", mock.Anything, orgID, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), @@ -316,14 +319,14 @@ func TestGetChildren(t *testing.T) { Limit: 10, Offset: 20, // should be set as limit * (page - 1) Page: 3, - }).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ - {Name: "folder", Type: resource.ResourceTableColumnDefinition_STRING}, + }).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ + {Name: "folder", Type: resourcepb.ResourceTableColumnDefinition_STRING}, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{Name: "folder2", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder2", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, }, @@ -349,14 +352,14 @@ func TestGetChildren(t *testing.T) { }) t.Run("k6 folder should only be returned to service accounts", func(t *testing.T) { - mockCli.On("Search", mock.Anything, orgID, mock.Anything).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ - {Name: "folder", Type: resource.ResourceTableColumnDefinition_STRING}, + mockCli.On("Search", mock.Anything, orgID, mock.Anything).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ + {Name: "folder", Type: resourcepb.ResourceTableColumnDefinition_STRING}, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{Name: accesscontrol.K6FolderUID, Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: accesscontrol.K6FolderUID, Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, }, @@ -391,9 +394,9 @@ func TestGetChildren(t *testing.T) { }) t.Run("should not do get requests for the children if RefOnly is true", func(t *testing.T) { - mockCli.On("Search", mock.Anything, orgID, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Fields: []*resource.Requirement{ + mockCli.On("Search", mock.Anything, orgID, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Fields: []*resourcepb.Requirement{ { Key: resource.SEARCH_FIELD_FOLDER, Operator: string(selection.In), @@ -404,18 +407,18 @@ func TestGetChildren(t *testing.T) { Limit: folderSearchLimit, // should default to folderSearchLimit Offset: 0, // should be set as limit * (page - 1) Page: 1, // should be set to 1 by default - }).Return(&resource.ResourceSearchResponse{ - Results: &resource.ResourceTable{ - Columns: []*resource.ResourceTableColumnDefinition{ - {Name: "folder", Type: resource.ResourceTableColumnDefinition_STRING}, + }).Return(&resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{ + Columns: []*resourcepb.ResourceTableColumnDefinition{ + {Name: "folder", Type: resourcepb.ResourceTableColumnDefinition_STRING}, }, - Rows: []*resource.ResourceTableRow{ + Rows: []*resourcepb.ResourceTableRow{ { - Key: &resource.ResourceKey{Name: "folder2", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder2", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, { - Key: &resource.ResourceKey{Name: "folder3", Resource: "folder"}, + Key: &resourcepb.ResourceKey{Name: "folder3", Resource: "folder"}, Cells: [][]byte{[]byte("folder1")}, }, }, diff --git a/pkg/storage/unified/apistore/fake_large.go b/pkg/storage/unified/apistore/fake_large.go index b92d4bbed12..aa4c0ca12bb 100644 --- a/pkg/storage/unified/apistore/fake_large.go +++ b/pkg/storage/unified/apistore/fake_large.go @@ -7,7 +7,7 @@ import ( dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type LargeObjectSupportFake struct { @@ -28,12 +28,12 @@ func (s *LargeObjectSupportFake) MaxSize() int { return 10 * 1024 * 1024 } -func (s *LargeObjectSupportFake) Deconstruct(ctx context.Context, key *resource.ResourceKey, client resource.BlobStoreClient, obj utils.GrafanaMetaAccessor, raw []byte) error { +func (s *LargeObjectSupportFake) Deconstruct(_ context.Context, _ *resourcepb.ResourceKey, _ resourcepb.BlobStoreClient, _ utils.GrafanaMetaAccessor, _ []byte) error { s.deconstructed = true return nil } -func (s *LargeObjectSupportFake) Reconstruct(ctx context.Context, key *resource.ResourceKey, client resource.BlobStoreClient, obj utils.GrafanaMetaAccessor) error { +func (s *LargeObjectSupportFake) Reconstruct(_ context.Context, _ *resourcepb.ResourceKey, _ resourcepb.BlobStoreClient, _ utils.GrafanaMetaAccessor) error { s.reconstructed = true return nil } diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index 6ac8dbdd091..73afedcde31 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -20,7 +20,7 @@ require ( github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20250422074709-7c8433fbb2c2 github.com/stretchr/testify v1.10.0 gocloud.dev v0.40.0 - google.golang.org/grpc v1.72.0 + google.golang.org/grpc v1.72.1 k8s.io/apimachinery v0.32.3 k8s.io/apiserver v0.32.3 k8s.io/client-go v0.32.3 diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 1b17e3df2ed..6b4e0bcf6d9 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -869,8 +869,7 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/storage/unified/apistore/large.go b/pkg/storage/unified/apistore/large.go index 71e646fdf53..374d0ebf5d4 100644 --- a/pkg/storage/unified/apistore/large.go +++ b/pkg/storage/unified/apistore/large.go @@ -10,7 +10,7 @@ import ( common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type LargeObjectSupport interface { @@ -27,11 +27,11 @@ type LargeObjectSupport interface { // Deconstruct takes a large object, write most of it to blob storage and leave a few metadata bits around to help with list // NOTE: changes to the object must be handled by mutating the input obj - Deconstruct(ctx context.Context, key *resource.ResourceKey, client resource.BlobStoreClient, obj utils.GrafanaMetaAccessor, raw []byte) error + Deconstruct(ctx context.Context, key *resourcepb.ResourceKey, client resourcepb.BlobStoreClient, obj utils.GrafanaMetaAccessor, raw []byte) error // Reconstruct will join the resource+blob back into a complete resource // NOTE: changes to the object must be handled by mutating the input obj - Reconstruct(ctx context.Context, key *resource.ResourceKey, client resource.BlobStoreClient, obj utils.GrafanaMetaAccessor) error + Reconstruct(ctx context.Context, key *resourcepb.ResourceKey, client resourcepb.BlobStoreClient, obj utils.GrafanaMetaAccessor) error } var _ LargeObjectSupport = (*BasicLargeObjectSupport)(nil) @@ -64,7 +64,7 @@ func (s *BasicLargeObjectSupport) MaxSize() int { } // Deconstruct implements LargeObjectSupport. -func (s *BasicLargeObjectSupport) Deconstruct(ctx context.Context, key *resource.ResourceKey, client resource.BlobStoreClient, obj utils.GrafanaMetaAccessor, raw []byte) error { +func (s *BasicLargeObjectSupport) Deconstruct(ctx context.Context, key *resourcepb.ResourceKey, client resourcepb.BlobStoreClient, obj utils.GrafanaMetaAccessor, raw []byte) error { if key.Group != s.TheGroupResource.Group { return fmt.Errorf("requested group mismatch") } @@ -104,7 +104,7 @@ func (s *BasicLargeObjectSupport) Deconstruct(ctx context.Context, key *resource } // Save the blob - info, err := client.PutBlob(ctx, &resource.PutBlobRequest{ + info, err := client.PutBlob(ctx, &resourcepb.PutBlobRequest{ ContentType: "application/json", Value: val, Resource: key, @@ -125,7 +125,7 @@ func (s *BasicLargeObjectSupport) Deconstruct(ctx context.Context, key *resource } // Reconstruct implements LargeObjectSupport. -func (s *BasicLargeObjectSupport) Reconstruct(ctx context.Context, key *resource.ResourceKey, client resource.BlobStoreClient, obj utils.GrafanaMetaAccessor) error { +func (s *BasicLargeObjectSupport) Reconstruct(ctx context.Context, key *resourcepb.ResourceKey, client resourcepb.BlobStoreClient, obj utils.GrafanaMetaAccessor) error { blobInfo := obj.GetBlob() if blobInfo == nil { return fmt.Errorf("the object does not have a blob") @@ -135,8 +135,8 @@ func (s *BasicLargeObjectSupport) Reconstruct(ctx context.Context, key *resource if err != nil { return err } - rsp, err := client.GetBlob(ctx, &resource.GetBlobRequest{ - Resource: &resource.ResourceKey{ + rsp, err := client.GetBlob(ctx, &resourcepb.GetBlobRequest{ + Resource: &resourcepb.ResourceKey{ Group: s.TheGroupResource.Group, Resource: s.TheGroupResource.Resource, Namespace: obj.GetNamespace(), diff --git a/pkg/storage/unified/apistore/managed.go b/pkg/storage/unified/apistore/managed.go index 1bb9e9f5c65..60447f80402 100644 --- a/pkg/storage/unified/apistore/managed.go +++ b/pkg/storage/unified/apistore/managed.go @@ -16,8 +16,9 @@ import ( "k8s.io/client-go/rest" authtypes "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var errResourceIsManagedInRepository = fmt.Errorf("this resource is managed by a repository") @@ -97,7 +98,7 @@ func enforceManagerProperties(auth authtypes.AuthInfo, obj utils.GrafanaMetaAcce func (s *Storage) handleManagedResourceRouting(ctx context.Context, err error, - action resource.WatchEvent_Type, + action resourcepb.WatchEvent_Type, key string, orig runtime.Object, rsp runtime.Object, @@ -137,7 +138,7 @@ func (s *Storage) handleManagedResourceRouting(ctx context.Context, return err } - if action == resource.WatchEvent_DELETED { + if action == resourcepb.WatchEvent_DELETED { // TODO? can we copy orig into rsp without a full get? if err = s.Get(ctx, key, storage.GetOptions{}, rsp); err != nil { // COPY? return err @@ -153,9 +154,9 @@ func (s *Storage) handleManagedResourceRouting(ctx context.Context, var req *rest.Request switch action { - case resource.WatchEvent_ADDED: + case resourcepb.WatchEvent_ADDED: req = client.Post() - case resource.WatchEvent_MODIFIED: + case resourcepb.WatchEvent_MODIFIED: req = client.Put() default: return fmt.Errorf("unsupported provisioning action: %v, %w", action, err) diff --git a/pkg/storage/unified/apistore/permissions.go b/pkg/storage/unified/apistore/permissions.go index bdb6b6e3540..d9850db2511 100644 --- a/pkg/storage/unified/apistore/permissions.go +++ b/pkg/storage/unified/apistore/permissions.go @@ -8,14 +8,15 @@ import ( "k8s.io/apimachinery/pkg/runtime" authtypes "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type permissionCreatorFunc = func(ctx context.Context) error func afterCreatePermissionCreator(ctx context.Context, - key *resource.ResourceKey, + key *resourcepb.ResourceKey, grantPermisions string, obj runtime.Object, setter DefaultPermissionSetter, diff --git a/pkg/storage/unified/apistore/permissions_test.go b/pkg/storage/unified/apistore/permissions_test.go index 1955ce7960b..57e1409cc24 100644 --- a/pkg/storage/unified/apistore/permissions_test.go +++ b/pkg/storage/unified/apistore/permissions_test.go @@ -8,14 +8,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" authtypes "github.com/grafana/authlib/types" + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestAfterCreatePermissionCreator(t *testing.T) { - mockSetter := func(ctx context.Context, key *resource.ResourceKey, auth authtypes.AuthInfo, val utils.GrafanaMetaAccessor) error { + mockSetter := func(ctx context.Context, key *resourcepb.ResourceKey, auth authtypes.AuthInfo, val utils.GrafanaMetaAccessor) error { return nil } @@ -69,7 +70,7 @@ func TestAfterCreatePermissionCreator(t *testing.T) { UserID: 1, }) obj := &v0alpha1.Dashboard{} - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "test", @@ -92,7 +93,7 @@ func TestAfterCreatePermissionCreator(t *testing.T) { UserID: 1, }) obj := &v0alpha1.Dashboard{} - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "test", diff --git a/pkg/storage/unified/apistore/prepare.go b/pkg/storage/unified/apistore/prepare.go index 5f4c697daa4..19ca5aeca9c 100644 --- a/pkg/storage/unified/apistore/prepare.go +++ b/pkg/storage/unified/apistore/prepare.go @@ -17,8 +17,9 @@ import ( "k8s.io/klog/v2" authtypes "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func logN(n, b float64) float64 { @@ -197,7 +198,7 @@ func (s *Storage) handleLargeResources(ctx context.Context, obj utils.GrafanaMet return nil, fmt.Errorf("request object is too big (%s > %s)", formatBytes(size), formatBytes(support.MaxSize())) } - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: s.gr.Group, Resource: s.gr.Resource, Namespace: obj.GetNamespace(), diff --git a/pkg/storage/unified/apistore/store.go b/pkg/storage/unified/apistore/store.go index 050ead22d4d..0e8575742c8 100644 --- a/pkg/storage/unified/apistore/store.go +++ b/pkg/storage/unified/apistore/store.go @@ -32,10 +32,12 @@ import ( "k8s.io/client-go/tools/cache" authtypes "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) const ( @@ -46,7 +48,7 @@ const ( var _ storage.Interface = (*Storage)(nil) -type DefaultPermissionSetter = func(ctx context.Context, key *resource.ResourceKey, id authtypes.AuthInfo, obj utils.GrafanaMetaAccessor) error +type DefaultPermissionSetter = func(ctx context.Context, key *resourcepb.ResourceKey, id authtypes.AuthInfo, obj utils.GrafanaMetaAccessor) error // Optional settings that apply to a single resource type StorageOptions struct { @@ -76,7 +78,7 @@ type Storage struct { indexers *cache.Indexers store resource.ResourceClient - getKey func(string) (*resource.ResourceKey, error) + getKey func(string) (*resourcepb.ResourceKey, error) snowflake *snowflake.Node // used to enforce internal ids configProvider RestConfigProvider // used for provisioning @@ -101,7 +103,7 @@ func NewStorage( config *storagebackend.ConfigForResource, store resource.ResourceClient, keyFunc func(obj runtime.Object) (string, error), - keyParser func(key string) (*resource.ResourceKey, error), + keyParser func(key string) (*resourcepb.ResourceKey, error), newFunc func() runtime.Object, newListFunc func() runtime.Object, getAttrsFunc storage.AttrFunc, @@ -139,7 +141,7 @@ func NewStorage( // The key parsing callback allows us to support the hardcoded paths from upstream tests if s.getKey == nil { - s.getKey = func(key string) (*resource.ResourceKey, error) { + s.getKey = func(key string) (*resourcepb.ResourceKey, error) { k, err := grafanaregistry.ParseKey(key) if err != nil { return nil, err @@ -150,7 +152,7 @@ func NewStorage( if k.Resource == "" { return nil, apierrors.NewInternalError(fmt.Errorf("missing resource in request")) } - return &resource.ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: k.Namespace, Group: k.Group, Resource: k.Resource, @@ -177,10 +179,10 @@ func (s *Storage) convertToObject(data []byte, obj runtime.Object) (runtime.Obje func (s *Storage) Create(ctx context.Context, key string, obj runtime.Object, out runtime.Object, ttl uint64) error { var err error var permissions string - req := &resource.CreateRequest{} + req := &resourcepb.CreateRequest{} req.Value, permissions, err = s.prepareObjectForStorage(ctx, obj) if err != nil { - return s.handleManagedResourceRouting(ctx, err, resource.WatchEvent_ADDED, key, obj, out) + return s.handleManagedResourceRouting(ctx, err, resourcepb.WatchEvent_ADDED, key, obj, out) } req.Key, err = s.getKey(key) @@ -258,7 +260,7 @@ func (s *Storage) Delete( if err != nil { return err } - cmd := &resource.DeleteRequest{Key: k} + cmd := &resourcepb.DeleteRequest{Key: k} if preconditions != nil { if err := preconditions.Check(key, out); err != nil { @@ -287,7 +289,7 @@ func (s *Storage) Delete( return fmt.Errorf("unable to read object %w", err) } if err = checkManagerPropertiesOnDelete(info, meta); err != nil { - return s.handleManagedResourceRouting(ctx, err, resource.WatchEvent_DELETED, key, out, out) + return s.handleManagedResourceRouting(ctx, err, resourcepb.WatchEvent_DELETED, key, out, out) } rsp, err := s.store.Delete(ctx, cmd) @@ -315,7 +317,7 @@ func (s *Storage) Watch(ctx context.Context, key string, opts storage.ListOption return watch.NewEmptyWatch(), nil } - cmd := &resource.WatchRequest{ + cmd := &resourcepb.WatchRequest{ Since: req.ResourceVersion, Options: req.Options, SendInitialEvents: false, @@ -349,7 +351,7 @@ func (s *Storage) Watch(ctx context.Context, key string, opts storage.ListOption // match 'opts.ResourceVersion' according 'opts.ResourceVersionMatch'. func (s *Storage) Get(ctx context.Context, key string, opts storage.GetOptions, objPtr runtime.Object) error { var err error - req := &resource.ReadRequest{} + req := &resourcepb.ReadRequest{} req.Key, err = s.getKey(key) if err != nil { if opts.IgnoreNotFound { @@ -497,7 +499,7 @@ func (s *Storage) GuaranteedUpdate( existingBytes []byte err error ) - req := &resource.UpdateRequest{} + req := &resourcepb.UpdateRequest{} req.Key, err = s.getKey(key) if err != nil { return err @@ -511,7 +513,7 @@ func (s *Storage) GuaranteedUpdate( for attempt := 1; attempt <= MaxUpdateAttempts; attempt = attempt + 1 { // Read the latest value - readResponse, err := s.store.Read(ctx, &resource.ReadRequest{Key: req.Key}) + readResponse, err := s.store.Read(ctx, &resourcepb.ReadRequest{Key: req.Key}) if err != nil { return resource.GetError(resource.AsErrorResult(err)) } @@ -587,7 +589,7 @@ func (s *Storage) GuaranteedUpdate( req.Value, err = s.prepareObjectForUpdate(ctx, updatedObj, existingObj) if err != nil { - return s.handleManagedResourceRouting(ctx, err, resource.WatchEvent_MODIFIED, key, updatedObj, destination) + return s.handleManagedResourceRouting(ctx, err, resourcepb.WatchEvent_MODIFIED, key, updatedObj, destination) } var rv uint64 diff --git a/pkg/storage/unified/apistore/store_test.go b/pkg/storage/unified/apistore/store_test.go index 5321f3f7c95..c1940b547d8 100644 --- a/pkg/storage/unified/apistore/store_test.go +++ b/pkg/storage/unified/apistore/store_test.go @@ -29,10 +29,11 @@ import ( "k8s.io/apiserver/pkg/storage/storagebackend" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" storagetesting "github.com/grafana/grafana/pkg/apiserver/storage/testing" "github.com/grafana/grafana/pkg/storage/unified/apistore" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func init() { @@ -160,17 +161,17 @@ func TestDeleteWithSuggestionAndConflict(t *testing.T) { } type resourceClientMock struct { - resource.ResourceStoreClient - resource.ResourceIndexClient - resource.ManagedObjectIndexClient - resource.BulkStoreClient - resource.BlobStoreClient - resource.DiagnosticsClient + resourcepb.ResourceStoreClient + resourcepb.ResourceIndexClient + resourcepb.ManagedObjectIndexClient + resourcepb.BulkStoreClient + resourcepb.BlobStoreClient + resourcepb.DiagnosticsClient } // always return GRPC Unauthenticated code -func (r resourceClientMock) List(ctx context.Context, in *resource.ListRequest, opts ...grpc.CallOption) (*resource.ListResponse, error) { - return &resource.ListResponse{}, status.Error(codes.Unauthenticated, "missing token") +func (r resourceClientMock) List(ctx context.Context, in *resourcepb.ListRequest, opts ...grpc.CallOption) (*resourcepb.ListResponse, error) { + return &resourcepb.ListResponse{}, status.Error(codes.Unauthenticated, "missing token") } func TestGRPCtoHTTPStatusMapping(t *testing.T) { diff --git a/pkg/storage/unified/apistore/stream.go b/pkg/storage/unified/apistore/stream.go index 4ef79e9d99e..880b14b9fc5 100644 --- a/pkg/storage/unified/apistore/stream.go +++ b/pkg/storage/unified/apistore/stream.go @@ -15,11 +15,11 @@ import ( "k8s.io/klog/v2" "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type streamDecoder struct { - client resource.ResourceStore_WatchClient + client resourcepb.ResourceStore_WatchClient newFunc func() runtime.Object predicate storage.SelectionPredicate codec runtime.Codec @@ -27,7 +27,7 @@ type streamDecoder struct { done sync.WaitGroup } -func newStreamDecoder(client resource.ResourceStore_WatchClient, newFunc func() runtime.Object, predicate storage.SelectionPredicate, codec runtime.Codec, cancelWatch context.CancelFunc) *streamDecoder { +func newStreamDecoder(client resourcepb.ResourceStore_WatchClient, newFunc func() runtime.Object, predicate storage.SelectionPredicate, codec runtime.Codec, cancelWatch context.CancelFunc) *streamDecoder { return &streamDecoder{ client: client, newFunc: newFunc, @@ -36,7 +36,7 @@ func newStreamDecoder(client resource.ResourceStore_WatchClient, newFunc func() cancelWatch: cancelWatch, } } -func (d *streamDecoder) toObject(w *resource.WatchEvent_Resource) (runtime.Object, error) { +func (d *streamDecoder) toObject(w *resourcepb.WatchEvent_Resource) (runtime.Object, error) { var obj runtime.Object var err error obj, _, err = d.codec.Decode(w.Value, nil, d.newFunc()) @@ -56,7 +56,7 @@ func (d *streamDecoder) Decode() (action watch.EventType, object runtime.Object, defer d.done.Done() decode: for { - var evt *resource.WatchEvent + var evt *resourcepb.WatchEvent var err error select { case <-d.client.Context().Done(): @@ -79,7 +79,7 @@ decode: } // Error event - if evt.Type == resource.WatchEvent_ERROR { + if evt.Type == resourcepb.WatchEvent_ERROR { err = fmt.Errorf("stream error") klog.Errorf("client: error receiving result: %s", err) return watch.Error, nil, err @@ -90,7 +90,7 @@ decode: continue decode } - if evt.Type == resource.WatchEvent_BOOKMARK { + if evt.Type == resourcepb.WatchEvent_BOOKMARK { obj := d.newFunc() // here k8s expects an empty object with just resource version and k8s.io/initial-events-end annotation @@ -113,7 +113,7 @@ decode: var watchAction watch.EventType switch evt.Type { - case resource.WatchEvent_ADDED: + case resourcepb.WatchEvent_ADDED: // apply any predicates not handled in storage matches, err := d.predicate.Matches(obj) if err != nil { @@ -125,7 +125,7 @@ decode: } watchAction = watch.Added - case resource.WatchEvent_MODIFIED: + case resourcepb.WatchEvent_MODIFIED: watchAction = watch.Modified // apply any predicates not handled in storage @@ -175,7 +175,7 @@ decode: // if the object didn't previously match, send an Added event watchAction = watch.Added } - case resource.WatchEvent_DELETED: + case resourcepb.WatchEvent_DELETED: watchAction = watch.Deleted // if we have a previous object, return that in the deleted event diff --git a/pkg/storage/unified/apistore/util.go b/pkg/storage/unified/apistore/util.go index c8e5b49f247..6e8bebf0b28 100644 --- a/pkg/storage/unified/apistore/util.go +++ b/pkg/storage/unified/apistore/util.go @@ -15,15 +15,14 @@ import ( "k8s.io/apiserver/pkg/storage" "github.com/grafana/grafana/pkg/apimachinery/utils" - - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) -func toListRequest(k *resource.ResourceKey, opts storage.ListOptions) (*resource.ListRequest, storage.SelectionPredicate, error) { +func toListRequest(k *resourcepb.ResourceKey, opts storage.ListOptions) (*resourcepb.ListRequest, storage.SelectionPredicate, error) { predicate := opts.Predicate - req := &resource.ListRequest{ + req := &resourcepb.ListRequest{ Limit: opts.Predicate.Limit, - Options: &resource.ListOptions{ + Options: &resourcepb.ListOptions{ Key: k, }, NextPageToken: predicate.Continue, @@ -39,11 +38,11 @@ func toListRequest(k *resource.ResourceKey, opts storage.ListOptions) (*resource switch opts.ResourceVersionMatch { case "": - req.VersionMatchV2 = resource.ResourceVersionMatchV2_Unset + req.VersionMatchV2 = resourcepb.ResourceVersionMatchV2_Unset case metav1.ResourceVersionMatchNotOlderThan: - req.VersionMatchV2 = resource.ResourceVersionMatchV2_NotOlderThan + req.VersionMatchV2 = resourcepb.ResourceVersionMatchV2_NotOlderThan case metav1.ResourceVersionMatchExact: - req.VersionMatchV2 = resource.ResourceVersionMatchV2_Exact + req.VersionMatchV2 = resourcepb.ResourceVersionMatchV2_Exact default: return nil, predicate, apierrors.NewBadRequest( fmt.Sprintf("unsupported version match: %v", opts.ResourceVersionMatch), @@ -85,12 +84,12 @@ func toListRequest(k *resource.ResourceKey, opts storage.ListOptions) (*resource switch v { case utils.LabelKeyGetTrash: - req.Source = resource.ListRequest_TRASH + req.Source = resourcepb.ListRequest_TRASH if vals[0] != "true" { return nil, predicate, apierrors.NewBadRequest("expecting true for: " + v) } case utils.LabelKeyGetHistory: - req.Source = resource.ListRequest_HISTORY + req.Source = resourcepb.ListRequest_HISTORY req.Options.Key.Name = vals[0] } @@ -99,7 +98,7 @@ func toListRequest(k *resource.ResourceKey, opts storage.ListOptions) (*resource return req, storage.Everything, nil } - req.Options.Labels = append(req.Options.Labels, &resource.Requirement{ + req.Options.Labels = append(req.Options.Labels, &resourcepb.Requirement{ Key: v, Operator: string(r.Operator()), Values: r.Values().List(), @@ -110,7 +109,7 @@ func toListRequest(k *resource.ResourceKey, opts storage.ListOptions) (*resource if opts.Predicate.Field != nil && !opts.Predicate.Field.Empty() { requirements := opts.Predicate.Field.Requirements() for _, r := range requirements { - requirement := &resource.Requirement{Key: r.Field, Operator: string(r.Operator)} + requirement := &resourcepb.Requirement{Key: r.Field, Operator: string(r.Operator)} if r.Value != "" { requirement.Values = append(requirement.Values, r.Value) } diff --git a/pkg/storage/unified/apistore/util_test.go b/pkg/storage/unified/apistore/util_test.go index 7c0b7f5b036..222dc1cab69 100644 --- a/pkg/storage/unified/apistore/util_test.go +++ b/pkg/storage/unified/apistore/util_test.go @@ -11,30 +11,30 @@ import ( "k8s.io/apiserver/pkg/storage" "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestToListRequest(t *testing.T) { tests := []struct { name string - key *resource.ResourceKey + key *resourcepb.ResourceKey opts storage.ListOptions - want *resource.ListRequest + want *resourcepb.ListRequest wantPredicate storage.SelectionPredicate wantErr error }{ { name: "basic list request", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", }, opts: storage.ListOptions{}, - want: &resource.ListRequest{ + want: &resourcepb.ListRequest{ VersionMatchV2: 1, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -46,7 +46,7 @@ func TestToListRequest(t *testing.T) { }, { name: "with resource version", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -54,11 +54,11 @@ func TestToListRequest(t *testing.T) { opts: storage.ListOptions{ ResourceVersion: "123", }, - want: &resource.ListRequest{ + want: &resourcepb.ListRequest{ VersionMatchV2: 1, ResourceVersion: 123, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -70,7 +70,7 @@ func TestToListRequest(t *testing.T) { }, { name: "invalid resource version", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -84,7 +84,7 @@ func TestToListRequest(t *testing.T) { }, { name: "with label selector", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -94,15 +94,15 @@ func TestToListRequest(t *testing.T) { Label: labels.SelectorFromSet(labels.Set{"key": "value"}), }, }, - want: &resource.ListRequest{ + want: &resourcepb.ListRequest{ VersionMatchV2: 1, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", }, - Labels: []*resource.Requirement{ + Labels: []*resourcepb.Requirement{ { Key: "key", Operator: string(selection.Equals), @@ -118,7 +118,7 @@ func TestToListRequest(t *testing.T) { }, { name: "with trash label", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -128,13 +128,13 @@ func TestToListRequest(t *testing.T) { Label: labels.SelectorFromSet(labels.Set{utils.LabelKeyGetTrash: "true"}), }, }, - want: &resource.ListRequest{ + want: &resourcepb.ListRequest{ VersionMatchV2: 1, - Source: resource.ListRequest_TRASH, - Options: &resource.ListOptions{ + Source: resourcepb.ListRequest_TRASH, + Options: &resourcepb.ListOptions{ Labels: nil, Fields: nil, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -146,7 +146,7 @@ func TestToListRequest(t *testing.T) { }, { name: "with history label", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -156,13 +156,13 @@ func TestToListRequest(t *testing.T) { Label: labels.SelectorFromSet(labels.Set{utils.LabelKeyGetHistory: "test-name"}), }, }, - want: &resource.ListRequest{ + want: &resourcepb.ListRequest{ VersionMatchV2: 1, - Source: resource.ListRequest_HISTORY, - Options: &resource.ListOptions{ + Source: resourcepb.ListRequest_HISTORY, + Options: &resourcepb.ListOptions{ Labels: nil, Fields: nil, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -175,7 +175,7 @@ func TestToListRequest(t *testing.T) { }, { name: "with fullpath label", - key: &resource.ResourceKey{ + key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", @@ -185,12 +185,12 @@ func TestToListRequest(t *testing.T) { Label: labels.SelectorFromSet(labels.Set{utils.LabelGetFullpath: "true"}), }, }, - want: &resource.ListRequest{ + want: &resourcepb.ListRequest{ VersionMatchV2: 1, - Options: &resource.ListOptions{ + Options: &resourcepb.ListOptions{ Labels: nil, Fields: nil, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Namespace: "default", diff --git a/pkg/storage/unified/apistore/watcher_test.go b/pkg/storage/unified/apistore/watcher_test.go index d6ede353f3f..c68415bca97 100644 --- a/pkg/storage/unified/apistore/watcher_test.go +++ b/pkg/storage/unified/apistore/watcher_test.go @@ -37,6 +37,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified/apistore" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql" "github.com/grafana/grafana/pkg/storage/unified/sql/db/dbimpl" "github.com/grafana/grafana/pkg/tests/testsuite" @@ -130,7 +131,7 @@ func testSetup(t testing.TB, opts ...setupOption) (context.Context, storage.Inte require.NoError(t, err) // Issue a health check to ensure the server is initialized - _, err = server.IsHealthy(ctx, &resource.HealthCheckRequest{}) + _, err = server.IsHealthy(ctx, &resourcepb.HealthCheckRequest{}) require.NoError(t, err) case StorageTypeUnified: if testing.Short() { @@ -377,7 +378,7 @@ func newPodList() runtime.Object { return &example.PodList{} } -func testKeyParser(val string) (*resource.ResourceKey, error) { +func testKeyParser(val string) (*resourcepb.ResourceKey, error) { k, err := grafanaregistry.ParseKey(val) if err != nil { if strings.HasPrefix(val, "pods/") { @@ -407,7 +408,7 @@ func testKeyParser(val string) (*resource.ResourceKey, error) { if k.Resource == "" { return nil, apierrors.NewInternalError(fmt.Errorf("missing resource in request")) } - return &resource.ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: k.Namespace, Group: k.Group, Resource: k.Resource, diff --git a/pkg/storage/unified/federated/client.go b/pkg/storage/unified/federated/client.go index 666ef7d3625..8ca3a32bbe3 100644 --- a/pkg/storage/unified/federated/client.go +++ b/pkg/storage/unified/federated/client.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/storage/legacysql" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func NewFederatedClient(base resource.ResourceClient, sql legacysql.LegacyDatabaseProvider) resource.ResourceClient { @@ -26,7 +27,7 @@ type federatedClient struct { } // Get the resource stats -func (s *federatedClient) GetStats(ctx context.Context, in *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) { +func (s *federatedClient) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { rsp, err := s.ResourceClient.GetStats(ctx, in, opts...) if err != nil { return nil, err diff --git a/pkg/storage/unified/federated/federatedtests/stats_test.go b/pkg/storage/unified/federated/federatedtests/stats_test.go index 5a8a6fd86e6..7c6980a1e74 100644 --- a/pkg/storage/unified/federated/federatedtests/stats_test.go +++ b/pkg/storage/unified/federated/federatedtests/stats_test.go @@ -31,7 +31,7 @@ import ( "github.com/grafana/grafana/pkg/storage/legacysql" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/storage/unified/federated" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/tests/testsuite" ) @@ -114,7 +114,7 @@ func TestDirectSQLStats(t *testing.T) { ctx := context.Background() ctx = request.WithNamespace(ctx, "default") - stats, err := store.GetStats(ctx, &resource.ResourceStatsRequest{ + stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{ Namespace: "default", Folder: folder1UID, }) @@ -147,7 +147,7 @@ func TestDirectSQLStats(t *testing.T) { ctx := context.Background() ctx = request.WithNamespace(ctx, "default") - stats, err := store.GetStats(ctx, &resource.ResourceStatsRequest{ + stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{ Namespace: "default", Folder: folder2UID, }) diff --git a/pkg/storage/unified/federated/stats.go b/pkg/storage/unified/federated/stats.go index a126bcb30fb..c7e922dd000 100644 --- a/pkg/storage/unified/federated/stats.go +++ b/pkg/storage/unified/federated/stats.go @@ -5,9 +5,10 @@ import ( "fmt" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/storage/legacysql" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // Read stats from legacy SQL @@ -15,7 +16,7 @@ type LegacyStatsGetter struct { SQL legacysql.LegacyDatabaseProvider } -func (s *LegacyStatsGetter) GetStats(ctx context.Context, in *resource.ResourceStatsRequest) (*resource.ResourceStatsResponse, error) { +func (s *LegacyStatsGetter) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest) (*resourcepb.ResourceStatsResponse, error) { info, err := claims.ParseNamespace(in.Namespace) if err != nil { return nil, fmt.Errorf("unable to read namespace") @@ -29,7 +30,7 @@ func (s *LegacyStatsGetter) GetStats(ctx context.Context, in *resource.ResourceS return nil, err } - rsp := &resource.ResourceStatsResponse{} + rsp := &resourcepb.ResourceStatsResponse{} err = helper.DB.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { fn := func(table, where, g, r string, existCheck bool) error { // if existCheck is true, do not error out if the table does not exist @@ -46,7 +47,7 @@ func (s *LegacyStatsGetter) GetStats(ctx context.Context, in *resource.ResourceS if err != nil { return err } - rsp.Stats = append(rsp.Stats, &resource.ResourceStatsResponse_Stats{ + rsp.Stats = append(rsp.Stats, &resourcepb.ResourceStatsResponse_Stats{ Group: g, // all legacy for now Resource: r, Count: count, diff --git a/pkg/storage/unified/parquet/client.go b/pkg/storage/unified/parquet/client.go index 73342e944d6..60065a613a1 100644 --- a/pkg/storage/unified/parquet/client.go +++ b/pkg/storage/unified/parquet/client.go @@ -9,11 +9,12 @@ import ( "google.golang.org/grpc/metadata" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var ( - _ resource.BulkStoreClient = (*writerClient)(nil) - _ resource.BulkStore_BulkProcessClient = (*writerClient)(nil) + _ resourcepb.BulkStoreClient = (*writerClient)(nil) + _ resourcepb.BulkStore_BulkProcessClient = (*writerClient)(nil) errUnimplemented = errors.New("not implemented (BulkResourceWriter as BulkStoreClient shim)") ) @@ -29,12 +30,12 @@ func NewBulkResourceWriterClient(writer resource.BulkResourceWriter) *writerClie } // Send implements resource.ResourceStore_BulkProcessClient. -func (w *writerClient) Send(req *resource.BulkRequest) error { +func (w *writerClient) Send(req *resourcepb.BulkRequest) error { return w.writer.Write(w.ctx, req.Key, req.Value) } // BulkProcess implements resource.ResourceStoreClient. -func (w *writerClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { +func (w *writerClient) BulkProcess(ctx context.Context, _ ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) { if w.ctx != nil { return nil, fmt.Errorf("only one batch request supported") } @@ -43,7 +44,7 @@ func (w *writerClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) } // CloseAndRecv implements resource.ResourceStore_BulkProcessClient. -func (w *writerClient) CloseAndRecv() (*resource.BulkResponse, error) { +func (w *writerClient) CloseAndRecv() (*resourcepb.BulkResponse, error) { return w.writer.CloseWithResults() } @@ -63,12 +64,12 @@ func (w *writerClient) Header() (metadata.MD, error) { } // RecvMsg implements resource.ResourceStore_BulkProcessClient. -func (w *writerClient) RecvMsg(m any) error { +func (w *writerClient) RecvMsg(_ any) error { return errUnimplemented } // SendMsg implements resource.ResourceStore_BulkProcessClient. -func (w *writerClient) SendMsg(m any) error { +func (w *writerClient) SendMsg(_ any) error { return errUnimplemented } diff --git a/pkg/storage/unified/parquet/reader.go b/pkg/storage/unified/parquet/reader.go index 7e327aa8a6d..5c6e697e726 100644 --- a/pkg/storage/unified/parquet/reader.go +++ b/pkg/storage/unified/parquet/reader.go @@ -7,6 +7,7 @@ import ( "github.com/apache/arrow-go/v18/parquet/file" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var ( @@ -39,7 +40,7 @@ type parquetReader struct { bufferIndex int rowGroupIDX int - req *resource.BulkRequest + req *resourcepb.BulkRequest err error } @@ -60,14 +61,14 @@ func (r *parquetReader) Next() bool { i := r.bufferIndex r.bufferIndex++ - r.req = &resource.BulkRequest{ - Key: &resource.ResourceKey{ + r.req = &resourcepb.BulkRequest{ + Key: &resourcepb.ResourceKey{ Group: r.group.buffer[i].String(), Resource: r.resource.buffer[i].String(), Namespace: r.namespace.buffer[i].String(), Name: r.name.buffer[i].String(), }, - Action: resource.BulkRequest_Action(r.action.buffer[i]), + Action: resourcepb.BulkRequest_Action(r.action.buffer[i]), Value: r.value.buffer[i].Bytes(), Folder: r.folder.buffer[i].String(), } @@ -88,7 +89,7 @@ func (r *parquetReader) Next() bool { } // Request implements resource.BulkRequestIterator. -func (r *parquetReader) Request() *resource.BulkRequest { +func (r *parquetReader) Request() *resourcepb.BulkRequest { return r.req } diff --git a/pkg/storage/unified/parquet/reader_test.go b/pkg/storage/unified/parquet/reader_test.go index e8414c36d74..c76e27afe36 100644 --- a/pkg/storage/unified/parquet/reader_test.go +++ b/pkg/storage/unified/parquet/reader_test.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestParquetWriteThenRead(t *testing.T) { @@ -75,7 +76,7 @@ func TestParquetWriteThenRead(t *testing.T) { require.NoError(t, err) for reader.Next() { req := reader.Request() - keys = append(keys, req.Key.SearchID()) + keys = append(keys, resource.SearchID(req.Key)) } // Verify that we read all values @@ -101,14 +102,14 @@ func TestParquetWriteThenRead(t *testing.T) { require.NoError(t, err) for reader.Next() { req := reader.Request() - keys = append(keys, req.Key.SearchID()) + keys = append(keys, resource.SearchID(req.Key)) } require.NoError(t, reader.err) require.Empty(t, keys) }) } -func toKeyAndBytes(ctx context.Context, group string, res string, obj *unstructured.Unstructured) (context.Context, *resource.ResourceKey, []byte) { +func toKeyAndBytes(ctx context.Context, group string, res string, obj *unstructured.Unstructured) (context.Context, *resourcepb.ResourceKey, []byte) { if obj.GetKind() == "" { obj.SetKind(res) } @@ -116,7 +117,7 @@ func toKeyAndBytes(ctx context.Context, group string, res string, obj *unstructu obj.SetAPIVersion(group + "/vXyz") } data, _ := obj.MarshalJSON() - return ctx, &resource.ResourceKey{ + return ctx, &resourcepb.ResourceKey{ Namespace: obj.GetNamespace(), Resource: res, Group: group, diff --git a/pkg/storage/unified/parquet/writer.go b/pkg/storage/unified/parquet/writer.go index 2ea626a2a62..3be36aea3df 100644 --- a/pkg/storage/unified/parquet/writer.go +++ b/pkg/storage/unified/parquet/writer.go @@ -13,8 +13,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var ( @@ -28,8 +30,8 @@ func NewParquetWriter(f io.Writer) (*parquetWriter, error) { schema: newSchema(nil), buffer: 1024 * 10 * 100 * 10, // 10MB logger: logging.DefaultLogger.With("logger", "parquet.writer"), - rsp: &resource.BulkResponse{}, - summary: make(map[string]*resource.BulkResponse_Summary), + rsp: &resourcepb.BulkResponse{}, + summary: make(map[string]*resourcepb.BulkResponse_Summary), } props := parquet.NewWriterProperties( @@ -44,7 +46,7 @@ func NewParquetWriter(f io.Writer) (*parquetWriter, error) { } // ProcessBulk implements resource.BulkProcessingBackend. -func (w *parquetWriter) ProcessBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resource.BulkResponse { +func (w *parquetWriter) ProcessBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resourcepb.BulkResponse { defer func() { _ = w.Close() }() var err error @@ -66,7 +68,7 @@ func (w *parquetWriter) ProcessBulk(ctx context.Context, setting resource.BulkSe w.logger.Warn("error closing parquet file", "err", err) } if rsp == nil { - rsp = &resource.BulkResponse{} + rsp = &resourcepb.BulkResponse{} } if err != nil { rsp.Error = resource.AsErrorResult(err) @@ -92,11 +94,11 @@ type parquetWriter struct { action *array.Int8Builder value *array.StringBuilder - rsp *resource.BulkResponse - summary map[string]*resource.BulkResponse_Summary + rsp *resourcepb.BulkResponse + summary map[string]*resourcepb.BulkResponse_Summary } -func (w *parquetWriter) CloseWithResults() (*resource.BulkResponse, error) { +func (w *parquetWriter) CloseWithResults() (*resourcepb.BulkResponse, error) { err := w.Close() return w.rsp, err } @@ -143,7 +145,7 @@ func (w *parquetWriter) init() error { return nil } -func (w *parquetWriter) Write(ctx context.Context, key *resource.ResourceKey, value []byte) error { +func (w *parquetWriter) Write(ctx context.Context, key *resourcepb.ResourceKey, value []byte) error { w.rsp.Processed++ obj := &unstructured.Unstructured{} err := obj.UnmarshalJSON(value) @@ -164,14 +166,14 @@ func (w *parquetWriter) Write(ctx context.Context, key *resource.ResourceKey, va w.folder.Append(meta.GetFolder()) w.value.Append(string(value)) - var action resource.WatchEvent_Type + var action resourcepb.WatchEvent_Type switch meta.GetGeneration() { case 0, 1: - action = resource.WatchEvent_ADDED + action = resourcepb.WatchEvent_ADDED case utils.DeletedGeneration: - action = resource.WatchEvent_DELETED + action = resourcepb.WatchEvent_DELETED default: - action = resource.WatchEvent_MODIFIED + action = resourcepb.WatchEvent_MODIFIED } w.action.Append(int8(action)) @@ -181,14 +183,14 @@ func (w *parquetWriter) Write(ctx context.Context, key *resource.ResourceKey, va return w.flush() } - summary := w.summary[key.NSGR()] + summary := w.summary[resource.NSGR(key)] if summary == nil { - summary = &resource.BulkResponse_Summary{ + summary = &resourcepb.BulkResponse_Summary{ Namespace: key.Namespace, Group: key.Group, Resource: key.Resource, } - w.summary[key.NSGR()] = summary + w.summary[resource.NSGR(key)] = summary w.rsp.Summary = append(w.rsp.Summary, summary) } summary.Count++ diff --git a/pkg/storage/unified/proto/blob.proto b/pkg/storage/unified/proto/blob.proto new file mode 100644 index 00000000000..9b58e09a713 --- /dev/null +++ b/pkg/storage/unified/proto/blob.proto @@ -0,0 +1,98 @@ +syntax = "proto3"; +package resource; + +option go_package = "github.com/grafana/grafana/pkg/storage/unified/resourcepb"; + +import "resource.proto"; + +//---------------------------- +// 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; +} + +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 +} diff --git a/pkg/storage/unified/resource/buf.gen.yaml b/pkg/storage/unified/proto/buf.gen.yaml similarity index 68% rename from pkg/storage/unified/resource/buf.gen.yaml rename to pkg/storage/unified/proto/buf.gen.yaml index f0d8393e9ac..ee4fd50abde 100644 --- a/pkg/storage/unified/resource/buf.gen.yaml +++ b/pkg/storage/unified/proto/buf.gen.yaml @@ -1,10 +1,10 @@ version: v1 plugins: - plugin: go - out: pkg/storage/unified/resource + out: pkg/storage/unified/resourcepb opt: paths=source_relative - plugin: go-grpc - out: pkg/storage/unified/resource + out: pkg/storage/unified/resourcepb opt: - paths=source_relative - require_unimplemented_servers=false diff --git a/pkg/storage/unified/resource/buf.yaml b/pkg/storage/unified/proto/buf.yaml similarity index 62% rename from pkg/storage/unified/resource/buf.yaml rename to pkg/storage/unified/proto/buf.yaml index 1a5194568a9..770116b1e86 100644 --- a/pkg/storage/unified/resource/buf.yaml +++ b/pkg/storage/unified/proto/buf.yaml @@ -1,4 +1,6 @@ -version: v1 +version: v2 +modules: + - path: . breaking: use: - FILE diff --git a/pkg/storage/unified/resource/resource.proto b/pkg/storage/unified/proto/resource.proto similarity index 77% rename from pkg/storage/unified/resource/resource.proto rename to pkg/storage/unified/proto/resource.proto index f5111d90657..91a9288b194 100644 --- a/pkg/storage/unified/resource/resource.proto +++ b/pkg/storage/unified/proto/resource.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package resource; -option go_package = "github.com/grafana/grafana/pkg/storage/unified/resource"; +option go_package = "github.com/grafana/grafana/pkg/storage/unified/resourcepb"; message ResourceKey { // Namespace (tenant) @@ -331,7 +331,7 @@ message WatchEvent { message BulkRequest { enum Action { // will be an error - UNKNOWN = 0; + UNKNOWN = 0; // Matches Watch event enum ADDED = 1; @@ -345,7 +345,7 @@ message BulkRequest { // Requested action Action action = 2; - // The resource value + // The resource value bytes value = 3; // Hint that a new version will be written on-top of this @@ -382,135 +382,10 @@ message BulkResponse { // Summary status for the processed values repeated Summary summary = 3; - // Rejected + // 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 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 facet = 7; -} - // List items within a resource type & repository name // Access control is managed above this request message ListManagedObjectsRequest { @@ -712,86 +587,6 @@ message ResourceTableRow { bytes object = 4; } -//---------------------------- -// 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 @@ -820,15 +615,6 @@ service BulkStore { rpc BulkProcess(stream BulkRequest) returns (BulkResponse); } -// 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 managed objects // Results access control is based on access to the repository *not* the items service ManagedObjectIndex { @@ -839,18 +625,6 @@ service ManagedObjectIndex { rpc ListManagedObjects(ListManagedObjectsRequest) returns (ListManagedObjectsResponse); } -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 { diff --git a/pkg/storage/unified/proto/search.proto b/pkg/storage/unified/proto/search.proto new file mode 100644 index 00000000000..d206060daf4 --- /dev/null +++ b/pkg/storage/unified/proto/search.proto @@ -0,0 +1,140 @@ +syntax = "proto3"; +package resource; + +option go_package = "github.com/grafana/grafana/pkg/storage/unified/resourcepb"; + +import "resource.proto"; + + +// 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); +} + +// 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 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 facet = 7; +} diff --git a/pkg/storage/unified/resource/bulk.go b/pkg/storage/unified/resource/bulk.go index aff0d472a38..b717585dbc4 100644 --- a/pkg/storage/unified/resource/bulk.go +++ b/pkg/storage/unified/resource/bulk.go @@ -10,7 +10,9 @@ import ( "google.golang.org/grpc/metadata" authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) const grpcMetaKeyCollection = "x-gf-batch-collection" @@ -25,28 +27,28 @@ type BulkRequestIterator interface { Next() bool // The next event we should process - Request() *BulkRequest + Request() *resourcepb.BulkRequest // Rollback requested RollbackRequested() bool } type BulkProcessingBackend interface { - ProcessBulk(ctx context.Context, setting BulkSettings, iter BulkRequestIterator) *BulkResponse + ProcessBulk(ctx context.Context, setting BulkSettings, iter BulkRequestIterator) *resourcepb.BulkResponse } type BulkResourceWriter interface { io.Closer - Write(ctx context.Context, key *ResourceKey, value []byte) error + Write(ctx context.Context, key *resourcepb.ResourceKey, value []byte) error // Called when finished writing - CloseWithResults() (*BulkResponse, error) + CloseWithResults() (*resourcepb.BulkResponse, error) } type BulkSettings struct { // All requests will be within this namespace/group/resource - Collection []*ResourceKey + Collection []*resourcepb.ResourceKey // The batch will include everything from the collection // - all existing values will be removed/replaced if the batch completes successfully @@ -60,7 +62,7 @@ func (x *BulkSettings) ToMD() metadata.MD { md := make(metadata.MD) if len(x.Collection) > 0 { for _, v := range x.Collection { - md[grpcMetaKeyCollection] = append(md[grpcMetaKeyCollection], v.SearchID()) + md[grpcMetaKeyCollection] = append(md[grpcMetaKeyCollection], SearchID(v)) } } if x.RebuildCollection { @@ -78,8 +80,8 @@ func NewBulkSettings(md metadata.MD) (BulkSettings, error) { switch k { case grpcMetaKeyCollection: for _, c := range v { - key := &ResourceKey{} - err := key.ReadSearchID(c) + key := &resourcepb.ResourceKey{} + err := ReadSearchID(key, c) if err != nil { return settings, fmt.Errorf("error reading collection metadata: %s / %w", c, err) } @@ -96,12 +98,12 @@ func NewBulkSettings(md metadata.MD) (BulkSettings, error) { // BulkWrite implements ResourceServer. // All requests must be to the same NAMESPACE/GROUP/RESOURCE -func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { +func (s *server) BulkProcess(stream resourcepb.BulkStore_BulkProcessServer) error { ctx := stream.Context() user, ok := authlib.AuthInfoFrom(ctx) if !ok || user == nil { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, }, @@ -110,8 +112,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { md, ok := metadata.FromIncomingContext(ctx) if !ok { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "unable to read metadata gRPC request", Code: http.StatusPreconditionFailed, }, @@ -123,8 +125,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { } settings, err := NewBulkSettings(md) if err != nil { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "error reading settings", Reason: err.Error(), Code: http.StatusPreconditionFailed, @@ -133,8 +135,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { } if len(settings.Collection) < 1 { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "Missing target collection(s) in request header", Code: http.StatusBadRequest, }, @@ -151,8 +153,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { Verb: utils.VerbDeleteCollection, }) if err != nil || !rsp.Allowed { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: fmt.Sprintf("Requester must be able to: %s", utils.VerbDeleteCollection), Code: http.StatusForbidden, }, @@ -160,15 +162,15 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { } // This will be called for each request -- with the folder ID - runner.checker[k.NSGR()], err = s.access.Compile(ctx, user, authlib.ListRequest{ + runner.checker[NSGR(k)], err = s.access.Compile(ctx, user, authlib.ListRequest{ Namespace: k.Namespace, Group: k.Group, Resource: k.Resource, Verb: utils.VerbCreate, }) if err != nil { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "Unable to check `create` permission", Code: http.StatusForbidden, }, @@ -176,8 +178,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { } } } else { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "Bulk currently only supports RebuildCollection", Code: http.StatusBadRequest, }, @@ -186,8 +188,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { backend, ok := s.backend.(BulkProcessingBackend) if !ok { - return stream.SendAndClose(&BulkResponse{ - Error: &ErrorResult{ + return stream.SendAndClose(&resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Message: "The server backend does not support batch processing", Code: http.StatusNotImplemented, }, @@ -197,8 +199,8 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { // BulkProcess requests rsp := backend.ProcessBulk(ctx, settings, runner) if rsp == nil { - rsp = &BulkResponse{ - Error: &ErrorResult{ + rsp = &resourcepb.BulkResponse{ + Error: &resourcepb.ErrorResult{ Code: http.StatusInternalServerError, Message: "Nothing returned from process batch", }, @@ -218,7 +220,7 @@ func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { }, summary.Count, summary.ResourceVersion) if err != nil { s.log.Warn("error building search index after batch load", "err", err) - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Code: http.StatusInternalServerError, Message: "err building search index: " + summary.Resource, Reason: err.Error(), @@ -234,9 +236,9 @@ var ( ) type batchRunner struct { - stream BulkStore_BulkProcessServer + stream resourcepb.BulkStore_BulkProcessServer rollback bool - request *BulkRequest + request *resourcepb.BulkRequest err error checker map[string]authlib.ItemChecker } @@ -262,7 +264,7 @@ func (b *batchRunner) Next() bool { if b.request != nil { key := b.request.Key - k := key.NSGR() + k := NSGR(key) checker, ok := b.checker[k] if !ok { b.err = fmt.Errorf("missing access control for: %s", k) @@ -277,7 +279,7 @@ func (b *batchRunner) Next() bool { } // Request implements BulkRequestIterator. -func (b *batchRunner) Request() *BulkRequest { +func (b *batchRunner) Request() *resourcepb.BulkRequest { if b.rollback { return nil } diff --git a/pkg/storage/unified/resource/cdk_backend.go b/pkg/storage/unified/resource/cdk_backend.go index 7baf4a53090..725feb11585 100644 --- a/pkg/storage/unified/resource/cdk_backend.go +++ b/pkg/storage/unified/resource/cdk_backend.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type CDKBackendOptions struct { @@ -73,7 +74,7 @@ type cdkBackend struct { stream chan<- *WrittenEvent } -func (s *cdkBackend) getPath(key *ResourceKey, rv int64) string { +func (s *cdkBackend) getPath(key *resourcepb.ResourceKey, rv int64) string { var buffer bytes.Buffer buffer.WriteString(s.root) @@ -116,9 +117,9 @@ func (s *cdkBackend) GetResourceStats(ctx context.Context, namespace string, min } func (s *cdkBackend) WriteEvent(ctx context.Context, event WriteEvent) (rv int64, err error) { - if event.Type == WatchEvent_ADDED { + if event.Type == resourcepb.WatchEvent_ADDED { // ReadResource deals with deleted values (i.e. a file exists but has generation -999). - resp := s.ReadResource(ctx, &ReadRequest{Key: event.Key}) + resp := s.ReadResource(ctx, &resourcepb.ReadRequest{Key: event.Key}) if resp.Error != nil && resp.Error.Code != http.StatusNotFound { return 0, GetError(resp.Error) } @@ -155,7 +156,7 @@ func (s *cdkBackend) WriteEvent(ctx context.Context, event WriteEvent) (rv int64 return rv, err } -func (s *cdkBackend) ReadResource(ctx context.Context, req *ReadRequest) *BackendReadResponse { +func (s *cdkBackend) ReadResource(ctx context.Context, req *resourcepb.ReadRequest) *BackendReadResponse { rv := req.ResourceVersion path := s.getPath(req.Key, rv) @@ -184,12 +185,12 @@ func (s *cdkBackend) ReadResource(ctx context.Context, req *ReadRequest) *Backen if raw == nil && req.ResourceVersion > 0 { if req.ResourceVersion > s.rv.Load() { return &BackendReadResponse{ - Error: &ErrorResult{ + Error: &resourcepb.ErrorResult{ Code: http.StatusGatewayTimeout, Reason: string(metav1.StatusReasonTimeout), // match etcd behavior Message: "ResourceVersion is larger than max", - Details: &ErrorDetails{ - Causes: []*ErrorCause{ + Details: &resourcepb.ErrorDetails{ + Causes: []*resourcepb.ErrorCause{ { Reason: string(metav1.CauseTypeResourceVersionTooLarge), Message: fmt.Sprintf("requested: %d, current %d", req.ResourceVersion, s.rv.Load()), @@ -201,7 +202,7 @@ func (s *cdkBackend) ReadResource(ctx context.Context, req *ReadRequest) *Backen } // If the there was an explicit request, get the latest - rsp := s.ReadResource(ctx, &ReadRequest{Key: req.Key}) + rsp := s.ReadResource(ctx, &resourcepb.ReadRequest{Key: req.Key}) if rsp != nil && len(rsp.Value) > 0 { raw = rsp.Value rv = rsp.ResourceVersion @@ -233,8 +234,8 @@ func isDeletedValue(raw []byte) bool { return false } -func (s *cdkBackend) ListIterator(ctx context.Context, req *ListRequest, cb func(ListIterator) error) (int64, error) { - if req.Source != ListRequest_STORE { +func (s *cdkBackend) ListIterator(ctx context.Context, req *resourcepb.ListRequest, cb func(ListIterator) error) (int64, error) { + if req.Source != resourcepb.ListRequest_STORE { return 0, fmt.Errorf("listing from history not supported in CDK backend") } @@ -356,7 +357,7 @@ func (c *cdkListIterator) Folder() string { var _ ListIterator = (*cdkListIterator)(nil) -func buildTree(ctx context.Context, s *cdkBackend, key *ResourceKey) (*cdkListIterator, error) { +func buildTree(ctx context.Context, s *cdkBackend, key *resourcepb.ResourceKey) (*cdkListIterator, error) { byPrefix := make(map[string]*cdkResource) path := s.getPath(key, 0) iter := s.bucket.List(&blob.ListOptions{Prefix: path, Delimiter: ""}) // "" is recursive diff --git a/pkg/storage/unified/resource/cdk_blob.go b/pkg/storage/unified/resource/cdk_blob.go index 8fd59fafaf1..e9dbdb22834 100644 --- a/pkg/storage/unified/resource/cdk_blob.go +++ b/pkg/storage/unified/resource/cdk_blob.go @@ -2,7 +2,7 @@ package resource import ( "bytes" - context "context" + "context" "crypto/md5" "encoding/hex" "fmt" @@ -16,6 +16,7 @@ import ( "gocloud.dev/blob" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" // Supported drivers _ "gocloud.dev/blob/azureblob" @@ -85,7 +86,7 @@ type cdkBlobSupport struct { expiration time.Duration } -func (s *cdkBlobSupport) getBlobPath(key *ResourceKey, info *utils.BlobInfo) (string, error) { +func (s *cdkBlobSupport) getBlobPath(key *resourcepb.ResourceKey, info *utils.BlobInfo) (string, error) { var buffer bytes.Buffer buffer.WriteString(s.root) @@ -129,7 +130,7 @@ func (s *cdkBlobSupport) SupportsSignedURLs() bool { return s.cansignurls } -func (s *cdkBlobSupport) PutResourceBlob(ctx context.Context, req *PutBlobRequest) (*PutBlobResponse, error) { +func (s *cdkBlobSupport) PutResourceBlob(ctx context.Context, req *resourcepb.PutBlobRequest) (*resourcepb.PutBlobResponse, error) { info := &utils.BlobInfo{ UID: uuid.New().String(), } @@ -139,8 +140,8 @@ func (s *cdkBlobSupport) PutResourceBlob(ctx context.Context, req *PutBlobReques return nil, err } - rsp := &PutBlobResponse{Uid: info.UID, MimeType: info.MimeType, Charset: info.Charset} - if req.Method == PutBlobRequest_HTTP { + rsp := &resourcepb.PutBlobResponse{Uid: info.UID, MimeType: info.MimeType, Charset: info.Charset} + if req.Method == resourcepb.PutBlobRequest_HTTP { rsp.Url, err = s.bucket.SignedURL(ctx, path, &blob.SignedURLOptions{ Method: "PUT", Expiry: s.expiration, @@ -176,12 +177,13 @@ func (s *cdkBlobSupport) PutResourceBlob(ctx context.Context, req *PutBlobReques return rsp, err } -func (s *cdkBlobSupport) GetResourceBlob(ctx context.Context, resource *ResourceKey, info *utils.BlobInfo, mustProxy bool) (*GetBlobResponse, error) { +func (s *cdkBlobSupport) GetResourceBlob(ctx context.Context, resource *resourcepb.ResourceKey, info *utils.BlobInfo, + mustProxy bool) (*resourcepb.GetBlobResponse, error) { path, err := s.getBlobPath(resource, info) if err != nil { return nil, err } - rsp := &GetBlobResponse{ContentType: info.ContentType()} + rsp := &resourcepb.GetBlobResponse{ContentType: info.ContentType()} if mustProxy || !s.cansignurls { rsp.Value, err = s.bucket.ReadAll(ctx, path) return rsp, err diff --git a/pkg/storage/unified/resource/cdk_blob_test.go b/pkg/storage/unified/resource/cdk_blob_test.go index 65ea7dcd7ec..1e20ad9ceb3 100644 --- a/pkg/storage/unified/resource/cdk_blob_test.go +++ b/pkg/storage/unified/resource/cdk_blob_test.go @@ -7,6 +7,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/require" "gocloud.dev/blob/fileblob" "gocloud.dev/blob/memblob" @@ -36,16 +38,16 @@ func TestCDKBlobStore(t *testing.T) { t.Run("can write then read a blob", func(t *testing.T) { raw := []byte(`{"hello": "world"}`) - key := &ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "playlist.grafana.app", Resource: "rrrr", // can be anything Namespace: "default", Name: "fdgsv37qslr0ga", } - rsp, err := store.PutResourceBlob(ctx, &PutBlobRequest{ + rsp, err := store.PutResourceBlob(ctx, &resourcepb.PutBlobRequest{ Resource: key, - Method: PutBlobRequest_GRPC, + Method: resourcepb.PutBlobRequest_GRPC, ContentType: "application/json", Value: raw, }) diff --git a/pkg/storage/unified/resource/client.go b/pkg/storage/unified/resource/client.go index 6f10346466e..26b36dcac4a 100644 --- a/pkg/storage/unified/resource/client.go +++ b/pkg/storage/unified/resource/client.go @@ -23,36 +23,37 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/identity" grpcUtils "github.com/grafana/grafana/pkg/storage/unified/resource/grpc" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type ResourceClient interface { - ResourceStoreClient - ResourceIndexClient - ManagedObjectIndexClient - BulkStoreClient - BlobStoreClient - DiagnosticsClient + resourcepb.ResourceStoreClient + resourcepb.ResourceIndexClient + resourcepb.ManagedObjectIndexClient + resourcepb.BulkStoreClient + resourcepb.BlobStoreClient + resourcepb.DiagnosticsClient } // Internal implementation type resourceClient struct { - ResourceStoreClient - ResourceIndexClient - ManagedObjectIndexClient - BulkStoreClient - BlobStoreClient - DiagnosticsClient + resourcepb.ResourceStoreClient + resourcepb.ResourceIndexClient + resourcepb.ManagedObjectIndexClient + resourcepb.BulkStoreClient + resourcepb.BlobStoreClient + resourcepb.DiagnosticsClient } func NewLegacyResourceClient(channel grpc.ClientConnInterface) ResourceClient { cc := grpchan.InterceptClientConn(channel, grpcUtils.UnaryClientInterceptor, grpcUtils.StreamClientInterceptor) return &resourceClient{ - ResourceStoreClient: NewResourceStoreClient(cc), - ResourceIndexClient: NewResourceIndexClient(cc), - ManagedObjectIndexClient: NewManagedObjectIndexClient(cc), - BulkStoreClient: NewBulkStoreClient(cc), - BlobStoreClient: NewBlobStoreClient(cc), - DiagnosticsClient: NewDiagnosticsClient(cc), + ResourceStoreClient: resourcepb.NewResourceStoreClient(cc), + ResourceIndexClient: resourcepb.NewResourceIndexClient(cc), + ManagedObjectIndexClient: resourcepb.NewManagedObjectIndexClient(cc), + BulkStoreClient: resourcepb.NewBulkStoreClient(cc), + BlobStoreClient: resourcepb.NewBlobStoreClient(cc), + DiagnosticsClient: resourcepb.NewDiagnosticsClient(cc), } } @@ -63,12 +64,12 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { grpcAuthInt := grpcutils.NewUnsafeAuthenticator(tracer) for _, desc := range []*grpc.ServiceDesc{ - &ResourceStore_ServiceDesc, - &ResourceIndex_ServiceDesc, - &ManagedObjectIndex_ServiceDesc, - &BlobStore_ServiceDesc, - &BulkStore_ServiceDesc, - &Diagnostics_ServiceDesc, + &resourcepb.ResourceStore_ServiceDesc, + &resourcepb.ResourceIndex_ServiceDesc, + &resourcepb.ManagedObjectIndex_ServiceDesc, + &resourcepb.BlobStore_ServiceDesc, + &resourcepb.BulkStore_ServiceDesc, + &resourcepb.Diagnostics_ServiceDesc, } { channel.RegisterService( grpchan.InterceptServer( @@ -87,12 +88,12 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { cc := grpchan.InterceptClientConn(channel, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) return &resourceClient{ - ResourceStoreClient: NewResourceStoreClient(cc), - ResourceIndexClient: NewResourceIndexClient(cc), - ManagedObjectIndexClient: NewManagedObjectIndexClient(cc), - BulkStoreClient: NewBulkStoreClient(cc), - BlobStoreClient: NewBlobStoreClient(cc), - DiagnosticsClient: NewDiagnosticsClient(cc), + ResourceStoreClient: resourcepb.NewResourceStoreClient(cc), + ResourceIndexClient: resourcepb.NewResourceIndexClient(cc), + ManagedObjectIndexClient: resourcepb.NewManagedObjectIndexClient(cc), + BulkStoreClient: resourcepb.NewBulkStoreClient(cc), + BlobStoreClient: resourcepb.NewBlobStoreClient(cc), + DiagnosticsClient: resourcepb.NewDiagnosticsClient(cc), } } @@ -129,12 +130,12 @@ func NewRemoteResourceClient(tracer trace.Tracer, conn grpc.ClientConnInterface, cc := grpchan.InterceptClientConn(conn, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) return &resourceClient{ - ResourceStoreClient: NewResourceStoreClient(cc), - ResourceIndexClient: NewResourceIndexClient(cc), - BlobStoreClient: NewBlobStoreClient(cc), - BulkStoreClient: NewBulkStoreClient(cc), - ManagedObjectIndexClient: NewManagedObjectIndexClient(cc), - DiagnosticsClient: NewDiagnosticsClient(cc), + ResourceStoreClient: resourcepb.NewResourceStoreClient(cc), + ResourceIndexClient: resourcepb.NewResourceIndexClient(cc), + BlobStoreClient: resourcepb.NewBlobStoreClient(cc), + BulkStoreClient: resourcepb.NewBulkStoreClient(cc), + ManagedObjectIndexClient: resourcepb.NewManagedObjectIndexClient(cc), + DiagnosticsClient: resourcepb.NewDiagnosticsClient(cc), }, nil } diff --git a/pkg/storage/unified/resource/document.go b/pkg/storage/unified/resource/document.go index d5224879330..3c5bbc6e5c0 100644 --- a/pkg/storage/unified/resource/document.go +++ b/pkg/storage/unified/resource/document.go @@ -10,18 +10,19 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // Convert raw resource bytes into an IndexableDocument type DocumentBuilder interface { // Convert raw bytes into an document that can be written - BuildDocument(ctx context.Context, key *ResourceKey, rv int64, value []byte) (*IndexableDocument, error) + BuildDocument(ctx context.Context, key *resourcepb.ResourceKey, rv int64, value []byte) (*IndexableDocument, error) } // Registry of the searchable document fields type SearchableDocumentFields interface { Fields() []string - Field(name string) *ResourceTableColumnDefinition + Field(name string) *resourcepb.ResourceTableColumnDefinition } // Some kinds will require special processing for their namespace @@ -51,7 +52,7 @@ type DocumentBuilderSupplier interface { // Although public, this is *NOT* an end user interface type IndexableDocument struct { // The resource key - Key *ResourceKey `json:"key"` + Key *resourcepb.ResourceKey `json:"key"` // The k8s name Name string `json:"name,omitempty"` @@ -165,7 +166,7 @@ func (m ResourceReferences) Less(i, j int) bool { } // Create a new indexable document based on a generic k8s resource -func NewIndexableDocument(key *ResourceKey, rv int64, obj utils.GrafanaMetaAccessor) *IndexableDocument { +func NewIndexableDocument(key *resourcepb.ResourceKey, rv int64, obj utils.GrafanaMetaAccessor) *IndexableDocument { title := obj.FindTitle(key.Name) if title == key.Name { // TODO: something wrong with FindTitle @@ -216,7 +217,7 @@ func StandardDocumentBuilder() DocumentBuilder { type standardDocumentBuilder struct{} -func (s *standardDocumentBuilder) BuildDocument(ctx context.Context, key *ResourceKey, rv int64, value []byte) (*IndexableDocument, error) { +func (s *standardDocumentBuilder) BuildDocument(ctx context.Context, key *resourcepb.ResourceKey, rv int64, value []byte) (*IndexableDocument, error) { tmp := &unstructured.Unstructured{} err := tmp.UnmarshalJSON(value) if err != nil { @@ -238,7 +239,7 @@ type searchableDocumentFields struct { } // This requires unique names -func NewSearchableDocumentFields(columns []*ResourceTableColumnDefinition) (SearchableDocumentFields, error) { +func NewSearchableDocumentFields(columns []*resourcepb.ResourceTableColumnDefinition) (SearchableDocumentFields, error) { f := &searchableDocumentFields{ names: make([]string, len(columns)), fields: make(map[string]*resourceTableColumn), @@ -261,7 +262,7 @@ func (x *searchableDocumentFields) Fields() []string { return x.names } -func (x *searchableDocumentFields) Field(name string) *ResourceTableColumnDefinition { +func (x *searchableDocumentFields) Field(name string) *resourcepb.ResourceTableColumnDefinition { name = strings.TrimPrefix(name, SEARCH_FIELD_PREFIX) f, ok := x.fields[name] @@ -308,94 +309,94 @@ var standardSearchFields SearchableDocumentFields func StandardSearchFields() SearchableDocumentFields { standardSearchFieldsInit.Do(func() { var err error - standardSearchFields, err = NewSearchableDocumentFields([]*ResourceTableColumnDefinition{ + standardSearchFields, err = NewSearchableDocumentFields([]*resourcepb.ResourceTableColumnDefinition{ { Name: SEARCH_FIELD_ID, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "Unique Identifier. {namespace}/{group}/{resource}/{name}", - Properties: &ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ NotNull: true, }, }, { Name: SEARCH_FIELD_GROUP_RESOURCE, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "The resource kind: {group}/{resource}", - Properties: &ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ NotNull: true, }, }, { Name: SEARCH_FIELD_NAMESPACE, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "Tenant isolation", - Properties: &ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ NotNull: true, }, }, { Name: SEARCH_FIELD_NAME, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "Kubernetes name. Unique identifier within a namespace+group+resource", - Properties: &ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ NotNull: true, }, }, { Name: SEARCH_FIELD_TITLE, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "Display name for the resource", }, { Name: SEARCH_FIELD_DESCRIPTION, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "An account of the resource.", - Properties: &ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ FreeText: true, }, }, { Name: SEARCH_FIELD_TAGS, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, IsArray: true, Description: "Unique tags", - Properties: &ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: SEARCH_FIELD_FOLDER, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "Kubernetes name for the folder", }, { Name: SEARCH_FIELD_RV, - Type: ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "resource version", }, { Name: SEARCH_FIELD_CREATED, - Type: ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "created timestamp", // date? }, { Name: SEARCH_FIELD_EXPLAIN, - Type: ResourceTableColumnDefinition_OBJECT, + Type: resourcepb.ResourceTableColumnDefinition_OBJECT, Description: "Explain why this result matches (depends on the engine)", }, { Name: SEARCH_FIELD_SCORE, - Type: ResourceTableColumnDefinition_DOUBLE, + Type: resourcepb.ResourceTableColumnDefinition_DOUBLE, Description: "The search score", }, { Name: SEARCH_FIELD_LEGACY_ID, - Type: ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Deprecated legacy id of the resource", }, { Name: SEARCH_FIELD_MANAGER_KIND, - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, Description: "Type of manager, which is responsible for managing the resource", }, }) diff --git a/pkg/storage/unified/resource/document_test.go b/pkg/storage/unified/resource/document_test.go index 838adfae494..f6bf17531d8 100644 --- a/pkg/storage/unified/resource/document_test.go +++ b/pkg/storage/unified/resource/document_test.go @@ -8,6 +8,8 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestStandardDocumentBuilder(t *testing.T) { @@ -16,7 +18,7 @@ func TestStandardDocumentBuilder(t *testing.T) { body, err := os.ReadFile("testdata/playlist-resource.json") require.NoError(t, err) - doc, err := builder.BuildDocument(ctx, &ResourceKey{ + doc, err := builder.BuildDocument(ctx, &resourcepb.ResourceKey{ Namespace: "default", Group: "playlists.grafana.app", Resource: "playlists", diff --git a/pkg/storage/unified/resource/errors.go b/pkg/storage/unified/resource/errors.go index d5b8a71abb3..fde29c71805 100644 --- a/pkg/storage/unified/resource/errors.go +++ b/pkg/storage/unified/resource/errors.go @@ -10,6 +10,8 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" grpcstatus "google.golang.org/grpc/status" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // Package-level errors. @@ -29,18 +31,18 @@ var ( } ) -func NewBadRequestError(msg string) *ErrorResult { - return &ErrorResult{ +func NewBadRequestError(msg string) *resourcepb.ErrorResult { + return &resourcepb.ErrorResult{ Message: msg, Code: http.StatusBadRequest, Reason: string(metav1.StatusReasonBadRequest), } } -func NewNotFoundError(key *ResourceKey) *ErrorResult { - return &ErrorResult{ +func NewNotFoundError(key *resourcepb.ResourceKey) *resourcepb.ErrorResult { + return &resourcepb.ErrorResult{ Code: http.StatusNotFound, - Details: &ErrorDetails{ + Details: &resourcepb.ErrorDetails{ Group: key.Group, Kind: key.Resource, // yup, resource as kind same is true in apierrors.NewNotFound() Name: key.Name, @@ -49,7 +51,7 @@ func NewNotFoundError(key *ResourceKey) *ErrorResult { } // Convert golang errors to status result errors that can be returned to a client -func AsErrorResult(err error) *ErrorResult { +func AsErrorResult(err error) *resourcepb.ErrorResult { if err == nil { return nil } @@ -57,13 +59,13 @@ func AsErrorResult(err error) *ErrorResult { var apistatus apierrors.APIStatus if errors.As(err, &apistatus) { s := apistatus.Status() - res := &ErrorResult{ + res := &resourcepb.ErrorResult{ Message: s.Message, Reason: string(s.Reason), Code: s.Code, } if s.Details != nil { - res.Details = &ErrorDetails{ + res.Details = &resourcepb.ErrorDetails{ Group: s.Details.Group, Kind: s.Details.Kind, Name: s.Details.Name, @@ -71,7 +73,7 @@ func AsErrorResult(err error) *ErrorResult { RetryAfterSeconds: s.Details.RetryAfterSeconds, } for _, c := range s.Details.Causes { - res.Details.Causes = append(res.Details.Causes, &ErrorCause{ + res.Details.Causes = append(res.Details.Causes, &resourcepb.ErrorCause{ Reason: string(c.Type), Message: c.Message, Field: c.Field, @@ -88,13 +90,13 @@ func AsErrorResult(err error) *ErrorResult { code = runtime.HTTPStatusFromCode(st.Code()) } - return &ErrorResult{ + return &resourcepb.ErrorResult{ Message: err.Error(), Code: int32(code), } } -func GetError(res *ErrorResult) error { +func GetError(res *resourcepb.ErrorResult) error { if res == nil { return nil } diff --git a/pkg/storage/unified/resource/event.go b/pkg/storage/unified/resource/event.go index fc408e23027..443e79d56a4 100644 --- a/pkg/storage/unified/resource/event.go +++ b/pkg/storage/unified/resource/event.go @@ -1,15 +1,16 @@ package resource import ( - context "context" + "context" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type WriteEvent struct { - Type WatchEvent_Type // ADDED, MODIFIED, DELETED - Key *ResourceKey // the request key - PreviousRV int64 // only for Update+Delete + Type resourcepb.WatchEvent_Type // ADDED, MODIFIED, DELETED + Key *resourcepb.ResourceKey // the request key + PreviousRV int64 // only for Update+Delete // The json payload (without resourceVersion) Value []byte @@ -23,8 +24,8 @@ type WriteEvent struct { // WrittenEvent is a WriteEvent reported with a resource version. type WrittenEvent struct { - Type WatchEvent_Type - Key *ResourceKey + Type resourcepb.WatchEvent_Type + Key *resourcepb.ResourceKey PreviousRV int64 // The json payload (without resourceVersion) diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 8513363100b..51fed757730 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -7,6 +7,7 @@ replace ( github.com/grafana/grafana/apps/folder => ../../../../apps/folder github.com/grafana/grafana/pkg/apimachinery => ../../../apimachinery github.com/grafana/grafana/pkg/apiserver => ../../../apiserver + github.com/grafana/grafana/pkg/storage/unified/resourcepb => ../resourcepb ) require ( @@ -21,6 +22,7 @@ require ( github.com/grafana/grafana/apps/dashboard v0.0.0-20250422074709-7c8433fbb2c2 github.com/grafana/grafana/apps/folder v0.0.0-20250422074709-7c8433fbb2c2 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250422074709-7c8433fbb2c2 + github.com/grafana/grafana/pkg/storage/unified/resourcepb v0.0.0-00010101000000-000000000000 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 github.com/hashicorp/golang-lru/v2 v2.0.7 @@ -30,8 +32,7 @@ require ( go.opentelemetry.io/otel/trace v1.35.0 gocloud.dev v0.40.0 golang.org/x/sync v0.14.0 - google.golang.org/grpc v1.72.0 - google.golang.org/protobuf v1.36.6 + google.golang.org/grpc v1.72.1 k8s.io/apimachinery v0.32.3 ) @@ -232,6 +233,7 @@ require ( google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index e83af3671ad..5e00b4b29dd 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -850,8 +850,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/storage/unified/resource/health.go b/pkg/storage/unified/resource/health.go index bb55864ce7f..0f787d62bb3 100644 --- a/pkg/storage/unified/resource/health.go +++ b/pkg/storage/unified/resource/health.go @@ -7,6 +7,8 @@ import ( grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth" "google.golang.org/grpc/health/grpc_health_v1" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // Compile-time assertion @@ -17,13 +19,13 @@ type HealthService interface { grpcAuth.ServiceAuthFuncOverride } -func ProvideHealthService(server DiagnosticsServer) (grpc_health_v1.HealthServer, error) { +func ProvideHealthService(server resourcepb.DiagnosticsServer) (grpc_health_v1.HealthServer, error) { h := &healthServer{srv: server} return h, nil } type healthServer struct { - srv DiagnosticsServer + srv resourcepb.DiagnosticsServer } // AuthFuncOverride for no auth for health service. @@ -45,8 +47,8 @@ func (s *healthServer) List(ctx context.Context, req *grpc_health_v1.HealthListR }, nil } -func (s *healthServer) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { - r, err := s.srv.IsHealthy(ctx, &HealthCheckRequest{}) +func (s *healthServer) Check(ctx context.Context, _ *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { + r, err := s.srv.IsHealthy(ctx, &resourcepb.HealthCheckRequest{}) if err != nil { return nil, err } @@ -56,8 +58,8 @@ func (s *healthServer) Check(ctx context.Context, req *grpc_health_v1.HealthChec }, nil } -func (s *healthServer) Watch(req *grpc_health_v1.HealthCheckRequest, stream grpc_health_v1.Health_WatchServer) error { - h, err := s.srv.IsHealthy(stream.Context(), &HealthCheckRequest{}) +func (s *healthServer) Watch(_ *grpc_health_v1.HealthCheckRequest, stream grpc_health_v1.Health_WatchServer) error { + h, err := s.srv.IsHealthy(stream.Context(), &resourcepb.HealthCheckRequest{}) if err != nil { return err } @@ -77,7 +79,7 @@ func (s *healthServer) Watch(req *grpc_health_v1.HealthCheckRequest, stream grpc select { case <-ticker.C: // get current health status - h, err := s.srv.IsHealthy(stream.Context(), &HealthCheckRequest{}) + h, err := s.srv.IsHealthy(stream.Context(), &resourcepb.HealthCheckRequest{}) if err != nil { return err } diff --git a/pkg/storage/unified/resource/health_test.go b/pkg/storage/unified/resource/health_test.go index 4aebcbb1fe5..ee26e01b8f3 100644 --- a/pkg/storage/unified/resource/health_test.go +++ b/pkg/storage/unified/resource/health_test.go @@ -3,7 +3,7 @@ package resource import ( "context" "errors" - sync "sync" + "sync" "testing" "time" @@ -11,11 +11,13 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/health/grpc_health_v1" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestHealthCheck(t *testing.T) { t.Run("will return serving response when healthy", func(t *testing.T) { - stub := &diag{healthResponse: HealthCheckResponse_SERVING} + stub := &diag{healthResponse: resourcepb.HealthCheckResponse_SERVING} svc, err := ProvideHealthService(stub) require.NoError(t, err) @@ -27,7 +29,7 @@ func TestHealthCheck(t *testing.T) { }) t.Run("will return not serving response when not healthy", func(t *testing.T) { - stub := &diag{healthResponse: HealthCheckResponse_NOT_SERVING} + stub := &diag{healthResponse: resourcepb.HealthCheckResponse_NOT_SERVING} svc, err := ProvideHealthService(stub) require.NoError(t, err) @@ -41,7 +43,7 @@ func TestHealthCheck(t *testing.T) { func TestHealthWatch(t *testing.T) { t.Run("watch will return message when called", func(t *testing.T) { - stub := &diag{healthResponse: HealthCheckResponse_SERVING} + stub := &diag{healthResponse: resourcepb.HealthCheckResponse_SERVING} svc, err := ProvideHealthService(stub) require.NoError(t, err) @@ -58,7 +60,7 @@ func TestHealthWatch(t *testing.T) { }) t.Run("watch will return error when context cancelled", func(t *testing.T) { - stub := &diag{healthResponse: HealthCheckResponse_NOT_SERVING} + stub := &diag{healthResponse: resourcepb.HealthCheckResponse_NOT_SERVING} svc, err := ProvideHealthService(stub) require.NoError(t, err) @@ -72,19 +74,19 @@ func TestHealthWatch(t *testing.T) { }) } -var _ DiagnosticsServer = &diag{} +var _ resourcepb.DiagnosticsServer = &diag{} type diag struct { - healthResponse HealthCheckResponse_ServingStatus + healthResponse resourcepb.HealthCheckResponse_ServingStatus error error } -func (s *diag) IsHealthy(ctx context.Context, req *HealthCheckRequest) (*HealthCheckResponse, error) { +func (s *diag) IsHealthy(ctx context.Context, req *resourcepb.HealthCheckRequest) (*resourcepb.HealthCheckResponse, error) { if s.error != nil { return nil, s.error } - return &HealthCheckResponse{Status: s.healthResponse}, nil + return &resourcepb.HealthCheckResponse{Status: s.healthResponse}, nil } type fakeHealthWatchServer struct { diff --git a/pkg/storage/unified/resource/keys.go b/pkg/storage/unified/resource/keys.go index 80e8fe21f1f..8922ab3e5ec 100644 --- a/pkg/storage/unified/resource/keys.go +++ b/pkg/storage/unified/resource/keys.go @@ -3,9 +3,11 @@ package resource import ( "fmt" "strings" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) -func verifyRequestKey(key *ResourceKey) *ErrorResult { +func verifyRequestKey(key *resourcepb.ResourceKey) *resourcepb.ErrorResult { if key == nil { return NewBadRequestError("missing resource key") } @@ -18,7 +20,7 @@ func verifyRequestKey(key *ResourceKey) *ErrorResult { return nil } -func matchesQueryKey(query *ResourceKey, key *ResourceKey) bool { +func matchesQueryKey(query *resourcepb.ResourceKey, key *resourcepb.ResourceKey) bool { if query.Group != key.Group { return false } @@ -37,7 +39,7 @@ func matchesQueryKey(query *ResourceKey, key *ResourceKey) bool { const clusterNamespace = "**cluster**" // Convert the key to a search ID string -func (x *ResourceKey) SearchID() string { +func SearchID(x *resourcepb.ResourceKey) string { var sb strings.Builder if x.Namespace == "" { sb.WriteString(clusterNamespace) @@ -55,7 +57,7 @@ func (x *ResourceKey) SearchID() string { return sb.String() } -func (x *ResourceKey) ReadSearchID(v string) error { +func ReadSearchID(x *resourcepb.ResourceKey, v string) error { parts := strings.Split(v, "/") if len(parts) < 3 { return fmt.Errorf("invalid search id (expecting 3 slashes)") @@ -75,7 +77,7 @@ func (x *ResourceKey) ReadSearchID(v string) error { } // The namespace/group/resource -func (x *ResourceKey) NSGR() string { +func NSGR(x *resourcepb.ResourceKey) string { var sb strings.Builder if x.Namespace == "" { sb.WriteString(clusterNamespace) diff --git a/pkg/storage/unified/resource/keys_test.go b/pkg/storage/unified/resource/keys_test.go index 96d4da3555b..d14c03fcc95 100644 --- a/pkg/storage/unified/resource/keys_test.go +++ b/pkg/storage/unified/resource/keys_test.go @@ -4,15 +4,17 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestKeyMatching(t *testing.T) { t.Run("key matching", func(t *testing.T) { - require.True(t, matchesQueryKey(&ResourceKey{ + require.True(t, matchesQueryKey(&resourcepb.ResourceKey{ Group: "ggg", Resource: "rrr", Namespace: "ns", - }, &ResourceKey{ + }, &resourcepb.ResourceKey{ Group: "ggg", Resource: "rrr", Namespace: "ns", @@ -23,32 +25,32 @@ func TestKeyMatching(t *testing.T) { func TestSearchIDKeys(t *testing.T) { tests := []struct { input string - expected *ResourceKey // nil error + expected *resourcepb.ResourceKey // nil error }{ {input: "a"}, // error {input: "default/group/resource/name", - expected: &ResourceKey{ + expected: &resourcepb.ResourceKey{ Namespace: "default", Group: "group", Resource: "resource", Name: "name", }}, {input: "/group/resource/", - expected: &ResourceKey{ + expected: &resourcepb.ResourceKey{ Namespace: "", Group: "group", Resource: "resource", Name: "", }}, {input: "default/group/resource", - expected: &ResourceKey{ + expected: &resourcepb.ResourceKey{ Namespace: "default", Group: "group", Resource: "resource", Name: "", }}, {input: "**cluster**/group/resource/aaa", // cluster namespace - expected: &ResourceKey{ + expected: &resourcepb.ResourceKey{ Namespace: "", Group: "group", Resource: "resource", @@ -57,8 +59,8 @@ func TestSearchIDKeys(t *testing.T) { } for _, test := range tests { - tmp := &ResourceKey{} - err := tmp.ReadSearchID(test.input) + tmp := &resourcepb.ResourceKey{} + err := ReadSearchID(tmp, test.input) if err == nil { require.Equal(t, test.expected, tmp, test.input) } diff --git a/pkg/storage/unified/resource/migrations.go b/pkg/storage/unified/resource/migrations.go index 1dd8b27e3c7..0d7a048261a 100644 --- a/pkg/storage/unified/resource/migrations.go +++ b/pkg/storage/unified/resource/migrations.go @@ -4,19 +4,21 @@ import ( "fmt" "github.com/grafana/grafana-app-sdk/logging" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // MigrateVersionMatch handles backwards compatibility for ResourceVersionMatch // by migrating from the deprecated version_match to version_match_v2. // It returns an error if the version match is unknown. -func MigrateListRequestVersionMatch(req *ListRequest, logger logging.Logger) error { - if req.VersionMatch != nil && req.GetVersionMatchV2() == ResourceVersionMatchV2_UNKNOWN { +func MigrateListRequestVersionMatch(req *resourcepb.ListRequest, logger logging.Logger) error { + if req.VersionMatch != nil && req.GetVersionMatchV2() == resourcepb.ResourceVersionMatchV2_UNKNOWN { switch req.GetVersionMatch() { - case ResourceVersionMatch_DEPRECATED_NotOlderThan: + case resourcepb.ResourceVersionMatch_DEPRECATED_NotOlderThan: // This is not a typo. The old implementation actually did behave like Unset. - req.VersionMatchV2 = ResourceVersionMatchV2_Unset - case ResourceVersionMatch_DEPRECATED_Exact: - req.VersionMatchV2 = ResourceVersionMatchV2_Exact + req.VersionMatchV2 = resourcepb.ResourceVersionMatchV2_Unset + case resourcepb.ResourceVersionMatch_DEPRECATED_Exact: + req.VersionMatchV2 = resourcepb.ResourceVersionMatchV2_Exact default: return fmt.Errorf("unknown version match: %v", req.GetVersionMatch()) } diff --git a/pkg/storage/unified/resource/noop.go b/pkg/storage/unified/resource/noop.go index 8d4d1350b6c..b3e0d19e452 100644 --- a/pkg/storage/unified/resource/noop.go +++ b/pkg/storage/unified/resource/noop.go @@ -2,11 +2,13 @@ package resource import ( "context" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var ( - _ DiagnosticsServer = (*noopService)(nil) - _ LifecycleHooks = (*noopService)(nil) + _ resourcepb.DiagnosticsServer = (*noopService)(nil) + _ LifecycleHooks = (*noopService)(nil) ) // noopService is a helper implementation to simplify tests @@ -24,12 +26,12 @@ func (n *noopService) Stop(context.Context) error { } // IsHealthy implements DiagnosticsServer -func (n *noopService) IsHealthy(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) { - return &HealthCheckResponse{ - Status: HealthCheckResponse_SERVING, +func (n *noopService) IsHealthy(context.Context, *resourcepb.HealthCheckRequest) (*resourcepb.HealthCheckResponse, error) { + return &resourcepb.HealthCheckResponse{ + Status: resourcepb.HealthCheckResponse_SERVING, }, nil } -func (n *noopService) Read(context.Context, *ReadRequest) (*ReadResponse, error) { +func (n *noopService) Read(context.Context, *resourcepb.ReadRequest) (*resourcepb.ReadResponse, error) { return nil, ErrNotImplementedYet } diff --git a/pkg/storage/unified/resource/search.go b/pkg/storage/unified/resource/search.go index ad1b982d93a..eacebd0d5d8 100644 --- a/pkg/storage/unified/resource/search.go +++ b/pkg/storage/unified/resource/search.go @@ -17,8 +17,10 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "github.com/grafana/authlib/types" + dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) const maxBatchSize = 1000 @@ -43,8 +45,8 @@ const ( type BulkIndexItem struct { Action IndexAction - Key *ResourceKey // Only used for delete actions - Doc *IndexableDocument // Only used for index actions + Key *resourcepb.ResourceKey // Only used for delete actions + Doc *IndexableDocument // Only used for index actions } type BulkIndexRequest struct { @@ -59,13 +61,13 @@ type ResourceIndex interface { // Search within a namespaced resource // When working with federated queries, the additional indexes will be passed in explicitly - Search(ctx context.Context, access types.AccessClient, req *ResourceSearchRequest, federate []ResourceIndex) (*ResourceSearchResponse, error) + Search(ctx context.Context, access types.AccessClient, req *resourcepb.ResourceSearchRequest, federate []ResourceIndex) (*resourcepb.ResourceSearchResponse, error) // List within an response - ListManagedObjects(ctx context.Context, req *ListManagedObjectsRequest) (*ListManagedObjectsResponse, error) + ListManagedObjects(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) // Counts the values in a repo - CountManagedObjects(ctx context.Context) ([]*CountManagedObjectsResponse_ResourceCount, error) + CountManagedObjects(ctx context.Context) ([]*resourcepb.CountManagedObjectsResponse_ResourceCount, error) // Get the number of documents in the index DocCount(ctx context.Context, folder string) (int64, error) @@ -122,8 +124,8 @@ type searchSupport struct { } var ( - _ ResourceIndexServer = (*searchSupport)(nil) - _ ManagedObjectIndexServer = (*searchSupport)(nil) + _ resourcepb.ResourceIndexServer = (*searchSupport)(nil) + _ resourcepb.ManagedObjectIndexServer = (*searchSupport)(nil) ) func newSearchSupport(opts SearchOptions, storage StorageBackend, access types.AccessClient, blob BlobSupport, tracer trace.Tracer, indexMetrics *BleveIndexMetrics) (support *searchSupport, err error) { @@ -166,14 +168,14 @@ func newSearchSupport(opts SearchOptions, storage StorageBackend, access types.A return support, err } -func (s *searchSupport) ListManagedObjects(ctx context.Context, req *ListManagedObjectsRequest) (*ListManagedObjectsResponse, error) { +func (s *searchSupport) ListManagedObjects(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { if req.NextPageToken != "" { - return &ListManagedObjectsResponse{ + return &resourcepb.ListManagedObjectsResponse{ Error: NewBadRequestError("multiple pages not yet supported"), }, nil } - rsp := &ListManagedObjectsResponse{} + rsp := &resourcepb.ListManagedObjectsResponse{} stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0) if err != nil { rsp.Error = AsErrorResult(err) @@ -197,7 +199,7 @@ func (s *searchSupport) ListManagedObjects(ctx context.Context, req *ListManaged return rsp, nil } if kind.NextPageToken != "" { - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Message: "Multiple pages are not yet supported", } return rsp, nil @@ -206,15 +208,15 @@ func (s *searchSupport) ListManagedObjects(ctx context.Context, req *ListManaged } // Sort based on path - slices.SortFunc(rsp.Items, func(a, b *ListManagedObjectsResponse_Item) int { + slices.SortFunc(rsp.Items, func(a, b *resourcepb.ListManagedObjectsResponse_Item) int { return cmp.Compare(a.Path, b.Path) }) return rsp, nil } -func (s *searchSupport) CountManagedObjects(ctx context.Context, req *CountManagedObjectsRequest) (*CountManagedObjectsResponse, error) { - rsp := &CountManagedObjectsResponse{} +func (s *searchSupport) CountManagedObjects(ctx context.Context, req *resourcepb.CountManagedObjectsRequest) (*resourcepb.CountManagedObjectsResponse, error) { + rsp := &resourcepb.CountManagedObjectsResponse{} stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0) if err != nil { rsp.Error = AsErrorResult(err) @@ -249,7 +251,7 @@ func (s *searchSupport) CountManagedObjects(ctx context.Context, req *CountManag } // Sort based on manager/group/resource - slices.SortFunc(rsp.Items, func(a, b *CountManagedObjectsResponse_ResourceCount) int { + slices.SortFunc(rsp.Items, func(a, b *resourcepb.CountManagedObjectsResponse_ResourceCount) int { return cmp.Or( cmp.Compare(a.Kind, b.Kind), cmp.Compare(a.Id, b.Id), @@ -262,7 +264,7 @@ func (s *searchSupport) CountManagedObjects(ctx context.Context, req *CountManag } // Search implements ResourceIndexServer. -func (s *searchSupport) Search(ctx context.Context, req *ResourceSearchRequest) (*ResourceSearchResponse, error) { +func (s *searchSupport) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { ctx, span := s.tracer.Start(ctx, tracingPrexfixSearch+"Search") defer span.End() @@ -273,7 +275,7 @@ func (s *searchSupport) Search(ctx context.Context, req *ResourceSearchRequest) } idx, err := s.getOrCreateIndex(ctx, nsr) if err != nil { - return &ResourceSearchResponse{ + return &resourcepb.ResourceSearchResponse{ Error: AsErrorResult(err), }, nil } @@ -285,7 +287,7 @@ func (s *searchSupport) Search(ctx context.Context, req *ResourceSearchRequest) nsr.Resource = f.Resource federate[i], err = s.getOrCreateIndex(ctx, nsr) if err != nil { - return &ResourceSearchResponse{ + return &resourcepb.ResourceSearchResponse{ Error: AsErrorResult(err), }, nil } @@ -295,17 +297,17 @@ func (s *searchSupport) Search(ctx context.Context, req *ResourceSearchRequest) } // GetStats implements ResourceServer. -func (s *searchSupport) GetStats(ctx context.Context, req *ResourceStatsRequest) (*ResourceStatsResponse, error) { +func (s *searchSupport) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest) (*resourcepb.ResourceStatsResponse, error) { if req.Namespace == "" { - return &ResourceStatsResponse{ + return &resourcepb.ResourceStatsResponse{ Error: NewBadRequestError("missing namespace"), }, nil } - rsp := &ResourceStatsResponse{} + rsp := &resourcepb.ResourceStatsResponse{} // Explicit list of kinds if len(req.Kinds) > 0 { - rsp.Stats = make([]*ResourceStatsResponse_Stats, len(req.Kinds)) + rsp.Stats = make([]*resourcepb.ResourceStatsResponse_Stats, len(req.Kinds)) for i, k := range req.Kinds { parts := strings.SplitN(k, "/", 2) index, err := s.getOrCreateIndex(ctx, NamespacedResource{ @@ -322,7 +324,7 @@ func (s *searchSupport) GetStats(ctx context.Context, req *ResourceStatsRequest) rsp.Error = AsErrorResult(err) return rsp, nil } - rsp.Stats[i] = &ResourceStatsResponse_Stats{ + rsp.Stats[i] = &resourcepb.ResourceStatsResponse_Stats{ Group: parts[0], Resource: parts[1], Count: count, @@ -333,16 +335,16 @@ func (s *searchSupport) GetStats(ctx context.Context, req *ResourceStatsRequest) stats, err := s.storage.GetResourceStats(ctx, req.Namespace, 0) if err != nil { - return &ResourceStatsResponse{ + return &resourcepb.ResourceStatsResponse{ Error: AsErrorResult(err), }, nil } - rsp.Stats = make([]*ResourceStatsResponse_Stats, len(stats)) + rsp.Stats = make([]*resourcepb.ResourceStatsResponse_Stats, len(stats)) // When not filtered by folder or repository, we can use the results directly if req.Folder == "" { for i, stat := range stats { - rsp.Stats[i] = &ResourceStatsResponse_Stats{ + rsp.Stats[i] = &resourcepb.ResourceStatsResponse_Stats{ Group: stat.Group, Resource: stat.Resource, Count: stat.Count, @@ -366,7 +368,7 @@ func (s *searchSupport) GetStats(ctx context.Context, req *ResourceStatsRequest) rsp.Error = AsErrorResult(err) return rsp, nil } - rsp.Stats[i] = &ResourceStatsResponse_Stats{ + rsp.Stats[i] = &resourcepb.ResourceStatsResponse_Stats{ Group: stat.Group, Resource: stat.Resource, Count: count, @@ -450,7 +452,7 @@ func (s *searchSupport) dispatchEvent(ctx context.Context, evt *WrittenEvent) { ) switch evt.Type { - case WatchEvent_ADDED, WatchEvent_MODIFIED, WatchEvent_DELETED: // OK + case resourcepb.WatchEvent_ADDED, resourcepb.WatchEvent_MODIFIED, resourcepb.WatchEvent_DELETED: // OK default: s.log.Info("ignoring watch event", "type", evt.Type) span.AddEvent("ignoring watch event", trace.WithAttributes(attribute.String("type", evt.Type.String()))) @@ -547,10 +549,10 @@ func (s *searchSupport) build(ctx context.Context, nsr NamespacedResource, size s.log.Debug("Building index", "resource", nsr.Resource, "size", size, "rv", rv) index, err := s.search.BuildIndex(ctx, nsr, size, rv, fields, func(index ResourceIndex) (int64, error) { - rv, err = s.storage.ListIterator(ctx, &ListRequest{ + rv, err = s.storage.ListIterator(ctx, &resourcepb.ListRequest{ Limit: 1000000000000, // big number - Options: &ListOptions{ - Key: &ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: nsr.Group, Resource: nsr.Resource, Namespace: nsr.Namespace, @@ -566,7 +568,7 @@ func (s *searchSupport) build(ctx context.Context, nsr NamespacedResource, size } // Update the key name - key := &ResourceKey{ + key := &resourcepb.ResourceKey{ Group: nsr.Group, Resource: nsr.Resource, Namespace: nsr.Namespace, @@ -576,7 +578,7 @@ func (s *searchSupport) build(ctx context.Context, nsr NamespacedResource, size // Convert it to an indexable document doc, err := builder.BuildDocument(ctx, key, iter.ResourceVersion(), iter.Value()) if err != nil { - s.log.Error("error building search document", "key", key.SearchID(), "err", err) + s.log.Error("error building search document", "key", SearchID(key), "err", err) continue } @@ -703,19 +705,19 @@ func (s *builderCache) get(ctx context.Context, key NamespacedResource) (Documen } // AsResourceKey converts the given namespace and type to a search key -func AsResourceKey(ns string, t string) (*ResourceKey, error) { +func AsResourceKey(ns string, t string) (*resourcepb.ResourceKey, error) { if ns == "" { return nil, fmt.Errorf("missing namespace") } switch t { case "folders", "folder": - return &ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: ns, Group: folders.GROUP, Resource: folders.RESOURCE, }, nil case "dashboards", "dashboard": - return &ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: ns, Group: dashboardv1.GROUP, Resource: dashboardv1.DASHBOARD_RESOURCE, @@ -723,7 +725,7 @@ func AsResourceKey(ns string, t string) (*ResourceKey, error) { // NOT really supported in the dashboard search UI, but useful for manual testing case "playlist", "playlists": - return &ResourceKey{ + return &resourcepb.ResourceKey{ Namespace: ns, Group: "playlist.grafana.app", Resource: "playlists", diff --git a/pkg/storage/unified/resource/search_client.go b/pkg/storage/unified/resource/search_client.go index cf94ed29fb5..5679711e9e3 100644 --- a/pkg/storage/unified/resource/search_client.go +++ b/pkg/storage/unified/resource/search_client.go @@ -5,6 +5,8 @@ import ( "google.golang.org/grpc" "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) type DualWriter interface { @@ -12,7 +14,8 @@ type DualWriter interface { ReadFromUnified(context.Context, schema.GroupResource) (bool, error) } -func NewSearchClient(dual DualWriter, gr schema.GroupResource, unifiedClient ResourceIndexClient, legacyClient ResourceIndexClient) ResourceIndexClient { +func NewSearchClient(dual DualWriter, gr schema.GroupResource, unifiedClient resourcepb.ResourceIndexClient, + legacyClient resourcepb.ResourceIndexClient) resourcepb.ResourceIndexClient { if dual.IsEnabled(gr) { return &searchWrapper{ dual: dual, @@ -32,11 +35,12 @@ type searchWrapper struct { dual DualWriter groupResource schema.GroupResource - unifiedClient ResourceIndexClient - legacyClient ResourceIndexClient + unifiedClient resourcepb.ResourceIndexClient + legacyClient resourcepb.ResourceIndexClient } -func (s *searchWrapper) GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error) { +func (s *searchWrapper) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, + opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { client := s.legacyClient unified, err := s.dual.ReadFromUnified(ctx, s.groupResource) if err != nil { @@ -48,7 +52,8 @@ func (s *searchWrapper) GetStats(ctx context.Context, in *ResourceStatsRequest, return client.GetStats(ctx, in, opts...) } -func (s *searchWrapper) Search(ctx context.Context, in *ResourceSearchRequest, opts ...grpc.CallOption) (*ResourceSearchResponse, error) { +func (s *searchWrapper) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, + opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { client := s.legacyClient unified, err := s.dual.ReadFromUnified(ctx, s.groupResource) if err != nil { diff --git a/pkg/storage/unified/resource/search_queue.go b/pkg/storage/unified/resource/search_queue.go index 71da4c04434..08f3e5eeac4 100644 --- a/pkg/storage/unified/resource/search_queue.go +++ b/pkg/storage/unified/resource/search_queue.go @@ -4,6 +4,8 @@ import ( "context" "sync" "time" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // indexQueueProcessor manages queue-based operations for a specific index @@ -108,7 +110,7 @@ func (b *indexQueueProcessor) process(batch []*WrittenEvent) { resp = append(resp, result) item := &BulkIndexItem{} - if evt.Type == WatchEvent_DELETED { + if evt.Type == resourcepb.WatchEvent_DELETED { item.Action = ActionDelete item.Key = evt.Key } else { diff --git a/pkg/storage/unified/resource/search_queue_test.go b/pkg/storage/unified/resource/search_queue_test.go index 9e19ea501cf..2c465a6ffef 100644 --- a/pkg/storage/unified/resource/search_queue_test.go +++ b/pkg/storage/unified/resource/search_queue_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestNewIndexQueueProcessor(t *testing.T) { @@ -32,11 +34,11 @@ func TestIndexQueueProcessor_SingleEvent(t *testing.T) { processor := newIndexQueueProcessor(mockIndex, nsr, 10, mockBuilder, resChan) // Test data - key := ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"} + key := resourcepb.ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"} evt := &WrittenEvent{ Key: &key, ResourceVersion: time.Now().UnixMicro(), - Type: WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Value: []byte(`{"test": "data"}`), } @@ -70,15 +72,15 @@ func TestIndexQueueProcessor_BatchProcessing(t *testing.T) { // Test data for two events events := []*WrittenEvent{ { - Key: &ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"}, + Key: &resourcepb.ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"}, ResourceVersion: time.Now().UnixMicro(), - Type: WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Value: []byte(`{"test": "data1"}`), }, { - Key: &ResourceKey{Resource: "test", Name: "obj2", Namespace: "default"}, + Key: &resourcepb.ResourceKey{Resource: "test", Name: "obj2", Namespace: "default"}, ResourceVersion: time.Now().UnixMicro(), - Type: WatchEvent_DELETED, + Type: resourcepb.WatchEvent_DELETED, }, } @@ -117,9 +119,9 @@ func TestIndexQueueProcessor_BuildDocumentError(t *testing.T) { processor := newIndexQueueProcessor(mockIndex, nsr, 10, mockBuilder, resChan) evt := &WrittenEvent{ - Key: &ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"}, + Key: &resourcepb.ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"}, ResourceVersion: time.Now().UnixMicro(), - Type: WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Value: []byte(`invalid json`), } @@ -151,9 +153,9 @@ func TestIndexQueueProcessor_BulkIndexError(t *testing.T) { processor := newIndexQueueProcessor(mockIndex, nsr, 10, mockBuilder, resChan) evt := &WrittenEvent{ - Key: &ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"}, + Key: &resourcepb.ResourceKey{Resource: "test", Name: "obj1", Namespace: "default"}, ResourceVersion: time.Now().UnixMicro(), - Type: WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Value: []byte(`{"test": "data"}`), } diff --git a/pkg/storage/unified/resource/search_test.go b/pkg/storage/unified/resource/search_test.go index 1f7d253002c..0ae694445b5 100644 --- a/pkg/storage/unified/resource/search_test.go +++ b/pkg/storage/unified/resource/search_test.go @@ -5,6 +5,8 @@ import ( "github.com/grafana/authlib/types" "github.com/stretchr/testify/mock" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var _ ResourceIndex = &MockResourceIndex{} @@ -19,14 +21,14 @@ func (m *MockResourceIndex) BulkIndex(req *BulkIndexRequest) error { return args.Error(0) } -func (m *MockResourceIndex) Search(ctx context.Context, access types.AccessClient, req *ResourceSearchRequest, federate []ResourceIndex) (*ResourceSearchResponse, error) { +func (m *MockResourceIndex) Search(ctx context.Context, access types.AccessClient, req *resourcepb.ResourceSearchRequest, federate []ResourceIndex) (*resourcepb.ResourceSearchResponse, error) { args := m.Called(ctx, access, req, federate) - return args.Get(0).(*ResourceSearchResponse), args.Error(1) + return args.Get(0).(*resourcepb.ResourceSearchResponse), args.Error(1) } -func (m *MockResourceIndex) CountManagedObjects(ctx context.Context) ([]*CountManagedObjectsResponse_ResourceCount, error) { +func (m *MockResourceIndex) CountManagedObjects(ctx context.Context) ([]*resourcepb.CountManagedObjectsResponse_ResourceCount, error) { args := m.Called(ctx) - return args.Get(0).([]*CountManagedObjectsResponse_ResourceCount), args.Error(1) + return args.Get(0).([]*resourcepb.CountManagedObjectsResponse_ResourceCount), args.Error(1) } func (m *MockResourceIndex) DocCount(ctx context.Context, folder string) (int64, error) { @@ -34,9 +36,9 @@ func (m *MockResourceIndex) DocCount(ctx context.Context, folder string) (int64, return args.Get(0).(int64), args.Error(1) } -func (m *MockResourceIndex) ListManagedObjects(ctx context.Context, req *ListManagedObjectsRequest) (*ListManagedObjectsResponse, error) { +func (m *MockResourceIndex) ListManagedObjects(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { args := m.Called(ctx, req) - return args.Get(0).(*ListManagedObjectsResponse), args.Error(1) + return args.Get(0).(*resourcepb.ListManagedObjectsResponse), args.Error(1) } var _ DocumentBuilder = &MockDocumentBuilder{} @@ -45,7 +47,7 @@ type MockDocumentBuilder struct { mock.Mock } -func (m *MockDocumentBuilder) BuildDocument(ctx context.Context, key *ResourceKey, resourceVersion int64, value []byte) (*IndexableDocument, error) { +func (m *MockDocumentBuilder) BuildDocument(ctx context.Context, key *resourcepb.ResourceKey, resourceVersion int64, value []byte) (*IndexableDocument, error) { args := m.Called(ctx, key, resourceVersion, value) if args.Get(0) == nil { return nil, args.Error(1) diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 3eb15c0e2d8..43a84e04e46 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -24,17 +24,19 @@ import ( "github.com/grafana/dskit/ring" ringclient "github.com/grafana/dskit/ring/client" userutils "github.com/grafana/dskit/user" + "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // ResourceServer implements all gRPC services type ResourceServer interface { - ResourceStoreServer - BulkStoreServer - ResourceIndexServer - ManagedObjectIndexServer - BlobStoreServer - DiagnosticsServer + resourcepb.ResourceStoreServer + resourcepb.BulkStoreServer + resourcepb.ResourceIndexServer + resourcepb.ManagedObjectIndexServer + resourcepb.BlobStoreServer + resourcepb.DiagnosticsServer } type ListIterator interface { @@ -73,7 +75,7 @@ type ListIterator interface { type BackendReadResponse struct { // Metadata - Key *ResourceKey + Key *resourcepb.ResourceKey Folder string // GUID that is used internally @@ -83,7 +85,7 @@ type BackendReadResponse struct { // The properties Value []byte // Error details - Error *ErrorResult + Error *resourcepb.ErrorResult } // The StorageBackend is an internal abstraction that supports interacting with @@ -96,14 +98,14 @@ type StorageBackend interface { WriteEvent(context.Context, WriteEvent) (int64, error) // Read a resource from storage optionally at an explicit version - ReadResource(context.Context, *ReadRequest) *BackendReadResponse + ReadResource(context.Context, *resourcepb.ReadRequest) *BackendReadResponse // When the ResourceServer executes a List request, this iterator will // query the backend for potential results. All results will be // checked against the kubernetes requirements before finally returning // results. The list options can be used to improve performance // but are the the final answer. - ListIterator(context.Context, *ListRequest, func(ListIterator) error) (int64, error) + ListIterator(context.Context, *resourcepb.ListRequest, func(ListIterator) error) (int64, error) // Get all events from the store // For HA setups, this will be more events than the local WriteEvent above! @@ -128,11 +130,11 @@ type BlobSupport interface { // Get the raw blob bytes and metadata -- limited to protobuf message size // For larger payloads, we should use presigned URLs to upload from the client - PutResourceBlob(context.Context, *PutBlobRequest) (*PutBlobResponse, error) + PutResourceBlob(context.Context, *resourcepb.PutBlobRequest) (*resourcepb.PutBlobResponse, error) // Get blob contents. When possible, this will return a signed URL // For large payloads, signed URLs are required to avoid protobuf message size limits - GetResourceBlob(ctx context.Context, resource *ResourceKey, info *utils.BlobInfo, mustProxy bool) (*GetBlobResponse, error) + GetResourceBlob(ctx context.Context, resource *resourcepb.ResourceKey, info *utils.BlobInfo, mustProxy bool) (*resourcepb.GetBlobResponse, error) // TODO? List+Delete? This is for admin access } @@ -177,7 +179,7 @@ type ResourceServerOptions struct { Search SearchOptions // Diagnostics - Diagnostics DiagnosticsServer + Diagnostics resourcepb.DiagnosticsServer // Check if a user has access to write folders // When this is nil, no resources can have folders configured @@ -298,7 +300,7 @@ type server struct { backend StorageBackend blob BlobSupport search *searchSupport - diagnostics DiagnosticsServer + diagnostics resourcepb.DiagnosticsServer access claims.AccessClient writeHooks WriteAccessHooks lifecycle LifecycleHooks @@ -431,7 +433,7 @@ func (s *server) Stop(ctx context.Context) error { } // Old value indicates an update -- otherwise a create -func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *ResourceKey, value, oldValue []byte) (*WriteEvent, *ErrorResult) { +func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *resourcepb.ResourceKey, value, oldValue []byte) (*WriteEvent, *resourcepb.ErrorResult) { tmp := &unstructured.Unstructured{} err := tmp.UnmarshalJSON(value) if err != nil { @@ -470,9 +472,9 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *Resour } if oldValue == nil { - event.Type = WatchEvent_ADDED + event.Type = resourcepb.WatchEvent_ADDED } else { - event.Type = WatchEvent_MODIFIED + event.Type = resourcepb.WatchEvent_MODIFIED temp := &unstructured.Unstructured{} err = temp.UnmarshalJSON(oldValue) @@ -530,7 +532,7 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *Resour Namespace: key.Namespace, } - if event.Type == WatchEvent_MODIFIED { + if event.Type == resourcepb.WatchEvent_MODIFIED { check.Verb = utils.VerbUpdate check.Name = key.Name } @@ -541,7 +543,7 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *Resour return nil, AsErrorResult(err) } if !a.Allowed { - return nil, &ErrorResult{ + return nil, &resourcepb.ErrorResult{ Code: http.StatusForbidden, } } @@ -559,13 +561,13 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *Resour // isFolderMove determines if an event represents a resource being moved between folders func (s *server) isFolderMove(event *WriteEvent) bool { - return event.Type == WatchEvent_MODIFIED && + return event.Type == resourcepb.WatchEvent_MODIFIED && event.ObjectOld != nil && event.ObjectOld.GetFolder() != event.Object.GetFolder() } // checkFolderMovePermissions handles permission checks when a resource is being moved between folders -func (s *server) checkFolderMovePermissions(ctx context.Context, user claims.AuthInfo, key *ResourceKey, oldFolder, newFolder string) *ErrorResult { +func (s *server) checkFolderMovePermissions(ctx context.Context, user claims.AuthInfo, key *resourcepb.ResourceKey, oldFolder, newFolder string) *resourcepb.ErrorResult { // First check if user can update the resource in the original folder updateCheck := claims.CheckRequest{ Verb: utils.VerbUpdate, @@ -581,7 +583,7 @@ func (s *server) checkFolderMovePermissions(ctx context.Context, user claims.Aut return AsErrorResult(err) } if !a.Allowed { - return &ErrorResult{ + return &resourcepb.ErrorResult{ Code: http.StatusForbidden, Message: "not allowed to update resource in the source folder", } @@ -601,7 +603,7 @@ func (s *server) checkFolderMovePermissions(ctx context.Context, user claims.Aut return AsErrorResult(err) } if !a.Allowed { - return &ErrorResult{ + return &resourcepb.ErrorResult{ Code: http.StatusForbidden, Message: "not allowed to create resource in the destination folder", } @@ -610,14 +612,14 @@ func (s *server) checkFolderMovePermissions(ctx context.Context, user claims.Aut return nil } -func (s *server) Create(ctx context.Context, req *CreateRequest) (*CreateResponse, error) { +func (s *server) Create(ctx context.Context, req *resourcepb.CreateRequest) (*resourcepb.CreateResponse, error) { ctx, span := s.tracer.Start(ctx, "storage_server.Create") defer span.End() - rsp := &CreateResponse{} + rsp := &resourcepb.CreateResponse{} user, ok := claims.AuthInfoFrom(ctx) if !ok || user == nil { - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, } @@ -641,14 +643,14 @@ func (s *server) Create(ctx context.Context, req *CreateRequest) (*CreateRespons return rsp, nil } -func (s *server) Update(ctx context.Context, req *UpdateRequest) (*UpdateResponse, error) { +func (s *server) Update(ctx context.Context, req *resourcepb.UpdateRequest) (*resourcepb.UpdateResponse, error) { ctx, span := s.tracer.Start(ctx, "storage_server.Update") defer span.End() - rsp := &UpdateResponse{} + rsp := &resourcepb.UpdateResponse{} user, ok := claims.AuthInfoFrom(ctx) if !ok || user == nil { - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, } @@ -659,7 +661,7 @@ func (s *server) Update(ctx context.Context, req *UpdateRequest) (*UpdateRespons return rsp, nil } - latest := s.backend.ReadResource(ctx, &ReadRequest{ + latest := s.backend.ReadResource(ctx, &resourcepb.ReadRequest{ Key: req.Key, }) if latest.Error != nil { @@ -680,7 +682,7 @@ func (s *server) Update(ctx context.Context, req *UpdateRequest) (*UpdateRespons return rsp, nil } - event.Type = WatchEvent_MODIFIED + event.Type = resourcepb.WatchEvent_MODIFIED event.PreviousRV = latest.ResourceVersion var err error @@ -691,24 +693,24 @@ func (s *server) Update(ctx context.Context, req *UpdateRequest) (*UpdateRespons return rsp, nil } -func (s *server) Delete(ctx context.Context, req *DeleteRequest) (*DeleteResponse, error) { +func (s *server) Delete(ctx context.Context, req *resourcepb.DeleteRequest) (*resourcepb.DeleteResponse, error) { ctx, span := s.tracer.Start(ctx, "storage_server.Delete") defer span.End() - rsp := &DeleteResponse{} + rsp := &resourcepb.DeleteResponse{} if req.ResourceVersion < 0 { return nil, apierrors.NewBadRequest("update must include the previous version") } user, ok := claims.AuthInfoFrom(ctx) if !ok || user == nil { - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, } return rsp, nil } - latest := s.backend.ReadResource(ctx, &ReadRequest{ + latest := s.backend.ReadResource(ctx, &resourcepb.ReadRequest{ Key: req.Key, }) if latest.Error != nil { @@ -733,7 +735,7 @@ func (s *server) Delete(ctx context.Context, req *DeleteRequest) (*DeleteRespons return rsp, nil } if !access.Allowed { - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Code: http.StatusForbidden, } return rsp, nil @@ -742,7 +744,7 @@ func (s *server) Delete(ctx context.Context, req *DeleteRequest) (*DeleteRespons now := metav1.NewTime(time.UnixMilli(s.now())) event := WriteEvent{ Key: req.Key, - Type: WatchEvent_DELETED, + Type: resourcepb.WatchEvent_DELETED, PreviousRV: latest.ResourceVersion, } requester, ok := claims.AuthInfoFrom(ctx) @@ -779,11 +781,11 @@ func (s *server) Delete(ctx context.Context, req *DeleteRequest) (*DeleteRespons return rsp, nil } -func (s *server) Read(ctx context.Context, req *ReadRequest) (*ReadResponse, error) { +func (s *server) Read(ctx context.Context, req *resourcepb.ReadRequest) (*resourcepb.ReadResponse, error) { user, ok := claims.AuthInfoFrom(ctx) if !ok || user == nil { - return &ReadResponse{ - Error: &ErrorResult{ + return &resourcepb.ReadResponse{ + Error: &resourcepb.ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, }}, nil @@ -794,12 +796,12 @@ func (s *server) Read(ctx context.Context, req *ReadRequest) (*ReadResponse, err // return &ReadResponse{Status: status}, nil // } if req.Key.Resource == "" { - return &ReadResponse{Error: NewBadRequestError("missing resource")}, nil + return &resourcepb.ReadResponse{Error: NewBadRequestError("missing resource")}, nil } rsp := s.backend.ReadResource(ctx, req) if rsp.Error != nil && rsp.Error.Code == http.StatusNotFound { - return &ReadResponse{Error: rsp.Error}, nil + return &resourcepb.ReadResponse{Error: rsp.Error}, nil } a, err := s.access.Check(ctx, user, claims.CheckRequest{ @@ -811,29 +813,29 @@ func (s *server) Read(ctx context.Context, req *ReadRequest) (*ReadResponse, err Folder: rsp.Folder, }) if err != nil { - return &ReadResponse{Error: AsErrorResult(err)}, nil + return &resourcepb.ReadResponse{Error: AsErrorResult(err)}, nil } if !a.Allowed { - return &ReadResponse{ - Error: &ErrorResult{ + return &resourcepb.ReadResponse{ + Error: &resourcepb.ErrorResult{ Code: http.StatusForbidden, }}, nil } - return &ReadResponse{ + return &resourcepb.ReadResponse{ ResourceVersion: rsp.ResourceVersion, Value: rsp.Value, Error: rsp.Error, }, nil } -func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, error) { +func (s *server) List(ctx context.Context, req *resourcepb.ListRequest) (*resourcepb.ListResponse, error) { ctx, span := s.tracer.Start(ctx, "storage_server.List") defer span.End() // The history + trash queries do not yet support additional filters - if req.Source != ListRequest_STORE { + if req.Source != resourcepb.ListRequest_STORE { if len(req.Options.Fields) > 0 || len(req.Options.Labels) > 0 { - return &ListResponse{ + return &resourcepb.ListResponse{ Error: NewBadRequestError("unexpected field/label selector for history query"), }, nil } @@ -841,8 +843,8 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err user, ok := claims.AuthInfoFrom(ctx) if !ok || user == nil { - return &ListResponse{ - Error: &ErrorResult{ + return &resourcepb.ListResponse{ + Error: &resourcepb.ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, }}, nil @@ -851,7 +853,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err // Do not allow label query for trash/history for _, v := range req.Options.Labels { if v.Key == utils.LabelKeyGetHistory || v.Key == utils.LabelKeyGetTrash { - return &ListResponse{Error: NewBadRequestError("history and trash must be requested as source")}, nil + return &resourcepb.ListResponse{Error: NewBadRequestError("history and trash must be requested as source")}, nil } } @@ -860,7 +862,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err } maxPageBytes := 1024 * 1024 * 2 // 2mb/page pageBytes := 0 - rsp := &ListResponse{} + rsp := &resourcepb.ListResponse{} key := req.Options.Key checker, err := s.access.Compile(ctx, user, claims.ListRequest{ @@ -870,10 +872,10 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err Verb: utils.VerbGet, }) if err != nil { - return &ListResponse{Error: AsErrorResult(err)}, nil + return &resourcepb.ListResponse{Error: AsErrorResult(err)}, nil } if checker == nil { - return &ListResponse{Error: &ErrorResult{ + return &resourcepb.ListResponse{Error: &resourcepb.ErrorResult{ Code: http.StatusForbidden, }}, nil } @@ -884,7 +886,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err return err } - item := &ResourceWrapper{ + item := &resourcepb.ResourceWrapper{ ResourceVersion: iter.ResourceVersion(), Value: iter.Value(), } @@ -897,7 +899,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err rsp.Items = append(rsp.Items, item) if len(rsp.Items) >= int(req.Limit) || pageBytes >= maxPageBytes { t := iter.ContinueToken() - if req.Source == ListRequest_HISTORY || req.Source == ListRequest_TRASH { + if req.Source == resourcepb.ListRequest_HISTORY || req.Source == resourcepb.ListRequest_TRASH { // For history lists, we need to use the current RV in the continue token // to ensure consistent pagination. The order depends on VersionMatch: // - NotOlderThan: ascending order (oldest to newest) @@ -918,7 +920,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err } if rv < 1 { - rsp.Error = &ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Code: http.StatusInternalServerError, Message: fmt.Sprintf("invalid resource version for list: %v", rv), } @@ -957,7 +959,7 @@ func (s *server) initWatcher() error { } //nolint:gocyclo -func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { +func (s *server) Watch(req *resourcepb.WatchRequest, srv resourcepb.ResourceStore_WatchServer) error { ctx := srv.Context() user, ok := claims.AuthInfoFrom(ctx) @@ -999,14 +1001,14 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { var initialEventsRV int64 // resource version coming from the initial events if req.SendInitialEvents { // Backfill the stream by adding every existing entities. - initialEventsRV, err = s.backend.ListIterator(ctx, &ListRequest{Options: req.Options}, func(iter ListIterator) error { + initialEventsRV, err = s.backend.ListIterator(ctx, &resourcepb.ListRequest{Options: req.Options}, func(iter ListIterator) error { for iter.Next() { if err := iter.Error(); err != nil { return err } - if err := srv.Send(&WatchEvent{ - Type: WatchEvent_ADDED, - Resource: &WatchEvent_Resource{ + if err := srv.Send(&resourcepb.WatchEvent{ + Type: resourcepb.WatchEvent_ADDED, + Resource: &resourcepb.WatchEvent_Resource{ Value: iter.Value(), Version: iter.ResourceVersion(), }, @@ -1021,9 +1023,9 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { } } if req.SendInitialEvents && req.AllowWatchBookmarks { - if err := srv.Send(&WatchEvent{ - Type: WatchEvent_BOOKMARK, - Resource: &WatchEvent_Resource{ + if err := srv.Send(&resourcepb.WatchEvent{ + Type: resourcepb.WatchEvent_BOOKMARK, + Resource: &resourcepb.WatchEvent_Resource{ Version: initialEventsRV, }, }); err != nil { @@ -1058,19 +1060,19 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { value := event.Value // remove the delete marker stored in the value for deleted objects - if event.Type == WatchEvent_DELETED { + if event.Type == resourcepb.WatchEvent_DELETED { value = []byte{} } - resp := &WatchEvent{ + resp := &resourcepb.WatchEvent{ Timestamp: event.Timestamp, Type: event.Type, - Resource: &WatchEvent_Resource{ + Resource: &resourcepb.WatchEvent_Resource{ Value: value, Version: event.ResourceVersion, }, } if event.PreviousRV > 0 { - prevObj, err := s.Read(ctx, &ReadRequest{Key: event.Key, ResourceVersion: event.PreviousRV}) + prevObj, err := s.Read(ctx, &resourcepb.ReadRequest{Key: event.Key, ResourceVersion: event.PreviousRV}) if err != nil { // This scenario should never happen, but if it does, we should log it and continue // sending the event without the previous object. The client will decide what to do. @@ -1080,7 +1082,7 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { s.log.Error("resource version mismatch", "key", event.Key, "resource_version", event.PreviousRV, "actual", prevObj.ResourceVersion) return fmt.Errorf("resource version mismatch") } - resp.Previous = &WatchEvent_Resource{ + resp.Previous = &resourcepb.WatchEvent_Resource{ Value: prevObj.Value, Version: prevObj.ResourceVersion, } @@ -1102,7 +1104,7 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { } } -func (s *server) Search(ctx context.Context, req *ResourceSearchRequest) (*ResourceSearchResponse, error) { +func (s *server) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { if s.search == nil { return nil, fmt.Errorf("search index not configured") } @@ -1118,7 +1120,7 @@ func (s *server) Search(ctx context.Context, req *ResourceSearchRequest) (*Resou } // GetStats implements ResourceServer. -func (s *server) GetStats(ctx context.Context, req *ResourceStatsRequest) (*ResourceStatsResponse, error) { +func (s *server) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest) (*resourcepb.ResourceStatsResponse, error) { if err := s.Init(ctx); err != nil { return nil, err } @@ -1132,7 +1134,7 @@ func (s *server) GetStats(ctx context.Context, req *ResourceStatsRequest) (*Reso if s.search == nil { // If the backend implements "GetStats", we can use it - srv, ok := s.backend.(ResourceIndexServer) + srv, ok := s.backend.(resourcepb.ResourceIndexServer) if ok { return srv.GetStats(ctx, req) } @@ -1141,23 +1143,23 @@ func (s *server) GetStats(ctx context.Context, req *ResourceStatsRequest) (*Reso return s.search.GetStats(ctx, req) } -func (s *server) ListManagedObjects(ctx context.Context, req *ListManagedObjectsRequest) (*ListManagedObjectsResponse, error) { +func (s *server) ListManagedObjects(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { return s.search.ListManagedObjects(ctx, req) } -func (s *server) CountManagedObjects(ctx context.Context, req *CountManagedObjectsRequest) (*CountManagedObjectsResponse, error) { +func (s *server) CountManagedObjects(ctx context.Context, req *resourcepb.CountManagedObjectsRequest) (*resourcepb.CountManagedObjectsResponse, error) { return s.search.CountManagedObjects(ctx, req) } // IsHealthy implements ResourceServer. -func (s *server) IsHealthy(ctx context.Context, req *HealthCheckRequest) (*HealthCheckResponse, error) { +func (s *server) IsHealthy(ctx context.Context, req *resourcepb.HealthCheckRequest) (*resourcepb.HealthCheckResponse, error) { return s.diagnostics.IsHealthy(ctx, req) } // GetBlob implements BlobStore. -func (s *server) PutBlob(ctx context.Context, req *PutBlobRequest) (*PutBlobResponse, error) { +func (s *server) PutBlob(ctx context.Context, req *resourcepb.PutBlobRequest) (*resourcepb.PutBlobResponse, error) { if s.blob == nil { - return &PutBlobResponse{Error: &ErrorResult{ + return &resourcepb.PutBlobResponse{Error: &resourcepb.ErrorResult{ Message: "blob store not configured", Code: http.StatusNotImplemented, }}, nil @@ -1170,12 +1172,12 @@ func (s *server) PutBlob(ctx context.Context, req *PutBlobRequest) (*PutBlobResp return rsp, nil } -func (s *server) getPartialObject(ctx context.Context, key *ResourceKey, rv int64) (utils.GrafanaMetaAccessor, *ErrorResult) { +func (s *server) getPartialObject(ctx context.Context, key *resourcepb.ResourceKey, rv int64) (utils.GrafanaMetaAccessor, *resourcepb.ErrorResult) { if r := verifyRequestKey(key); r != nil { return nil, r } - rsp := s.backend.ReadResource(ctx, &ReadRequest{ + rsp := s.backend.ReadResource(ctx, &resourcepb.ReadRequest{ Key: key, ResourceVersion: rv, }) @@ -1196,9 +1198,9 @@ func (s *server) getPartialObject(ctx context.Context, key *ResourceKey, rv int6 } // GetBlob implements BlobStore. -func (s *server) GetBlob(ctx context.Context, req *GetBlobRequest) (*GetBlobResponse, error) { +func (s *server) GetBlob(ctx context.Context, req *resourcepb.GetBlobRequest) (*resourcepb.GetBlobResponse, error) { if s.blob == nil { - return &GetBlobResponse{Error: &ErrorResult{ + return &resourcepb.GetBlobResponse{Error: &resourcepb.ErrorResult{ Message: "blob store not configured", Code: http.StatusNotImplemented, }}, nil @@ -1209,12 +1211,12 @@ func (s *server) GetBlob(ctx context.Context, req *GetBlobRequest) (*GetBlobResp // The linked blob is stored in the resource metadata attributes obj, status := s.getPartialObject(ctx, req.Resource, req.ResourceVersion) if status != nil { - return &GetBlobResponse{Error: status}, nil + return &resourcepb.GetBlobResponse{Error: status}, nil } info = obj.GetBlob() if info == nil || info.UID == "" { - return &GetBlobResponse{Error: &ErrorResult{ + return &resourcepb.GetBlobResponse{Error: &resourcepb.ErrorResult{ Message: "Resource does not have a linked blob", Code: 404, }}, nil diff --git a/pkg/storage/unified/resource/server_test.go b/pkg/storage/unified/resource/server_test.go index ce965041637..da92e67d7c0 100644 --- a/pkg/storage/unified/resource/server_test.go +++ b/pkg/storage/unified/resource/server_test.go @@ -15,8 +15,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestSimpleServer(t *testing.T) { @@ -78,7 +80,7 @@ func TestSimpleServer(t *testing.T) { } }`) - key := &ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "playlist.grafana.app", Resource: "rrrr", // can be anything :( Namespace: "default", @@ -86,8 +88,8 @@ func TestSimpleServer(t *testing.T) { } // Should be empty when we start - all, err := server.List(ctx, &ListRequest{Options: &ListOptions{ - Key: &ResourceKey{ + all, err := server.List(ctx, &resourcepb.ListRequest{Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: key.Group, Resource: key.Resource, }, @@ -96,12 +98,12 @@ func TestSimpleServer(t *testing.T) { require.Len(t, all.Items, 0) // should return 404 if not found - found, err := server.Read(ctx, &ReadRequest{Key: key}) + found, err := server.Read(ctx, &resourcepb.ReadRequest{Key: key}) require.NoError(t, err) require.NotNil(t, found.Error) require.Equal(t, int32(http.StatusNotFound), found.Error.Code) - created, err := server.Create(ctx, &CreateRequest{ + created, err := server.Create(ctx, &resourcepb.CreateRequest{ Value: raw, Key: key, }) @@ -110,7 +112,7 @@ func TestSimpleServer(t *testing.T) { require.True(t, created.ResourceVersion > 0) // The key does not include resource version - found, err = server.Read(ctx, &ReadRequest{Key: key}) + found, err = server.Read(ctx, &resourcepb.ReadRequest{Key: key}) require.NoError(t, err) require.Nil(t, found.Error) require.Equal(t, created.ResourceVersion, found.ResourceVersion) @@ -131,7 +133,7 @@ func TestSimpleServer(t *testing.T) { }) raw, err = json.Marshal(tmp) require.NoError(t, err) - updated, err := server.Update(ctx, &UpdateRequest{ + updated, err := server.Update(ctx, &resourcepb.UpdateRequest{ Key: key, Value: raw, ResourceVersion: created.ResourceVersion}) @@ -142,7 +144,7 @@ func TestSimpleServer(t *testing.T) { obj.SetLabels(nil) raw, err = json.Marshal(tmp) require.NoError(t, err) - updated, err = server.Update(ctx, &UpdateRequest{ + updated, err = server.Update(ctx, &resourcepb.UpdateRequest{ Key: key, Value: raw, ResourceVersion: created.ResourceVersion}) @@ -151,13 +153,13 @@ func TestSimpleServer(t *testing.T) { require.True(t, updated.ResourceVersion > created.ResourceVersion) // We should still get the latest - found, err = server.Read(ctx, &ReadRequest{Key: key}) + found, err = server.Read(ctx, &resourcepb.ReadRequest{Key: key}) require.NoError(t, err) require.Nil(t, found.Error) require.Equal(t, updated.ResourceVersion, found.ResourceVersion) - all, err = server.List(ctx, &ListRequest{Options: &ListOptions{ - Key: &ResourceKey{ + all, err = server.List(ctx, &resourcepb.ListRequest{Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: key.Group, Resource: key.Resource, }, @@ -166,19 +168,19 @@ func TestSimpleServer(t *testing.T) { require.Len(t, all.Items, 1) require.Equal(t, updated.ResourceVersion, all.Items[0].ResourceVersion) - deleted, err := server.Delete(ctx, &DeleteRequest{Key: key, ResourceVersion: updated.ResourceVersion}) + deleted, err := server.Delete(ctx, &resourcepb.DeleteRequest{Key: key, ResourceVersion: updated.ResourceVersion}) require.NoError(t, err) require.True(t, deleted.ResourceVersion > updated.ResourceVersion) // We should get not found status when trying to read the latest value - found, err = server.Read(ctx, &ReadRequest{Key: key}) + found, err = server.Read(ctx, &resourcepb.ReadRequest{Key: key}) require.NoError(t, err) require.NotNil(t, found.Error) require.Equal(t, int32(404), found.Error.Code) // And the deleted value should not be in the results - all, err = server.List(ctx, &ListRequest{Options: &ListOptions{ - Key: &ResourceKey{ + all, err = server.List(ctx, &resourcepb.ListRequest{Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: key.Group, Resource: key.Resource, }, @@ -213,14 +215,14 @@ func TestSimpleServer(t *testing.T) { } }`) - key := &ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "playlist.grafana.app", Resource: "rrrr", // can be anything :( Namespace: "default", Name: "fdgsv37qslr0ga", } - created, err := server.Create(ctx, &CreateRequest{ + created, err := server.Create(ctx, &resourcepb.CreateRequest{ Value: raw, Key: key, }) @@ -228,13 +230,13 @@ func TestSimpleServer(t *testing.T) { // Update should return an ErrOptimisticLockingFailed the second time - _, err = server.Update(ctx, &UpdateRequest{ + _, err = server.Update(ctx, &resourcepb.UpdateRequest{ Key: key, Value: raw, ResourceVersion: created.ResourceVersion}) require.NoError(t, err) - _, err = server.Update(ctx, &UpdateRequest{ + _, err = server.Update(ctx, &resourcepb.UpdateRequest{ Key: key, Value: raw, ResourceVersion: created.ResourceVersion}) diff --git a/pkg/storage/unified/resource/table.go b/pkg/storage/unified/resource/table.go index 99c737ce3f7..8ec8ca80105 100644 --- a/pkg/storage/unified/resource/table.go +++ b/pkg/storage/unified/resource/table.go @@ -8,7 +8,7 @@ import ( "fmt" "io" "os" - reflect "reflect" + "reflect" "strconv" "testing" "time" @@ -20,10 +20,12 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana-plugin-sdk-go/data/utils/jsoniter" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) // Convert the the protobuf model into k8s (will decode each value) -func (x *ResourceTable) ToK8s() (metav1.Table, error) { +func toK8s(x *resourcepb.ResourceTable) (metav1.Table, error) { table := metav1.Table{ ListMeta: metav1.ListMeta{ Continue: x.NextPageToken, @@ -103,7 +105,7 @@ func (x *ResourceTable) ToK8s() (metav1.Table, error) { } type TableBuilder struct { - ResourceTable + resourcepb.ResourceTable lookup map[string]*resourceTableColumn @@ -113,9 +115,9 @@ type TableBuilder struct { type ResourceColumnEncoder = func(v any) ([]byte, error) -func NewTableBuilder(cols []*ResourceTableColumnDefinition) (*TableBuilder, error) { +func NewTableBuilder(cols []*resourcepb.ResourceTableColumnDefinition) (*TableBuilder, error) { table := &TableBuilder{ - ResourceTable: ResourceTable{ + ResourceTable: resourcepb.ResourceTable{ Columns: cols, }, @@ -147,8 +149,8 @@ func (x *TableBuilder) Encoders() []ResourceColumnEncoder { return encoders } -func (x *TableBuilder) AddRow(key *ResourceKey, rv int64, vals map[string]any) error { - row := &ResourceTableRow{ +func (x *TableBuilder) AddRow(key *resourcepb.ResourceKey, rv int64, vals map[string]any) error { + row := &resourcepb.ResourceTableRow{ Key: key, ResourceVersion: rv, Cells: make([][]byte, len(x.Columns)), @@ -171,7 +173,7 @@ func (x *TableBuilder) AddRow(key *ResourceKey, rv int64, vals map[string]any) e } type resourceTableColumn struct { - def *ResourceTableColumnDefinition + def *resourcepb.ResourceTableColumnDefinition index int // Used for array indexing @@ -183,7 +185,7 @@ type resourceTableColumn struct { } // helper to decode a cell value -func DecodeCell(columnDef *ResourceTableColumnDefinition, index int, cellVal []byte) (any, error) { +func DecodeCell(columnDef *resourcepb.ResourceTableColumnDefinition, index int, cellVal []byte) (any, error) { col, err := newResourceTableColumn(columnDef, index) if err != nil { return nil, err @@ -196,48 +198,48 @@ func DecodeCell(columnDef *ResourceTableColumnDefinition, index int, cellVal []b } // nolint:gocyclo -func newResourceTableColumn(def *ResourceTableColumnDefinition, index int) (*resourceTableColumn, error) { +func newResourceTableColumn(def *resourcepb.ResourceTableColumnDefinition, index int) (*resourceTableColumn, error) { col := &resourceTableColumn{def: def, index: index} // Initially ignore the array property, we wil wrap that at the end switch def.Type { - case ResourceTableColumnDefinition_UNKNOWN_TYPE: + case resourcepb.ResourceTableColumnDefinition_UNKNOWN_TYPE: return nil, fmt.Errorf("unknown column type") - case ResourceTableColumnDefinition_STRING: + case resourcepb.ResourceTableColumnDefinition_STRING: col.OpenAPIType = "string" col.reader = func(iter *jsoniter.Iterator) (any, error) { return iter.ReadString() } - case ResourceTableColumnDefinition_BOOLEAN: + case resourcepb.ResourceTableColumnDefinition_BOOLEAN: col.OpenAPIType = "boolean" col.reader = func(iter *jsoniter.Iterator) (any, error) { return iter.ReadBool() } - case ResourceTableColumnDefinition_INT32: + case resourcepb.ResourceTableColumnDefinition_INT32: col.OpenAPIType = "number" col.OpenAPIFormat = "int32" col.reader = func(iter *jsoniter.Iterator) (any, error) { return iter.ReadInt32() } - case ResourceTableColumnDefinition_INT64: + case resourcepb.ResourceTableColumnDefinition_INT64: col.OpenAPIType = "number" col.OpenAPIFormat = "int64" col.reader = func(iter *jsoniter.Iterator) (any, error) { return iter.ReadInt64() } - case ResourceTableColumnDefinition_DOUBLE: + case resourcepb.ResourceTableColumnDefinition_DOUBLE: col.OpenAPIType = "number" col.OpenAPIFormat = "double" col.reader = func(iter *jsoniter.Iterator) (any, error) { return iter.ReadFloat64() } - case ResourceTableColumnDefinition_FLOAT: + case resourcepb.ResourceTableColumnDefinition_FLOAT: col.OpenAPIType = "number" col.OpenAPIFormat = "float" col.reader = func(iter *jsoniter.Iterator) (any, error) { @@ -245,10 +247,10 @@ func newResourceTableColumn(def *ResourceTableColumnDefinition, index int) (*res } // Encode everything we can -- the lower conversion can happen later? - case ResourceTableColumnDefinition_DATE, ResourceTableColumnDefinition_DATE_TIME: + case resourcepb.ResourceTableColumnDefinition_DATE, resourcepb.ResourceTableColumnDefinition_DATE_TIME: col.OpenAPIType = "string" col.OpenAPIFormat = "date" - if def.Type == ResourceTableColumnDefinition_DATE_TIME { + if def.Type == resourcepb.ResourceTableColumnDefinition_DATE_TIME { col.OpenAPIFormat = "date_time" } col.writer = func(v any, stream *jsoniter.Stream) error { @@ -287,7 +289,7 @@ func newResourceTableColumn(def *ResourceTableColumnDefinition, index int) (*res } } - case ResourceTableColumnDefinition_BINARY: + case resourcepb.ResourceTableColumnDefinition_BINARY: col.OpenAPIType = "binary" col.writer = func(v any, stream *jsoniter.Stream) error { b, ok := v.([]byte) @@ -306,7 +308,7 @@ func newResourceTableColumn(def *ResourceTableColumnDefinition, index int) (*res return base64.StdEncoding.DecodeString(str) } - case ResourceTableColumnDefinition_OBJECT: + case resourcepb.ResourceTableColumnDefinition_OBJECT: col.OpenAPIType = "string" col.OpenAPIFormat = "json" @@ -337,7 +339,7 @@ func (x *resourceTableColumn) Encode(v any) ([]byte, error) { // Arrays will always use JSON formatting if !x.def.IsArray { switch x.def.Type { - case ResourceTableColumnDefinition_STRING: + case resourcepb.ResourceTableColumnDefinition_STRING: { s, ok := v.(string) if !ok { @@ -345,7 +347,7 @@ func (x *resourceTableColumn) Encode(v any) ([]byte, error) { } return []byte(s), nil } - case ResourceTableColumnDefinition_BINARY: + case resourcepb.ResourceTableColumnDefinition_BINARY: { s, ok := v.([]byte) if !ok { @@ -353,7 +355,7 @@ func (x *resourceTableColumn) Encode(v any) ([]byte, error) { } return s, nil } - case ResourceTableColumnDefinition_BOOLEAN: + case resourcepb.ResourceTableColumnDefinition_BOOLEAN: { b, ok := v.(bool) if !ok { @@ -375,7 +377,7 @@ func (x *resourceTableColumn) Encode(v any) ([]byte, error) { } return []byte{0}, nil } - case ResourceTableColumnDefinition_DATE_TIME, ResourceTableColumnDefinition_DATE: + case resourcepb.ResourceTableColumnDefinition_DATE_TIME, resourcepb.ResourceTableColumnDefinition_DATE: { f, ok := v.(time.Time) if !ok { @@ -397,7 +399,7 @@ func (x *resourceTableColumn) Encode(v any) ([]byte, error) { err := binary.Write(&buf, binary.BigEndian, ts) return buf.Bytes(), err } - case ResourceTableColumnDefinition_DOUBLE: + case resourcepb.ResourceTableColumnDefinition_DOUBLE: { f, ok := v.(float64) if !ok { @@ -420,7 +422,7 @@ func (x *resourceTableColumn) Encode(v any) ([]byte, error) { err := binary.Write(&buf, binary.BigEndian, f) return buf.Bytes(), err } - case ResourceTableColumnDefinition_INT64: + case resourcepb.ResourceTableColumnDefinition_INT64: { f, ok := v.(int64) if !ok { @@ -516,15 +518,15 @@ func (x *resourceTableColumn) Decode(buff []byte) (any, error) { } if !x.def.IsArray { switch x.def.Type { - case ResourceTableColumnDefinition_STRING: + case resourcepb.ResourceTableColumnDefinition_STRING: return string(buff), nil - case ResourceTableColumnDefinition_BINARY: + case resourcepb.ResourceTableColumnDefinition_BINARY: return buff, nil - case ResourceTableColumnDefinition_BOOLEAN: + case resourcepb.ResourceTableColumnDefinition_BOOLEAN: if len(buff) == 1 { return buff[0] != 0, nil } - case ResourceTableColumnDefinition_DOUBLE: + case resourcepb.ResourceTableColumnDefinition_DOUBLE: { var f float64 count, err := binary.Decode(buff, binary.BigEndian, &f) @@ -532,7 +534,7 @@ func (x *resourceTableColumn) Decode(buff []byte) (any, error) { return f, nil } } - case ResourceTableColumnDefinition_INT64: + case resourcepb.ResourceTableColumnDefinition_INT64: { var f int64 count, err := binary.Decode(buff, binary.BigEndian, &f) @@ -540,7 +542,7 @@ func (x *resourceTableColumn) Decode(buff []byte) (any, error) { return f, nil } } - case ResourceTableColumnDefinition_DATE_TIME, ResourceTableColumnDefinition_DATE: + case resourcepb.ResourceTableColumnDefinition_DATE_TIME, resourcepb.ResourceTableColumnDefinition_DATE: { var f int64 count, err := binary.Decode(buff, binary.BigEndian, &f) @@ -587,10 +589,10 @@ func (x *resourceTableColumn) Decode(buff []byte) (any, error) { } // AssertTableSnapshot will match a ResourceTable vs the saved value -func AssertTableSnapshot(t *testing.T, path string, table *ResourceTable) { +func AssertTableSnapshot(t *testing.T, path string, table *resourcepb.ResourceTable) { t.Helper() - k8sTable, err := table.ToK8s() + k8sTable, err := toK8s(table) require.NoError(t, err, "unable to create table response", path) actual, err := json.MarshalIndent(k8sTable, "", " ") require.NoError(t, err, "unable to write table json", path) diff --git a/pkg/storage/unified/resource/table_test.go b/pkg/storage/unified/resource/table_test.go index 9e37a902d1c..a725d0049c6 100644 --- a/pkg/storage/unified/resource/table_test.go +++ b/pkg/storage/unified/resource/table_test.go @@ -10,27 +10,29 @@ import ( "time" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestTableFormat(t *testing.T) { - columns := []*ResourceTableColumnDefinition{ + columns := []*resourcepb.ResourceTableColumnDefinition{ { Name: "title", - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, { Name: "stats.count", - Type: ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, { Name: "number", - Type: ResourceTableColumnDefinition_DOUBLE, + Type: resourcepb.ResourceTableColumnDefinition_DOUBLE, Description: "float64 value", }, { Name: "tags", - Type: ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, IsArray: true, }, } @@ -39,7 +41,7 @@ func TestTableFormat(t *testing.T) { builder, err := NewTableBuilder(columns) require.NoError(t, err) - err = builder.AddRow(&ResourceKey{ + err = builder.AddRow(&resourcepb.ResourceKey{ Namespace: "default", Group: "ggg", Resource: "xyz", // does not have a home in table! @@ -51,7 +53,7 @@ func TestTableFormat(t *testing.T) { }) require.NoError(t, err) - err = builder.AddRow(&ResourceKey{ + err = builder.AddRow(&resourcepb.ResourceKey{ Namespace: "default", Group: "ggg", Resource: "xyz", // does not have a home in table! @@ -70,7 +72,7 @@ func TestTableFormat(t *testing.T) { func TestColumnEncoding(t *testing.T) { tests := []struct { // The table definition - def *ResourceTableColumnDefinition + def *resourcepb.ResourceTableColumnDefinition // Passed to the encode function input any @@ -88,101 +90,101 @@ func TestColumnEncoding(t *testing.T) { output_err error }{ { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_STRING, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_STRING, }, input: "aaa", // expects output to match }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_STRING, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_STRING, IsArray: true, }, input: "bbb", output: []any{"bbb"}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_INT64, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_INT64, }, input: 12345, output: int64(12345), }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_INT64, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_INT64, IsArray: true, }, input: 12345, output: []any{int64(12345)}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_DOUBLE, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_DOUBLE, }, input: 12345, output: float64(12345), }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_DOUBLE, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_DOUBLE, IsArray: true, }, input: 12345, output: []any{float64(12345)}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_BOOLEAN, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_BOOLEAN, }, input: true, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_BOOLEAN, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_BOOLEAN, IsArray: true, }, input: []any{true, false, true}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_FLOAT, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_FLOAT, }, input: 23.4, output: float32(23.4), }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_FLOAT, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_FLOAT, IsArray: true, }, input: 23.4, output: []any{float32(23.4)}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_INT32, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_INT32, }, input: 56, output: int32(56), }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_INT32, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_INT32, IsArray: true, }, input: 56, output: []any{int32(56)}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_DATE_TIME, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_DATE_TIME, }, input: time.UnixMilli(946674000000).UTC(), }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_DATE_TIME, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_DATE_TIME, IsArray: true, }, input: time.UnixMilli(946674000000).UTC(), @@ -191,14 +193,14 @@ func TestColumnEncoding(t *testing.T) { }, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_DATE, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_DATE, }, input: time.UnixMilli(946674000000).UTC(), }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_DATE, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_DATE, IsArray: true, }, input: time.UnixMilli(946674000000).UTC(), @@ -207,14 +209,14 @@ func TestColumnEncoding(t *testing.T) { }, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_BINARY, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_BINARY, }, input: []byte{1, 2, 3, 4}, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_BINARY, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_BINARY, IsArray: true, }, input: []any{ @@ -222,16 +224,16 @@ func TestColumnEncoding(t *testing.T) { }, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_OBJECT, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_OBJECT, }, input: map[string]any{ "hello": "world", }, }, { - def: &ResourceTableColumnDefinition{ - Type: ResourceTableColumnDefinition_OBJECT, + def: &resourcepb.ResourceTableColumnDefinition{ + Type: resourcepb.ResourceTableColumnDefinition_OBJECT, IsArray: true, }, input: map[string]any{ @@ -246,8 +248,8 @@ func TestColumnEncoding(t *testing.T) { } // Keep track of the types that have tests - testedTypes := make(map[ResourceTableColumnDefinition_ColumnType]bool) - testedArrays := make(map[ResourceTableColumnDefinition_ColumnType]bool) + testedTypes := make(map[resourcepb.ResourceTableColumnDefinition_ColumnType]bool) + testedArrays := make(map[resourcepb.ResourceTableColumnDefinition_ColumnType]bool) for _, test := range tests { var sb strings.Builder if test.def.IsArray { @@ -301,7 +303,7 @@ func TestColumnEncoding(t *testing.T) { missingArrays := []string{} // Make sure we have at least one test for each type - for i := ResourceTableColumnDefinition_STRING; i <= ResourceTableColumnDefinition_OBJECT; i++ { + for i := resourcepb.ResourceTableColumnDefinition_STRING; i <= resourcepb.ResourceTableColumnDefinition_OBJECT; i++ { if !testedTypes[i] { missingTypes = append(missingTypes, i.String()) } @@ -316,7 +318,7 @@ func TestColumnEncoding(t *testing.T) { } func TestDecodeCell(t *testing.T) { - colDef := &ResourceTableColumnDefinition{Type: ResourceTableColumnDefinition_INT64} + colDef := &resourcepb.ResourceTableColumnDefinition{Type: resourcepb.ResourceTableColumnDefinition_INT64} var buf bytes.Buffer err := binary.Write(&buf, binary.BigEndian, int64(123)) require.NoError(t, err) diff --git a/pkg/storage/unified/resource/validation.go b/pkg/storage/unified/resource/validation.go index 066ac42c2af..2c1b5cf3740 100644 --- a/pkg/storage/unified/resource/validation.go +++ b/pkg/storage/unified/resource/validation.go @@ -2,12 +2,14 @@ package resource import ( "regexp" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var validNameCharPattern = `a-zA-Z0-9:\-\_\.` var validNamePattern = regexp.MustCompile(`^[` + validNameCharPattern + `]*$`).MatchString -func validateName(name string) *ErrorResult { +func validateName(name string) *resourcepb.ErrorResult { if len(name) == 0 { return NewBadRequestError("name is too short") } diff --git a/pkg/storage/unified/resourcepb/blob.pb.go b/pkg/storage/unified/resourcepb/blob.pb.go new file mode 100644 index 00000000000..7e3deecc5bc --- /dev/null +++ b/pkg/storage/unified/resourcepb/blob.pb.go @@ -0,0 +1,520 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.5 +// protoc (unknown) +// source: blob.proto + +package resourcepb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +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 PutBlobRequest_Method int32 + +const ( + // Use the inline raw []byte + PutBlobRequest_GRPC PutBlobRequest_Method = 0 + // Get a signed URL and PUT the value + PutBlobRequest_HTTP PutBlobRequest_Method = 1 +) + +// Enum value maps for PutBlobRequest_Method. +var ( + PutBlobRequest_Method_name = map[int32]string{ + 0: "GRPC", + 1: "HTTP", + } + PutBlobRequest_Method_value = map[string]int32{ + "GRPC": 0, + "HTTP": 1, + } +) + +func (x PutBlobRequest_Method) Enum() *PutBlobRequest_Method { + p := new(PutBlobRequest_Method) + *p = x + return p +} + +func (x PutBlobRequest_Method) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PutBlobRequest_Method) Descriptor() protoreflect.EnumDescriptor { + return file_blob_proto_enumTypes[0].Descriptor() +} + +func (PutBlobRequest_Method) Type() protoreflect.EnumType { + return &file_blob_proto_enumTypes[0] +} + +func (x PutBlobRequest_Method) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PutBlobRequest_Method.Descriptor instead. +func (PutBlobRequest_Method) EnumDescriptor() ([]byte, []int) { + return file_blob_proto_rawDescGZIP(), []int{0, 0} +} + +type PutBlobRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The resource that will use this blob + // NOTE: the name may not yet exist, but group+resource are required + Resource *ResourceKey `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + // How to upload + Method PutBlobRequest_Method `protobuf:"varint,2,opt,name=method,proto3,enum=resource.PutBlobRequest_Method" json:"method,omitempty"` + // Content type header + ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + // Raw value to write + // Not valid when method == HTTP + Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PutBlobRequest) Reset() { + *x = PutBlobRequest{} + mi := &file_blob_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PutBlobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PutBlobRequest) ProtoMessage() {} + +func (x *PutBlobRequest) ProtoReflect() protoreflect.Message { + mi := &file_blob_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PutBlobRequest.ProtoReflect.Descriptor instead. +func (*PutBlobRequest) Descriptor() ([]byte, []int) { + return file_blob_proto_rawDescGZIP(), []int{0} +} + +func (x *PutBlobRequest) GetResource() *ResourceKey { + if x != nil { + return x.Resource + } + return nil +} + +func (x *PutBlobRequest) GetMethod() PutBlobRequest_Method { + if x != nil { + return x.Method + } + return PutBlobRequest_GRPC +} + +func (x *PutBlobRequest) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *PutBlobRequest) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +type PutBlobResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Error details + Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + // The blob uid. This must be saved into the resource to support access + Uid string `protobuf:"bytes,2,opt,name=uid,proto3" json:"uid,omitempty"` + // The URL where this value can be PUT + Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url,omitempty"` + // Size of the uploaded blob + Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` + // Content hash used for an etag + Hash string `protobuf:"bytes,5,opt,name=hash,proto3" json:"hash,omitempty"` + // Validated mimetype (from content_type) + MimeType string `protobuf:"bytes,6,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"` + // Validated charset (from content_type) + Charset string `protobuf:"bytes,7,opt,name=charset,proto3" json:"charset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PutBlobResponse) Reset() { + *x = PutBlobResponse{} + mi := &file_blob_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PutBlobResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PutBlobResponse) ProtoMessage() {} + +func (x *PutBlobResponse) ProtoReflect() protoreflect.Message { + mi := &file_blob_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PutBlobResponse.ProtoReflect.Descriptor instead. +func (*PutBlobResponse) Descriptor() ([]byte, []int) { + return file_blob_proto_rawDescGZIP(), []int{1} +} + +func (x *PutBlobResponse) GetError() *ErrorResult { + if x != nil { + return x.Error + } + return nil +} + +func (x *PutBlobResponse) GetUid() string { + if x != nil { + return x.Uid + } + return "" +} + +func (x *PutBlobResponse) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *PutBlobResponse) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *PutBlobResponse) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *PutBlobResponse) GetMimeType() string { + if x != nil { + return x.MimeType + } + return "" +} + +func (x *PutBlobResponse) GetCharset() string { + if x != nil { + return x.Charset + } + return "" +} + +type GetBlobRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Resource *ResourceKey `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + // The new resource version + ResourceVersion int64 `protobuf:"varint,2,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + // Do not return a pre-signed URL (when possible) + MustProxyBytes bool `protobuf:"varint,3,opt,name=must_proxy_bytes,json=mustProxyBytes,proto3" json:"must_proxy_bytes,omitempty"` + // The blob UID -- when empty, the value is loaded from annotations in the matching resource + Uid string `protobuf:"bytes,4,opt,name=uid,proto3" json:"uid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetBlobRequest) Reset() { + *x = GetBlobRequest{} + mi := &file_blob_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetBlobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlobRequest) ProtoMessage() {} + +func (x *GetBlobRequest) ProtoReflect() protoreflect.Message { + mi := &file_blob_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlobRequest.ProtoReflect.Descriptor instead. +func (*GetBlobRequest) Descriptor() ([]byte, []int) { + return file_blob_proto_rawDescGZIP(), []int{2} +} + +func (x *GetBlobRequest) GetResource() *ResourceKey { + if x != nil { + return x.Resource + } + return nil +} + +func (x *GetBlobRequest) GetResourceVersion() int64 { + if x != nil { + return x.ResourceVersion + } + return 0 +} + +func (x *GetBlobRequest) GetMustProxyBytes() bool { + if x != nil { + return x.MustProxyBytes + } + return false +} + +func (x *GetBlobRequest) GetUid() string { + if x != nil { + return x.Uid + } + return "" +} + +type GetBlobResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Error details + Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + // (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 + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + // Content type + ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + // The raw object value + Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetBlobResponse) Reset() { + *x = GetBlobResponse{} + mi := &file_blob_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetBlobResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlobResponse) ProtoMessage() {} + +func (x *GetBlobResponse) ProtoReflect() protoreflect.Message { + mi := &file_blob_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlobResponse.ProtoReflect.Descriptor instead. +func (*GetBlobResponse) Descriptor() ([]byte, []int) { + return file_blob_proto_rawDescGZIP(), []int{3} +} + +func (x *GetBlobResponse) GetError() *ErrorResult { + if x != nil { + return x.Error + } + return nil +} + +func (x *GetBlobResponse) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *GetBlobResponse) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *GetBlobResponse) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +var File_blob_proto protoreflect.FileDescriptor + +var file_blob_proto_rawDesc = string([]byte{ + 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd3, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x42, 0x6c, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, + 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1c, + 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, + 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x22, 0xc1, 0x01, 0x0a, + 0x0f, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, + 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, + 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, + 0x22, 0xaa, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x73, + 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x22, 0x89, 0x01, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x09, 0x42, 0x6c, + 0x6f, 0x62, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x50, 0x75, 0x74, 0x42, 0x6c, + 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, + 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3b, 0x5a, 0x39, 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, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) + +var ( + file_blob_proto_rawDescOnce sync.Once + file_blob_proto_rawDescData []byte +) + +func file_blob_proto_rawDescGZIP() []byte { + file_blob_proto_rawDescOnce.Do(func() { + file_blob_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_blob_proto_rawDesc), len(file_blob_proto_rawDesc))) + }) + return file_blob_proto_rawDescData +} + +var file_blob_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_blob_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_blob_proto_goTypes = []any{ + (PutBlobRequest_Method)(0), // 0: resource.PutBlobRequest.Method + (*PutBlobRequest)(nil), // 1: resource.PutBlobRequest + (*PutBlobResponse)(nil), // 2: resource.PutBlobResponse + (*GetBlobRequest)(nil), // 3: resource.GetBlobRequest + (*GetBlobResponse)(nil), // 4: resource.GetBlobResponse + (*ResourceKey)(nil), // 5: resource.ResourceKey + (*ErrorResult)(nil), // 6: resource.ErrorResult +} +var file_blob_proto_depIdxs = []int32{ + 5, // 0: resource.PutBlobRequest.resource:type_name -> resource.ResourceKey + 0, // 1: resource.PutBlobRequest.method:type_name -> resource.PutBlobRequest.Method + 6, // 2: resource.PutBlobResponse.error:type_name -> resource.ErrorResult + 5, // 3: resource.GetBlobRequest.resource:type_name -> resource.ResourceKey + 6, // 4: resource.GetBlobResponse.error:type_name -> resource.ErrorResult + 1, // 5: resource.BlobStore.PutBlob:input_type -> resource.PutBlobRequest + 3, // 6: resource.BlobStore.GetBlob:input_type -> resource.GetBlobRequest + 2, // 7: resource.BlobStore.PutBlob:output_type -> resource.PutBlobResponse + 4, // 8: resource.BlobStore.GetBlob:output_type -> resource.GetBlobResponse + 7, // [7:9] is the sub-list for method output_type + 5, // [5:7] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_blob_proto_init() } +func file_blob_proto_init() { + if File_blob_proto != nil { + return + } + file_resource_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_blob_proto_rawDesc), len(file_blob_proto_rawDesc)), + NumEnums: 1, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_blob_proto_goTypes, + DependencyIndexes: file_blob_proto_depIdxs, + EnumInfos: file_blob_proto_enumTypes, + MessageInfos: file_blob_proto_msgTypes, + }.Build() + File_blob_proto = out.File + file_blob_proto_goTypes = nil + file_blob_proto_depIdxs = nil +} diff --git a/pkg/storage/unified/resourcepb/blob_grpc.pb.go b/pkg/storage/unified/resourcepb/blob_grpc.pb.go new file mode 100644 index 00000000000..faee8d14d8d --- /dev/null +++ b/pkg/storage/unified/resourcepb/blob_grpc.pb.go @@ -0,0 +1,152 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.4.0 +// - protoc (unknown) +// source: blob.proto + +package resourcepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 + +const ( + BlobStore_PutBlob_FullMethodName = "/resource.BlobStore/PutBlob" + BlobStore_GetBlob_FullMethodName = "/resource.BlobStore/GetBlob" +) + +// BlobStoreClient is the client API for BlobStore service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BlobStoreClient interface { + // Upload a blob that will be saved in a resource + PutBlob(ctx context.Context, in *PutBlobRequest, opts ...grpc.CallOption) (*PutBlobResponse, error) + // Get blob contents. When possible, this will return a signed URL + // For large payloads, signed URLs are required to avoid protobuf message size limits + GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error) +} + +type blobStoreClient struct { + cc grpc.ClientConnInterface +} + +func NewBlobStoreClient(cc grpc.ClientConnInterface) BlobStoreClient { + return &blobStoreClient{cc} +} + +func (c *blobStoreClient) PutBlob(ctx context.Context, in *PutBlobRequest, opts ...grpc.CallOption) (*PutBlobResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PutBlobResponse) + err := c.cc.Invoke(ctx, BlobStore_PutBlob_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *blobStoreClient) GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetBlobResponse) + err := c.cc.Invoke(ctx, BlobStore_GetBlob_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// BlobStoreServer is the server API for BlobStore service. +// All implementations should embed UnimplementedBlobStoreServer +// for forward compatibility +type BlobStoreServer interface { + // Upload a blob that will be saved in a resource + PutBlob(context.Context, *PutBlobRequest) (*PutBlobResponse, error) + // Get blob contents. When possible, this will return a signed URL + // For large payloads, signed URLs are required to avoid protobuf message size limits + GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error) +} + +// UnimplementedBlobStoreServer should be embedded to have forward compatible implementations. +type UnimplementedBlobStoreServer struct { +} + +func (UnimplementedBlobStoreServer) PutBlob(context.Context, *PutBlobRequest) (*PutBlobResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PutBlob not implemented") +} +func (UnimplementedBlobStoreServer) GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetBlob not implemented") +} + +// UnsafeBlobStoreServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BlobStoreServer will +// result in compilation errors. +type UnsafeBlobStoreServer interface { + mustEmbedUnimplementedBlobStoreServer() +} + +func RegisterBlobStoreServer(s grpc.ServiceRegistrar, srv BlobStoreServer) { + s.RegisterService(&BlobStore_ServiceDesc, srv) +} + +func _BlobStore_PutBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PutBlobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BlobStoreServer).PutBlob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BlobStore_PutBlob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BlobStoreServer).PutBlob(ctx, req.(*PutBlobRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BlobStore_GetBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBlobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BlobStoreServer).GetBlob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BlobStore_GetBlob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BlobStoreServer).GetBlob(ctx, req.(*GetBlobRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// BlobStore_ServiceDesc is the grpc.ServiceDesc for BlobStore service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BlobStore_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "resource.BlobStore", + HandlerType: (*BlobStoreServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "PutBlob", + Handler: _BlobStore_PutBlob_Handler, + }, + { + MethodName: "GetBlob", + Handler: _BlobStore_GetBlob_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "blob.proto", +} diff --git a/pkg/storage/unified/resourcepb/go.mod b/pkg/storage/unified/resourcepb/go.mod new file mode 100644 index 00000000000..d3748f8cc15 --- /dev/null +++ b/pkg/storage/unified/resourcepb/go.mod @@ -0,0 +1,18 @@ +module github.com/grafana/grafana/pkg/storage/unified/resourcepb + +go 1.24.3 + +require ( + google.golang.org/grpc v1.72.1 + google.golang.org/protobuf v1.36.6 +) + +require ( + github.com/google/go-cmp v0.7.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect +) diff --git a/pkg/storage/unified/resourcepb/go.sum b/pkg/storage/unified/resourcepb/go.sum new file mode 100644 index 00000000000..04ea318c08b --- /dev/null +++ b/pkg/storage/unified/resourcepb/go.sum @@ -0,0 +1,34 @@ +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= diff --git a/pkg/storage/unified/resource/resource.pb.go b/pkg/storage/unified/resourcepb/resource.pb.go similarity index 61% rename from pkg/storage/unified/resource/resource.pb.go rename to pkg/storage/unified/resourcepb/resource.pb.go index 69f2de4f1a9..8c6fb47b491 100644 --- a/pkg/storage/unified/resource/resource.pb.go +++ b/pkg/storage/unified/resourcepb/resource.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: resource.proto -package resource +package resourcepb import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -330,7 +330,7 @@ func (x HealthCheckResponse_ServingStatus) Number() protoreflect.EnumNumber { // Deprecated: Use HealthCheckResponse_ServingStatus.Descriptor instead. func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{30, 0} + return file_resource_proto_rawDescGZIP(), []int{26, 0} } // See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more. @@ -405,55 +405,7 @@ func (x ResourceTableColumnDefinition_ColumnType) Number() protoreflect.EnumNumb // Deprecated: Use ResourceTableColumnDefinition_ColumnType.Descriptor instead. func (ResourceTableColumnDefinition_ColumnType) EnumDescriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{32, 0} -} - -type PutBlobRequest_Method int32 - -const ( - // Use the inline raw []byte - PutBlobRequest_GRPC PutBlobRequest_Method = 0 - // Get a signed URL and PUT the value - PutBlobRequest_HTTP PutBlobRequest_Method = 1 -) - -// Enum value maps for PutBlobRequest_Method. -var ( - PutBlobRequest_Method_name = map[int32]string{ - 0: "GRPC", - 1: "HTTP", - } - PutBlobRequest_Method_value = map[string]int32{ - "GRPC": 0, - "HTTP": 1, - } -) - -func (x PutBlobRequest_Method) Enum() *PutBlobRequest_Method { - p := new(PutBlobRequest_Method) - *p = x - return p -} - -func (x PutBlobRequest_Method) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (PutBlobRequest_Method) Descriptor() protoreflect.EnumDescriptor { - return file_resource_proto_enumTypes[7].Descriptor() -} - -func (PutBlobRequest_Method) Type() protoreflect.EnumType { - return &file_resource_proto_enumTypes[7] -} - -func (x PutBlobRequest_Method) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use PutBlobRequest_Method.Descriptor instead. -func (PutBlobRequest_Method) EnumDescriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{34, 0} + return file_resource_proto_rawDescGZIP(), []int{28, 0} } type ResourceKey struct { @@ -1922,36 +1874,36 @@ func (x *BulkResponse) GetRejected() []*BulkResponse_Rejected { return nil } -// Get statistics across multiple resources -// For these queries, we do not need authorization to see the actual values -type ResourceStatsRequest struct { +// List items within a resource type & repository name +// Access control is managed above this request +type ListManagedObjectsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` + // Starting from the requested page (other query parameters must match!) + NextPageToken string `protobuf:"bytes,1,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` // Namespace (tenant) - Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` - // 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 - Kinds []string `protobuf:"bytes,2,rep,name=kinds,proto3" json:"kinds,omitempty"` - // Limit the stats within a folder (not recursive!) - Folder string `protobuf:"bytes,3,opt,name=folder,proto3" json:"folder,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + // The manager type (eg, terraform vs repo) + Kind string `protobuf:"bytes,3,opt,name=kind,proto3" json:"kind,omitempty"` + // The name of the manager + Id string `protobuf:"bytes,4,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ResourceStatsRequest) Reset() { - *x = ResourceStatsRequest{} +func (x *ListManagedObjectsRequest) Reset() { + *x = ListManagedObjectsRequest{} mi := &file_resource_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResourceStatsRequest) String() string { +func (x *ListManagedObjectsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResourceStatsRequest) ProtoMessage() {} +func (*ListManagedObjectsRequest) ProtoMessage() {} -func (x *ResourceStatsRequest) ProtoReflect() protoreflect.Message { +func (x *ListManagedObjectsRequest) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1963,56 +1915,65 @@ func (x *ResourceStatsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResourceStatsRequest.ProtoReflect.Descriptor instead. -func (*ResourceStatsRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListManagedObjectsRequest.ProtoReflect.Descriptor instead. +func (*ListManagedObjectsRequest) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{21} } -func (x *ResourceStatsRequest) GetNamespace() string { +func (x *ListManagedObjectsRequest) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +func (x *ListManagedObjectsRequest) GetNamespace() string { if x != nil { return x.Namespace } return "" } -func (x *ResourceStatsRequest) GetKinds() []string { +func (x *ListManagedObjectsRequest) GetKind() string { if x != nil { - return x.Kinds + return x.Kind } - return nil + return "" } -func (x *ResourceStatsRequest) GetFolder() string { +func (x *ListManagedObjectsRequest) GetId() string { if x != nil { - return x.Folder + return x.Id } return "" } -type ResourceStatsResponse struct { +type ListManagedObjectsResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + // Item iterator + Items []*ListManagedObjectsResponse_Item `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + // More results exist... pass this in the next request + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` // Error details - Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` - // All results exist within this key - Stats []*ResourceStatsResponse_Stats `protobuf:"bytes,2,rep,name=stats,proto3" json:"stats,omitempty"` + Error *ErrorResult `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ResourceStatsResponse) Reset() { - *x = ResourceStatsResponse{} +func (x *ListManagedObjectsResponse) Reset() { + *x = ListManagedObjectsResponse{} mi := &file_resource_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResourceStatsResponse) String() string { +func (x *ListManagedObjectsResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResourceStatsResponse) ProtoMessage() {} +func (*ListManagedObjectsResponse) ProtoMessage() {} -func (x *ResourceStatsResponse) ProtoReflect() protoreflect.Message { +func (x *ListManagedObjectsResponse) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2024,70 +1985,59 @@ func (x *ResourceStatsResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResourceStatsResponse.ProtoReflect.Descriptor instead. -func (*ResourceStatsResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use ListManagedObjectsResponse.ProtoReflect.Descriptor instead. +func (*ListManagedObjectsResponse) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{22} } -func (x *ResourceStatsResponse) GetError() *ErrorResult { +func (x *ListManagedObjectsResponse) GetItems() []*ListManagedObjectsResponse_Item { if x != nil { - return x.Error + return x.Items } return nil } -func (x *ResourceStatsResponse) GetStats() []*ResourceStatsResponse_Stats { +func (x *ListManagedObjectsResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +func (x *ListManagedObjectsResponse) GetError() *ErrorResult { if x != nil { - return x.Stats + return x.Error } return nil } -// Search within a single resource -type ResourceSearchRequest struct { +// Count the items that exist with +type CountManagedObjectsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // The key must include namespace + group + resource - Options *ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` - // To search additional resource types, add additional keys to this list - // NOTE: queries will only support federation across kinds with common fields - Federated []*ResourceKey `protobuf:"bytes,2,rep,name=federated,proto3" json:"federated,omitempty"` - // 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 - Query string `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` - // max results - Limit int64 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"` - // where to start the query (eg, From) - Offset int64 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` - // sorting - SortBy []*ResourceSearchRequest_Sort `protobuf:"bytes,6,rep,name=sortBy,proto3" json:"sortBy,omitempty"` - // calculate field statistics - Facet map[string]*ResourceSearchRequest_Facet `protobuf:"bytes,7,rep,name=facet,proto3" json:"facet,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - // the return fields (empty will return everything) - Fields []string `protobuf:"bytes,8,rep,name=fields,proto3" json:"fields,omitempty"` - // explain each result (added to the each row) - Explain bool `protobuf:"varint,9,opt,name=explain,proto3" json:"explain,omitempty"` - IsDeleted bool `protobuf:"varint,10,opt,name=is_deleted,json=isDeleted,proto3" json:"is_deleted,omitempty"` - Page int64 `protobuf:"varint,11,opt,name=page,proto3" json:"page,omitempty"` - Permission int64 `protobuf:"varint,12,opt,name=permission,proto3" json:"permission,omitempty"` + // Namespace (tenant) + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + // Manager kind: terraform, plugin, kubectl, repo + Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` + // Name of the manager (meaningful inside kind) + Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ResourceSearchRequest) Reset() { - *x = ResourceSearchRequest{} +func (x *CountManagedObjectsRequest) Reset() { + *x = CountManagedObjectsRequest{} mi := &file_resource_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResourceSearchRequest) String() string { +func (x *CountManagedObjectsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResourceSearchRequest) ProtoMessage() {} +func (*CountManagedObjectsRequest) ProtoMessage() {} -func (x *ResourceSearchRequest) ProtoReflect() protoreflect.Message { +func (x *CountManagedObjectsRequest) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2099,129 +2049,57 @@ func (x *ResourceSearchRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResourceSearchRequest.ProtoReflect.Descriptor instead. -func (*ResourceSearchRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use CountManagedObjectsRequest.ProtoReflect.Descriptor instead. +func (*CountManagedObjectsRequest) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{23} } -func (x *ResourceSearchRequest) GetOptions() *ListOptions { - if x != nil { - return x.Options - } - return nil -} - -func (x *ResourceSearchRequest) GetFederated() []*ResourceKey { - if x != nil { - return x.Federated - } - return nil -} - -func (x *ResourceSearchRequest) GetQuery() string { +func (x *CountManagedObjectsRequest) GetNamespace() string { if x != nil { - return x.Query + return x.Namespace } return "" } -func (x *ResourceSearchRequest) GetLimit() int64 { - if x != nil { - return x.Limit - } - return 0 -} - -func (x *ResourceSearchRequest) GetOffset() int64 { - if x != nil { - return x.Offset - } - return 0 -} - -func (x *ResourceSearchRequest) GetSortBy() []*ResourceSearchRequest_Sort { - if x != nil { - return x.SortBy - } - return nil -} - -func (x *ResourceSearchRequest) GetFacet() map[string]*ResourceSearchRequest_Facet { - if x != nil { - return x.Facet - } - return nil -} - -func (x *ResourceSearchRequest) GetFields() []string { - if x != nil { - return x.Fields - } - return nil -} - -func (x *ResourceSearchRequest) GetExplain() bool { - if x != nil { - return x.Explain - } - return false -} - -func (x *ResourceSearchRequest) GetIsDeleted() bool { - if x != nil { - return x.IsDeleted - } - return false -} - -func (x *ResourceSearchRequest) GetPage() int64 { +func (x *CountManagedObjectsRequest) GetKind() string { if x != nil { - return x.Page + return x.Kind } - return 0 + return "" } -func (x *ResourceSearchRequest) GetPermission() int64 { +func (x *CountManagedObjectsRequest) GetId() string { if x != nil { - return x.Permission + return x.Id } - return 0 + return "" } -type ResourceSearchResponse struct { +// Count the items that exist with +type CountManagedObjectsResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + // Resource counts + Items []*CountManagedObjectsResponse_ResourceCount `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` // Error details - Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` - // All results exist within this key - Key *ResourceKey `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` - // Query results - Results *ResourceTable `protobuf:"bytes,3,opt,name=results,proto3" json:"results,omitempty"` - // The total hit count - TotalHits int64 `protobuf:"varint,4,opt,name=total_hits,json=totalHits,proto3" json:"total_hits,omitempty"` - // indicates how expensive was the query with respect to bytes read - QueryCost float64 `protobuf:"fixed64,5,opt,name=query_cost,json=queryCost,proto3" json:"query_cost,omitempty"` - // maximum score across all fields - MaxScore float64 `protobuf:"fixed64,6,opt,name=max_score,json=maxScore,proto3" json:"max_score,omitempty"` - // Facet results - Facet map[string]*ResourceSearchResponse_Facet `protobuf:"bytes,7,rep,name=facet,proto3" json:"facet,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Error *ErrorResult `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ResourceSearchResponse) Reset() { - *x = ResourceSearchResponse{} +func (x *CountManagedObjectsResponse) Reset() { + *x = CountManagedObjectsResponse{} mi := &file_resource_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResourceSearchResponse) String() string { +func (x *CountManagedObjectsResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResourceSearchResponse) ProtoMessage() {} +func (*CountManagedObjectsResponse) ProtoMessage() {} -func (x *ResourceSearchResponse) ProtoReflect() protoreflect.Message { +func (x *CountManagedObjectsResponse) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2233,91 +2111,91 @@ func (x *ResourceSearchResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResourceSearchResponse.ProtoReflect.Descriptor instead. -func (*ResourceSearchResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use CountManagedObjectsResponse.ProtoReflect.Descriptor instead. +func (*CountManagedObjectsResponse) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{24} } -func (x *ResourceSearchResponse) GetError() *ErrorResult { +func (x *CountManagedObjectsResponse) GetItems() []*CountManagedObjectsResponse_ResourceCount { if x != nil { - return x.Error + return x.Items } return nil } -func (x *ResourceSearchResponse) GetKey() *ResourceKey { +func (x *CountManagedObjectsResponse) GetError() *ErrorResult { if x != nil { - return x.Key + return x.Error } return nil } -func (x *ResourceSearchResponse) GetResults() *ResourceTable { - if x != nil { - return x.Results - } - return nil +type HealthCheckRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *ResourceSearchResponse) GetTotalHits() int64 { - if x != nil { - return x.TotalHits - } - return 0 +func (x *HealthCheckRequest) Reset() { + *x = HealthCheckRequest{} + mi := &file_resource_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *ResourceSearchResponse) GetQueryCost() float64 { - if x != nil { - return x.QueryCost - } - return 0 +func (x *HealthCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (x *ResourceSearchResponse) GetMaxScore() float64 { +func (*HealthCheckRequest) ProtoMessage() {} + +func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_resource_proto_msgTypes[25] if x != nil { - return x.MaxScore + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return 0 + return mi.MessageOf(x) +} + +// Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. +func (*HealthCheckRequest) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{25} } -func (x *ResourceSearchResponse) GetFacet() map[string]*ResourceSearchResponse_Facet { +func (x *HealthCheckRequest) GetService() string { if x != nil { - return x.Facet + return x.Service } - return nil + return "" } -// List items within a resource type & repository name -// Access control is managed above this request -type ListManagedObjectsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Starting from the requested page (other query parameters must match!) - NextPageToken string `protobuf:"bytes,1,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` - // Namespace (tenant) - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` - // The manager type (eg, terraform vs repo) - Kind string `protobuf:"bytes,3,opt,name=kind,proto3" json:"kind,omitempty"` - // The name of the manager - Id string `protobuf:"bytes,4,opt,name=id,proto3" json:"id,omitempty"` +type HealthCheckResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=resource.HealthCheckResponse_ServingStatus" json:"status,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ListManagedObjectsRequest) Reset() { - *x = ListManagedObjectsRequest{} - mi := &file_resource_proto_msgTypes[25] +func (x *HealthCheckResponse) Reset() { + *x = HealthCheckResponse{} + mi := &file_resource_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ListManagedObjectsRequest) String() string { +func (x *HealthCheckResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ListManagedObjectsRequest) ProtoMessage() {} +func (*HealthCheckResponse) ProtoMessage() {} -func (x *ListManagedObjectsRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[25] +func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_resource_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2328,300 +2206,9 @@ func (x *ListManagedObjectsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ListManagedObjectsRequest.ProtoReflect.Descriptor instead. -func (*ListManagedObjectsRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{25} -} - -func (x *ListManagedObjectsRequest) GetNextPageToken() string { - if x != nil { - return x.NextPageToken - } - return "" -} - -func (x *ListManagedObjectsRequest) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - -func (x *ListManagedObjectsRequest) GetKind() string { - if x != nil { - return x.Kind - } - return "" -} - -func (x *ListManagedObjectsRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type ListManagedObjectsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Item iterator - Items []*ListManagedObjectsResponse_Item `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` - // More results exist... pass this in the next request - NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` - // Error details - Error *ErrorResult `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ListManagedObjectsResponse) Reset() { - *x = ListManagedObjectsResponse{} - mi := &file_resource_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ListManagedObjectsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListManagedObjectsResponse) ProtoMessage() {} - -func (x *ListManagedObjectsResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[26] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListManagedObjectsResponse.ProtoReflect.Descriptor instead. -func (*ListManagedObjectsResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{26} -} - -func (x *ListManagedObjectsResponse) GetItems() []*ListManagedObjectsResponse_Item { - if x != nil { - return x.Items - } - return nil -} - -func (x *ListManagedObjectsResponse) GetNextPageToken() string { - if x != nil { - return x.NextPageToken - } - return "" -} - -func (x *ListManagedObjectsResponse) GetError() *ErrorResult { - if x != nil { - return x.Error - } - return nil -} - -// Count the items that exist with -type CountManagedObjectsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Namespace (tenant) - Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` - // Manager kind: terraform, plugin, kubectl, repo - Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` - // Name of the manager (meaningful inside kind) - Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CountManagedObjectsRequest) Reset() { - *x = CountManagedObjectsRequest{} - mi := &file_resource_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CountManagedObjectsRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CountManagedObjectsRequest) ProtoMessage() {} - -func (x *CountManagedObjectsRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[27] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CountManagedObjectsRequest.ProtoReflect.Descriptor instead. -func (*CountManagedObjectsRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{27} -} - -func (x *CountManagedObjectsRequest) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - -func (x *CountManagedObjectsRequest) GetKind() string { - if x != nil { - return x.Kind - } - return "" -} - -func (x *CountManagedObjectsRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -// Count the items that exist with -type CountManagedObjectsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Resource counts - Items []*CountManagedObjectsResponse_ResourceCount `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` - // Error details - Error *ErrorResult `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CountManagedObjectsResponse) Reset() { - *x = CountManagedObjectsResponse{} - mi := &file_resource_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CountManagedObjectsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CountManagedObjectsResponse) ProtoMessage() {} - -func (x *CountManagedObjectsResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[28] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CountManagedObjectsResponse.ProtoReflect.Descriptor instead. -func (*CountManagedObjectsResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{28} -} - -func (x *CountManagedObjectsResponse) GetItems() []*CountManagedObjectsResponse_ResourceCount { - if x != nil { - return x.Items - } - return nil -} - -func (x *CountManagedObjectsResponse) GetError() *ErrorResult { - if x != nil { - return x.Error - } - return nil -} - -type HealthCheckRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *HealthCheckRequest) Reset() { - *x = HealthCheckRequest{} - mi := &file_resource_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *HealthCheckRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HealthCheckRequest) ProtoMessage() {} - -func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[29] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. -func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{29} -} - -func (x *HealthCheckRequest) GetService() string { - if x != nil { - return x.Service - } - return "" -} - -type HealthCheckResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=resource.HealthCheckResponse_ServingStatus" json:"status,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *HealthCheckResponse) Reset() { - *x = HealthCheckResponse{} - mi := &file_resource_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *HealthCheckResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HealthCheckResponse) ProtoMessage() {} - -func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[30] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. -func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{30} +// Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. +func (*HealthCheckResponse) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{26} } func (x *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus { @@ -2662,7 +2249,7 @@ type ResourceTable struct { func (x *ResourceTable) Reset() { *x = ResourceTable{} - mi := &file_resource_proto_msgTypes[31] + mi := &file_resource_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2674,7 +2261,7 @@ func (x *ResourceTable) String() string { func (*ResourceTable) ProtoMessage() {} func (x *ResourceTable) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[31] + mi := &file_resource_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2687,7 +2274,7 @@ func (x *ResourceTable) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceTable.ProtoReflect.Descriptor instead. func (*ResourceTable) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{31} + return file_resource_proto_rawDescGZIP(), []int{27} } func (x *ResourceTable) GetColumns() []*ResourceTableColumnDefinition { @@ -2748,7 +2335,7 @@ type ResourceTableColumnDefinition struct { func (x *ResourceTableColumnDefinition) Reset() { *x = ResourceTableColumnDefinition{} - mi := &file_resource_proto_msgTypes[32] + mi := &file_resource_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2760,7 +2347,7 @@ func (x *ResourceTableColumnDefinition) String() string { func (*ResourceTableColumnDefinition) ProtoMessage() {} func (x *ResourceTableColumnDefinition) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[32] + mi := &file_resource_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2773,7 +2360,7 @@ func (x *ResourceTableColumnDefinition) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceTableColumnDefinition.ProtoReflect.Descriptor instead. func (*ResourceTableColumnDefinition) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{32} + return file_resource_proto_rawDescGZIP(), []int{28} } func (x *ResourceTableColumnDefinition) GetName() string { @@ -2841,7 +2428,7 @@ type ResourceTableRow struct { func (x *ResourceTableRow) Reset() { *x = ResourceTableRow{} - mi := &file_resource_proto_msgTypes[33] + mi := &file_resource_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2853,7 +2440,7 @@ func (x *ResourceTableRow) String() string { func (*ResourceTableRow) ProtoMessage() {} func (x *ResourceTableRow) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[33] + mi := &file_resource_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2865,352 +2452,34 @@ func (x *ResourceTableRow) ProtoReflect() protoreflect.Message { } // Deprecated: Use ResourceTableRow.ProtoReflect.Descriptor instead. -func (*ResourceTableRow) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{33} -} - -func (x *ResourceTableRow) GetKey() *ResourceKey { - if x != nil { - return x.Key - } - return nil -} - -func (x *ResourceTableRow) GetResourceVersion() int64 { - if x != nil { - return x.ResourceVersion - } - return 0 -} - -func (x *ResourceTableRow) GetCells() [][]byte { - if x != nil { - return x.Cells - } - return nil -} - -func (x *ResourceTableRow) GetObject() []byte { - if x != nil { - return x.Object - } - return nil -} - -type PutBlobRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // The resource that will use this blob - // NOTE: the name may not yet exist, but group+resource are required - Resource *ResourceKey `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` - // How to upload - Method PutBlobRequest_Method `protobuf:"varint,2,opt,name=method,proto3,enum=resource.PutBlobRequest_Method" json:"method,omitempty"` - // Content type header - ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` - // Raw value to write - // Not valid when method == HTTP - Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *PutBlobRequest) Reset() { - *x = PutBlobRequest{} - mi := &file_resource_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *PutBlobRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PutBlobRequest) ProtoMessage() {} - -func (x *PutBlobRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[34] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PutBlobRequest.ProtoReflect.Descriptor instead. -func (*PutBlobRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{34} -} - -func (x *PutBlobRequest) GetResource() *ResourceKey { - if x != nil { - return x.Resource - } - return nil -} - -func (x *PutBlobRequest) GetMethod() PutBlobRequest_Method { - if x != nil { - return x.Method - } - return PutBlobRequest_GRPC -} - -func (x *PutBlobRequest) GetContentType() string { - if x != nil { - return x.ContentType - } - return "" -} - -func (x *PutBlobRequest) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - -type PutBlobResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Error details - Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` - // The blob uid. This must be saved into the resource to support access - Uid string `protobuf:"bytes,2,opt,name=uid,proto3" json:"uid,omitempty"` - // The URL where this value can be PUT - Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url,omitempty"` - // Size of the uploaded blob - Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` - // Content hash used for an etag - Hash string `protobuf:"bytes,5,opt,name=hash,proto3" json:"hash,omitempty"` - // Validated mimetype (from content_type) - MimeType string `protobuf:"bytes,6,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"` - // Validated charset (from content_type) - Charset string `protobuf:"bytes,7,opt,name=charset,proto3" json:"charset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *PutBlobResponse) Reset() { - *x = PutBlobResponse{} - mi := &file_resource_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *PutBlobResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PutBlobResponse) ProtoMessage() {} - -func (x *PutBlobResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[35] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PutBlobResponse.ProtoReflect.Descriptor instead. -func (*PutBlobResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{35} -} - -func (x *PutBlobResponse) GetError() *ErrorResult { - if x != nil { - return x.Error - } - return nil -} - -func (x *PutBlobResponse) GetUid() string { - if x != nil { - return x.Uid - } - return "" -} - -func (x *PutBlobResponse) GetUrl() string { - if x != nil { - return x.Url - } - return "" -} - -func (x *PutBlobResponse) GetSize() int64 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *PutBlobResponse) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *PutBlobResponse) GetMimeType() string { - if x != nil { - return x.MimeType - } - return "" -} - -func (x *PutBlobResponse) GetCharset() string { - if x != nil { - return x.Charset - } - return "" -} - -type GetBlobRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Resource *ResourceKey `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` - // The new resource version - ResourceVersion int64 `protobuf:"varint,2,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` - // Do not return a pre-signed URL (when possible) - MustProxyBytes bool `protobuf:"varint,3,opt,name=must_proxy_bytes,json=mustProxyBytes,proto3" json:"must_proxy_bytes,omitempty"` - // The blob UID -- when empty, the value is loaded from annotations in the matching resource - Uid string `protobuf:"bytes,4,opt,name=uid,proto3" json:"uid,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetBlobRequest) Reset() { - *x = GetBlobRequest{} - mi := &file_resource_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetBlobRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlobRequest) ProtoMessage() {} - -func (x *GetBlobRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[36] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlobRequest.ProtoReflect.Descriptor instead. -func (*GetBlobRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{36} -} - -func (x *GetBlobRequest) GetResource() *ResourceKey { - if x != nil { - return x.Resource - } - return nil -} - -func (x *GetBlobRequest) GetResourceVersion() int64 { - if x != nil { - return x.ResourceVersion - } - return 0 -} - -func (x *GetBlobRequest) GetMustProxyBytes() bool { - if x != nil { - return x.MustProxyBytes - } - return false -} - -func (x *GetBlobRequest) GetUid() string { - if x != nil { - return x.Uid - } - return "" -} - -type GetBlobResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Error details - Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` - // (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 - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - // Content type - ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` - // The raw object value - Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetBlobResponse) Reset() { - *x = GetBlobResponse{} - mi := &file_resource_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetBlobResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlobResponse) ProtoMessage() {} - -func (x *GetBlobResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[37] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlobResponse.ProtoReflect.Descriptor instead. -func (*GetBlobResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{37} +func (*ResourceTableRow) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{29} } -func (x *GetBlobResponse) GetError() *ErrorResult { +func (x *ResourceTableRow) GetKey() *ResourceKey { if x != nil { - return x.Error + return x.Key } return nil } -func (x *GetBlobResponse) GetUrl() string { +func (x *ResourceTableRow) GetResourceVersion() int64 { if x != nil { - return x.Url + return x.ResourceVersion } - return "" + return 0 } -func (x *GetBlobResponse) GetContentType() string { +func (x *ResourceTableRow) GetCells() [][]byte { if x != nil { - return x.ContentType + return x.Cells } - return "" + return nil } -func (x *GetBlobResponse) GetValue() []byte { +func (x *ResourceTableRow) GetObject() []byte { if x != nil { - return x.Value + return x.Object } return nil } @@ -3225,7 +2494,7 @@ type WatchEvent_Resource struct { func (x *WatchEvent_Resource) Reset() { *x = WatchEvent_Resource{} - mi := &file_resource_proto_msgTypes[38] + mi := &file_resource_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3237,7 +2506,7 @@ func (x *WatchEvent_Resource) String() string { func (*WatchEvent_Resource) ProtoMessage() {} func (x *WatchEvent_Resource) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[38] + mi := &file_resource_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3284,7 +2553,7 @@ type BulkResponse_Summary struct { func (x *BulkResponse_Summary) Reset() { *x = BulkResponse_Summary{} - mi := &file_resource_proto_msgTypes[39] + mi := &file_resource_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3296,7 +2565,7 @@ func (x *BulkResponse_Summary) String() string { func (*BulkResponse_Summary) ProtoMessage() {} func (x *BulkResponse_Summary) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[39] + mi := &file_resource_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3380,7 +2649,7 @@ type BulkResponse_Rejected struct { func (x *BulkResponse_Rejected) Reset() { *x = BulkResponse_Rejected{} - mi := &file_resource_proto_msgTypes[40] + mi := &file_resource_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3392,7 +2661,7 @@ func (x *BulkResponse_Rejected) String() string { func (*BulkResponse_Rejected) ProtoMessage() {} func (x *BulkResponse_Rejected) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[40] + mi := &file_resource_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3429,296 +2698,6 @@ func (x *BulkResponse_Rejected) GetError() string { return "" } -type ResourceStatsResponse_Stats struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Resource group - Group string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - // Resource name - Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` - // Number of items - Count int64 `protobuf:"varint,3,opt,name=count,proto3" json:"count,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ResourceStatsResponse_Stats) Reset() { - *x = ResourceStatsResponse_Stats{} - mi := &file_resource_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ResourceStatsResponse_Stats) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResourceStatsResponse_Stats) ProtoMessage() {} - -func (x *ResourceStatsResponse_Stats) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[41] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResourceStatsResponse_Stats.ProtoReflect.Descriptor instead. -func (*ResourceStatsResponse_Stats) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{22, 0} -} - -func (x *ResourceStatsResponse_Stats) GetGroup() string { - if x != nil { - return x.Group - } - return "" -} - -func (x *ResourceStatsResponse_Stats) GetResource() string { - if x != nil { - return x.Resource - } - return "" -} - -func (x *ResourceStatsResponse_Stats) GetCount() int64 { - if x != nil { - return x.Count - } - return 0 -} - -type ResourceSearchRequest_Sort struct { - state protoimpl.MessageState `protogen:"open.v1"` - Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` - Desc bool `protobuf:"varint,2,opt,name=desc,proto3" json:"desc,omitempty"` // defaults to ascending - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ResourceSearchRequest_Sort) Reset() { - *x = ResourceSearchRequest_Sort{} - mi := &file_resource_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ResourceSearchRequest_Sort) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResourceSearchRequest_Sort) ProtoMessage() {} - -func (x *ResourceSearchRequest_Sort) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[42] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResourceSearchRequest_Sort.ProtoReflect.Descriptor instead. -func (*ResourceSearchRequest_Sort) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{23, 0} -} - -func (x *ResourceSearchRequest_Sort) GetField() string { - if x != nil { - return x.Field - } - return "" -} - -func (x *ResourceSearchRequest_Sort) GetDesc() bool { - if x != nil { - return x.Desc - } - return false -} - -type ResourceSearchRequest_Facet struct { - state protoimpl.MessageState `protogen:"open.v1"` - Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` - Limit int64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ResourceSearchRequest_Facet) Reset() { - *x = ResourceSearchRequest_Facet{} - mi := &file_resource_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ResourceSearchRequest_Facet) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResourceSearchRequest_Facet) ProtoMessage() {} - -func (x *ResourceSearchRequest_Facet) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[43] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResourceSearchRequest_Facet.ProtoReflect.Descriptor instead. -func (*ResourceSearchRequest_Facet) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{23, 1} -} - -func (x *ResourceSearchRequest_Facet) GetField() string { - if x != nil { - return x.Field - } - return "" -} - -func (x *ResourceSearchRequest_Facet) GetLimit() int64 { - if x != nil { - return x.Limit - } - return 0 -} - -type ResourceSearchResponse_Facet struct { - state protoimpl.MessageState `protogen:"open.v1"` - Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` - // The distinct terms - Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - // The number of documents that do *not* have this field - Missing int64 `protobuf:"varint,3,opt,name=missing,proto3" json:"missing,omitempty"` - // Top term stats - Terms []*ResourceSearchResponse_TermFacet `protobuf:"bytes,4,rep,name=terms,proto3" json:"terms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ResourceSearchResponse_Facet) Reset() { - *x = ResourceSearchResponse_Facet{} - mi := &file_resource_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ResourceSearchResponse_Facet) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResourceSearchResponse_Facet) ProtoMessage() {} - -func (x *ResourceSearchResponse_Facet) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[45] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResourceSearchResponse_Facet.ProtoReflect.Descriptor instead. -func (*ResourceSearchResponse_Facet) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{24, 0} -} - -func (x *ResourceSearchResponse_Facet) GetField() string { - if x != nil { - return x.Field - } - return "" -} - -func (x *ResourceSearchResponse_Facet) GetTotal() int64 { - if x != nil { - return x.Total - } - return 0 -} - -func (x *ResourceSearchResponse_Facet) GetMissing() int64 { - if x != nil { - return x.Missing - } - return 0 -} - -func (x *ResourceSearchResponse_Facet) GetTerms() []*ResourceSearchResponse_TermFacet { - if x != nil { - return x.Terms - } - return nil -} - -type ResourceSearchResponse_TermFacet struct { - state protoimpl.MessageState `protogen:"open.v1"` - Term string `protobuf:"bytes,1,opt,name=term,proto3" json:"term,omitempty"` - Count int64 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ResourceSearchResponse_TermFacet) Reset() { - *x = ResourceSearchResponse_TermFacet{} - mi := &file_resource_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ResourceSearchResponse_TermFacet) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResourceSearchResponse_TermFacet) ProtoMessage() {} - -func (x *ResourceSearchResponse_TermFacet) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[46] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResourceSearchResponse_TermFacet.ProtoReflect.Descriptor instead. -func (*ResourceSearchResponse_TermFacet) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{24, 1} -} - -func (x *ResourceSearchResponse_TermFacet) GetTerm() string { - if x != nil { - return x.Term - } - return "" -} - -func (x *ResourceSearchResponse_TermFacet) GetCount() int64 { - if x != nil { - return x.Count - } - return 0 -} - type ListManagedObjectsResponse_Item struct { state protoimpl.MessageState `protogen:"open.v1"` // The resource object key @@ -3739,7 +2718,7 @@ type ListManagedObjectsResponse_Item struct { func (x *ListManagedObjectsResponse_Item) Reset() { *x = ListManagedObjectsResponse_Item{} - mi := &file_resource_proto_msgTypes[48] + mi := &file_resource_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3751,7 +2730,7 @@ func (x *ListManagedObjectsResponse_Item) String() string { func (*ListManagedObjectsResponse_Item) ProtoMessage() {} func (x *ListManagedObjectsResponse_Item) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[48] + mi := &file_resource_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3764,7 +2743,7 @@ func (x *ListManagedObjectsResponse_Item) ProtoReflect() protoreflect.Message { // Deprecated: Use ListManagedObjectsResponse_Item.ProtoReflect.Descriptor instead. func (*ListManagedObjectsResponse_Item) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{26, 0} + return file_resource_proto_rawDescGZIP(), []int{22, 0} } func (x *ListManagedObjectsResponse_Item) GetObject() *ResourceKey { @@ -3822,7 +2801,7 @@ type CountManagedObjectsResponse_ResourceCount struct { func (x *CountManagedObjectsResponse_ResourceCount) Reset() { *x = CountManagedObjectsResponse_ResourceCount{} - mi := &file_resource_proto_msgTypes[49] + mi := &file_resource_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3834,7 +2813,7 @@ func (x *CountManagedObjectsResponse_ResourceCount) String() string { func (*CountManagedObjectsResponse_ResourceCount) ProtoMessage() {} func (x *CountManagedObjectsResponse_ResourceCount) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[49] + mi := &file_resource_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3847,7 +2826,7 @@ func (x *CountManagedObjectsResponse_ResourceCount) ProtoReflect() protoreflect. // Deprecated: Use CountManagedObjectsResponse_ResourceCount.ProtoReflect.Descriptor instead. func (*CountManagedObjectsResponse_ResourceCount) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{28, 0} + return file_resource_proto_rawDescGZIP(), []int{24, 0} } func (x *CountManagedObjectsResponse_ResourceCount) GetKind() string { @@ -3907,7 +2886,7 @@ type ResourceTableColumnDefinition_Properties struct { func (x *ResourceTableColumnDefinition_Properties) Reset() { *x = ResourceTableColumnDefinition_Properties{} - mi := &file_resource_proto_msgTypes[50] + mi := &file_resource_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3919,7 +2898,7 @@ func (x *ResourceTableColumnDefinition_Properties) String() string { func (*ResourceTableColumnDefinition_Properties) ProtoMessage() {} func (x *ResourceTableColumnDefinition_Properties) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[50] + mi := &file_resource_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3932,7 +2911,7 @@ func (x *ResourceTableColumnDefinition_Properties) ProtoReflect() protoreflect.M // Deprecated: Use ResourceTableColumnDefinition_Properties.ProtoReflect.Descriptor instead. func (*ResourceTableColumnDefinition_Properties) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{32, 0} + return file_resource_proto_rawDescGZIP(), []int{28, 0} } func (x *ResourceTableColumnDefinition_Properties) GetUniqueValues() bool { @@ -4209,365 +3188,200 @@ var file_resource_proto_rawDesc = string([]byte{ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x62, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x69, - 0x6e, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0xd2, 0x01, 0x0a, 0x15, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x1a, - 0x4f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, - 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x22, 0x8e, 0x05, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x66, - 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, - 0x42, 0x79, 0x12, 0x40, 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, - 0x61, 0x63, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x08, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, - 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, - 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x30, 0x0a, 0x04, 0x53, 0x6f, 0x72, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x1a, 0x33, 0x0a, 0x05, 0x46, - 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x1a, 0x5f, 0x0a, 0x0a, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x3b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0xea, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x07, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x68, - 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x48, 0x69, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, - 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x43, - 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x12, 0x41, 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x61, - 0x63, 0x65, 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x05, 0x46, 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6e, 0x67, 0x12, 0x40, 0x0a, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, - 0x74, 0x65, 0x72, 0x6d, 0x73, 0x1a, 0x35, 0x0a, 0x09, 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, 0x63, - 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x60, 0x0a, 0x0a, - 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x61, - 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x85, - 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, - 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xd4, 0x02, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x4d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, - 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, - 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x9f, 0x01, 0x0a, 0x04, - 0x49, 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0x5e, 0x0a, - 0x1a, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x92, 0x02, - 0x0a, 0x1b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, - 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x85, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, + 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, + 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0xd4, 0x02, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, + 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x7b, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, - 0x4f, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, - 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, - 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, - 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, - 0x22, 0x87, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x52, - 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, - 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x61, - 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, - 0x67, 0x49, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xf1, 0x04, 0x0a, 0x1d, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, - 0x72, 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, - 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x52, 0x0a, 0x70, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x1a, 0xae, 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, - 0x71, 0x75, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x65, - 0x65, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x72, - 0x65, 0x65, 0x54, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x75, - 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x6f, 0x74, 0x4e, 0x75, 0x6c, - 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x95, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, - 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, - 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, - 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, - 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, - 0x04, 0x44, 0x41, 0x54, 0x45, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, - 0x54, 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, - 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0a, 0x22, 0x94, - 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x52, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x16, 0x0a, - 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xd3, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, - 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, - 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x6d, - 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1c, 0x0a, - 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x10, - 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x22, 0xc1, 0x01, 0x0a, 0x0f, - 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, - 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, - 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x22, - 0xaa, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, + 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, + 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x9f, 0x01, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, + 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0x5e, 0x0a, 0x1a, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x92, 0x02, 0x0a, 0x1b, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x7b, + 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, + 0x69, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, + 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, + 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, + 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x22, 0x87, 0x02, 0x0a, 0x0d, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x07, 0x63, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2e, + 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x26, + 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x69, + 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x12, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x22, 0xf1, 0x04, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, + 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x1a, 0xae, + 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, + 0x0d, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x72, 0x65, 0x65, 0x54, 0x65, 0x78, 0x74, 0x12, + 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x6e, 0x6f, 0x74, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x95, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, + 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, + 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, + 0x33, 0x32, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, + 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, + 0x55, 0x42, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x45, 0x10, 0x07, + 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, + 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x4f, + 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0a, 0x22, 0x94, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x73, 0x74, - 0x50, 0x72, 0x6f, 0x78, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x22, 0x89, 0x01, 0x0a, - 0x0f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, - 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, - 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x49, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, - 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x4e, - 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x14, 0x0a, - 0x10, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x45, 0x78, 0x61, 0x63, - 0x74, 0x10, 0x01, 0x2a, 0x4d, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x56, 0x32, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x6e, - 0x73, 0x65, 0x74, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x02, - 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, - 0x10, 0x03, 0x32, 0xed, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, - 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, - 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, - 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x30, 0x01, 0x32, 0x4b, 0x0a, 0x09, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, - 0x3e, 0x0a, 0x0b, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x15, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x32, - 0xa9, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x4b, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, - 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd9, 0x01, 0x0a, 0x12, - 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2a, 0x49, + 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, + 0x41, 0x54, 0x45, 0x44, 0x5f, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, + 0x6e, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, + 0x44, 0x5f, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x01, 0x2a, 0x4d, 0x0a, 0x16, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x56, 0x32, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, + 0x78, 0x61, 0x63, 0x74, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, + 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x03, 0x32, 0xed, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65, + 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, + 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0x4b, 0x0a, 0x09, 0x42, 0x75, 0x6c, 0x6b, + 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x28, 0x01, 0x32, 0xd9, 0x01, 0x0a, 0x12, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x62, 0x0a, 0x13, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x62, - 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, - 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, - 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, - 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, - 0x74, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, - 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x39, - 0x5a, 0x37, 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, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5f, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x32, 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x12, 0x48, 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3b, 0x5a, 0x39, 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, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -4582,8 +3396,8 @@ func file_resource_proto_rawDescGZIP() []byte { return file_resource_proto_rawDescData } -var file_resource_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 51) +var file_resource_proto_enumTypes = make([]protoimpl.EnumInfo, 7) +var file_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 36) var file_resource_proto_goTypes = []any{ (ResourceVersionMatch)(0), // 0: resource.ResourceVersionMatch (ResourceVersionMatchV2)(0), // 1: resource.ResourceVersionMatchV2 @@ -4592,152 +3406,110 @@ var file_resource_proto_goTypes = []any{ (BulkRequest_Action)(0), // 4: resource.BulkRequest.Action (HealthCheckResponse_ServingStatus)(0), // 5: resource.HealthCheckResponse.ServingStatus (ResourceTableColumnDefinition_ColumnType)(0), // 6: resource.ResourceTableColumnDefinition.ColumnType - (PutBlobRequest_Method)(0), // 7: resource.PutBlobRequest.Method - (*ResourceKey)(nil), // 8: resource.ResourceKey - (*ResourceWrapper)(nil), // 9: resource.ResourceWrapper - (*ErrorResult)(nil), // 10: resource.ErrorResult - (*ErrorDetails)(nil), // 11: resource.ErrorDetails - (*ErrorCause)(nil), // 12: resource.ErrorCause - (*CreateRequest)(nil), // 13: resource.CreateRequest - (*CreateResponse)(nil), // 14: resource.CreateResponse - (*UpdateRequest)(nil), // 15: resource.UpdateRequest - (*UpdateResponse)(nil), // 16: resource.UpdateResponse - (*DeleteRequest)(nil), // 17: resource.DeleteRequest - (*DeleteResponse)(nil), // 18: resource.DeleteResponse - (*ReadRequest)(nil), // 19: resource.ReadRequest - (*ReadResponse)(nil), // 20: resource.ReadResponse - (*Requirement)(nil), // 21: resource.Requirement - (*ListOptions)(nil), // 22: resource.ListOptions - (*ListRequest)(nil), // 23: resource.ListRequest - (*ListResponse)(nil), // 24: resource.ListResponse - (*WatchRequest)(nil), // 25: resource.WatchRequest - (*WatchEvent)(nil), // 26: resource.WatchEvent - (*BulkRequest)(nil), // 27: resource.BulkRequest - (*BulkResponse)(nil), // 28: resource.BulkResponse - (*ResourceStatsRequest)(nil), // 29: resource.ResourceStatsRequest - (*ResourceStatsResponse)(nil), // 30: resource.ResourceStatsResponse - (*ResourceSearchRequest)(nil), // 31: resource.ResourceSearchRequest - (*ResourceSearchResponse)(nil), // 32: resource.ResourceSearchResponse - (*ListManagedObjectsRequest)(nil), // 33: resource.ListManagedObjectsRequest - (*ListManagedObjectsResponse)(nil), // 34: resource.ListManagedObjectsResponse - (*CountManagedObjectsRequest)(nil), // 35: resource.CountManagedObjectsRequest - (*CountManagedObjectsResponse)(nil), // 36: resource.CountManagedObjectsResponse - (*HealthCheckRequest)(nil), // 37: resource.HealthCheckRequest - (*HealthCheckResponse)(nil), // 38: resource.HealthCheckResponse - (*ResourceTable)(nil), // 39: resource.ResourceTable - (*ResourceTableColumnDefinition)(nil), // 40: resource.ResourceTableColumnDefinition - (*ResourceTableRow)(nil), // 41: resource.ResourceTableRow - (*PutBlobRequest)(nil), // 42: resource.PutBlobRequest - (*PutBlobResponse)(nil), // 43: resource.PutBlobResponse - (*GetBlobRequest)(nil), // 44: resource.GetBlobRequest - (*GetBlobResponse)(nil), // 45: resource.GetBlobResponse - (*WatchEvent_Resource)(nil), // 46: resource.WatchEvent.Resource - (*BulkResponse_Summary)(nil), // 47: resource.BulkResponse.Summary - (*BulkResponse_Rejected)(nil), // 48: resource.BulkResponse.Rejected - (*ResourceStatsResponse_Stats)(nil), // 49: resource.ResourceStatsResponse.Stats - (*ResourceSearchRequest_Sort)(nil), // 50: resource.ResourceSearchRequest.Sort - (*ResourceSearchRequest_Facet)(nil), // 51: resource.ResourceSearchRequest.Facet - nil, // 52: resource.ResourceSearchRequest.FacetEntry - (*ResourceSearchResponse_Facet)(nil), // 53: resource.ResourceSearchResponse.Facet - (*ResourceSearchResponse_TermFacet)(nil), // 54: resource.ResourceSearchResponse.TermFacet - nil, // 55: resource.ResourceSearchResponse.FacetEntry - (*ListManagedObjectsResponse_Item)(nil), // 56: resource.ListManagedObjectsResponse.Item - (*CountManagedObjectsResponse_ResourceCount)(nil), // 57: resource.CountManagedObjectsResponse.ResourceCount - (*ResourceTableColumnDefinition_Properties)(nil), // 58: resource.ResourceTableColumnDefinition.Properties + (*ResourceKey)(nil), // 7: resource.ResourceKey + (*ResourceWrapper)(nil), // 8: resource.ResourceWrapper + (*ErrorResult)(nil), // 9: resource.ErrorResult + (*ErrorDetails)(nil), // 10: resource.ErrorDetails + (*ErrorCause)(nil), // 11: resource.ErrorCause + (*CreateRequest)(nil), // 12: resource.CreateRequest + (*CreateResponse)(nil), // 13: resource.CreateResponse + (*UpdateRequest)(nil), // 14: resource.UpdateRequest + (*UpdateResponse)(nil), // 15: resource.UpdateResponse + (*DeleteRequest)(nil), // 16: resource.DeleteRequest + (*DeleteResponse)(nil), // 17: resource.DeleteResponse + (*ReadRequest)(nil), // 18: resource.ReadRequest + (*ReadResponse)(nil), // 19: resource.ReadResponse + (*Requirement)(nil), // 20: resource.Requirement + (*ListOptions)(nil), // 21: resource.ListOptions + (*ListRequest)(nil), // 22: resource.ListRequest + (*ListResponse)(nil), // 23: resource.ListResponse + (*WatchRequest)(nil), // 24: resource.WatchRequest + (*WatchEvent)(nil), // 25: resource.WatchEvent + (*BulkRequest)(nil), // 26: resource.BulkRequest + (*BulkResponse)(nil), // 27: resource.BulkResponse + (*ListManagedObjectsRequest)(nil), // 28: resource.ListManagedObjectsRequest + (*ListManagedObjectsResponse)(nil), // 29: resource.ListManagedObjectsResponse + (*CountManagedObjectsRequest)(nil), // 30: resource.CountManagedObjectsRequest + (*CountManagedObjectsResponse)(nil), // 31: resource.CountManagedObjectsResponse + (*HealthCheckRequest)(nil), // 32: resource.HealthCheckRequest + (*HealthCheckResponse)(nil), // 33: resource.HealthCheckResponse + (*ResourceTable)(nil), // 34: resource.ResourceTable + (*ResourceTableColumnDefinition)(nil), // 35: resource.ResourceTableColumnDefinition + (*ResourceTableRow)(nil), // 36: resource.ResourceTableRow + (*WatchEvent_Resource)(nil), // 37: resource.WatchEvent.Resource + (*BulkResponse_Summary)(nil), // 38: resource.BulkResponse.Summary + (*BulkResponse_Rejected)(nil), // 39: resource.BulkResponse.Rejected + (*ListManagedObjectsResponse_Item)(nil), // 40: resource.ListManagedObjectsResponse.Item + (*CountManagedObjectsResponse_ResourceCount)(nil), // 41: resource.CountManagedObjectsResponse.ResourceCount + (*ResourceTableColumnDefinition_Properties)(nil), // 42: resource.ResourceTableColumnDefinition.Properties } var file_resource_proto_depIdxs = []int32{ - 11, // 0: resource.ErrorResult.details:type_name -> resource.ErrorDetails - 12, // 1: resource.ErrorDetails.causes:type_name -> resource.ErrorCause - 8, // 2: resource.CreateRequest.key:type_name -> resource.ResourceKey - 10, // 3: resource.CreateResponse.error:type_name -> resource.ErrorResult - 8, // 4: resource.UpdateRequest.key:type_name -> resource.ResourceKey - 10, // 5: resource.UpdateResponse.error:type_name -> resource.ErrorResult - 8, // 6: resource.DeleteRequest.key:type_name -> resource.ResourceKey - 10, // 7: resource.DeleteResponse.error:type_name -> resource.ErrorResult - 8, // 8: resource.ReadRequest.key:type_name -> resource.ResourceKey - 10, // 9: resource.ReadResponse.error:type_name -> resource.ErrorResult - 8, // 10: resource.ListOptions.key:type_name -> resource.ResourceKey - 21, // 11: resource.ListOptions.labels:type_name -> resource.Requirement - 21, // 12: resource.ListOptions.fields:type_name -> resource.Requirement + 10, // 0: resource.ErrorResult.details:type_name -> resource.ErrorDetails + 11, // 1: resource.ErrorDetails.causes:type_name -> resource.ErrorCause + 7, // 2: resource.CreateRequest.key:type_name -> resource.ResourceKey + 9, // 3: resource.CreateResponse.error:type_name -> resource.ErrorResult + 7, // 4: resource.UpdateRequest.key:type_name -> resource.ResourceKey + 9, // 5: resource.UpdateResponse.error:type_name -> resource.ErrorResult + 7, // 6: resource.DeleteRequest.key:type_name -> resource.ResourceKey + 9, // 7: resource.DeleteResponse.error:type_name -> resource.ErrorResult + 7, // 8: resource.ReadRequest.key:type_name -> resource.ResourceKey + 9, // 9: resource.ReadResponse.error:type_name -> resource.ErrorResult + 7, // 10: resource.ListOptions.key:type_name -> resource.ResourceKey + 20, // 11: resource.ListOptions.labels:type_name -> resource.Requirement + 20, // 12: resource.ListOptions.fields:type_name -> resource.Requirement 0, // 13: resource.ListRequest.version_match:type_name -> resource.ResourceVersionMatch - 22, // 14: resource.ListRequest.options:type_name -> resource.ListOptions + 21, // 14: resource.ListRequest.options:type_name -> resource.ListOptions 2, // 15: resource.ListRequest.source:type_name -> resource.ListRequest.Source 1, // 16: resource.ListRequest.version_match_v2:type_name -> resource.ResourceVersionMatchV2 - 9, // 17: resource.ListResponse.items:type_name -> resource.ResourceWrapper - 10, // 18: resource.ListResponse.error:type_name -> resource.ErrorResult - 22, // 19: resource.WatchRequest.options:type_name -> resource.ListOptions + 8, // 17: resource.ListResponse.items:type_name -> resource.ResourceWrapper + 9, // 18: resource.ListResponse.error:type_name -> resource.ErrorResult + 21, // 19: resource.WatchRequest.options:type_name -> resource.ListOptions 3, // 20: resource.WatchEvent.type:type_name -> resource.WatchEvent.Type - 46, // 21: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource - 46, // 22: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource - 8, // 23: resource.BulkRequest.key:type_name -> resource.ResourceKey + 37, // 21: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource + 37, // 22: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource + 7, // 23: resource.BulkRequest.key:type_name -> resource.ResourceKey 4, // 24: resource.BulkRequest.action:type_name -> resource.BulkRequest.Action - 10, // 25: resource.BulkResponse.error:type_name -> resource.ErrorResult - 47, // 26: resource.BulkResponse.summary:type_name -> resource.BulkResponse.Summary - 48, // 27: resource.BulkResponse.rejected:type_name -> resource.BulkResponse.Rejected - 10, // 28: resource.ResourceStatsResponse.error:type_name -> resource.ErrorResult - 49, // 29: resource.ResourceStatsResponse.stats:type_name -> resource.ResourceStatsResponse.Stats - 22, // 30: resource.ResourceSearchRequest.options:type_name -> resource.ListOptions - 8, // 31: resource.ResourceSearchRequest.federated:type_name -> resource.ResourceKey - 50, // 32: resource.ResourceSearchRequest.sortBy:type_name -> resource.ResourceSearchRequest.Sort - 52, // 33: resource.ResourceSearchRequest.facet:type_name -> resource.ResourceSearchRequest.FacetEntry - 10, // 34: resource.ResourceSearchResponse.error:type_name -> resource.ErrorResult - 8, // 35: resource.ResourceSearchResponse.key:type_name -> resource.ResourceKey - 39, // 36: resource.ResourceSearchResponse.results:type_name -> resource.ResourceTable - 55, // 37: resource.ResourceSearchResponse.facet:type_name -> resource.ResourceSearchResponse.FacetEntry - 56, // 38: resource.ListManagedObjectsResponse.items:type_name -> resource.ListManagedObjectsResponse.Item - 10, // 39: resource.ListManagedObjectsResponse.error:type_name -> resource.ErrorResult - 57, // 40: resource.CountManagedObjectsResponse.items:type_name -> resource.CountManagedObjectsResponse.ResourceCount - 10, // 41: resource.CountManagedObjectsResponse.error:type_name -> resource.ErrorResult - 5, // 42: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus - 40, // 43: resource.ResourceTable.columns:type_name -> resource.ResourceTableColumnDefinition - 41, // 44: resource.ResourceTable.rows:type_name -> resource.ResourceTableRow - 6, // 45: resource.ResourceTableColumnDefinition.type:type_name -> resource.ResourceTableColumnDefinition.ColumnType - 58, // 46: resource.ResourceTableColumnDefinition.properties:type_name -> resource.ResourceTableColumnDefinition.Properties - 8, // 47: resource.ResourceTableRow.key:type_name -> resource.ResourceKey - 8, // 48: resource.PutBlobRequest.resource:type_name -> resource.ResourceKey - 7, // 49: resource.PutBlobRequest.method:type_name -> resource.PutBlobRequest.Method - 10, // 50: resource.PutBlobResponse.error:type_name -> resource.ErrorResult - 8, // 51: resource.GetBlobRequest.resource:type_name -> resource.ResourceKey - 10, // 52: resource.GetBlobResponse.error:type_name -> resource.ErrorResult - 8, // 53: resource.BulkResponse.Rejected.key:type_name -> resource.ResourceKey - 4, // 54: resource.BulkResponse.Rejected.action:type_name -> resource.BulkRequest.Action - 51, // 55: resource.ResourceSearchRequest.FacetEntry.value:type_name -> resource.ResourceSearchRequest.Facet - 54, // 56: resource.ResourceSearchResponse.Facet.terms:type_name -> resource.ResourceSearchResponse.TermFacet - 53, // 57: resource.ResourceSearchResponse.FacetEntry.value:type_name -> resource.ResourceSearchResponse.Facet - 8, // 58: resource.ListManagedObjectsResponse.Item.object:type_name -> resource.ResourceKey - 19, // 59: resource.ResourceStore.Read:input_type -> resource.ReadRequest - 13, // 60: resource.ResourceStore.Create:input_type -> resource.CreateRequest - 15, // 61: resource.ResourceStore.Update:input_type -> resource.UpdateRequest - 17, // 62: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest - 23, // 63: resource.ResourceStore.List:input_type -> resource.ListRequest - 25, // 64: resource.ResourceStore.Watch:input_type -> resource.WatchRequest - 27, // 65: resource.BulkStore.BulkProcess:input_type -> resource.BulkRequest - 31, // 66: resource.ResourceIndex.Search:input_type -> resource.ResourceSearchRequest - 29, // 67: resource.ResourceIndex.GetStats:input_type -> resource.ResourceStatsRequest - 35, // 68: resource.ManagedObjectIndex.CountManagedObjects:input_type -> resource.CountManagedObjectsRequest - 33, // 69: resource.ManagedObjectIndex.ListManagedObjects:input_type -> resource.ListManagedObjectsRequest - 42, // 70: resource.BlobStore.PutBlob:input_type -> resource.PutBlobRequest - 44, // 71: resource.BlobStore.GetBlob:input_type -> resource.GetBlobRequest - 37, // 72: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest - 20, // 73: resource.ResourceStore.Read:output_type -> resource.ReadResponse - 14, // 74: resource.ResourceStore.Create:output_type -> resource.CreateResponse - 16, // 75: resource.ResourceStore.Update:output_type -> resource.UpdateResponse - 18, // 76: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse - 24, // 77: resource.ResourceStore.List:output_type -> resource.ListResponse - 26, // 78: resource.ResourceStore.Watch:output_type -> resource.WatchEvent - 28, // 79: resource.BulkStore.BulkProcess:output_type -> resource.BulkResponse - 32, // 80: resource.ResourceIndex.Search:output_type -> resource.ResourceSearchResponse - 30, // 81: resource.ResourceIndex.GetStats:output_type -> resource.ResourceStatsResponse - 36, // 82: resource.ManagedObjectIndex.CountManagedObjects:output_type -> resource.CountManagedObjectsResponse - 34, // 83: resource.ManagedObjectIndex.ListManagedObjects:output_type -> resource.ListManagedObjectsResponse - 43, // 84: resource.BlobStore.PutBlob:output_type -> resource.PutBlobResponse - 45, // 85: resource.BlobStore.GetBlob:output_type -> resource.GetBlobResponse - 38, // 86: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse - 73, // [73:87] is the sub-list for method output_type - 59, // [59:73] is the sub-list for method input_type - 59, // [59:59] is the sub-list for extension type_name - 59, // [59:59] is the sub-list for extension extendee - 0, // [0:59] is the sub-list for field type_name + 9, // 25: resource.BulkResponse.error:type_name -> resource.ErrorResult + 38, // 26: resource.BulkResponse.summary:type_name -> resource.BulkResponse.Summary + 39, // 27: resource.BulkResponse.rejected:type_name -> resource.BulkResponse.Rejected + 40, // 28: resource.ListManagedObjectsResponse.items:type_name -> resource.ListManagedObjectsResponse.Item + 9, // 29: resource.ListManagedObjectsResponse.error:type_name -> resource.ErrorResult + 41, // 30: resource.CountManagedObjectsResponse.items:type_name -> resource.CountManagedObjectsResponse.ResourceCount + 9, // 31: resource.CountManagedObjectsResponse.error:type_name -> resource.ErrorResult + 5, // 32: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus + 35, // 33: resource.ResourceTable.columns:type_name -> resource.ResourceTableColumnDefinition + 36, // 34: resource.ResourceTable.rows:type_name -> resource.ResourceTableRow + 6, // 35: resource.ResourceTableColumnDefinition.type:type_name -> resource.ResourceTableColumnDefinition.ColumnType + 42, // 36: resource.ResourceTableColumnDefinition.properties:type_name -> resource.ResourceTableColumnDefinition.Properties + 7, // 37: resource.ResourceTableRow.key:type_name -> resource.ResourceKey + 7, // 38: resource.BulkResponse.Rejected.key:type_name -> resource.ResourceKey + 4, // 39: resource.BulkResponse.Rejected.action:type_name -> resource.BulkRequest.Action + 7, // 40: resource.ListManagedObjectsResponse.Item.object:type_name -> resource.ResourceKey + 18, // 41: resource.ResourceStore.Read:input_type -> resource.ReadRequest + 12, // 42: resource.ResourceStore.Create:input_type -> resource.CreateRequest + 14, // 43: resource.ResourceStore.Update:input_type -> resource.UpdateRequest + 16, // 44: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest + 22, // 45: resource.ResourceStore.List:input_type -> resource.ListRequest + 24, // 46: resource.ResourceStore.Watch:input_type -> resource.WatchRequest + 26, // 47: resource.BulkStore.BulkProcess:input_type -> resource.BulkRequest + 30, // 48: resource.ManagedObjectIndex.CountManagedObjects:input_type -> resource.CountManagedObjectsRequest + 28, // 49: resource.ManagedObjectIndex.ListManagedObjects:input_type -> resource.ListManagedObjectsRequest + 32, // 50: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest + 19, // 51: resource.ResourceStore.Read:output_type -> resource.ReadResponse + 13, // 52: resource.ResourceStore.Create:output_type -> resource.CreateResponse + 15, // 53: resource.ResourceStore.Update:output_type -> resource.UpdateResponse + 17, // 54: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse + 23, // 55: resource.ResourceStore.List:output_type -> resource.ListResponse + 25, // 56: resource.ResourceStore.Watch:output_type -> resource.WatchEvent + 27, // 57: resource.BulkStore.BulkProcess:output_type -> resource.BulkResponse + 31, // 58: resource.ManagedObjectIndex.CountManagedObjects:output_type -> resource.CountManagedObjectsResponse + 29, // 59: resource.ManagedObjectIndex.ListManagedObjects:output_type -> resource.ListManagedObjectsResponse + 33, // 60: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse + 51, // [51:61] is the sub-list for method output_type + 41, // [41:51] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name } func init() { file_resource_proto_init() } @@ -4751,10 +3523,10 @@ func file_resource_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_proto_rawDesc), len(file_resource_proto_rawDesc)), - NumEnums: 8, - NumMessages: 51, + NumEnums: 7, + NumMessages: 36, NumExtensions: 0, - NumServices: 6, + NumServices: 4, }, GoTypes: file_resource_proto_goTypes, DependencyIndexes: file_resource_proto_depIdxs, diff --git a/pkg/storage/unified/resource/resource_grpc.pb.go b/pkg/storage/unified/resourcepb/resource_grpc.pb.go similarity index 72% rename from pkg/storage/unified/resource/resource_grpc.pb.go rename to pkg/storage/unified/resourcepb/resource_grpc.pb.go index 4186147ef7c..c90aa0f26a6 100644 --- a/pkg/storage/unified/resource/resource_grpc.pb.go +++ b/pkg/storage/unified/resourcepb/resource_grpc.pb.go @@ -4,7 +4,7 @@ // - protoc (unknown) // source: resource.proto -package resource +package resourcepb import ( context "context" @@ -476,141 +476,6 @@ var BulkStore_ServiceDesc = grpc.ServiceDesc{ Metadata: "resource.proto", } -const ( - ResourceIndex_Search_FullMethodName = "/resource.ResourceIndex/Search" - ResourceIndex_GetStats_FullMethodName = "/resource.ResourceIndex/GetStats" -) - -// ResourceIndexClient is the client API for ResourceIndex service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -// -// 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 -type ResourceIndexClient interface { - Search(ctx context.Context, in *ResourceSearchRequest, opts ...grpc.CallOption) (*ResourceSearchResponse, error) - // Get the resource stats - GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error) -} - -type resourceIndexClient struct { - cc grpc.ClientConnInterface -} - -func NewResourceIndexClient(cc grpc.ClientConnInterface) ResourceIndexClient { - return &resourceIndexClient{cc} -} - -func (c *resourceIndexClient) Search(ctx context.Context, in *ResourceSearchRequest, opts ...grpc.CallOption) (*ResourceSearchResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(ResourceSearchResponse) - err := c.cc.Invoke(ctx, ResourceIndex_Search_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *resourceIndexClient) GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(ResourceStatsResponse) - err := c.cc.Invoke(ctx, ResourceIndex_GetStats_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ResourceIndexServer is the server API for ResourceIndex service. -// All implementations should embed UnimplementedResourceIndexServer -// for forward compatibility -// -// 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 -type ResourceIndexServer interface { - Search(context.Context, *ResourceSearchRequest) (*ResourceSearchResponse, error) - // Get the resource stats - GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error) -} - -// UnimplementedResourceIndexServer should be embedded to have forward compatible implementations. -type UnimplementedResourceIndexServer struct { -} - -func (UnimplementedResourceIndexServer) Search(context.Context, *ResourceSearchRequest) (*ResourceSearchResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Search not implemented") -} -func (UnimplementedResourceIndexServer) GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetStats not implemented") -} - -// UnsafeResourceIndexServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to ResourceIndexServer will -// result in compilation errors. -type UnsafeResourceIndexServer interface { - mustEmbedUnimplementedResourceIndexServer() -} - -func RegisterResourceIndexServer(s grpc.ServiceRegistrar, srv ResourceIndexServer) { - s.RegisterService(&ResourceIndex_ServiceDesc, srv) -} - -func _ResourceIndex_Search_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ResourceSearchRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ResourceIndexServer).Search(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ResourceIndex_Search_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ResourceIndexServer).Search(ctx, req.(*ResourceSearchRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ResourceIndex_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ResourceStatsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ResourceIndexServer).GetStats(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ResourceIndex_GetStats_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ResourceIndexServer).GetStats(ctx, req.(*ResourceStatsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// ResourceIndex_ServiceDesc is the grpc.ServiceDesc for ResourceIndex service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var ResourceIndex_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "resource.ResourceIndex", - HandlerType: (*ResourceIndexServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Search", - Handler: _ResourceIndex_Search_Handler, - }, - { - MethodName: "GetStats", - Handler: _ResourceIndex_GetStats_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "resource.proto", -} - const ( ManagedObjectIndex_CountManagedObjects_FullMethodName = "/resource.ManagedObjectIndex/CountManagedObjects" ManagedObjectIndex_ListManagedObjects_FullMethodName = "/resource.ManagedObjectIndex/ListManagedObjects" @@ -748,139 +613,6 @@ var ManagedObjectIndex_ServiceDesc = grpc.ServiceDesc{ Metadata: "resource.proto", } -const ( - BlobStore_PutBlob_FullMethodName = "/resource.BlobStore/PutBlob" - BlobStore_GetBlob_FullMethodName = "/resource.BlobStore/GetBlob" -) - -// BlobStoreClient is the client API for BlobStore service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type BlobStoreClient interface { - // Upload a blob that will be saved in a resource - PutBlob(ctx context.Context, in *PutBlobRequest, opts ...grpc.CallOption) (*PutBlobResponse, error) - // Get blob contents. When possible, this will return a signed URL - // For large payloads, signed URLs are required to avoid protobuf message size limits - GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error) -} - -type blobStoreClient struct { - cc grpc.ClientConnInterface -} - -func NewBlobStoreClient(cc grpc.ClientConnInterface) BlobStoreClient { - return &blobStoreClient{cc} -} - -func (c *blobStoreClient) PutBlob(ctx context.Context, in *PutBlobRequest, opts ...grpc.CallOption) (*PutBlobResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(PutBlobResponse) - err := c.cc.Invoke(ctx, BlobStore_PutBlob_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *blobStoreClient) GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetBlobResponse) - err := c.cc.Invoke(ctx, BlobStore_GetBlob_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// BlobStoreServer is the server API for BlobStore service. -// All implementations should embed UnimplementedBlobStoreServer -// for forward compatibility -type BlobStoreServer interface { - // Upload a blob that will be saved in a resource - PutBlob(context.Context, *PutBlobRequest) (*PutBlobResponse, error) - // Get blob contents. When possible, this will return a signed URL - // For large payloads, signed URLs are required to avoid protobuf message size limits - GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error) -} - -// UnimplementedBlobStoreServer should be embedded to have forward compatible implementations. -type UnimplementedBlobStoreServer struct { -} - -func (UnimplementedBlobStoreServer) PutBlob(context.Context, *PutBlobRequest) (*PutBlobResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method PutBlob not implemented") -} -func (UnimplementedBlobStoreServer) GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetBlob not implemented") -} - -// UnsafeBlobStoreServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to BlobStoreServer will -// result in compilation errors. -type UnsafeBlobStoreServer interface { - mustEmbedUnimplementedBlobStoreServer() -} - -func RegisterBlobStoreServer(s grpc.ServiceRegistrar, srv BlobStoreServer) { - s.RegisterService(&BlobStore_ServiceDesc, srv) -} - -func _BlobStore_PutBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(PutBlobRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BlobStoreServer).PutBlob(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: BlobStore_PutBlob_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BlobStoreServer).PutBlob(ctx, req.(*PutBlobRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BlobStore_GetBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetBlobRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BlobStoreServer).GetBlob(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: BlobStore_GetBlob_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BlobStoreServer).GetBlob(ctx, req.(*GetBlobRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// BlobStore_ServiceDesc is the grpc.ServiceDesc for BlobStore service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var BlobStore_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "resource.BlobStore", - HandlerType: (*BlobStoreServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "PutBlob", - Handler: _BlobStore_PutBlob_Handler, - }, - { - MethodName: "GetBlob", - Handler: _BlobStore_GetBlob_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "resource.proto", -} - const ( Diagnostics_IsHealthy_FullMethodName = "/resource.Diagnostics/IsHealthy" ) diff --git a/pkg/storage/unified/resourcepb/search.pb.go b/pkg/storage/unified/resourcepb/search.pb.go new file mode 100644 index 00000000000..c10b2f2fe53 --- /dev/null +++ b/pkg/storage/unified/resourcepb/search.pb.go @@ -0,0 +1,879 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.5 +// protoc (unknown) +// source: search.proto + +package resourcepb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +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) +) + +// Get statistics across multiple resources +// For these queries, we do not need authorization to see the actual values +type ResourceStatsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Namespace (tenant) + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + // 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 + Kinds []string `protobuf:"bytes,2,rep,name=kinds,proto3" json:"kinds,omitempty"` + // Limit the stats within a folder (not recursive!) + Folder string `protobuf:"bytes,3,opt,name=folder,proto3" json:"folder,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceStatsRequest) Reset() { + *x = ResourceStatsRequest{} + mi := &file_search_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceStatsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceStatsRequest) ProtoMessage() {} + +func (x *ResourceStatsRequest) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceStatsRequest.ProtoReflect.Descriptor instead. +func (*ResourceStatsRequest) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{0} +} + +func (x *ResourceStatsRequest) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *ResourceStatsRequest) GetKinds() []string { + if x != nil { + return x.Kinds + } + return nil +} + +func (x *ResourceStatsRequest) GetFolder() string { + if x != nil { + return x.Folder + } + return "" +} + +type ResourceStatsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Error details + Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + // All results exist within this key + Stats []*ResourceStatsResponse_Stats `protobuf:"bytes,2,rep,name=stats,proto3" json:"stats,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceStatsResponse) Reset() { + *x = ResourceStatsResponse{} + mi := &file_search_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceStatsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceStatsResponse) ProtoMessage() {} + +func (x *ResourceStatsResponse) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceStatsResponse.ProtoReflect.Descriptor instead. +func (*ResourceStatsResponse) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{1} +} + +func (x *ResourceStatsResponse) GetError() *ErrorResult { + if x != nil { + return x.Error + } + return nil +} + +func (x *ResourceStatsResponse) GetStats() []*ResourceStatsResponse_Stats { + if x != nil { + return x.Stats + } + return nil +} + +// Search within a single resource +type ResourceSearchRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The key must include namespace + group + resource + Options *ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` + // To search additional resource types, add additional keys to this list + // NOTE: queries will only support federation across kinds with common fields + Federated []*ResourceKey `protobuf:"bytes,2,rep,name=federated,proto3" json:"federated,omitempty"` + // 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 + Query string `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` + // max results + Limit int64 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"` + // where to start the query (eg, From) + Offset int64 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` + // sorting + SortBy []*ResourceSearchRequest_Sort `protobuf:"bytes,6,rep,name=sortBy,proto3" json:"sortBy,omitempty"` + // calculate field statistics + Facet map[string]*ResourceSearchRequest_Facet `protobuf:"bytes,7,rep,name=facet,proto3" json:"facet,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // the return fields (empty will return everything) + Fields []string `protobuf:"bytes,8,rep,name=fields,proto3" json:"fields,omitempty"` + // explain each result (added to the each row) + Explain bool `protobuf:"varint,9,opt,name=explain,proto3" json:"explain,omitempty"` + IsDeleted bool `protobuf:"varint,10,opt,name=is_deleted,json=isDeleted,proto3" json:"is_deleted,omitempty"` + Page int64 `protobuf:"varint,11,opt,name=page,proto3" json:"page,omitempty"` + Permission int64 `protobuf:"varint,12,opt,name=permission,proto3" json:"permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceSearchRequest) Reset() { + *x = ResourceSearchRequest{} + mi := &file_search_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceSearchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceSearchRequest) ProtoMessage() {} + +func (x *ResourceSearchRequest) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceSearchRequest.ProtoReflect.Descriptor instead. +func (*ResourceSearchRequest) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{2} +} + +func (x *ResourceSearchRequest) GetOptions() *ListOptions { + if x != nil { + return x.Options + } + return nil +} + +func (x *ResourceSearchRequest) GetFederated() []*ResourceKey { + if x != nil { + return x.Federated + } + return nil +} + +func (x *ResourceSearchRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *ResourceSearchRequest) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ResourceSearchRequest) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *ResourceSearchRequest) GetSortBy() []*ResourceSearchRequest_Sort { + if x != nil { + return x.SortBy + } + return nil +} + +func (x *ResourceSearchRequest) GetFacet() map[string]*ResourceSearchRequest_Facet { + if x != nil { + return x.Facet + } + return nil +} + +func (x *ResourceSearchRequest) GetFields() []string { + if x != nil { + return x.Fields + } + return nil +} + +func (x *ResourceSearchRequest) GetExplain() bool { + if x != nil { + return x.Explain + } + return false +} + +func (x *ResourceSearchRequest) GetIsDeleted() bool { + if x != nil { + return x.IsDeleted + } + return false +} + +func (x *ResourceSearchRequest) GetPage() int64 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ResourceSearchRequest) GetPermission() int64 { + if x != nil { + return x.Permission + } + return 0 +} + +type ResourceSearchResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Error details + Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + // All results exist within this key + Key *ResourceKey `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + // Query results + Results *ResourceTable `protobuf:"bytes,3,opt,name=results,proto3" json:"results,omitempty"` + // The total hit count + TotalHits int64 `protobuf:"varint,4,opt,name=total_hits,json=totalHits,proto3" json:"total_hits,omitempty"` + // indicates how expensive was the query with respect to bytes read + QueryCost float64 `protobuf:"fixed64,5,opt,name=query_cost,json=queryCost,proto3" json:"query_cost,omitempty"` + // maximum score across all fields + MaxScore float64 `protobuf:"fixed64,6,opt,name=max_score,json=maxScore,proto3" json:"max_score,omitempty"` + // Facet results + Facet map[string]*ResourceSearchResponse_Facet `protobuf:"bytes,7,rep,name=facet,proto3" json:"facet,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceSearchResponse) Reset() { + *x = ResourceSearchResponse{} + mi := &file_search_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceSearchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceSearchResponse) ProtoMessage() {} + +func (x *ResourceSearchResponse) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceSearchResponse.ProtoReflect.Descriptor instead. +func (*ResourceSearchResponse) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{3} +} + +func (x *ResourceSearchResponse) GetError() *ErrorResult { + if x != nil { + return x.Error + } + return nil +} + +func (x *ResourceSearchResponse) GetKey() *ResourceKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *ResourceSearchResponse) GetResults() *ResourceTable { + if x != nil { + return x.Results + } + return nil +} + +func (x *ResourceSearchResponse) GetTotalHits() int64 { + if x != nil { + return x.TotalHits + } + return 0 +} + +func (x *ResourceSearchResponse) GetQueryCost() float64 { + if x != nil { + return x.QueryCost + } + return 0 +} + +func (x *ResourceSearchResponse) GetMaxScore() float64 { + if x != nil { + return x.MaxScore + } + return 0 +} + +func (x *ResourceSearchResponse) GetFacet() map[string]*ResourceSearchResponse_Facet { + if x != nil { + return x.Facet + } + return nil +} + +type ResourceStatsResponse_Stats struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Resource group + Group string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + // Resource name + Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` + // Number of items + Count int64 `protobuf:"varint,3,opt,name=count,proto3" json:"count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceStatsResponse_Stats) Reset() { + *x = ResourceStatsResponse_Stats{} + mi := &file_search_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceStatsResponse_Stats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceStatsResponse_Stats) ProtoMessage() {} + +func (x *ResourceStatsResponse_Stats) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceStatsResponse_Stats.ProtoReflect.Descriptor instead. +func (*ResourceStatsResponse_Stats) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *ResourceStatsResponse_Stats) GetGroup() string { + if x != nil { + return x.Group + } + return "" +} + +func (x *ResourceStatsResponse_Stats) GetResource() string { + if x != nil { + return x.Resource + } + return "" +} + +func (x *ResourceStatsResponse_Stats) GetCount() int64 { + if x != nil { + return x.Count + } + return 0 +} + +type ResourceSearchRequest_Sort struct { + state protoimpl.MessageState `protogen:"open.v1"` + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + Desc bool `protobuf:"varint,2,opt,name=desc,proto3" json:"desc,omitempty"` // defaults to ascending + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceSearchRequest_Sort) Reset() { + *x = ResourceSearchRequest_Sort{} + mi := &file_search_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceSearchRequest_Sort) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceSearchRequest_Sort) ProtoMessage() {} + +func (x *ResourceSearchRequest_Sort) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceSearchRequest_Sort.ProtoReflect.Descriptor instead. +func (*ResourceSearchRequest_Sort) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *ResourceSearchRequest_Sort) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *ResourceSearchRequest_Sort) GetDesc() bool { + if x != nil { + return x.Desc + } + return false +} + +type ResourceSearchRequest_Facet struct { + state protoimpl.MessageState `protogen:"open.v1"` + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + Limit int64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceSearchRequest_Facet) Reset() { + *x = ResourceSearchRequest_Facet{} + mi := &file_search_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceSearchRequest_Facet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceSearchRequest_Facet) ProtoMessage() {} + +func (x *ResourceSearchRequest_Facet) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceSearchRequest_Facet.ProtoReflect.Descriptor instead. +func (*ResourceSearchRequest_Facet) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *ResourceSearchRequest_Facet) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *ResourceSearchRequest_Facet) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +type ResourceSearchResponse_Facet struct { + state protoimpl.MessageState `protogen:"open.v1"` + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + // The distinct terms + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` + // The number of documents that do *not* have this field + Missing int64 `protobuf:"varint,3,opt,name=missing,proto3" json:"missing,omitempty"` + // Top term stats + Terms []*ResourceSearchResponse_TermFacet `protobuf:"bytes,4,rep,name=terms,proto3" json:"terms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceSearchResponse_Facet) Reset() { + *x = ResourceSearchResponse_Facet{} + mi := &file_search_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceSearchResponse_Facet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceSearchResponse_Facet) ProtoMessage() {} + +func (x *ResourceSearchResponse_Facet) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceSearchResponse_Facet.ProtoReflect.Descriptor instead. +func (*ResourceSearchResponse_Facet) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *ResourceSearchResponse_Facet) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *ResourceSearchResponse_Facet) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *ResourceSearchResponse_Facet) GetMissing() int64 { + if x != nil { + return x.Missing + } + return 0 +} + +func (x *ResourceSearchResponse_Facet) GetTerms() []*ResourceSearchResponse_TermFacet { + if x != nil { + return x.Terms + } + return nil +} + +type ResourceSearchResponse_TermFacet struct { + state protoimpl.MessageState `protogen:"open.v1"` + Term string `protobuf:"bytes,1,opt,name=term,proto3" json:"term,omitempty"` + Count int64 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResourceSearchResponse_TermFacet) Reset() { + *x = ResourceSearchResponse_TermFacet{} + mi := &file_search_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResourceSearchResponse_TermFacet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceSearchResponse_TermFacet) ProtoMessage() {} + +func (x *ResourceSearchResponse_TermFacet) ProtoReflect() protoreflect.Message { + mi := &file_search_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceSearchResponse_TermFacet.ProtoReflect.Descriptor instead. +func (*ResourceSearchResponse_TermFacet) Descriptor() ([]byte, []int) { + return file_search_proto_rawDescGZIP(), []int{3, 1} +} + +func (x *ResourceSearchResponse_TermFacet) GetTerm() string { + if x != nil { + return x.Term + } + return "" +} + +func (x *ResourceSearchResponse_TermFacet) GetCount() int64 { + if x != nil { + return x.Count + } + return 0 +} + +var File_search_proto protoreflect.FileDescriptor + +var file_search_proto_rawDesc = string([]byte{ + 0x0a, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x62, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, + 0x69, 0x6e, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0xd2, 0x01, 0x0a, + 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, + 0x1a, 0x4f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x22, 0x8e, 0x05, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x09, + 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x73, 0x6f, 0x72, + 0x74, 0x42, 0x79, 0x12, 0x40, 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, + 0x66, 0x61, 0x63, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, + 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x30, 0x0a, 0x04, 0x53, 0x6f, + 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x1a, 0x33, 0x0a, 0x05, + 0x46, 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x1a, 0x5f, 0x0a, 0x0a, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x3b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0xea, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x07, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, + 0x68, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x48, 0x69, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x63, + 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x63, 0x6f, 0x72, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x12, 0x41, 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, + 0x61, 0x63, 0x65, 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x05, 0x46, 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6e, 0x67, 0x12, 0x40, 0x0a, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, + 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x1a, 0x35, 0x0a, 0x09, 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, + 0x63, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x60, 0x0a, + 0x0a, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, + 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, + 0xa9, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x4b, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, + 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3b, 0x5a, 0x39, 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, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) + +var ( + file_search_proto_rawDescOnce sync.Once + file_search_proto_rawDescData []byte +) + +func file_search_proto_rawDescGZIP() []byte { + file_search_proto_rawDescOnce.Do(func() { + file_search_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_search_proto_rawDesc), len(file_search_proto_rawDesc))) + }) + return file_search_proto_rawDescData +} + +var file_search_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_search_proto_goTypes = []any{ + (*ResourceStatsRequest)(nil), // 0: resource.ResourceStatsRequest + (*ResourceStatsResponse)(nil), // 1: resource.ResourceStatsResponse + (*ResourceSearchRequest)(nil), // 2: resource.ResourceSearchRequest + (*ResourceSearchResponse)(nil), // 3: resource.ResourceSearchResponse + (*ResourceStatsResponse_Stats)(nil), // 4: resource.ResourceStatsResponse.Stats + (*ResourceSearchRequest_Sort)(nil), // 5: resource.ResourceSearchRequest.Sort + (*ResourceSearchRequest_Facet)(nil), // 6: resource.ResourceSearchRequest.Facet + nil, // 7: resource.ResourceSearchRequest.FacetEntry + (*ResourceSearchResponse_Facet)(nil), // 8: resource.ResourceSearchResponse.Facet + (*ResourceSearchResponse_TermFacet)(nil), // 9: resource.ResourceSearchResponse.TermFacet + nil, // 10: resource.ResourceSearchResponse.FacetEntry + (*ErrorResult)(nil), // 11: resource.ErrorResult + (*ListOptions)(nil), // 12: resource.ListOptions + (*ResourceKey)(nil), // 13: resource.ResourceKey + (*ResourceTable)(nil), // 14: resource.ResourceTable +} +var file_search_proto_depIdxs = []int32{ + 11, // 0: resource.ResourceStatsResponse.error:type_name -> resource.ErrorResult + 4, // 1: resource.ResourceStatsResponse.stats:type_name -> resource.ResourceStatsResponse.Stats + 12, // 2: resource.ResourceSearchRequest.options:type_name -> resource.ListOptions + 13, // 3: resource.ResourceSearchRequest.federated:type_name -> resource.ResourceKey + 5, // 4: resource.ResourceSearchRequest.sortBy:type_name -> resource.ResourceSearchRequest.Sort + 7, // 5: resource.ResourceSearchRequest.facet:type_name -> resource.ResourceSearchRequest.FacetEntry + 11, // 6: resource.ResourceSearchResponse.error:type_name -> resource.ErrorResult + 13, // 7: resource.ResourceSearchResponse.key:type_name -> resource.ResourceKey + 14, // 8: resource.ResourceSearchResponse.results:type_name -> resource.ResourceTable + 10, // 9: resource.ResourceSearchResponse.facet:type_name -> resource.ResourceSearchResponse.FacetEntry + 6, // 10: resource.ResourceSearchRequest.FacetEntry.value:type_name -> resource.ResourceSearchRequest.Facet + 9, // 11: resource.ResourceSearchResponse.Facet.terms:type_name -> resource.ResourceSearchResponse.TermFacet + 8, // 12: resource.ResourceSearchResponse.FacetEntry.value:type_name -> resource.ResourceSearchResponse.Facet + 2, // 13: resource.ResourceIndex.Search:input_type -> resource.ResourceSearchRequest + 0, // 14: resource.ResourceIndex.GetStats:input_type -> resource.ResourceStatsRequest + 3, // 15: resource.ResourceIndex.Search:output_type -> resource.ResourceSearchResponse + 1, // 16: resource.ResourceIndex.GetStats:output_type -> resource.ResourceStatsResponse + 15, // [15:17] is the sub-list for method output_type + 13, // [13:15] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name +} + +func init() { file_search_proto_init() } +func file_search_proto_init() { + if File_search_proto != nil { + return + } + file_resource_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_search_proto_rawDesc), len(file_search_proto_rawDesc)), + NumEnums: 0, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_search_proto_goTypes, + DependencyIndexes: file_search_proto_depIdxs, + MessageInfos: file_search_proto_msgTypes, + }.Build() + File_search_proto = out.File + file_search_proto_goTypes = nil + file_search_proto_depIdxs = nil +} diff --git a/pkg/storage/unified/resourcepb/search_grpc.pb.go b/pkg/storage/unified/resourcepb/search_grpc.pb.go new file mode 100644 index 00000000000..2fa3f16c611 --- /dev/null +++ b/pkg/storage/unified/resourcepb/search_grpc.pb.go @@ -0,0 +1,154 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.4.0 +// - protoc (unknown) +// source: search.proto + +package resourcepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 + +const ( + ResourceIndex_Search_FullMethodName = "/resource.ResourceIndex/Search" + ResourceIndex_GetStats_FullMethodName = "/resource.ResourceIndex/GetStats" +) + +// ResourceIndexClient is the client API for ResourceIndex service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// 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 +type ResourceIndexClient interface { + Search(ctx context.Context, in *ResourceSearchRequest, opts ...grpc.CallOption) (*ResourceSearchResponse, error) + // Get the resource stats + GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error) +} + +type resourceIndexClient struct { + cc grpc.ClientConnInterface +} + +func NewResourceIndexClient(cc grpc.ClientConnInterface) ResourceIndexClient { + return &resourceIndexClient{cc} +} + +func (c *resourceIndexClient) Search(ctx context.Context, in *ResourceSearchRequest, opts ...grpc.CallOption) (*ResourceSearchResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ResourceSearchResponse) + err := c.cc.Invoke(ctx, ResourceIndex_Search_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *resourceIndexClient) GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ResourceStatsResponse) + err := c.cc.Invoke(ctx, ResourceIndex_GetStats_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ResourceIndexServer is the server API for ResourceIndex service. +// All implementations should embed UnimplementedResourceIndexServer +// for forward compatibility +// +// 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 +type ResourceIndexServer interface { + Search(context.Context, *ResourceSearchRequest) (*ResourceSearchResponse, error) + // Get the resource stats + GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error) +} + +// UnimplementedResourceIndexServer should be embedded to have forward compatible implementations. +type UnimplementedResourceIndexServer struct { +} + +func (UnimplementedResourceIndexServer) Search(context.Context, *ResourceSearchRequest) (*ResourceSearchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Search not implemented") +} +func (UnimplementedResourceIndexServer) GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStats not implemented") +} + +// UnsafeResourceIndexServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ResourceIndexServer will +// result in compilation errors. +type UnsafeResourceIndexServer interface { + mustEmbedUnimplementedResourceIndexServer() +} + +func RegisterResourceIndexServer(s grpc.ServiceRegistrar, srv ResourceIndexServer) { + s.RegisterService(&ResourceIndex_ServiceDesc, srv) +} + +func _ResourceIndex_Search_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResourceSearchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ResourceIndexServer).Search(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ResourceIndex_Search_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ResourceIndexServer).Search(ctx, req.(*ResourceSearchRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ResourceIndex_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResourceStatsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ResourceIndexServer).GetStats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ResourceIndex_GetStats_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ResourceIndexServer).GetStats(ctx, req.(*ResourceStatsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ResourceIndex_ServiceDesc is the grpc.ServiceDesc for ResourceIndex service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ResourceIndex_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "resource.ResourceIndex", + HandlerType: (*ResourceIndexServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Search", + Handler: _ResourceIndex_Search_Handler, + }, + { + MethodName: "GetStats", + Handler: _ResourceIndex_GetStats_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "search.proto", +} diff --git a/pkg/storage/unified/search/bleve.go b/pkg/storage/unified/search/bleve.go index 0bb24127aca..d44cd0ecc78 100644 --- a/pkg/storage/unified/search/bleve.go +++ b/pkg/storage/unified/search/bleve.go @@ -27,8 +27,10 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/storage/unified/resource" @@ -309,7 +311,7 @@ type bleveIndex struct { fields resource.SearchableDocumentFields // The values returned with all - allFields []*resource.ResourceTableColumnDefinition + allFields []*resourcepb.ResourceTableColumnDefinition features featuremgmt.FeatureToggles tracing trace.Tracer } @@ -330,29 +332,29 @@ func (b *bleveIndex) BulkIndex(req *resource.BulkIndexRequest) error { doc := item.Doc.UpdateCopyFields() doc.References = nil // remove references (for now!) - err := batch.Index(doc.Key.SearchID(), doc) + err := batch.Index(resource.SearchID(doc.Key), doc) if err != nil { return err } case resource.ActionDelete: - batch.Delete(item.Key.SearchID()) + batch.Delete(resource.SearchID(item.Key)) } } return b.index.Batch(batch) } -func (b *bleveIndex) ListManagedObjects(ctx context.Context, req *resource.ListManagedObjectsRequest) (*resource.ListManagedObjectsResponse, error) { +func (b *bleveIndex) ListManagedObjects(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { if req.NextPageToken != "" { return nil, fmt.Errorf("next page not implemented yet") } if req.Kind == "" { - return &resource.ListManagedObjectsResponse{ + return &resourcepb.ListManagedObjectsResponse{ Error: resource.NewBadRequestError("empty manager kind"), }, nil } if req.Id == "" { - return &resource.ListManagedObjectsResponse{ + return &resourcepb.ListManagedObjectsResponse{ Error: resource.NewBadRequestError("empty manager id"), }, nil } @@ -423,17 +425,17 @@ func (b *bleveIndex) ListManagedObjects(ctx context.Context, req *resource.ListM return 0 } - rsp := &resource.ListManagedObjectsResponse{} + rsp := &resourcepb.ListManagedObjectsResponse{} for _, hit := range found.Hits { - item := &resource.ListManagedObjectsResponse_Item{ - Object: &resource.ResourceKey{}, + item := &resourcepb.ListManagedObjectsResponse_Item{ + Object: &resourcepb.ResourceKey{}, Hash: asString(hit.Fields[resource.SEARCH_FIELD_SOURCE_CHECKSUM]), Path: asString(hit.Fields[resource.SEARCH_FIELD_SOURCE_PATH]), Time: asTime(hit.Fields[resource.SEARCH_FIELD_SOURCE_TIME]), Title: asString(hit.Fields[resource.SEARCH_FIELD_TITLE]), Folder: asString(hit.Fields[resource.SEARCH_FIELD_FOLDER]), } - err := item.Object.ReadSearchID(hit.ID) + err := resource.ReadSearchID(item.Object, hit.ID) if err != nil { return nil, err } @@ -442,7 +444,7 @@ func (b *bleveIndex) ListManagedObjects(ctx context.Context, req *resource.ListM return rsp, nil } -func (b *bleveIndex) CountManagedObjects(ctx context.Context) ([]*resource.CountManagedObjectsResponse_ResourceCount, error) { +func (b *bleveIndex) CountManagedObjects(ctx context.Context) ([]*resourcepb.CountManagedObjectsResponse_ResourceCount, error) { found, err := b.index.SearchInContext(ctx, &bleve.SearchRequest{ Query: bleve.NewMatchAllQuery(), Size: 0, @@ -453,14 +455,14 @@ func (b *bleveIndex) CountManagedObjects(ctx context.Context) ([]*resource.Count if err != nil { return nil, err } - vals := make([]*resource.CountManagedObjectsResponse_ResourceCount, 0) + vals := make([]*resourcepb.CountManagedObjectsResponse_ResourceCount, 0) f, ok := found.Facets["count"] if ok && f.Terms != nil { for _, v := range f.Terms.Terms() { val := v.Term idx := strings.Index(val, ":") if idx > 0 { - vals = append(vals, &resource.CountManagedObjectsResponse_ResourceCount{ + vals = append(vals, &resourcepb.CountManagedObjectsResponse_ResourceCount{ Kind: val[0:idx], Id: val[idx+1:], Group: b.key.Group, @@ -477,19 +479,19 @@ func (b *bleveIndex) CountManagedObjects(ctx context.Context) ([]*resource.Count func (b *bleveIndex) Search( ctx context.Context, access authlib.AccessClient, - req *resource.ResourceSearchRequest, + req *resourcepb.ResourceSearchRequest, federate []resource.ResourceIndex, // For federated queries, these will match the values in req.federate -) (*resource.ResourceSearchResponse, error) { +) (*resourcepb.ResourceSearchResponse, error) { ctx, span := b.tracing.Start(ctx, tracingPrexfixBleve+"Search") defer span.End() if req.Options == nil || req.Options.Key == nil { - return &resource.ResourceSearchResponse{ + return &resourcepb.ResourceSearchResponse{ Error: resource.NewBadRequestError("missing query key"), }, nil } - response := &resource.ResourceSearchResponse{ + response := &resourcepb.ResourceSearchResponse{ Error: b.verifyKey(req.Options.Key), } if response.Error != nil { @@ -545,7 +547,7 @@ func (b *bleveIndex) Search( for k, v := range res.Facets { f := newResponseFacet(v) if response.Facet == nil { - response.Facet = make(map[string]*resource.ResourceSearchResponse_Facet) + response.Facet = make(map[string]*resourcepb.ResourceSearchResponse_Facet) } response.Facet[k] = f } @@ -577,7 +579,7 @@ func (b *bleveIndex) DocCount(ctx context.Context, folder string) (int64, error) } // make sure the request key matches the index -func (b *bleveIndex) verifyKey(key *resource.ResourceKey) *resource.ErrorResult { +func (b *bleveIndex) verifyKey(key *resourcepb.ResourceKey) *resourcepb.ErrorResult { if key.Namespace != b.key.Namespace { return resource.NewBadRequestError("namespace mismatch (expected " + b.key.Namespace + ")") } @@ -592,7 +594,7 @@ func (b *bleveIndex) verifyKey(key *resource.ResourceKey) *resource.ErrorResult func (b *bleveIndex) getIndex( ctx context.Context, - req *resource.ResourceSearchRequest, + req *resourcepb.ResourceSearchRequest, federate []resource.ResourceIndex, ) (bleve.Index, error) { _, span := b.tracing.Start(ctx, tracingPrexfixBleve+"getIndex") @@ -621,7 +623,7 @@ func (b *bleveIndex) getIndex( return b.index, nil } -func (b *bleveIndex) toBleveSearchRequest(ctx context.Context, req *resource.ResourceSearchRequest, access authlib.AccessClient) (*bleve.SearchRequest, *resource.ErrorResult) { +func (b *bleveIndex) toBleveSearchRequest(ctx context.Context, req *resourcepb.ResourceSearchRequest, access authlib.AccessClient) (*bleve.SearchRequest, *resourcepb.ErrorResult) { ctx, span := b.tracing.Start(ctx, tracingPrexfixBleve+"toBleveSearchRequest") defer span.End() @@ -793,7 +795,7 @@ func safeInt64ToInt(i64 int64) (int, error) { return int(i64), nil } -func getSortFields(req *resource.ResourceSearchRequest) []string { +func getSortFields(req *resourcepb.ResourceSearchRequest) []string { sorting := []string{} for _, sort := range req.SortBy { input := sort.Field @@ -826,7 +828,7 @@ var termFields = []string{ } // Convert a "requirement" into a bleve query -func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *resource.ErrorResult) { +func requirementQuery(req *resourcepb.Requirement, prefix string) (query.Query, *resourcepb.ErrorResult) { switch selection.Operator(req.Operator) { case selection.Equals, selection.DoubleEquals: if len(req.Values) == 0 { @@ -946,11 +948,11 @@ func filterValue(field string, v string) string { return v } -func (b *bleveIndex) hitsToTable(ctx context.Context, selectFields []string, hits search.DocumentMatchCollection, explain bool) (*resource.ResourceTable, error) { +func (b *bleveIndex) hitsToTable(ctx context.Context, selectFields []string, hits search.DocumentMatchCollection, explain bool) (*resourcepb.ResourceTable, error) { _, span := b.tracing.Start(ctx, tracingPrexfixBleve+"hitsToTable") defer span.End() - fields := []*resource.ResourceTableColumnDefinition{} + fields := []*resourcepb.ResourceTableColumnDefinition{} for _, name := range selectFields { if name == "_all" { fields = b.allFields @@ -964,9 +966,9 @@ func (b *bleveIndex) hitsToTable(ctx context.Context, selectFields []string, hit if f == nil { // Labels as a string if strings.HasPrefix(name, "labels.") { - f = &resource.ResourceTableColumnDefinition{ + f = &resourcepb.ResourceTableColumnDefinition{ Name: name, - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, } } @@ -987,18 +989,18 @@ func (b *bleveIndex) hitsToTable(ctx context.Context, selectFields []string, hit } encoders := builder.Encoders() - table := &resource.ResourceTable{ + table := &resourcepb.ResourceTable{ Columns: fields, - Rows: make([]*resource.ResourceTableRow, hits.Len()), + Rows: make([]*resourcepb.ResourceTableRow, hits.Len()), } for rowID, match := range hits { - row := &resource.ResourceTableRow{ - Key: &resource.ResourceKey{}, + row := &resourcepb.ResourceTableRow{ + Key: &resourcepb.ResourceKey{}, Cells: make([][]byte, len(fields)), } table.Rows[rowID] = row - err := row.Key.ReadSearchID(match.ID) + err := resource.ReadSearchID(row.Key, match.ID) if err != nil { return nil, err } @@ -1048,8 +1050,8 @@ func (b *bleveIndex) hitsToTable(ctx context.Context, selectFields []string, hit return table, nil } -func getAllFields(standard resource.SearchableDocumentFields, custom resource.SearchableDocumentFields) ([]*resource.ResourceTableColumnDefinition, error) { - fields := []*resource.ResourceTableColumnDefinition{ +func getAllFields(standard resource.SearchableDocumentFields, custom resource.SearchableDocumentFields) ([]*resourcepb.ResourceTableColumnDefinition, error) { + fields := []*resourcepb.ResourceTableColumnDefinition{ standard.Field(resource.SEARCH_FIELD_ID), standard.Field(resource.SEARCH_FIELD_TITLE), standard.Field(resource.SEARCH_FIELD_TAGS), @@ -1077,15 +1079,15 @@ func getAllFields(standard resource.SearchableDocumentFields, custom resource.Se return fields, nil } -func newResponseFacet(v *search.FacetResult) *resource.ResourceSearchResponse_Facet { - f := &resource.ResourceSearchResponse_Facet{ +func newResponseFacet(v *search.FacetResult) *resourcepb.ResourceSearchResponse_Facet { + f := &resourcepb.ResourceSearchResponse_Facet{ Field: v.Field, Total: int64(v.Total), Missing: int64(v.Missing), } if v.Terms != nil { for _, t := range v.Terms.Terms() { - f.Terms = append(f.Terms, &resource.ResourceSearchResponse_TermFacet{ + f.Terms = append(f.Terms, &resourcepb.ResourceSearchResponse_TermFacet{ Term: t.Term, Count: int64(t.Count), }) diff --git a/pkg/storage/unified/search/bleve_performance_test.go b/pkg/storage/unified/search/bleve_performance_test.go index 3598e579114..e1ae015efd2 100644 --- a/pkg/storage/unified/search/bleve_performance_test.go +++ b/pkg/storage/unified/search/bleve_performance_test.go @@ -9,6 +9,8 @@ import ( "time" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/require" ) @@ -85,7 +87,7 @@ func BenchmarkBleveQuery(b *testing.B) { } func newTestWriter(size int, batchSize int) IndexWriter { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", @@ -105,7 +107,7 @@ func newTestWriter(size int, batchSize int) IndexWriter { Doc: &resource.IndexableDocument{ RV: int64(i), Name: name, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: name, Namespace: key.Namespace, Group: key.Group, diff --git a/pkg/storage/unified/search/bleve_search_test.go b/pkg/storage/unified/search/bleve_search_test.go index ee1ee12f5fc..a795b4c0f8d 100644 --- a/pkg/storage/unified/search/bleve_search_test.go +++ b/pkg/storage/unified/search/bleve_search_test.go @@ -16,13 +16,14 @@ import ( "github.com/grafana/grafana/pkg/services/store/kind/dashboard" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" ) const threshold = 9999 func TestCanSearchByTitle(t *testing.T) { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", @@ -37,7 +38,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name1", Namespace: key.Namespace, Group: key.Group, @@ -51,7 +52,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name2", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name2", Namespace: key.Namespace, Group: key.Group, @@ -81,7 +82,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name1", Namespace: key.Namespace, Group: key.Group, @@ -95,7 +96,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name2", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name2", Namespace: key.Namespace, Group: key.Group, @@ -125,7 +126,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name1", Namespace: key.Namespace, Group: key.Group, @@ -139,7 +140,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name2", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name2", Namespace: key.Namespace, Group: key.Group, @@ -168,7 +169,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name1", Namespace: key.Namespace, Group: key.Group, @@ -182,7 +183,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name2", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name2", Namespace: key.Namespace, Group: key.Group, @@ -212,7 +213,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "aaa", Namespace: key.Namespace, Group: key.Group, @@ -253,7 +254,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "aaa", Namespace: key.Namespace, Group: key.Group, @@ -267,7 +268,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 2, Name: "name2", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name2", Namespace: key.Namespace, Group: key.Group, @@ -300,7 +301,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "aaa", Namespace: key.Namespace, Group: key.Group, @@ -365,7 +366,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name1", Namespace: key.Namespace, Group: key.Group, @@ -379,7 +380,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name2", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name2", Namespace: key.Namespace, Group: key.Group, @@ -393,7 +394,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name3", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "name3", Namespace: key.Namespace, Group: key.Group, @@ -434,7 +435,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "name1", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "aaa", Namespace: key.Namespace, Group: key.Group, @@ -455,7 +456,7 @@ func TestCanSearchByTitle(t *testing.T) { Doc: &resource.IndexableDocument{ RV: int64(i), Name: fmt.Sprintf("name%d", i), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: fmt.Sprintf("name%d", i), Namespace: key.Namespace, Group: key.Group, @@ -491,10 +492,10 @@ func TestCanSearchByTitle(t *testing.T) { }) } -func newTestQuery(query string) *resource.ResourceSearchRequest { - return &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ +func newTestQuery(query string) *resourcepb.ResourceSearchRequest { + return &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", @@ -505,22 +506,22 @@ func newTestQuery(query string) *resource.ResourceSearchRequest { } } -func newQueryByTitle(query string) *resource.ResourceSearchRequest { - return &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ +func newQueryByTitle(query string) *resourcepb.ResourceSearchRequest { + return &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", }, - Fields: []*resource.Requirement{{Key: "title", Operator: "=", Values: []string{query}}}, + Fields: []*resourcepb.Requirement{{Key: "title", Operator: "=", Values: []string{query}}}, }, Limit: 100000, } } func newTestDashboardsIndex(t TB, threshold int64, size int64, batchSize int64, writer IndexWriter) (resource.ResourceIndex, string) { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", diff --git a/pkg/storage/unified/search/bleve_test.go b/pkg/storage/unified/search/bleve_test.go index f3a1473c2f0..a2ea6afaced 100644 --- a/pkg/storage/unified/search/bleve_test.go +++ b/pkg/storage/unified/search/bleve_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/infra/tracing" @@ -21,15 +22,16 @@ import ( "github.com/grafana/grafana/pkg/services/store/kind/dashboard" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) func TestBleveBackend(t *testing.T) { - dashboardskey := &resource.ResourceKey{ + dashboardskey := &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", } - folderKey := &resource.ResourceKey{ + folderKey := &resourcepb.ResourceKey{ Namespace: dashboardskey.Namespace, Group: "folder.grafana.app", Resource: "folders", @@ -72,7 +74,7 @@ func TestBleveBackend(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 1, Name: "aaa", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "aaa", Namespace: "ns", Group: "dashboard.grafana.app", @@ -105,7 +107,7 @@ func TestBleveBackend(t *testing.T) { Doc: &resource.IndexableDocument{ RV: 2, Name: "bbb", - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "bbb", Namespace: "ns", Group: "dashboard.grafana.app", @@ -138,7 +140,7 @@ func TestBleveBackend(t *testing.T) { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ RV: 3, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "ccc", Namespace: "ns", Group: "dashboard.grafana.app", @@ -172,15 +174,15 @@ func TestBleveBackend(t *testing.T) { require.NotNil(t, index) dashboardsIndex = index - rsp, err := index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err := index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: key, }, Limit: 100000, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: resource.SEARCH_FIELD_TITLE, Desc: true}, // ccc,bbb,aaa }, - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "tags": { Field: "tags", Limit: 100, @@ -221,10 +223,10 @@ func TestBleveBackend(t *testing.T) { count, _ = index.DocCount(ctx, "zzz") assert.Equal(t, int64(1), count) - rsp, err = index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err = index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: key, - Labels: []*resource.Requirement{{ + Labels: []*resourcepb.Requirement{{ Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck Operator: "in", Values: []string{"10", "11"}, @@ -240,13 +242,13 @@ func TestBleveBackend(t *testing.T) { }) // can get sprinkles fields and sort by them - rsp, err = index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err = index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: key, }, Limit: 100000, Fields: []string{DASHBOARD_ERRORS_TODAY, DASHBOARD_VIEWS_LAST_1_DAYS, "fieldThatDoesntExist"}, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "fields." + DASHBOARD_VIEWS_LAST_1_DAYS, Desc: true}, }, }, nil) @@ -260,13 +262,13 @@ func TestBleveBackend(t *testing.T) { require.Equal(t, int64(100), val) // check auth will exclude results we don't have access to - rsp, err = index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": false}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err = index.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": false}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: key, }, Limit: 100000, Fields: []string{DASHBOARD_ERRORS_TODAY, DASHBOARD_VIEWS_LAST_1_DAYS, "fieldThatDoesntExist"}, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "fields." + DASHBOARD_VIEWS_LAST_1_DAYS, Desc: true}, }, }, nil) @@ -274,7 +276,7 @@ func TestBleveBackend(t *testing.T) { require.Equal(t, 0, len(rsp.Results.Rows)) // Now look for repositories - found, err := index.ListManagedObjects(ctx, &resource.ListManagedObjectsRequest{ + found, err := index.ListManagedObjects(ctx, &resourcepb.ListManagedObjectsRequest{ Kind: "repo", Id: "repo-1", }) @@ -352,7 +354,7 @@ func TestBleveBackend(t *testing.T) { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ RV: 1, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "zzz", Namespace: "ns", Group: "folder.grafana.app", @@ -377,7 +379,7 @@ func TestBleveBackend(t *testing.T) { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ RV: 2, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Name: "yyy", Namespace: "ns", Group: "folder.grafana.app", @@ -401,8 +403,8 @@ func TestBleveBackend(t *testing.T) { require.NotNil(t, index) foldersIndex = index - rsp, err := index.Search(ctx, NewStubAccessClient(map[string]bool{"folders": true}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err := index.Search(ctx, NewStubAccessClient(map[string]bool{"folders": true}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: key, }, Limit: 100000, @@ -421,21 +423,21 @@ func TestBleveBackend(t *testing.T) { require.NotNil(t, foldersIndex) // Use a federated query to get both results together, sorted by title - rsp, err := dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true, "folders": true}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err := dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true, "folders": true}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardskey, }, Fields: []string{ "title", "_id", }, - Federated: []*resource.ResourceKey{ + Federated: []*resourcepb.ResourceKey{ folderKey, // This will join in the }, Limit: 100000, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "title", Desc: false}, }, - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "region": { Field: "labels.region", Limit: 100, @@ -485,21 +487,21 @@ func TestBleveBackend(t *testing.T) { }`, string(disp)) // now only when we have permissions to see dashboards - rsp, err = dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true, "folders": false}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err = dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": true, "folders": false}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardskey, }, Fields: []string{ "title", "_id", }, - Federated: []*resource.ResourceKey{ + Federated: []*resourcepb.ResourceKey{ folderKey, // This will join in the }, Limit: 100000, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "title", Desc: false}, }, - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "region": { Field: "labels.region", Limit: 100, @@ -514,21 +516,21 @@ func TestBleveBackend(t *testing.T) { require.Equal(t, "dashboards", rsp.Results.Rows[2].Key.Resource) // now only when we have permissions to see folders - rsp, err = dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": false, "folders": true}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err = dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": false, "folders": true}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardskey, }, Fields: []string{ "title", "_id", }, - Federated: []*resource.ResourceKey{ + Federated: []*resourcepb.ResourceKey{ folderKey, // This will join in the }, Limit: 100000, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "title", Desc: false}, }, - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "region": { Field: "labels.region", Limit: 100, @@ -542,21 +544,21 @@ func TestBleveBackend(t *testing.T) { require.Equal(t, "folders", rsp.Results.Rows[1].Key.Resource) // now when we have permissions to see nothing - rsp, err = dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": false, "folders": false}), &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ + rsp, err = dashboardsIndex.Search(ctx, NewStubAccessClient(map[string]bool{"dashboards": false, "folders": false}), &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ Key: dashboardskey, }, Fields: []string{ "title", "_id", }, - Federated: []*resource.ResourceKey{ + Federated: []*resourcepb.ResourceKey{ folderKey, // This will join in the }, Limit: 100000, - SortBy: []*resource.ResourceSearchRequest_Sort{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "title", Desc: false}, }, - Facet: map[string]*resource.ResourceSearchRequest_Facet{ + Facet: map[string]*resourcepb.ResourceSearchRequest_Facet{ "region": { Field: "labels.region", Limit: 100, @@ -571,8 +573,8 @@ func TestBleveBackend(t *testing.T) { func TestGetSortFields(t *testing.T) { t.Run("will prepend 'fields.' to sort fields when they are dashboard fields", func(t *testing.T) { - searchReq := &resource.ResourceSearchRequest{ - SortBy: []*resource.ResourceSearchRequest_Sort{ + searchReq := &resourcepb.ResourceSearchRequest{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "views_total", Desc: false}, }, } @@ -580,8 +582,8 @@ func TestGetSortFields(t *testing.T) { assert.Equal(t, []string{"fields.views_total"}, sortFields) }) t.Run("will prepend sort fields with a '-' when sort is Desc", func(t *testing.T) { - searchReq := &resource.ResourceSearchRequest{ - SortBy: []*resource.ResourceSearchRequest_Sort{ + searchReq := &resourcepb.ResourceSearchRequest{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "views_total", Desc: true}, }, } @@ -589,8 +591,8 @@ func TestGetSortFields(t *testing.T) { assert.Equal(t, []string{"-fields.views_total"}, sortFields) }) t.Run("will not prepend 'fields.' to common fields", func(t *testing.T) { - searchReq := &resource.ResourceSearchRequest{ - SortBy: []*resource.ResourceSearchRequest_Sort{ + searchReq := &resourcepb.ResourceSearchRequest{ + SortBy: []*resourcepb.ResourceSearchRequest_Sort{ {Field: "description", Desc: false}, }, } diff --git a/pkg/storage/unified/search/dashboard.go b/pkg/storage/unified/search/dashboard.go index fc44c4cb034..300a48b8456 100644 --- a/pkg/storage/unified/search/dashboard.go +++ b/pkg/storage/unified/search/dashboard.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/services/store/kind/dashboard" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) //------------------------------------------------------------ @@ -45,146 +46,146 @@ const DASHBOARD_ERRORS_TOTAL = "errors_total" const DASHBOARD_ERRORS_TODAY = "errors_today" func DashboardBuilder(namespaced resource.NamespacedDocumentSupplier) (resource.DocumentBuilderInfo, error) { - fields, err := resource.NewSearchableDocumentFields([]*resource.ResourceTableColumnDefinition{ + fields, err := resource.NewSearchableDocumentFields([]*resourcepb.ResourceTableColumnDefinition{ { Name: DASHBOARD_SCHEMA_VERSION, - Type: resource.ResourceTableColumnDefinition_INT32, + Type: resourcepb.ResourceTableColumnDefinition_INT32, Description: "Numeric version saying when the schema was saved", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ NotNull: true, }, }, { Name: DASHBOARD_LINK_COUNT, - Type: resource.ResourceTableColumnDefinition_INT32, + Type: resourcepb.ResourceTableColumnDefinition_INT32, Description: "How many links appear on the page", }, { Name: DASHBOARD_PANEL_TYPES, - Type: resource.ResourceTableColumnDefinition_STRING, + Type: resourcepb.ResourceTableColumnDefinition_STRING, IsArray: true, Description: "How many links appear on the page", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_ERRORS_TODAY, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of errors that occurred today", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_ERRORS_LAST_1_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of errors that occurred in the last 1 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_ERRORS_LAST_7_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of errors that occurred in the last 7 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_ERRORS_LAST_30_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of errors that occurred in the last 30 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_ERRORS_TOTAL, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Total number of errors", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_QUERIES_TODAY, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of queries that occurred today", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_QUERIES_LAST_1_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of queries that occurred in the last 1 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_QUERIES_LAST_7_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of queries that occurred in the last 7 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_QUERIES_LAST_30_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of queries that occurred in the last 30 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_QUERIES_TOTAL, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Total number of queries", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_VIEWS_TODAY, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of views that occurred today", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_VIEWS_LAST_1_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of views that occurred in the last 1 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_VIEWS_LAST_7_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of views that occurred in the last 7 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_VIEWS_LAST_30_DAYS, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Number of views that occurred in the last 30 days", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, { Name: DASHBOARD_VIEWS_TOTAL, - Type: resource.ResourceTableColumnDefinition_INT64, + Type: resourcepb.ResourceTableColumnDefinition_INT64, Description: "Total number of views", - Properties: &resource.ResourceTableColumnDefinition_Properties{ + Properties: &resourcepb.ResourceTableColumnDefinition_Properties{ Filterable: true, }, }, @@ -231,7 +232,7 @@ type DashboardStatsLookup = func(ctx context.Context, uid string) map[string]int var _ resource.DocumentBuilder = &DashboardDocumentBuilder{} -func (s *DashboardDocumentBuilder) BuildDocument(ctx context.Context, key *resource.ResourceKey, rv int64, value []byte) (*resource.IndexableDocument, error) { +func (s *DashboardDocumentBuilder) BuildDocument(ctx context.Context, key *resourcepb.ResourceKey, rv int64, value []byte) (*resource.IndexableDocument, error) { if s.Namespace != "" && s.Namespace != key.Namespace { return nil, fmt.Errorf("invalid namespace") } diff --git a/pkg/storage/unified/search/document_test.go b/pkg/storage/unified/search/document_test.go index 49c7e0c9e89..285f3178120 100644 --- a/pkg/storage/unified/search/document_test.go +++ b/pkg/storage/unified/search/document_test.go @@ -13,10 +13,11 @@ import ( "github.com/grafana/grafana/pkg/services/store/kind/dashboard" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" ) -func doSnapshotTests(t *testing.T, builder resource.DocumentBuilder, kind string, key *resource.ResourceKey, names []string) { +func doSnapshotTests(t *testing.T, builder resource.DocumentBuilder, kind string, key *resourcepb.ResourceKey, names []string) { t.Helper() for _, name := range names { @@ -47,7 +48,7 @@ func doSnapshotTests(t *testing.T, builder resource.DocumentBuilder, kind string } func TestDashboardDocumentBuilder(t *testing.T) { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", @@ -82,7 +83,7 @@ func TestDashboardDocumentBuilder(t *testing.T) { // Standard builder = resource.StandardDocumentBuilder() - doSnapshotTests(t, builder, "folder", &resource.ResourceKey{ + doSnapshotTests(t, builder, "folder", &resourcepb.ResourceKey{ Namespace: "default", Group: "folder.grafana.app", Resource: "folders", @@ -90,14 +91,14 @@ func TestDashboardDocumentBuilder(t *testing.T) { "aaa", "bbb", }) - doSnapshotTests(t, builder, "playlist", &resource.ResourceKey{ + doSnapshotTests(t, builder, "playlist", &resourcepb.ResourceKey{ Namespace: "default", Group: "playlist.grafana.app", Resource: "playlists", }, []string{ "aaa", }) - doSnapshotTests(t, builder, "report", &resource.ResourceKey{ + doSnapshotTests(t, builder, "report", &resourcepb.ResourceKey{ Namespace: "default", Group: "reporting.grafana.app", Resource: "reports", diff --git a/pkg/storage/unified/sql/backend.go b/pkg/storage/unified/sql/backend.go index 8cbc8b91eea..15281b9dfcb 100644 --- a/pkg/storage/unified/sql/backend.go +++ b/pkg/storage/unified/sql/backend.go @@ -23,6 +23,7 @@ import ( "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" @@ -36,7 +37,7 @@ const defaultPrunerHistoryLimit = 20 type Backend interface { resource.StorageBackend - resource.DiagnosticsServer + resourcepb.DiagnosticsServer resource.LifecycleHooks } @@ -218,7 +219,7 @@ func (b *backend) initPruner(ctx context.Context) error { res, err := dbutil.Exec(ctx, tx, sqlResourceHistoryPrune, &sqlPruneHistoryRequest{ SQLTemplate: sqltemplate.New(b.dialect), HistoryLimit: defaultPrunerHistoryLimit, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: key.namespace, Group: key.group, Resource: key.resource, @@ -260,14 +261,14 @@ func (b *backend) initPruner(ctx context.Context) error { return nil } -func (b *backend) IsHealthy(ctx context.Context, r *resource.HealthCheckRequest) (*resource.HealthCheckResponse, error) { +func (b *backend) IsHealthy(ctx context.Context, _ *resourcepb.HealthCheckRequest) (*resourcepb.HealthCheckResponse, error) { // ctxLogger := s.log.FromContext(log.WithContextualAttributes(ctx, []any{"method", "isHealthy"})) if err := b.db.PingContext(ctx); err != nil { return nil, err } - return &resource.HealthCheckResponse{Status: resource.HealthCheckResponse_SERVING}, nil + return &resourcepb.HealthCheckResponse{Status: resourcepb.HealthCheckResponse_SERVING}, nil } func (b *backend) Stop(_ context.Context) error { @@ -313,11 +314,11 @@ func (b *backend) WriteEvent(ctx context.Context, event resource.WriteEvent) (in defer span.End() // TODO: validate key ? switch event.Type { - case resource.WatchEvent_ADDED: + case resourcepb.WatchEvent_ADDED: return b.create(ctx, event) - case resource.WatchEvent_MODIFIED: + case resourcepb.WatchEvent_MODIFIED: return b.update(ctx, event) - case resource.WatchEvent_DELETED: + case resourcepb.WatchEvent_DELETED: return b.delete(ctx, event) default: return 0, fmt.Errorf("unsupported event type") @@ -525,7 +526,7 @@ func (b *backend) delete(ctx context.Context, event resource.WriteEvent) (int64, return rv, nil } -func (b *backend) ReadResource(ctx context.Context, req *resource.ReadRequest) *resource.BackendReadResponse { +func (b *backend) ReadResource(ctx context.Context, req *resourcepb.ReadRequest) *resource.BackendReadResponse { _, span := b.tracer.Start(ctx, tracePrefix+".Read") defer span.End() @@ -558,7 +559,7 @@ func (b *backend) ReadResource(ctx context.Context, req *resource.ReadRequest) * return res } -func (b *backend) ListIterator(ctx context.Context, req *resource.ListRequest, cb func(resource.ListIterator) error) (int64, error) { +func (b *backend) ListIterator(ctx context.Context, req *resourcepb.ListRequest, cb func(resource.ListIterator) error) (int64, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"List") defer span.End() @@ -570,7 +571,7 @@ func (b *backend) ListIterator(ctx context.Context, req *resource.ListRequest, c return 0, fmt.Errorf("missing group or resource") } - if req.Source != resource.ListRequest_STORE { + if req.Source != resourcepb.ListRequest_STORE { return b.getHistory(ctx, req, cb) } @@ -652,7 +653,7 @@ func (l *listIter) Next() bool { var _ resource.ListIterator = (*listIter)(nil) // listLatest fetches the resources from the resource table. -func (b *backend) listLatest(ctx context.Context, req *resource.ListRequest, cb func(resource.ListIterator) error) (int64, error) { +func (b *backend) listLatest(ctx context.Context, req *resourcepb.ListRequest, cb func(resource.ListIterator) error) (int64, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"listLatest") defer span.End() @@ -673,9 +674,9 @@ func (b *backend) listLatest(ctx context.Context, req *resource.ListRequest, cb listReq := sqlResourceListRequest{ SQLTemplate: sqltemplate.New(b.dialect), - Request: new(resource.ListRequest), + Request: new(resourcepb.ListRequest), } - listReq.Request = proto.Clone(req).(*resource.ListRequest) + listReq.Request = proto.Clone(req).(*resourcepb.ListRequest) rows, err := dbutil.QueryRows(ctx, tx, sqlResourceList, listReq) if rows != nil { @@ -696,7 +697,7 @@ func (b *backend) listLatest(ctx context.Context, req *resource.ListRequest, cb } // listAtRevision fetches the resources from the resource_history table at a specific revision. -func (b *backend) listAtRevision(ctx context.Context, req *resource.ListRequest, cb func(resource.ListIterator) error) (int64, error) { +func (b *backend) listAtRevision(ctx context.Context, req *resourcepb.ListRequest, cb func(resource.ListIterator) error) (int64, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"listAtRevision") defer span.End() @@ -756,7 +757,7 @@ func (b *backend) listAtRevision(ctx context.Context, req *resource.ListRequest, } // readHistory fetches the resource history from the resource_history table. -func (b *backend) readHistory(ctx context.Context, key *resource.ResourceKey, rv int64) *resource.BackendReadResponse { +func (b *backend) readHistory(ctx context.Context, key *resourcepb.ResourceKey, rv int64) *resource.BackendReadResponse { _, span := b.tracer.Start(ctx, tracePrefix+".ReadHistory") defer span.End() @@ -787,19 +788,19 @@ func (b *backend) readHistory(ctx context.Context, key *resource.ResourceKey, rv } // getHistory fetches the resource history from the resource_history table. -func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb func(resource.ListIterator) error) (int64, error) { +func (b *backend) getHistory(ctx context.Context, req *resourcepb.ListRequest, cb func(resource.ListIterator) error) (int64, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"getHistory") defer span.End() listReq := sqlGetHistoryRequest{ SQLTemplate: sqltemplate.New(b.dialect), Key: req.Options.Key, - Trash: req.Source == resource.ListRequest_TRASH, + Trash: req.Source == resourcepb.ListRequest_TRASH, } // We are assuming that users want history in ascending order // when they are using NotOlderThan matching, and descending order // for Unset (default) and Exact matching. - listReq.SortAscending = req.GetVersionMatchV2() == resource.ResourceVersionMatchV2_NotOlderThan + listReq.SortAscending = req.GetVersionMatchV2() == resourcepb.ResourceVersionMatchV2_NotOlderThan iter := &listIter{} if req.NextPageToken != "" { @@ -813,7 +814,7 @@ func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb iter.sortAsc = listReq.SortAscending // Set ExactRV when using Exact matching - if req.VersionMatchV2 == resource.ResourceVersionMatchV2_Exact { + if req.VersionMatchV2 == resourcepb.ResourceVersionMatchV2_Exact { if req.ResourceVersion <= 0 { return 0, fmt.Errorf("expecting an explicit resource version query when using Exact matching") } @@ -821,12 +822,12 @@ func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb } // Set MinRV when using NotOlderThan matching to filter at the database level - if req.ResourceVersion > 0 && req.VersionMatchV2 == resource.ResourceVersionMatchV2_NotOlderThan { + if req.ResourceVersion > 0 && req.VersionMatchV2 == resourcepb.ResourceVersionMatchV2_NotOlderThan { listReq.MinRV = req.ResourceVersion } // Ignore last deleted history record when listing the trash, using exact matching or not older than matching with a specific RV - useLatestDeletionAsMinRV := listReq.MinRV == 0 && !listReq.Trash && req.VersionMatchV2 != resource.ResourceVersionMatchV2_Exact + useLatestDeletionAsMinRV := listReq.MinRV == 0 && !listReq.Trash && req.VersionMatchV2 != resourcepb.ResourceVersionMatchV2_Exact err := b.db.WithTx(ctx, ReadCommittedRO, func(ctx context.Context, tx db.Tx) error { var err error @@ -836,7 +837,7 @@ func (b *backend) getHistory(ctx context.Context, req *resource.ListRequest, cb } if useLatestDeletionAsMinRV { - latestDeletedRV, err := b.fetchLatestHistoryRV(ctx, tx, b.dialect, req.Options.Key, resource.WatchEvent_DELETED) + latestDeletedRV, err := b.fetchLatestHistoryRV(ctx, tx, b.dialect, req.Options.Key, resourcepb.WatchEvent_DELETED) if err != nil { return err } @@ -914,7 +915,7 @@ func (b *backend) fetchLatestRV(ctx context.Context, x db.ContextExecer, d sqlte } // fetchLatestHistoryRV returns the current maximum RV in the resource_history table -func (b *backend) fetchLatestHistoryRV(ctx context.Context, x db.ContextExecer, d sqltemplate.Dialect, key *resource.ResourceKey, eventType resource.WatchEvent_Type) (int64, error) { +func (b *backend) fetchLatestHistoryRV(ctx context.Context, x db.ContextExecer, d sqltemplate.Dialect, key *resourcepb.ResourceKey, eventType resourcepb.WatchEvent_Type) (int64, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"fetchLatestHistoryRV") defer span.End() res, err := dbutil.QueryRow(ctx, x, sqlResourceHistoryReadLatestRV, sqlResourceHistoryReadLatestRVRequest{ diff --git a/pkg/storage/unified/sql/backend_test.go b/pkg/storage/unified/sql/backend_test.go index 2540452a9d2..92989e8454a 100644 --- a/pkg/storage/unified/sql/backend_test.go +++ b/pkg/storage/unified/sql/backend_test.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db/dbimpl" "github.com/grafana/grafana/pkg/storage/unified/sql/test" "github.com/grafana/grafana/pkg/util/testutil" @@ -22,7 +23,7 @@ import ( var ( errTest = errors.New("things happened") - resKey = &resource.ResourceKey{ + resKey = &resourcepb.ResourceKey{ Namespace: "ns", Group: "gr", Resource: "rs", @@ -212,7 +213,7 @@ func TestBackend_create(t *testing.T) { }) require.NoError(t, err) event := resource.WriteEvent{ - Type: resource.WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Key: resKey, Object: meta, } @@ -292,7 +293,7 @@ func TestBackend_update(t *testing.T) { require.NoError(t, err) meta.SetFolder("folderuid") event := resource.WriteEvent{ - Type: resource.WatchEvent_MODIFIED, + Type: resourcepb.WatchEvent_MODIFIED, Key: resKey, Object: meta, } @@ -350,7 +351,7 @@ func TestBackend_delete(t *testing.T) { }) require.NoError(t, err) event := resource.WriteEvent{ - Type: resource.WatchEvent_DELETED, + Type: resourcepb.WatchEvent_DELETED, Key: resKey, Object: meta, } @@ -445,7 +446,7 @@ func TestBackend_ReadResource(t *testing.T) { )) b.SQLMock.ExpectCommit() - req := &resource.ReadRequest{ + req := &resourcepb.ReadRequest{ Key: resKey, } rps := b.ReadResource(ctx, req) @@ -464,7 +465,7 @@ func TestBackend_ReadResource(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{})) b.SQLMock.ExpectCommit() - req := &resource.ReadRequest{ + req := &resourcepb.ReadRequest{ Key: resKey, } res := b.ReadResource(ctx, req) @@ -503,7 +504,7 @@ func TestBackend_ReadResource(t *testing.T) { )) b.SQLMock.ExpectCommit() - req := &resource.ReadRequest{ + req := &resourcepb.ReadRequest{ Key: resKey, ResourceVersion: 300, } @@ -521,7 +522,7 @@ func TestBackend_ReadResource(t *testing.T) { b.SQLMock.ExpectQuery("SELECT .* FROM resource_history"). WillReturnError(errTest) - req := &resource.ReadRequest{ + req := &resourcepb.ReadRequest{ Key: resKey, } rps := b.ReadResource(ctx, req) @@ -533,7 +534,7 @@ func TestBackend_getHistory(t *testing.T) { t.Parallel() // Common setup - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: "ns", Group: "gr", Resource: "rs", @@ -544,8 +545,8 @@ func TestBackend_getHistory(t *testing.T) { tests := []struct { name string - source resource.ListRequest_Source - versionMatch resource.ResourceVersionMatchV2 + source resourcepb.ListRequest_Source + versionMatch resourcepb.ResourceVersionMatchV2 resourceVersion int64 expectedVersions []int64 expectedListRv int64 @@ -555,8 +556,8 @@ func TestBackend_getHistory(t *testing.T) { }{ { name: "with ResourceVersionMatch_NotOlderThan", - source: resource.ListRequest_HISTORY, - versionMatch: resource.ResourceVersionMatchV2_NotOlderThan, + source: resourcepb.ListRequest_HISTORY, + versionMatch: resourcepb.ResourceVersionMatchV2_NotOlderThan, resourceVersion: rv2, expectedVersions: []int64{rv2, rv3}, // Should be in ASC order due to NotOlderThan expectedListRv: rv3, @@ -564,8 +565,8 @@ func TestBackend_getHistory(t *testing.T) { }, { name: "with ResourceVersionMatch_NotOlderThan and ResourceVersion=0", - source: resource.ListRequest_HISTORY, - versionMatch: resource.ResourceVersionMatchV2_NotOlderThan, + source: resourcepb.ListRequest_HISTORY, + versionMatch: resourcepb.ResourceVersionMatchV2_NotOlderThan, resourceVersion: 0, expectedVersions: []int64{rv1, rv2, rv3}, // Should be in ASC order due to NotOlderThan expectedListRv: rv3, @@ -574,8 +575,8 @@ func TestBackend_getHistory(t *testing.T) { }, { name: "with ResourceVersionMatch_Exact", - source: resource.ListRequest_HISTORY, - versionMatch: resource.ResourceVersionMatchV2_Exact, + source: resourcepb.ListRequest_HISTORY, + versionMatch: resourcepb.ResourceVersionMatchV2_Exact, resourceVersion: rv2, expectedVersions: []int64{rv2}, expectedListRv: rv3, @@ -583,7 +584,7 @@ func TestBackend_getHistory(t *testing.T) { }, { name: "with ResourceVersionMatch_Unset (default)", - source: resource.ListRequest_HISTORY, + source: resourcepb.ListRequest_HISTORY, expectedVersions: []int64{rv3, rv2, rv1}, // Should be in DESC order by default expectedListRv: rv3, expectedRowsCount: 3, @@ -591,14 +592,14 @@ func TestBackend_getHistory(t *testing.T) { }, { name: "error with ResourceVersionMatch_Exact and ResourceVersion <= 0", - source: resource.ListRequest_HISTORY, - versionMatch: resource.ResourceVersionMatchV2_Exact, + source: resourcepb.ListRequest_HISTORY, + versionMatch: resourcepb.ResourceVersionMatchV2_Exact, resourceVersion: 0, expectedErr: "expecting an explicit resource version query when using Exact matching", }, { name: "with ListRequest_TRASH", - source: resource.ListRequest_TRASH, + source: resourcepb.ListRequest_TRASH, expectedVersions: []int64{rv3, rv2, rv1}, // Should be in DESC order by default expectedListRv: rv3, expectedRowsCount: 3, @@ -612,8 +613,8 @@ func TestBackend_getHistory(t *testing.T) { b, ctx := setupBackendTest(t) // Build request with appropriate matcher - req := &resource.ListRequest{ - Options: &resource.ListOptions{Key: key}, + req := &resourcepb.ListRequest{ + Options: &resourcepb.ListOptions{Key: key}, ResourceVersion: tc.resourceVersion, VersionMatchV2: tc.versionMatch, Source: tc.source, @@ -700,7 +701,7 @@ func TestBackend_getHistoryPagination(t *testing.T) { t.Parallel() // Common setup - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: "ns", Group: "gr", Resource: "rs", @@ -749,11 +750,11 @@ func TestBackend_getHistoryPagination(t *testing.T) { // Test each page for _, page := range pages { - req := &resource.ListRequest{ - Options: &resource.ListOptions{Key: key}, + req := &resourcepb.ListRequest{ + Options: &resourcepb.ListOptions{Key: key}, ResourceVersion: initialRV, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Source: resource.ListRequest_HISTORY, + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Source: resourcepb.ListRequest_HISTORY, Limit: 4, } if page.token != nil { @@ -790,11 +791,11 @@ func TestBackend_getHistoryPagination(t *testing.T) { t.Run("pagination with ResourceVersion=0 and NotOlderThan should return entries in ASC order", func(t *testing.T) { b, ctx := setupBackendTest(t) - req := &resource.ListRequest{ - Options: &resource.ListOptions{Key: key}, + req := &resourcepb.ListRequest{ + Options: &resourcepb.ListOptions{Key: key}, ResourceVersion: 0, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Source: resource.ListRequest_HISTORY, + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Source: resourcepb.ListRequest_HISTORY, Limit: 4, } diff --git a/pkg/storage/unified/sql/blob.go b/pkg/storage/unified/sql/blob.go index 27fa219c416..3a1690fd580 100644 --- a/pkg/storage/unified/sql/blob.go +++ b/pkg/storage/unified/sql/blob.go @@ -1,7 +1,7 @@ package sql import ( - context "context" + "context" "crypto/md5" "encoding/hex" "fmt" @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" @@ -25,12 +26,12 @@ func (b *backend) SupportsSignedURLs() bool { return false } -func (b *backend) PutResourceBlob(ctx context.Context, req *resource.PutBlobRequest) (*resource.PutBlobResponse, error) { +func (b *backend) PutResourceBlob(ctx context.Context, req *resourcepb.PutBlobRequest) (*resourcepb.PutBlobResponse, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"PutResourceBlob") defer span.End() - if req.Method == resource.PutBlobRequest_HTTP { - return &resource.PutBlobResponse{ + if req.Method == resourcepb.PutBlobRequest_HTTP { + return &resourcepb.PutBlobResponse{ Error: resource.NewBadRequestError("signed url upload not supported"), }, nil } @@ -49,7 +50,7 @@ func (b *backend) PutResourceBlob(ctx context.Context, req *resource.PutBlobRequ info.SetContentType(req.ContentType) if info.Size < 1 { - return &resource.PutBlobResponse{ + return &resourcepb.PutBlobResponse{ Error: resource.NewBadRequestError("empty content"), }, nil } @@ -68,11 +69,11 @@ func (b *backend) PutResourceBlob(ctx context.Context, req *resource.PutBlobRequ }) if err != nil { - return &resource.PutBlobResponse{ + return &resourcepb.PutBlobResponse{ Error: resource.AsErrorResult(err), }, nil } - return &resource.PutBlobResponse{ + return &resourcepb.PutBlobResponse{ Uid: info.UID, Size: info.Size, MimeType: info.MimeType, @@ -81,17 +82,17 @@ func (b *backend) PutResourceBlob(ctx context.Context, req *resource.PutBlobRequ }, nil } -func (b *backend) GetResourceBlob(ctx context.Context, key *resource.ResourceKey, info *utils.BlobInfo, mustProxy bool) (*resource.GetBlobResponse, error) { +func (b *backend) GetResourceBlob(ctx context.Context, key *resourcepb.ResourceKey, info *utils.BlobInfo, mustProxy bool) (*resourcepb.GetBlobResponse, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+"GetResourceBlob") defer span.End() if info == nil { - return &resource.GetBlobResponse{ + return &resourcepb.GetBlobResponse{ Error: resource.NewBadRequestError("missing blob info"), }, nil } - rsp := &resource.GetBlobResponse{} + rsp := &resourcepb.GetBlobResponse{} err := b.db.WithTx(ctx, ReadCommitted, func(ctx context.Context, tx db.Tx) error { rows, err := dbutil.QueryRows(ctx, tx, sqlResourceBlobQuery, sqlResourceBlobQueryRequest{ SQLTemplate: sqltemplate.New(b.dialect), @@ -109,7 +110,7 @@ func (b *backend) GetResourceBlob(ctx context.Context, key *resource.ResourceKey } return err } - rsp.Error = &resource.ErrorResult{ + rsp.Error = &resourcepb.ErrorResult{ Code: http.StatusNotFound, } return err diff --git a/pkg/storage/unified/sql/bulk.go b/pkg/storage/unified/sql/bulk.go index a39147ee640..401017d435f 100644 --- a/pkg/storage/unified/sql/bulk.go +++ b/pkg/storage/unified/sql/bulk.go @@ -14,9 +14,11 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/parquet" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" @@ -62,14 +64,14 @@ type bulkLock struct { mu sync.Mutex } -func (x *bulkLock) Start(keys []*resource.ResourceKey) error { +func (x *bulkLock) Start(keys []*resourcepb.ResourceKey) error { x.mu.Lock() defer x.mu.Unlock() // First verify that it is not already running ids := make([]string, len(keys)) for i, k := range keys { - id := k.NSGR() + id := resource.NSGR(k) if x.running[id] { return &apierrors.StatusError{ErrStatus: metav1.Status{ Code: http.StatusPreconditionFailed, @@ -86,11 +88,11 @@ func (x *bulkLock) Start(keys []*resource.ResourceKey) error { return nil } -func (x *bulkLock) Finish(keys []*resource.ResourceKey) { +func (x *bulkLock) Finish(keys []*resourcepb.ResourceKey) { x.mu.Lock() defer x.mu.Unlock() for _, k := range keys { - delete(x.running, k.NSGR()) + delete(x.running, resource.NSGR(k)) } } @@ -100,10 +102,10 @@ func (x *bulkLock) Active() bool { return len(x.running) > 0 } -func (b *backend) ProcessBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resource.BulkResponse { +func (b *backend) ProcessBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resourcepb.BulkResponse { err := b.bulkLock.Start(setting.Collection) if err != nil { - return &resource.BulkResponse{ + return &resourcepb.BulkResponse{ Error: resource.AsErrorResult(err), } } @@ -113,14 +115,14 @@ func (b *backend) ProcessBulk(ctx context.Context, setting resource.BulkSettings if b.dialect.DialectName() == "sqlite" { file, err := os.CreateTemp("", "grafana-bulk-export-*.parquet") if err != nil { - return &resource.BulkResponse{ + return &resourcepb.BulkResponse{ Error: resource.AsErrorResult(err), } } writer, err := parquet.NewParquetWriter(file) if err != nil { - return &resource.BulkResponse{ + return &resourcepb.BulkResponse{ Error: resource.AsErrorResult(err), } } @@ -136,7 +138,7 @@ func (b *backend) ProcessBulk(ctx context.Context, setting resource.BulkSettings // Replace the iterator with one from parquet iter, err = parquet.NewParquetReader(file.Name(), 50) if err != nil { - return &resource.BulkResponse{ + return &resourcepb.BulkResponse{ Error: resource.AsErrorResult(err), } } @@ -146,8 +148,8 @@ func (b *backend) ProcessBulk(ctx context.Context, setting resource.BulkSettings } // internal bulk process -func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resource.BulkResponse { - rsp := &resource.BulkResponse{} +func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resourcepb.BulkResponse { + rsp := &resourcepb.BulkResponse{} err := b.db.WithTx(ctx, ReadCommitted, func(ctx context.Context, tx db.Tx) error { rollbackWithError := func(err error) error { txerr := tx.Rollback() @@ -168,7 +170,7 @@ func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings // Calculate the RV based on incoming request timestamps rv := newBulkRV() - summaries := make(map[string]*resource.BulkResponse_Summary, len(setting.Collection)*4) + summaries := make(map[string]*resourcepb.BulkResponse_Summary, len(setting.Collection)*4) // First clear everything in the transaction if setting.RebuildCollection { @@ -177,7 +179,7 @@ func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings if err != nil { return rollbackWithError(err) } - summaries[key.NSGR()] = summary + summaries[resource.NSGR(key)] = summary rsp.Summary = append(rsp.Summary, summary) } } @@ -195,8 +197,8 @@ func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings } rsp.Processed++ - if req.Action == resource.BulkRequest_UNKNOWN { - rsp.Rejected = append(rsp.Rejected, &resource.BulkResponse_Rejected{ + if req.Action == resourcepb.BulkRequest_UNKNOWN { + rsp.Rejected = append(rsp.Rejected, &resourcepb.BulkResponse_Rejected{ Key: req.Key, Action: req.Action, Error: "unknown action", @@ -206,7 +208,7 @@ func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings err := obj.UnmarshalJSON(req.Value) if err != nil { - rsp.Rejected = append(rsp.Rejected, &resource.BulkResponse_Rejected{ + rsp.Rejected = append(rsp.Rejected, &resourcepb.BulkResponse_Rejected{ Key: req.Key, Action: req.Action, Error: "unable to unmarshal json", @@ -219,7 +221,7 @@ func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings SQLTemplate: sqltemplate.New(b.dialect), WriteEvent: resource.WriteEvent{ Key: req.Key, - Type: resource.WatchEvent_Type(req.Action), + Type: resourcepb.WatchEvent_Type(req.Action), Value: req.Value, PreviousRV: -1, // Used for WATCH, but we want to skip watch events }, @@ -268,8 +270,8 @@ type bulkWroker struct { } // This will remove everything from the `resource` and `resource_history` table for a given namespace/group/resource -func (w *bulkWroker) deleteCollection(key *resource.ResourceKey) (*resource.BulkResponse_Summary, error) { - summary := &resource.BulkResponse_Summary{ +func (w *bulkWroker) deleteCollection(key *resourcepb.ResourceKey) (*resourcepb.BulkResponse_Summary, error) { + summary := &resourcepb.BulkResponse_Summary{ Namespace: key.Namespace, Group: key.Group, Resource: key.Resource, @@ -306,8 +308,8 @@ func (w *bulkWroker) deleteCollection(key *resource.ResourceKey) (*resource.Bulk } // Copy the latest value from history into the active resource table -func (w *bulkWroker) syncCollection(key *resource.ResourceKey, summary *resource.BulkResponse_Summary) error { - w.logger.Info("synchronize collection", "key", key.NSGR()) +func (w *bulkWroker) syncCollection(key *resourcepb.ResourceKey, summary *resourcepb.BulkResponse_Summary) error { + w.logger.Info("synchronize collection", "key", resource.NSGR(key)) _, err := dbutil.Exec(w.ctx, w.tx, sqlResourceInsertFromHistory, &sqlResourceInsertFromHistoryRequest{ SQLTemplate: sqltemplate.New(w.dialect), Key: key, @@ -316,7 +318,7 @@ func (w *bulkWroker) syncCollection(key *resource.ResourceKey, summary *resource return err } - w.logger.Info("get stats (still in transaction)", "key", key.NSGR()) + w.logger.Info("get stats (still in transaction)", "key", resource.NSGR(key)) rows, err := dbutil.QueryRows(w.ctx, w.tx, sqlResourceStats, &sqlStatsRequest{ SQLTemplate: sqltemplate.New(w.dialect), Namespace: key.Namespace, diff --git a/pkg/storage/unified/sql/notifier_sql.go b/pkg/storage/unified/sql/notifier_sql.go index fda635eebdc..da06c5b6555 100644 --- a/pkg/storage/unified/sql/notifier_sql.go +++ b/pkg/storage/unified/sql/notifier_sql.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) @@ -197,13 +198,13 @@ func (p *pollingNotifier) poll(ctx context.Context, grp string, res string, sinc } stream <- &resource.WrittenEvent{ Value: rec.Value, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: rec.Key.Namespace, Group: rec.Key.Group, Resource: rec.Key.Resource, Name: rec.Key.Name, }, - Type: resource.WatchEvent_Type(rec.Action), + Type: resourcepb.WatchEvent_Type(rec.Action), PreviousRV: *prevRV, Folder: rec.Folder, ResourceVersion: rec.ResourceVersion, diff --git a/pkg/storage/unified/sql/notifier_sql_test.go b/pkg/storage/unified/sql/notifier_sql_test.go index af4344c0c85..d0998d71d86 100644 --- a/pkg/storage/unified/sql/notifier_sql_test.go +++ b/pkg/storage/unified/sql/notifier_sql_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) @@ -209,7 +209,7 @@ func TestPollingNotifier(t *testing.T) { defer close(done) testEvent := &historyPollResponse{ - Key: resource.ResourceKey{ + Key: resourcepb.ResourceKey{ Namespace: "test-ns", Group: "test-group", Resource: "test-resource", diff --git a/pkg/storage/unified/sql/notifier_test.go b/pkg/storage/unified/sql/notifier_test.go index 95e4f0a8cde..7c6a0d0a249 100644 --- a/pkg/storage/unified/sql/notifier_test.go +++ b/pkg/storage/unified/sql/notifier_test.go @@ -6,7 +6,10 @@ import ( "time" "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/require" ) @@ -21,8 +24,8 @@ func TestChannelNotifier(t *testing.T) { require.NoError(t, err) testEvent := &resource.WrittenEvent{ - Type: resource.WatchEvent_ADDED, - Key: &resource.ResourceKey{ + Type: resourcepb.WatchEvent_ADDED, + Key: &resourcepb.ResourceKey{ Group: "test", Resource: "test", Name: "test1", diff --git a/pkg/storage/unified/sql/queries.go b/pkg/storage/unified/sql/queries.go index e754881b0c6..52778613a82 100644 --- a/pkg/storage/unified/sql/queries.go +++ b/pkg/storage/unified/sql/queries.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) @@ -88,7 +89,7 @@ func (r sqlResourceRequest) Validate() error { type sqlResourceInsertFromHistoryRequest struct { sqltemplate.SQLTemplate - Key *resource.ResourceKey + Key *resourcepb.ResourceKey } func (r sqlResourceInsertFromHistoryRequest) Validate() error { @@ -115,7 +116,7 @@ func (r sqlStatsRequest) Validate() error { } type historyPollResponse struct { - Key resource.ResourceKey + Key resourcepb.ResourceKey GUID string ResourceVersion int64 PreviousRV *int64 @@ -148,7 +149,7 @@ func (r *sqlResourceHistoryPollRequest) Results() (*historyPollResponse, error) prevRV = new(int64) } return &historyPollResponse{ - Key: resource.ResourceKey{ + Key: resourcepb.ResourceKey{ Namespace: r.Response.Key.Namespace, Group: r.Response.Key.Group, Resource: r.Response.Key.Resource, @@ -165,13 +166,13 @@ func (r *sqlResourceHistoryPollRequest) Results() (*historyPollResponse, error) // sqlResourceReadRequest can be used to retrieve a row fromthe "resource" tables. func NewReadResponse() *resource.BackendReadResponse { return &resource.BackendReadResponse{ - Key: &resource.ResourceKey{}, + Key: &resourcepb.ResourceKey{}, } } type sqlResourceReadRequest struct { sqltemplate.SQLTemplate - Request *resource.ReadRequest + Request *resourcepb.ReadRequest Response *resource.BackendReadResponse } @@ -186,7 +187,7 @@ func (r *sqlResourceReadRequest) Results() (*resource.BackendReadResponse, error // List type sqlResourceListRequest struct { sqltemplate.SQLTemplate - Request *resource.ListRequest + Request *resourcepb.ListRequest } func (r sqlResourceListRequest) Validate() error { @@ -194,7 +195,7 @@ func (r sqlResourceListRequest) Validate() error { } type historyReadRequest struct { - Key *resource.ResourceKey + Key *resourcepb.ResourceKey ResourceVersion int64 } @@ -213,8 +214,8 @@ func (r sqlResourceHistoryReadRequest) Results() (*resource.BackendReadResponse, } type historyReadLatestRVRequest struct { - Key *resource.ResourceKey - EventType resource.WatchEvent_Type + Key *resourcepb.ResourceKey + EventType resourcepb.WatchEvent_Type } type sqlResourceHistoryReadLatestRVRequest struct { @@ -242,25 +243,25 @@ func (r *resourceHistoryReadLatestRVResponse) Results() (*resourceHistoryReadLat type historyListRequest struct { ResourceVersion, Limit, Offset int64 Folder string - Options *resource.ListOptions + Options *resourcepb.ListOptions } type sqlResourceHistoryListRequest struct { sqltemplate.SQLTemplate Request *historyListRequest - Response *resource.ResourceWrapper + Response *resourcepb.ResourceWrapper } func (r sqlResourceHistoryListRequest) Validate() error { return nil // TODO } -func (r sqlResourceHistoryListRequest) Results() (*resource.ResourceWrapper, error) { +func (r sqlResourceHistoryListRequest) Results() (*resourcepb.ResourceWrapper, error) { // sqlResourceHistoryListRequest is a set-returning query. As such, it // should not return its *Response, since that will be overwritten in the // next call to `Scan`, so it needs to return a copy of it. Note, though, // that it is safe to return the same `Response.Value` since `Scan` // allocates a new slice of bytes each time. - return &resource.ResourceWrapper{ + return &resourcepb.ResourceWrapper{ ResourceVersion: r.Response.ResourceVersion, Value: r.Response.Value, }, nil @@ -292,7 +293,7 @@ func (r *sqlResourceHistoryDeleteRequest) Validate() error { type sqlGetHistoryRequest struct { sqltemplate.SQLTemplate - Key *resource.ResourceKey + Key *resourcepb.ResourceKey Trash bool // only deleted items StartRV int64 // from NextPageToken MinRV int64 // minimum resource version for NotOlderThan @@ -307,7 +308,7 @@ func (r sqlGetHistoryRequest) Validate() error { // prune resource history type sqlPruneHistoryRequest struct { sqltemplate.SQLTemplate - Key *resource.ResourceKey + Key *resourcepb.ResourceKey PartitionByGeneration bool // include generation in the partition HistoryLimit int64 } @@ -335,7 +336,7 @@ type sqlResourceBlobInsertRequest struct { sqltemplate.SQLTemplate Now time.Time Info *utils.BlobInfo - Key *resource.ResourceKey + Key *resourcepb.ResourceKey Value []byte ContentType string } @@ -349,7 +350,7 @@ func (r sqlResourceBlobInsertRequest) Validate() error { type sqlResourceBlobQueryRequest struct { sqltemplate.SQLTemplate - Key *resource.ResourceKey + Key *resourcepb.ResourceKey UID string } diff --git a/pkg/storage/unified/sql/queries_test.go b/pkg/storage/unified/sql/queries_test.go index ad07baec565..4d5941e25dc 100644 --- a/pkg/storage/unified/sql/queries_test.go +++ b/pkg/storage/unified/sql/queries_test.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks" ) @@ -21,7 +22,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Data: &sqlResourceRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), WriteEvent: resource.WriteEvent{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -37,13 +38,13 @@ func TestUnifiedStorageQueries(t *testing.T) { Data: &sqlResourceRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), WriteEvent: resource.WriteEvent{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", Name: "name", }, - Type: resource.WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, PreviousRV: 123, }, Folder: "fldr", @@ -56,7 +57,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Data: &sqlResourceRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), WriteEvent: resource.WriteEvent{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -72,8 +73,8 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "without_resource_version", Data: &sqlResourceReadRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Request: &resource.ReadRequest{ - Key: &resource.ResourceKey{ + Request: &resourcepb.ReadRequest{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -90,10 +91,10 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "filter_on_namespace", Data: &sqlResourceListRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Request: &resource.ListRequest{ + Request: &resourcepb.ListRequest{ Limit: 10, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "ns", }, }, @@ -109,13 +110,13 @@ func TestUnifiedStorageQueries(t *testing.T) { SQLTemplate: mocks.NewTestingSQLTemplate(), Request: &historyListRequest{ Limit: 10, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: "ns", }, }, }, - Response: new(resource.ResourceWrapper), + Response: new(resourcepb.ResourceWrapper), }, }, }, @@ -152,7 +153,7 @@ func TestUnifiedStorageQueries(t *testing.T) { SQLTemplate: mocks.NewTestingSQLTemplate(), Request: &historyReadRequest{ ResourceVersion: 123, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "ns", Group: "gp", Resource: "rs", @@ -170,7 +171,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Data: &sqlResourceHistoryReadLatestRVRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), Request: &historyReadLatestRVRequest{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "ns", Group: "gp", Resource: "rs", @@ -185,13 +186,13 @@ func TestUnifiedStorageQueries(t *testing.T) { Data: &sqlResourceHistoryReadLatestRVRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), Request: &historyReadLatestRVRequest{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "ns", Group: "gp", Resource: "rs", Name: "nm", }, - EventType: resource.WatchEvent_DELETED, + EventType: resourcepb.WatchEvent_DELETED, }, Response: new(resourceHistoryReadLatestRVResponse), }, @@ -218,7 +219,7 @@ func TestUnifiedStorageQueries(t *testing.T) { SQLTemplate: mocks.NewTestingSQLTemplate(), Generation: 789, WriteEvent: resource.WriteEvent{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -236,7 +237,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "read object history", Data: &sqlGetHistoryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -248,7 +249,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "read trash", Data: &sqlGetHistoryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -260,7 +261,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "read trash second page", Data: &sqlGetHistoryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "nn", Group: "gg", Resource: "rr", @@ -276,7 +277,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "max-versions", Data: &sqlPruneHistoryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: "provisioning.grafana.app", Resource: "repositories", @@ -289,7 +290,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "collapse-generations", Data: &sqlPruneHistoryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: "provisioning.grafana.app", Resource: "repositories", @@ -386,7 +387,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "basic", Data: &sqlResourceBlobInsertRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "x", Group: "g", Resource: "r", @@ -409,7 +410,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "basic", Data: &sqlResourceBlobQueryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "x", Group: "g", Resource: "r", @@ -422,7 +423,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "resource", // NOTE: this returns multiple values Data: &sqlResourceBlobQueryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "x", Group: "g", Resource: "r", @@ -454,7 +455,7 @@ func TestUnifiedStorageQueries(t *testing.T) { Name: "update", Data: &sqlResourceInsertFromHistoryRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: "dashboard.grafana.app", Resource: "dashboards", diff --git a/pkg/storage/unified/sql/rv_manager.go b/pkg/storage/unified/sql/rv_manager.go index 1f3211dc9ec..0ffce47b259 100644 --- a/pkg/storage/unified/sql/rv_manager.go +++ b/pkg/storage/unified/sql/rv_manager.go @@ -8,15 +8,16 @@ import ( "sync" "time" - "github.com/grafana/grafana/pkg/storage/unified/resource" - "github.com/grafana/grafana/pkg/storage/unified/sql/db" - "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" - "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/grafana/grafana/pkg/storage/unified/sql/db" + "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) var ( @@ -82,9 +83,9 @@ type writeOpResult struct { // writeOp is a write operation that is executed with an incremented resource version type writeOp struct { - key *resource.ResourceKey // The key of the resource - fn WriteEventFunc // The function to execute to write the event - done chan writeOpResult // A channel informing the operation is done + key *resourcepb.ResourceKey // The key of the resource + fn WriteEventFunc // The function to execute to write the event + done chan writeOpResult // A channel informing the operation is done } // WriteEventFunc is a function that writes a resource to the database @@ -128,7 +129,7 @@ func NewResourceVersionManager(opts ResourceManagerOptions) (*resourceVersionMan } // ExecWithRV executes the given function with an incremented resource version -func (m *resourceVersionManager) ExecWithRV(ctx context.Context, key *resource.ResourceKey, fn WriteEventFunc) (rv int64, err error) { +func (m *resourceVersionManager) ExecWithRV(ctx context.Context, key *resourcepb.ResourceKey, fn WriteEventFunc) (rv int64, err error) { rvmInflightWrites.WithLabelValues(key.Group, key.Resource).Inc() defer rvmInflightWrites.WithLabelValues(key.Group, key.Resource).Dec() diff --git a/pkg/storage/unified/sql/rv_manager_test.go b/pkg/storage/unified/sql/rv_manager_test.go index 2186323f845..46d23d26a59 100644 --- a/pkg/storage/unified/sql/rv_manager_test.go +++ b/pkg/storage/unified/sql/rv_manager_test.go @@ -3,13 +3,14 @@ package sql import ( "testing" - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" "github.com/grafana/grafana/pkg/storage/unified/sql/test" "github.com/grafana/grafana/pkg/util/testutil" - "github.com/stretchr/testify/require" ) func expectSuccessfulResourceVersionLock(t *testing.T, dbp test.TestDBProvider, rv int64, timestamp int64) { @@ -44,7 +45,7 @@ func TestResourceVersionManager(t *testing.T) { require.NotNil(t, manager) t.Run("should handle single operation", func(t *testing.T) { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "test-group", Resource: "test-resource", } diff --git a/pkg/storage/unified/sql/search.go b/pkg/storage/unified/sql/search.go index 8c15be1ae66..0a28e48e190 100644 --- a/pkg/storage/unified/sql/search.go +++ b/pkg/storage/unified/sql/search.go @@ -6,17 +6,18 @@ import ( "net/http" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) // Support using SQL as fallback when the indexer is not running -var _ resource.ResourceIndexServer = &backend{} +var _ resourcepb.ResourceIndexServer = &backend{} // GetStats implements resource.ResourceIndexServer. // This will use the SQL index to count values -func (b *backend) GetStats(ctx context.Context, req *resource.ResourceStatsRequest) (*resource.ResourceStatsResponse, error) { +func (b *backend) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest) (*resourcepb.ResourceStatsResponse, error) { ctx, span := b.tracer.Start(ctx, tracePrefix+".GetStats") defer span.End() @@ -26,7 +27,7 @@ func (b *backend) GetStats(ctx context.Context, req *resource.ResourceStatsReque Folder: req.Folder, } - rsp := &resource.ResourceStatsResponse{} + rsp := &resourcepb.ResourceStatsResponse{} err := b.db.WithTx(ctx, ReadCommittedRO, func(ctx context.Context, tx db.Tx) error { rows, err := dbutil.QueryRows(ctx, tx, sqlResourceStats, sreq) if err != nil { @@ -39,7 +40,7 @@ func (b *backend) GetStats(ctx context.Context, req *resource.ResourceStatsReque return err } - rsp.Stats = append(rsp.Stats, &resource.ResourceStatsResponse_Stats{ + rsp.Stats = append(rsp.Stats, &resourcepb.ResourceStatsResponse_Stats{ Group: row.Group, Resource: row.Resource, Count: row.Count, @@ -53,18 +54,18 @@ func (b *backend) GetStats(ctx context.Context, req *resource.ResourceStatsReque return rsp, nil } -func (b *backend) RepositoryList(ctx context.Context, req *resource.ListManagedObjectsRequest) (*resource.ListManagedObjectsResponse, error) { +func (b *backend) RepositoryList(ctx context.Context, req *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { return nil, fmt.Errorf("SQL backend does not implement RepositoryList") } -func (b *backend) RepositoryStats(context.Context, *resource.CountManagedObjectsRequest) (*resource.CountManagedObjectsResponse, error) { +func (b *backend) RepositoryStats(context.Context, *resourcepb.CountManagedObjectsRequest) (*resourcepb.CountManagedObjectsResponse, error) { return nil, fmt.Errorf("SQL backend does not implement RepositoryStats") } // Search implements resource.ResourceIndexServer. -func (b *backend) Search(context.Context, *resource.ResourceSearchRequest) (*resource.ResourceSearchResponse, error) { - return &resource.ResourceSearchResponse{ - Error: &resource.ErrorResult{ +func (b *backend) Search(context.Context, *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { + return &resourcepb.ResourceSearchResponse{ + Error: &resourcepb.ErrorResult{ Code: http.StatusNotImplemented, Message: "SQL backend does not implement Search", }, diff --git a/pkg/storage/unified/sql/service.go b/pkg/storage/unified/sql/service.go index 764fa046f99..d917b66875e 100644 --- a/pkg/storage/unified/sql/service.go +++ b/pkg/storage/unified/sql/service.go @@ -25,6 +25,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resource/grpc" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" ) @@ -136,12 +137,12 @@ func (s *service) start(ctx context.Context) error { } srv := s.handler.GetServer() - resource.RegisterResourceStoreServer(srv, server) - resource.RegisterBulkStoreServer(srv, server) - resource.RegisterResourceIndexServer(srv, server) - resource.RegisterManagedObjectIndexServer(srv, server) - resource.RegisterBlobStoreServer(srv, server) - resource.RegisterDiagnosticsServer(srv, server) + resourcepb.RegisterResourceStoreServer(srv, server) + resourcepb.RegisterBulkStoreServer(srv, server) + resourcepb.RegisterResourceIndexServer(srv, server) + resourcepb.RegisterManagedObjectIndexServer(srv, server) + resourcepb.RegisterBlobStoreServer(srv, server) + resourcepb.RegisterDiagnosticsServer(srv, server) grpc_health_v1.RegisterHealthServer(srv, healthService) // register reflection service diff --git a/pkg/storage/unified/sql/test/integration_test.go b/pkg/storage/unified/sql/test/integration_test.go index 8a3b0435dda..7c5fd5b5bac 100644 --- a/pkg/storage/unified/sql/test/integration_test.go +++ b/pkg/storage/unified/sql/test/integration_test.go @@ -13,12 +13,14 @@ import ( "github.com/grafana/authlib/authn" "github.com/grafana/authlib/types" "github.com/grafana/dskit/services" + "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" "github.com/grafana/grafana/pkg/storage/unified/sql" "github.com/grafana/grafana/pkg/storage/unified/sql/db/dbimpl" @@ -157,7 +159,7 @@ func TestClientServer(t *testing.T) { svc, err := sql.ProvideUnifiedStorageGrpcService(cfg, features, dbstore, nil, prometheus.NewPedanticRegistry(), nil, nil, nil, nil) require.NoError(t, err) - var client resource.ResourceStoreClient + var client resourcepb.ResourceStoreClient clientCtx := types.WithAuthInfo(context.Background(), authn.NewAccessTokenAuthInfo(authn.Claims[authn.AccessTokenClaims]{ Claims: jwt.Claims{ @@ -193,7 +195,7 @@ func TestClientServer(t *testing.T) { }, "spec": {} }`) - resp, err := client.Create(clientCtx, &resource.CreateRequest{ + resp, err := client.Create(clientCtx, &resourcepb.CreateRequest{ Key: resourceKey("item1"), Value: raw, }) @@ -203,7 +205,7 @@ func TestClientServer(t *testing.T) { }) t.Run("Read the resource", func(t *testing.T) { - resp, err := client.Read(clientCtx, &resource.ReadRequest{ + resp, err := client.Read(clientCtx, &resourcepb.ReadRequest{ Key: resourceKey("item1"), }) require.NoError(t, err) @@ -217,8 +219,8 @@ func TestClientServer(t *testing.T) { }) } -func resourceKey(name string) *resource.ResourceKey { - return &resource.ResourceKey{ +func resourceKey(name string) *resourcepb.ResourceKey { + return &resourcepb.ResourceKey{ Namespace: "namespace", Group: "group", Resource: "resource", diff --git a/pkg/storage/unified/testing/benchmark.go b/pkg/storage/unified/testing/benchmark.go index e3dab5acbeb..dfcacde86c1 100644 --- a/pkg/storage/unified/testing/benchmark.go +++ b/pkg/storage/unified/testing/benchmark.go @@ -10,6 +10,8 @@ import ( "time" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -53,7 +55,7 @@ func initializeBackend(ctx context.Context, backend resource.StorageBackend, opt group := fmt.Sprintf("group-%d", g) for r := 0; r < opts.NumResourceTypes; r++ { resourceType := fmt.Sprintf("resource-%d", r) - _, err := writeEvent(ctx, backend, "init", resource.WatchEvent_ADDED, + _, err := writeEvent(ctx, backend, "init", resourcepb.WatchEvent_ADDED, WithNamespace(namespace), WithGroup(group), WithResource(resourceType), @@ -104,7 +106,7 @@ func runStorageBackendBenchmark(ctx context.Context, backend resource.StorageBac name := fmt.Sprintf("item-%d", uniqueID) writeStart := time.Now() - _, err := writeEvent(ctx, backend, name, resource.WatchEvent_ADDED, + _, err := writeEvent(ctx, backend, name, resourcepb.WatchEvent_ADDED, WithNamespace(namespace), WithGroup(group), WithResource(resourceType), @@ -232,7 +234,7 @@ func runSearchBackendBenchmarkWriteThroughput(ctx context.Context, backend resou for jobID := range jobs { doc := &resource.IndexableDocument{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: nr.Namespace, Group: nr.Group, Resource: nr.Resource, @@ -420,7 +422,7 @@ func BenchmarkIndexServer(tb testing.TB, ctx context.Context, backend resource.S // testDocumentBuilder implements DocumentBuilder for testing type testDocumentBuilder struct{} -func (b *testDocumentBuilder) BuildDocument(ctx context.Context, key *resource.ResourceKey, rv int64, value []byte) (*resource.IndexableDocument, error) { +func (b *testDocumentBuilder) BuildDocument(ctx context.Context, key *resourcepb.ResourceKey, rv int64, value []byte) (*resource.IndexableDocument, error) { // convert value to unstructured.Unstructured var u unstructured.Unstructured if err := u.UnmarshalJSON(value); err != nil { @@ -451,7 +453,7 @@ func (b *testDocumentBuilder) BuildDocument(ctx context.Context, key *resource.R } } return &resource.IndexableDocument{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: key.Namespace, Group: key.Group, Resource: key.Resource, diff --git a/pkg/storage/unified/testing/search_and_storage.go b/pkg/storage/unified/testing/search_and_storage.go index ba0b83dbf19..015a499bd12 100644 --- a/pkg/storage/unified/testing/search_and_storage.go +++ b/pkg/storage/unified/testing/search_and_storage.go @@ -7,9 +7,12 @@ import ( "github.com/stretchr/testify/require" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) @@ -48,7 +51,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource } for _, doc := range initialResources { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix, @@ -80,7 +83,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource // Create document rv, err := backend.WriteEvent(ctx, resource.WriteEvent{ - Type: resource.WatchEvent_ADDED, + Type: resourcepb.WatchEvent_ADDED, Key: key, Value: value, Object: meta, @@ -111,9 +114,9 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource t.Run("Search for initial resources", func(t *testing.T) { // Test 1: Search for initial resources - searchResp, err := server.Search(ctx, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix, @@ -152,7 +155,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource } for _, doc := range testDocs { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix, @@ -180,7 +183,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource require.NoError(t, err) // Create document - createResp, err := server.Create(ctx, &resource.CreateRequest{ + createResp, err := server.Create(ctx, &resourcepb.CreateRequest{ Key: key, Value: value, }) @@ -194,9 +197,9 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Search for documents", func(t *testing.T) { - searchResp, err := server.Search(ctx, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix, @@ -212,9 +215,9 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Search with tags", func(t *testing.T) { - searchResp, err := server.Search(ctx, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix, @@ -230,9 +233,9 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Search with specific tag", func(t *testing.T) { - searchResp, err := server.Search(ctx, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix, diff --git a/pkg/storage/unified/testing/search_backend.go b/pkg/storage/unified/testing/search_backend.go index 55b7722b756..e42e3aae12e 100644 --- a/pkg/storage/unified/testing/search_backend.go +++ b/pkg/storage/unified/testing/search_backend.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/util/testutil" ) @@ -74,7 +75,7 @@ func runTestSearchBackendBuildIndex(t *testing.T, backend resource.SearchBackend { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, @@ -120,7 +121,7 @@ func runTestResourceIndex(t *testing.T, backend resource.SearchBackend, nsPrefix { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, @@ -137,7 +138,7 @@ func runTestResourceIndex(t *testing.T, backend resource.SearchBackend, nsPrefix { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, @@ -160,9 +161,9 @@ func runTestResourceIndex(t *testing.T, backend resource.SearchBackend, nsPrefix require.NotNil(t, index) t.Run("Search", func(t *testing.T) { - resp, err := index.Search(ctx, nil, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + resp, err := index.Search(ctx, nil, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, @@ -177,9 +178,9 @@ func runTestResourceIndex(t *testing.T, backend resource.SearchBackend, nsPrefix require.Equal(t, int64(1), resp.TotalHits) // Only doc3 should have tag3 now // Search for Document - resp, err = index.Search(ctx, nil, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + resp, err = index.Search(ctx, nil, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, @@ -201,7 +202,7 @@ func runTestResourceIndex(t *testing.T, backend resource.SearchBackend, nsPrefix { Action: resource.ActionIndex, Doc: &resource.IndexableDocument{ - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, @@ -219,9 +220,9 @@ func runTestResourceIndex(t *testing.T, backend resource.SearchBackend, nsPrefix }) require.NoError(t, err) // Search for Document - resp, err := index.Search(ctx, nil, &resource.ResourceSearchRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + resp, err := index.Search(ctx, nil, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns.Namespace, Group: ns.Group, Resource: ns.Resource, diff --git a/pkg/storage/unified/testing/server.go b/pkg/storage/unified/testing/server.go index 3195ef82637..fde4440a8e5 100644 --- a/pkg/storage/unified/testing/server.go +++ b/pkg/storage/unified/testing/server.go @@ -7,9 +7,12 @@ import ( "testing" "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/stretchr/testify/require" ) @@ -137,7 +140,7 @@ func runTestResourcePermissionScenarios(t *testing.T, backend resource.StorageBa ctx := types.WithAuthInfo(context.Background(), testUser) - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Group: "test.grafana.app", Resource: "testresources", Namespace: nsPrefix + "-ns1", @@ -163,7 +166,7 @@ func runTestResourcePermissionScenarios(t *testing.T, backend resource.StorageBa }`, resourceName, resourceUID, nsPrefix+"-ns1", tc.initialFolder, i) checksPerformed = []types.CheckRequest{} - created, err := server.Create(ctx, &resource.CreateRequest{ + created, err := server.Create(ctx, &resourcepb.CreateRequest{ Value: []byte(resourceJSON), Key: key, }) @@ -202,7 +205,7 @@ func runTestResourcePermissionScenarios(t *testing.T, backend resource.StorageBa // Override permissions for initial creation to always succeed mockAccess.allowed = true - created, err := server.Create(ctx, &resource.CreateRequest{ + created, err := server.Create(ctx, &resourcepb.CreateRequest{ Value: []byte(initialResourceJSON), Key: key, }) @@ -229,7 +232,7 @@ func runTestResourcePermissionScenarios(t *testing.T, backend resource.StorageBa mockAccess.allowed = false // Reset to use the map checksPerformed = []types.CheckRequest{} - updated, err := server.Update(ctx, &resource.UpdateRequest{ + updated, err := server.Update(ctx, &resourcepb.UpdateRequest{ Key: key, Value: []byte(targetResourceJSON), ResourceVersion: created.ResourceVersion, diff --git a/pkg/storage/unified/testing/storage_backend.go b/pkg/storage/unified/testing/storage_backend.go index 71849648943..6295f5fdb90 100644 --- a/pkg/storage/unified/testing/storage_backend.go +++ b/pkg/storage/unified/testing/storage_backend.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/util/testutil" ) @@ -108,34 +109,34 @@ func runTestIntegrationBackendHappyPath(t *testing.T, backend resource.StorageBa var rv1, rv2, rv3, rv4, rv5 int64 t.Run("Add 3 resources", func(t *testing.T) { - rv1, err = writeEvent(ctx, backend, "item1", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv1, err = writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv1, int64(0)) - rv2, err = writeEvent(ctx, backend, "item2", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv2, err = writeEvent(ctx, backend, "item2", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv2, rv1) - rv3, err = writeEvent(ctx, backend, "item3", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv3, err = writeEvent(ctx, backend, "item3", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv3, rv2) }) t.Run("Update item2", func(t *testing.T) { - rv4, err = writeEvent(ctx, backend, "item2", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rv4, err = writeEvent(ctx, backend, "item2", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv4, rv3) }) t.Run("Delete item1", func(t *testing.T) { - rv5, err = writeEvent(ctx, backend, "item1", resource.WatchEvent_DELETED, WithNamespace(ns)) + rv5, err = writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_DELETED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv5, rv4) }) t.Run("Read latest item 2", func(t *testing.T) { - resp := backend.ReadResource(ctx, &resource.ReadRequest{ - Key: &resource.ResourceKey{ + resp := backend.ReadResource(ctx, &resourcepb.ReadRequest{ + Key: &resourcepb.ResourceKey{ Name: "item2", Namespace: ns, Group: "group", @@ -149,8 +150,8 @@ func runTestIntegrationBackendHappyPath(t *testing.T, backend resource.StorageBa }) t.Run("Read early version of item2", func(t *testing.T) { - resp := backend.ReadResource(ctx, &resource.ReadRequest{ - Key: &resource.ResourceKey{ + resp := backend.ReadResource(ctx, &resourcepb.ReadRequest{ + Key: &resourcepb.ResourceKey{ Name: "item2", Namespace: ns, Group: "group", @@ -164,9 +165,9 @@ func runTestIntegrationBackendHappyPath(t *testing.T, backend resource.StorageBa }) t.Run("List latest", func(t *testing.T) { - resp, err := server.List(ctx, &resource.ListRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + resp, err := server.List(ctx, &resourcepb.ListRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns, Group: "group", Resource: "resource", @@ -185,29 +186,29 @@ func runTestIntegrationBackendHappyPath(t *testing.T, backend resource.StorageBa event := <-stream require.Equal(t, "item1", event.Key.Name) require.Equal(t, rv1, event.ResourceVersion) - require.Equal(t, resource.WatchEvent_ADDED, event.Type) + require.Equal(t, resourcepb.WatchEvent_ADDED, event.Type) require.Equal(t, "folderuid", event.Folder) event = <-stream require.Equal(t, "item2", event.Key.Name) require.Equal(t, rv2, event.ResourceVersion) - require.Equal(t, resource.WatchEvent_ADDED, event.Type) + require.Equal(t, resourcepb.WatchEvent_ADDED, event.Type) require.Equal(t, "folderuid", event.Folder) event = <-stream require.Equal(t, "item3", event.Key.Name) require.Equal(t, rv3, event.ResourceVersion) - require.Equal(t, resource.WatchEvent_ADDED, event.Type) + require.Equal(t, resourcepb.WatchEvent_ADDED, event.Type) event = <-stream require.Equal(t, "item2", event.Key.Name) require.Equal(t, rv4, event.ResourceVersion) - require.Equal(t, resource.WatchEvent_MODIFIED, event.Type) + require.Equal(t, resourcepb.WatchEvent_MODIFIED, event.Type) event = <-stream require.Equal(t, "item1", event.Key.Name) require.Equal(t, rv5, event.ResourceVersion) - require.Equal(t, resource.WatchEvent_DELETED, event.Type) + require.Equal(t, resourcepb.WatchEvent_DELETED, event.Type) }) } @@ -224,31 +225,31 @@ func runTestIntegrationBackendGetResourceStats(t *testing.T, backend resource.St return strings.Compare(a.Resource, b.Resource) } // Create resources across different namespaces/groups - _, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_ADDED, + _, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1"), WithGroup("group"), WithResource("resource1")) require.NoError(t, err) - _, err = writeEvent(ctx, backend, "item2", resource.WatchEvent_ADDED, + _, err = writeEvent(ctx, backend, "item2", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1"), WithGroup("group"), WithResource("resource1")) require.NoError(t, err) - _, err = writeEvent(ctx, backend, "item3", resource.WatchEvent_ADDED, + _, err = writeEvent(ctx, backend, "item3", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1"), WithGroup("group"), WithResource("resource2")) require.NoError(t, err) - _, err = writeEvent(ctx, backend, "item4", resource.WatchEvent_ADDED, + _, err = writeEvent(ctx, backend, "item4", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns2"), WithGroup("group"), WithResource("resource1")) require.NoError(t, err) - _, err = writeEvent(ctx, backend, "item5", resource.WatchEvent_ADDED, + _, err = writeEvent(ctx, backend, "item5", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns2"), WithGroup("group"), WithResource("resource1")) @@ -311,7 +312,7 @@ func runTestIntegrationBackendWatchWriteEvents(t *testing.T, backend resource.St ctx := testutil.NewTestContext(t, time.Now().Add(5*time.Second)) // Create a few resources before initing the watch - _, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1")) + _, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1")) require.NoError(t, err) // Start the watch @@ -319,7 +320,7 @@ func runTestIntegrationBackendWatchWriteEvents(t *testing.T, backend resource.St require.NoError(t, err) // Create one more event - _, err = writeEvent(ctx, backend, "item2", resource.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1")) + _, err = writeEvent(ctx, backend, "item2", resourcepb.WatchEvent_ADDED, WithNamespace(nsPrefix+"-ns1")) require.NoError(t, err) require.Equal(t, "item2", (<-stream).Key.Name) @@ -335,35 +336,35 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend server := newServer(t, backend) ns := nsPrefix + "-ns1" // Create a few resources before starting the watch - rv1, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv1, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv1, int64(0)) - rv2, err := writeEvent(ctx, backend, "item2", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv2, err := writeEvent(ctx, backend, "item2", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv2, rv1) - rv3, err := writeEvent(ctx, backend, "item3", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv3, err := writeEvent(ctx, backend, "item3", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv3, rv2) - rv4, err := writeEvent(ctx, backend, "item4", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv4, err := writeEvent(ctx, backend, "item4", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv4, rv3) - rv5, err := writeEvent(ctx, backend, "item5", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv5, err := writeEvent(ctx, backend, "item5", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv5, rv4) - rv6, err := writeEvent(ctx, backend, "item2", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rv6, err := writeEvent(ctx, backend, "item2", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv6, rv5) - rv7, err := writeEvent(ctx, backend, "item3", resource.WatchEvent_DELETED, WithNamespace(ns)) + rv7, err := writeEvent(ctx, backend, "item3", resourcepb.WatchEvent_DELETED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv7, rv6) - rv8, err := writeEvent(ctx, backend, "item6", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv8, err := writeEvent(ctx, backend, "item6", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv8, rv7) t.Run("fetch all latest", func(t *testing.T) { - res, err := server.List(ctx, &resource.ListRequest{ - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + res, err := server.List(ctx, &resourcepb.ListRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "group", Resource: "resource", }, @@ -383,10 +384,10 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend }) t.Run("list latest first page ", func(t *testing.T) { - res, err := server.List(ctx, &resource.ListRequest{ + res, err := server.List(ctx, &resourcepb.ListRequest{ Limit: 3, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "group", Resource: "resource", }, @@ -404,10 +405,10 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend }) t.Run("list at revision", func(t *testing.T) { - res, err := server.List(ctx, &resource.ListRequest{ + res, err := server.List(ctx, &resourcepb.ListRequest{ ResourceVersion: rv4, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "group", Resource: "resource", }, @@ -424,11 +425,11 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend }) t.Run("fetch first page at revision with limit", func(t *testing.T) { - res, err := server.List(ctx, &resource.ListRequest{ + res, err := server.List(ctx, &resourcepb.ListRequest{ Limit: 3, ResourceVersion: rv7, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "group", Resource: "resource", }, @@ -454,11 +455,11 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend StartOffset: 2, SortAscending: false, } - res, err := server.List(ctx, &resource.ListRequest{ + res, err := server.List(ctx, &resourcepb.ListRequest{ NextPageToken: continueToken.String(), Limit: 2, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Group: "group", Resource: "resource", }, @@ -482,28 +483,28 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) server := newServer(t, backend) ns := nsPrefix + "-ns1" - rv1, _ := writeEvent(ctx, backend, "item1", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv1, _ := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.Greater(t, rv1, int64(0)) // add 5 events for item1 - should be saved to history - rvHistory1, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rvHistory1, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvHistory1, rv1) - rvHistory2, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rvHistory2, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvHistory2, rvHistory1) - rvHistory3, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rvHistory3, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvHistory3, rvHistory2) - rvHistory4, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rvHistory4, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvHistory4, rvHistory3) - rvHistory5, err := writeEvent(ctx, backend, "item1", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rvHistory5, err := writeEvent(ctx, backend, "item1", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvHistory5, rvHistory4) t.Run("fetch history with different version matching", func(t *testing.T) { - baseKey := &resource.ResourceKey{ + baseKey := &resourcepb.ResourceKey{ Namespace: ns, Group: "group", Resource: "resource", @@ -512,7 +513,7 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage tests := []struct { name string - request *resource.ListRequest + request *resourcepb.ListRequest expectedVersions []int64 expectedValues []string minExpectedHeadRV int64 @@ -521,12 +522,12 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage }{ { name: "NotOlderThan with rv1 (ASC order)", - request: &resource.ListRequest{ + request: &resourcepb.ListRequest{ Limit: 3, - Source: resource.ListRequest_HISTORY, + Source: resourcepb.ListRequest_HISTORY, ResourceVersion: rv1, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Options: &resource.ListOptions{ + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Options: &resourcepb.ListOptions{ Key: baseKey, }, }, @@ -538,12 +539,12 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage }, { name: "NotOlderThan with rv=0 (ASC order)", - request: &resource.ListRequest{ + request: &resourcepb.ListRequest{ Limit: 3, - Source: resource.ListRequest_HISTORY, + Source: resourcepb.ListRequest_HISTORY, ResourceVersion: 0, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Options: &resource.ListOptions{ + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Options: &resourcepb.ListOptions{ Key: baseKey, }, }, @@ -555,10 +556,10 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage }, { name: "ResourceVersionMatch_Unset (DESC order)", - request: &resource.ListRequest{ + request: &resourcepb.ListRequest{ Limit: 3, - Source: resource.ListRequest_HISTORY, - Options: &resource.ListOptions{ + Source: resourcepb.ListRequest_HISTORY, + Options: &resourcepb.ListOptions{ Key: baseKey, }, }, @@ -597,12 +598,12 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage // Test pagination for NotOlderThan (second page) t.Run("second page with NotOlderThan", func(t *testing.T) { // Get first page - firstRequest := &resource.ListRequest{ + firstRequest := &resourcepb.ListRequest{ Limit: 3, - Source: resource.ListRequest_HISTORY, + Source: resourcepb.ListRequest_HISTORY, ResourceVersion: rv1, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Options: &resource.ListOptions{Key: baseKey}, + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Options: &resourcepb.ListOptions{Key: baseKey}, } firstPageRes, err := server.List(ctx, firstRequest) require.NoError(t, err) @@ -612,13 +613,13 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage require.NoError(t, err) // Get second page - secondPageRes, err := server.List(ctx, &resource.ListRequest{ + secondPageRes, err := server.List(ctx, &resourcepb.ListRequest{ Limit: 3, - Source: resource.ListRequest_HISTORY, + Source: resourcepb.ListRequest_HISTORY, ResourceVersion: rv1, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, NextPageToken: continueToken.String(), - Options: &resource.ListOptions{Key: baseKey}, + Options: &resourcepb.ListOptions{Key: baseKey}, }) require.NoError(t, err) require.Nil(t, secondPageRes.Error) @@ -639,12 +640,12 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage StartOffset: 2, SortAscending: false, } - res, err := server.List(ctx, &resource.ListRequest{ + res, err := server.List(ctx, &resourcepb.ListRequest{ NextPageToken: continueToken.String(), Limit: 2, - Source: resource.ListRequest_HISTORY, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + Source: resourcepb.ListRequest_HISTORY, + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns, Group: "group", Resource: "resource", @@ -665,7 +666,7 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage t.Run("paginated history with NotOlderThan returns items in ascending order", func(t *testing.T) { // Create 10 versions of a resource to test pagination ns2 := nsPrefix + "-ns2" - resourceKey := &resource.ResourceKey{ + resourceKey := &resourcepb.ResourceKey{ Namespace: ns2, Group: "group", Resource: "resource", @@ -675,13 +676,13 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage var resourceVersions []int64 // First create the initial resource - initialRV, err := writeEvent(ctx, backend, "paged-item", resource.WatchEvent_ADDED, WithNamespace(ns2)) + initialRV, err := writeEvent(ctx, backend, "paged-item", resourcepb.WatchEvent_ADDED, WithNamespace(ns2)) require.NoError(t, err) resourceVersions = append(resourceVersions, initialRV) // Create 9 more versions with modifications for i := 0; i < 9; i++ { - rv, err := writeEvent(ctx, backend, "paged-item", resource.WatchEvent_MODIFIED, WithNamespace(ns2)) + rv, err := writeEvent(ctx, backend, "paged-item", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns2)) require.NoError(t, err) resourceVersions = append(resourceVersions, rv) } @@ -701,16 +702,16 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage {pageNumber: 4, pageSize: 1, startToken: ""}, // Will be set in the test - last page with remaining item } - var allItems []*resource.ResourceWrapper + var allItems []*resourcepb.ResourceWrapper // Request first page with NotOlderThan and ResourceVersion=0 (should start from oldest) for i, page := range pages { - req := &resource.ListRequest{ + req := &resourcepb.ListRequest{ Limit: int64(page.pageSize), - Source: resource.ListRequest_HISTORY, + Source: resourcepb.ListRequest_HISTORY, ResourceVersion: 0, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Options: &resource.ListOptions{ + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Options: &resourcepb.ListOptions{ Key: resourceKey, }, } @@ -781,17 +782,17 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage t.Run("fetch history with deleted item", func(t *testing.T) { // Create a resource and delete it - rv, err := writeEvent(ctx, backend, "deleted-item", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv, err := writeEvent(ctx, backend, "deleted-item", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) - rvDeleted, err := writeEvent(ctx, backend, "deleted-item", resource.WatchEvent_DELETED, WithNamespace(ns)) + rvDeleted, err := writeEvent(ctx, backend, "deleted-item", resourcepb.WatchEvent_DELETED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvDeleted, rv) // Fetch history for the deleted item - res, err := server.List(ctx, &resource.ListRequest{ - Source: resource.ListRequest_HISTORY, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + res, err := server.List(ctx, &resourcepb.ListRequest{ + Source: resourcepb.ListRequest_HISTORY, + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns, Group: "group", Resource: "resource", @@ -806,25 +807,25 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage t.Run("fetch history with recreated item", func(t *testing.T) { // Create a resource and delete it - rv, err := writeEvent(ctx, backend, "deleted-item", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv, err := writeEvent(ctx, backend, "deleted-item", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) - rvDeleted, err := writeEvent(ctx, backend, "deleted-item", resource.WatchEvent_DELETED, WithNamespace(ns)) + rvDeleted, err := writeEvent(ctx, backend, "deleted-item", resourcepb.WatchEvent_DELETED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rvDeleted, rv) // Create a few more versions after deletion - rv1, err := writeEvent(ctx, backend, "deleted-item", resource.WatchEvent_ADDED, WithNamespace(ns)) + rv1, err := writeEvent(ctx, backend, "deleted-item", resourcepb.WatchEvent_ADDED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv1, rvDeleted) - rv2, err := writeEvent(ctx, backend, "deleted-item", resource.WatchEvent_MODIFIED, WithNamespace(ns)) + rv2, err := writeEvent(ctx, backend, "deleted-item", resourcepb.WatchEvent_MODIFIED, WithNamespace(ns)) require.NoError(t, err) require.Greater(t, rv2, rv1) // Fetch history for the deleted item - res, err := server.List(ctx, &resource.ListRequest{ - Source: resource.ListRequest_HISTORY, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + res, err := server.List(ctx, &resourcepb.ListRequest{ + Source: resourcepb.ListRequest_HISTORY, + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns, Group: "group", Resource: "resource", @@ -854,26 +855,26 @@ func runTestIntegrationBackendListHistoryErrorReporting(t *testing.T, backend re ) start := time.Now() - origRv, _ := writeEvent(ctx, backend, name, resource.WatchEvent_ADDED, WithNamespace(ns), WithGroup(group), WithResource(resourceName)) + origRv, _ := writeEvent(ctx, backend, name, resourcepb.WatchEvent_ADDED, WithNamespace(ns), WithGroup(group), WithResource(resourceName)) require.Greater(t, origRv, int64(0)) const events = 500 prevRv := origRv for i := 0; i < events; i++ { - rv, err := writeEvent(ctx, backend, name, resource.WatchEvent_MODIFIED, WithNamespace(ns), WithGroup(group), WithResource(resourceName)) + rv, err := writeEvent(ctx, backend, name, resourcepb.WatchEvent_MODIFIED, WithNamespace(ns), WithGroup(group), WithResource(resourceName)) require.NoError(t, err) require.Greater(t, rv, prevRv) prevRv = rv } t.Log("added events in ", time.Since(start)) - req := &resource.ListRequest{ + req := &resourcepb.ListRequest{ Limit: 2 * events, - Source: resource.ListRequest_HISTORY, + Source: resourcepb.ListRequest_HISTORY, ResourceVersion: origRv, - VersionMatchV2: resource.ResourceVersionMatchV2_NotOlderThan, - Options: &resource.ListOptions{ - Key: &resource.ResourceKey{ + VersionMatchV2: resourcepb.ResourceVersionMatchV2_NotOlderThan, + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ Namespace: ns, Group: group, Resource: resourceName, @@ -903,16 +904,15 @@ func runTestIntegrationBlobSupport(t *testing.T, backend resource.StorageBackend ns := nsPrefix + "-ns1" t.Run("put and fetch blob", func(t *testing.T) { - key := &resource.ResourceKey{ + key := &resourcepb.ResourceKey{ Namespace: ns, Group: "g", Resource: "r", Name: "n", } - - b1, err := server.PutBlob(ctx, &resource.PutBlobRequest{ + b1, err := server.PutBlob(ctx, &resourcepb.PutBlobRequest{ Resource: key, - Method: resource.PutBlobRequest_GRPC, + Method: resourcepb.PutBlobRequest_GRPC, ContentType: "plain/text", Value: []byte("hello 11111"), }) @@ -920,9 +920,9 @@ func runTestIntegrationBlobSupport(t *testing.T, backend resource.StorageBackend require.Nil(t, b1.Error) require.Equal(t, "c894ae57bd227b8f8c63f38a2ddf458b", b1.Hash) - b2, err := server.PutBlob(ctx, &resource.PutBlobRequest{ + b2, err := server.PutBlob(ctx, &resourcepb.PutBlobRequest{ Resource: key, - Method: resource.PutBlobRequest_GRPC, + Method: resourcepb.PutBlobRequest_GRPC, ContentType: "plain/text", Value: []byte("hello 22222"), // the most recent }) @@ -950,19 +950,19 @@ func runTestIntegrationBlobSupport(t *testing.T, backend resource.StorageBackend obj.SetKind("Test") val, err := obj.MarshalJSON() require.NoError(t, err) - out, err := server.Create(ctx, &resource.CreateRequest{Key: key, Value: val}) + out, err := server.Create(ctx, &resourcepb.CreateRequest{Key: key, Value: val}) require.NoError(t, err) require.Nil(t, out.Error) require.True(t, out.ResourceVersion > 0) // The server (not store!) will lookup the saved annotation and return the correct payload - res, err := server.GetBlob(ctx, &resource.GetBlobRequest{Resource: key}) + res, err := server.GetBlob(ctx, &resourcepb.GetBlobRequest{Resource: key}) require.NoError(t, err) require.Nil(t, out.Error) require.Contains(t, string(res.Value), "hello 22222") // But we can still get an older version with an explicit UID - res, err = server.GetBlob(ctx, &resource.GetBlobRequest{Resource: key, Uid: b1.Uid}) + res, err = server.GetBlob(ctx, &resourcepb.GetBlobRequest{Resource: key, Uid: b1.Uid}) require.NoError(t, err) require.Nil(t, out.Error) require.Contains(t, string(res.Value), "hello 11111") @@ -981,8 +981,8 @@ func runTestIntegrationBackendCreateNewResource(t *testing.T, backend resource.S ns := nsPrefix + "-create-resource" ctx = request.WithNamespace(ctx, ns) - request := &resource.CreateRequest{ - Key: &resource.ResourceKey{ + request := &resourcepb.CreateRequest{ + Key: &resourcepb.ResourceKey{ Namespace: "default", Group: "test.grafana", Resource: "Test", @@ -1064,7 +1064,7 @@ type WriteEventOptions struct { Value []byte } -func writeEvent(ctx context.Context, store resource.StorageBackend, name string, action resource.WatchEvent_Type, opts ...WriteEventOption) (int64, error) { +func writeEvent(ctx context.Context, store resource.StorageBackend, name string, action resourcepb.WatchEvent_Type, opts ...WriteEventOption) (int64, error) { // Default options options := WriteEventOptions{ Namespace: "namespace", @@ -1087,7 +1087,7 @@ func writeEvent(ctx context.Context, store resource.StorageBackend, name string, "namespace": options.Namespace, }, "spec": map[string]any{ - "value": name + " " + resource.WatchEvent_Type_name[int32(action)], + "value": name + " " + resourcepb.WatchEvent_Type_name[int32(action)], }, }, } @@ -1106,7 +1106,7 @@ func writeEvent(ctx context.Context, store resource.StorageBackend, name string, return store.WriteEvent(ctx, resource.WriteEvent{ Type: action, Value: options.Value, - Key: &resource.ResourceKey{ + Key: &resourcepb.ResourceKey{ Namespace: options.Namespace, Group: options.Group, Resource: options.Resource, diff --git a/pkg/tests/apis/helper.go b/pkg/tests/apis/helper.go index 62f1877586c..9b73ff80407 100644 --- a/pkg/tests/apis/helper.go +++ b/pkg/tests/apis/helper.go @@ -48,7 +48,7 @@ import ( "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user/userimpl" - "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -121,9 +121,9 @@ func NewK8sTestHelper(t *testing.T, opts testinfra.GrafanaOpts) *K8sTestHelper { // ensure unified storage is alive and running ctx := identity.WithRequester(context.Background(), c.Org1.Admin.Identity) - rsp, err := c.env.ResourceClient.IsHealthy(ctx, &resource.HealthCheckRequest{}) + rsp, err := c.env.ResourceClient.IsHealthy(ctx, &resourcepb.HealthCheckRequest{}) require.NoError(t, err, "unable to read resource client health check") - require.Equal(t, resource.HealthCheckResponse_SERVING, rsp.Status) + require.Equal(t, resourcepb.HealthCheckResponse_SERVING, rsp.Status) return c }