mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
wire up unified search from the ui; add basic search support (#94358)
* wire up search from the ui; add basic search support
This commit is contained in:
parent
8cade5c550
commit
c2fb2dcfbe
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -298,6 +298,7 @@
|
|||||||
/pkg/modules/ @grafana/grafana-app-platform-squad
|
/pkg/modules/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/services/grpcserver/ @grafana/grafana-search-and-storage
|
/pkg/services/grpcserver/ @grafana/grafana-search-and-storage
|
||||||
/pkg/generated @grafana/grafana-app-platform-squad
|
/pkg/generated @grafana/grafana-app-platform-squad
|
||||||
|
/pkg/services/unifiedSearch/ @grafana/grafana-search-and-storage
|
||||||
|
|
||||||
# Alerting
|
# Alerting
|
||||||
/pkg/services/ngalert/ @grafana/alerting-backend
|
/pkg/services/ngalert/ @grafana/alerting-backend
|
||||||
|
@ -306,6 +306,10 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
apiRoute.Group("/search-v2", hs.SearchV2HTTPService.RegisterHTTPRoutes)
|
apiRoute.Group("/search-v2", hs.SearchV2HTTPService.RegisterHTTPRoutes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hs.Features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageSearch) {
|
||||||
|
apiRoute.Group("/unified-search", hs.UnifiedSearchHTTPService.RegisterHTTPRoutes)
|
||||||
|
}
|
||||||
|
|
||||||
// current org
|
// current org
|
||||||
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
|
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
|
||||||
userIDScope := ac.Scope("users", "id", ac.Parameter(":userId"))
|
userIDScope := ac.Scope("users", "id", ac.Parameter(":userId"))
|
||||||
|
@ -104,6 +104,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/tag"
|
"github.com/grafana/grafana/pkg/services/tag"
|
||||||
"github.com/grafana/grafana/pkg/services/team"
|
"github.com/grafana/grafana/pkg/services/team"
|
||||||
tempUser "github.com/grafana/grafana/pkg/services/temp_user"
|
tempUser "github.com/grafana/grafana/pkg/services/temp_user"
|
||||||
|
"github.com/grafana/grafana/pkg/services/unifiedSearch"
|
||||||
"github.com/grafana/grafana/pkg/services/updatechecker"
|
"github.com/grafana/grafana/pkg/services/updatechecker"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/services/validations"
|
"github.com/grafana/grafana/pkg/services/validations"
|
||||||
@ -156,6 +157,7 @@ type HTTPServer struct {
|
|||||||
LivePushGateway *pushhttp.Gateway
|
LivePushGateway *pushhttp.Gateway
|
||||||
StorageService store.StorageService
|
StorageService store.StorageService
|
||||||
SearchV2HTTPService searchV2.SearchHTTPService
|
SearchV2HTTPService searchV2.SearchHTTPService
|
||||||
|
UnifiedSearchHTTPService unifiedSearch.SearchHTTPService
|
||||||
ContextHandler *contexthandler.ContextHandler
|
ContextHandler *contexthandler.ContextHandler
|
||||||
LoggerMiddleware loggermw.Logger
|
LoggerMiddleware loggermw.Logger
|
||||||
SQLStore db.DB
|
SQLStore db.DB
|
||||||
@ -266,7 +268,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
|||||||
publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service,
|
publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service,
|
||||||
loginAttemptService loginAttempt.Service, orgService org.Service, teamService team.Service,
|
loginAttemptService loginAttempt.Service, orgService org.Service, teamService team.Service,
|
||||||
accesscontrolService accesscontrol.Service, navTreeService navtree.Service,
|
accesscontrolService accesscontrol.Service, navTreeService navtree.Service,
|
||||||
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService, oauthTokenService oauthtoken.OAuthTokenService,
|
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService, unifiedSearchHTTPService unifiedSearch.SearchHTTPService, oauthTokenService oauthtoken.OAuthTokenService,
|
||||||
statsService stats.Service, authnService authn.Service, pluginsCDNService *pluginscdn.Service, promGatherer prometheus.Gatherer,
|
statsService stats.Service, authnService authn.Service, pluginsCDNService *pluginscdn.Service, promGatherer prometheus.Gatherer,
|
||||||
starApi *starApi.API, promRegister prometheus.Registerer, clientConfigProvider grafanaapiserver.DirectRestConfigProvider, anonService anonymous.Service,
|
starApi *starApi.API, promRegister prometheus.Registerer, clientConfigProvider grafanaapiserver.DirectRestConfigProvider, anonService anonymous.Service,
|
||||||
userVerifier user.Verifier,
|
userVerifier user.Verifier,
|
||||||
@ -308,6 +310,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
|||||||
AccessControl: accessControl,
|
AccessControl: accessControl,
|
||||||
DataProxy: dataSourceProxy,
|
DataProxy: dataSourceProxy,
|
||||||
SearchV2HTTPService: searchv2HTTPService,
|
SearchV2HTTPService: searchv2HTTPService,
|
||||||
|
UnifiedSearchHTTPService: unifiedSearchHTTPService,
|
||||||
SearchService: searchService,
|
SearchService: searchService,
|
||||||
Live: live,
|
Live: live,
|
||||||
LivePushGateway: livePushGateway,
|
LivePushGateway: livePushGateway,
|
||||||
|
@ -149,6 +149,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
||||||
tempuser "github.com/grafana/grafana/pkg/services/temp_user"
|
tempuser "github.com/grafana/grafana/pkg/services/temp_user"
|
||||||
"github.com/grafana/grafana/pkg/services/temp_user/tempuserimpl"
|
"github.com/grafana/grafana/pkg/services/temp_user/tempuserimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/services/unifiedSearch"
|
||||||
"github.com/grafana/grafana/pkg/services/updatechecker"
|
"github.com/grafana/grafana/pkg/services/updatechecker"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
||||||
@ -229,6 +230,8 @@ var wireBasicSet = wire.NewSet(
|
|||||||
search.ProvideService,
|
search.ProvideService,
|
||||||
searchV2.ProvideService,
|
searchV2.ProvideService,
|
||||||
searchV2.ProvideSearchHTTPService,
|
searchV2.ProvideSearchHTTPService,
|
||||||
|
unifiedSearch.ProvideService,
|
||||||
|
unifiedSearch.ProvideSearchHTTPService,
|
||||||
store.ProvideService,
|
store.ProvideService,
|
||||||
store.ProvideSystemUsersService,
|
store.ProvideSystemUsersService,
|
||||||
live.ProvideService,
|
live.ProvideService,
|
||||||
|
@ -91,7 +91,7 @@ func TestIntegrationPluginManager(t *testing.T) {
|
|||||||
ms := mssql.ProvideService(cfg)
|
ms := mssql.ProvideService(cfg)
|
||||||
db := db.InitTestDB(t, sqlstore.InitTestDBOpt{Cfg: cfg})
|
db := db.InitTestDB(t, sqlstore.InitTestDBOpt{Cfg: cfg})
|
||||||
sv2 := searchV2.ProvideService(cfg, db, nil, nil, tracer, features, nil, nil, nil)
|
sv2 := searchV2.ProvideService(cfg, db, nil, nil, tracer, features, nil, nil, nil)
|
||||||
graf := grafanads.ProvideService(sv2, nil)
|
graf := grafanads.ProvideService(sv2, nil, nil, features)
|
||||||
pyroscope := pyroscope.ProvideService(hcp)
|
pyroscope := pyroscope.ProvideService(hcp)
|
||||||
parca := parca.ProvideService(hcp)
|
parca := parca.ProvideService(hcp)
|
||||||
coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, pyroscope, parca)
|
coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, pyroscope, parca)
|
||||||
|
73
pkg/services/unifiedSearch/http.go
Normal file
73
pkg/services/unifiedSearch/http.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package unifiedSearch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SearchHTTPService interface {
|
||||||
|
RegisterHTTPRoutes(storageRoute routing.RouteRegister)
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchHTTPService struct {
|
||||||
|
search SearchService
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideSearchHTTPService(search SearchService) SearchHTTPService {
|
||||||
|
return &searchHTTPService{search: search}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *searchHTTPService) RegisterHTTPRoutes(storageRoute routing.RouteRegister) {
|
||||||
|
storageRoute.Post("/", middleware.ReqSignedIn, routing.Wrap(s.doQuery))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *searchHTTPService) doQuery(c *contextmodel.ReqContext) response.Response {
|
||||||
|
searchReadinessCheckResp := s.search.IsReady(c.Req.Context(), c.SignedInUser.GetOrgID())
|
||||||
|
if !searchReadinessCheckResp.IsReady {
|
||||||
|
return response.JSON(http.StatusOK, &backend.DataResponse{
|
||||||
|
Frames: []*data.Frame{{
|
||||||
|
Name: "Loading",
|
||||||
|
}},
|
||||||
|
Error: nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(c.Req.Body)
|
||||||
|
if err != nil {
|
||||||
|
return response.Error(http.StatusInternalServerError, "error reading bytes", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := &Query{}
|
||||||
|
err = json.Unmarshal(body, query)
|
||||||
|
if err != nil {
|
||||||
|
return response.Error(http.StatusBadRequest, "error parsing body", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := s.search.doQuery(c.Req.Context(), c.SignedInUser, c.SignedInUser.GetOrgID(), *query)
|
||||||
|
|
||||||
|
if resp.Error != nil {
|
||||||
|
return response.Error(http.StatusInternalServerError, "error handling search request", resp.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Frames) == 0 {
|
||||||
|
msg := "invalid search response"
|
||||||
|
return response.Error(http.StatusInternalServerError, msg, errors.New(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := resp.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return response.Error(http.StatusInternalServerError, "error marshalling response", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(http.StatusOK, bytes)
|
||||||
|
}
|
176
pkg/services/unifiedSearch/service.go
Normal file
176
pkg/services/unifiedSearch/service.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package unifiedSearch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
|
"github.com/grafana/grafana/pkg/registry"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
|
"github.com/grafana/grafana/pkg/services/store"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StandardSearchService struct {
|
||||||
|
registry.BackgroundService
|
||||||
|
cfg *setting.Cfg
|
||||||
|
sql db.DB
|
||||||
|
ac accesscontrol.Service
|
||||||
|
orgService org.Service
|
||||||
|
userService user.Service
|
||||||
|
logger log.Logger
|
||||||
|
reIndexCh chan struct{}
|
||||||
|
features featuremgmt.FeatureToggles
|
||||||
|
resourceClient resource.ResourceClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) IsReady(ctx context.Context, orgId int64) IsSearchReadyResponse {
|
||||||
|
return IsSearchReadyResponse{IsReady: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideService(cfg *setting.Cfg, sql db.DB, entityEventStore store.EntityEventsService,
|
||||||
|
ac accesscontrol.Service, tracer tracing.Tracer, features featuremgmt.FeatureToggles, orgService org.Service,
|
||||||
|
userService user.Service, folderStore folder.Store, resourceClient resource.ResourceClient) SearchService {
|
||||||
|
logger := log.New("searchV3")
|
||||||
|
s := &StandardSearchService{
|
||||||
|
cfg: cfg,
|
||||||
|
sql: sql,
|
||||||
|
ac: ac,
|
||||||
|
logger: logger,
|
||||||
|
reIndexCh: make(chan struct{}, 1),
|
||||||
|
orgService: orgService,
|
||||||
|
userService: userService,
|
||||||
|
features: features,
|
||||||
|
resourceClient: resourceClient,
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) IsDisabled() bool {
|
||||||
|
return !s.features.IsEnabledGlobally(featuremgmt.FlagPanelTitleSearch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) Run(ctx context.Context) error {
|
||||||
|
// TODO: implement this? ( copied from pkg/services/searchV2/service.go )
|
||||||
|
// orgQuery := &org.SearchOrgsQuery{}
|
||||||
|
// result, err := s.orgService.Search(ctx, orgQuery)
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("can't get org list: %w", err)
|
||||||
|
// }
|
||||||
|
// orgIDs := make([]int64, 0, len(result))
|
||||||
|
// for _, org := range result {
|
||||||
|
// orgIDs = append(orgIDs, org.ID)
|
||||||
|
// }
|
||||||
|
// TODO: do we need to initialize the bleve index again ( should be initialized on startup )?
|
||||||
|
// return s.dashboardIndex.run(ctx, orgIDs, s.reIndexCh)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) TriggerReIndex() {
|
||||||
|
select {
|
||||||
|
case s.reIndexCh <- struct{}{}:
|
||||||
|
default:
|
||||||
|
// channel is full => re-index will happen soon anyway.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) getUser(ctx context.Context, backendUser *backend.User, orgId int64) (*user.SignedInUser, error) {
|
||||||
|
// TODO: get user & user's permissions from the request context
|
||||||
|
var usr *user.SignedInUser
|
||||||
|
if s.cfg.AnonymousEnabled && backendUser.Email == "" && backendUser.Login == "" {
|
||||||
|
getOrg := org.GetOrgByNameQuery{Name: s.cfg.AnonymousOrgName}
|
||||||
|
orga, err := s.orgService.GetByName(ctx, &getOrg)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Anonymous access organization error.", "org_name", s.cfg.AnonymousOrgName, "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
usr = &user.SignedInUser{
|
||||||
|
OrgID: orga.ID,
|
||||||
|
OrgName: orga.Name,
|
||||||
|
OrgRole: org.RoleType(s.cfg.AnonymousOrgRole),
|
||||||
|
IsAnonymous: true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getSignedInUserQuery := &user.GetSignedInUserQuery{
|
||||||
|
Login: backendUser.Login,
|
||||||
|
Email: backendUser.Email,
|
||||||
|
OrgID: orgId,
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
usr, err = s.userService.GetSignedInUser(ctx, getSignedInUserQuery)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Error while retrieving user", "error", err, "email", backendUser.Email, "login", getSignedInUserQuery.Login)
|
||||||
|
return nil, errors.New("auth error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if usr == nil {
|
||||||
|
s.logger.Error("No user found", "email", backendUser.Email)
|
||||||
|
return nil, errors.New("auth error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if usr.Permissions == nil {
|
||||||
|
usr.Permissions = make(map[int64]map[string][]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := usr.Permissions[orgId]; ok {
|
||||||
|
// permissions as part of the `s.sql.GetSignedInUser` query - return early
|
||||||
|
return usr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ensure this is cached
|
||||||
|
permissions, err := s.ac.GetUserPermissions(ctx, usr,
|
||||||
|
accesscontrol.Options{ReloadCache: false})
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to retrieve user permissions", "error", err, "email", backendUser.Email)
|
||||||
|
return nil, errors.New("auth error")
|
||||||
|
}
|
||||||
|
|
||||||
|
usr.Permissions[orgId] = accesscontrol.GroupScopesByActionContext(ctx, permissions)
|
||||||
|
return usr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) DoQuery(ctx context.Context, user *backend.User, orgID int64, q Query) *backend.DataResponse {
|
||||||
|
signedInUser, err := s.getUser(ctx, user, orgID)
|
||||||
|
if err != nil {
|
||||||
|
return &backend.DataResponse{Error: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
query := s.doQuery(ctx, signedInUser, orgID, q)
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) doQuery(ctx context.Context, signedInUser *user.SignedInUser, orgID int64, q Query) *backend.DataResponse {
|
||||||
|
response := s.doSearchQuery(ctx, q, s.cfg.AppSubURL)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StandardSearchService) doSearchQuery(ctx context.Context, qry Query, _ string) *backend.DataResponse {
|
||||||
|
response := &backend.DataResponse{}
|
||||||
|
|
||||||
|
req := &resource.SearchRequest{Tenant: s.cfg.StackID, Query: qry.Query}
|
||||||
|
res, err := s.resourceClient.Search(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
response.Error = err
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement this correctly
|
||||||
|
frame := data.NewFrame("results", data.NewField("value", nil, []string{}))
|
||||||
|
frame.Meta = &data.FrameMeta{Notices: []data.Notice{{Text: "TODO"}}}
|
||||||
|
for _, r := range res.Items {
|
||||||
|
frame.AppendRow(string(r.Value))
|
||||||
|
}
|
||||||
|
response.Frames = append(response.Frames, frame)
|
||||||
|
return response
|
||||||
|
}
|
49
pkg/services/unifiedSearch/types.go
Normal file
49
pkg/services/unifiedSearch/types.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package unifiedSearch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/registry"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FacetField struct {
|
||||||
|
Field string `json:"field"`
|
||||||
|
Limit int `json:"limit,omitempty"` // explicit page size
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
Query string `json:"query"`
|
||||||
|
Location string `json:"location,omitempty"` // parent folder ID
|
||||||
|
Sort string `json:"sort,omitempty"` // field ASC/DESC
|
||||||
|
Datasource string `json:"ds_uid,omitempty"` // "datasource" collides with the JSON value at the same level :()
|
||||||
|
DatasourceType string `json:"ds_type,omitempty"`
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
Kind []string `json:"kind,omitempty"`
|
||||||
|
PanelType string `json:"panel_type,omitempty"`
|
||||||
|
UIDs []string `json:"uid,omitempty"`
|
||||||
|
Explain bool `json:"explain,omitempty"` // adds details on why document matched
|
||||||
|
WithAllowedActions bool `json:"withAllowedActions,omitempty"` // adds allowed actions per entity
|
||||||
|
Facet []FacetField `json:"facet,omitempty"`
|
||||||
|
SkipLocation bool `json:"skipLocation,omitempty"`
|
||||||
|
HasPreview string `json:"hasPreview,omitempty"` // the light|dark theme
|
||||||
|
Limit int `json:"limit,omitempty"` // explicit page size
|
||||||
|
From int `json:"from,omitempty"` // for paging
|
||||||
|
}
|
||||||
|
|
||||||
|
type IsSearchReadyResponse struct {
|
||||||
|
IsReady bool
|
||||||
|
Reason string // initial-indexing-ongoing, org-indexing-ongoing
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchService interface {
|
||||||
|
registry.CanBeDisabled
|
||||||
|
registry.BackgroundService
|
||||||
|
DoQuery(ctx context.Context, user *backend.User, orgId int64, query Query) *backend.DataResponse
|
||||||
|
doQuery(ctx context.Context, user *user.SignedInUser, orgId int64, query Query) *backend.DataResponse
|
||||||
|
IsReady(ctx context.Context, orgId int64) IsSearchReadyResponse
|
||||||
|
// RegisterDashboardIndexExtender(ext DashboardIndexExtender)
|
||||||
|
TriggerReIndex()
|
||||||
|
}
|
@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/blevesearch/bleve/v2"
|
"github.com/blevesearch/bleve/v2"
|
||||||
|
"github.com/blevesearch/bleve/v2/analysis/lang/en"
|
||||||
"github.com/blevesearch/bleve/v2/mapping"
|
"github.com/blevesearch/bleve/v2/mapping"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
@ -52,7 +53,13 @@ func (i *Index) Init(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = shard.batch.Index(res.Metadata.Uid, obj)
|
|
||||||
|
var jsonDoc interface{}
|
||||||
|
err = json.Unmarshal(obj.Value, &jsonDoc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = shard.batch.Index(res.Metadata.Uid, jsonDoc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -99,6 +106,31 @@ func (i *Index) Delete(ctx context.Context, uid string, key *ResourceKey) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Index) Search(ctx context.Context, tenant string, query string) ([]string, error) {
|
||||||
|
if tenant == "" {
|
||||||
|
tenant = "default"
|
||||||
|
}
|
||||||
|
shard, err := i.getShard(tenant)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req := bleve.NewSearchRequest(bleve.NewQueryStringQuery(query))
|
||||||
|
req.Fields = []string{"kind", "spec.title"}
|
||||||
|
|
||||||
|
res, err := shard.index.Search(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hits := res.Hits
|
||||||
|
results := []string{}
|
||||||
|
for _, hit := range hits {
|
||||||
|
val := fmt.Sprintf("%s:%s", hit.Fields["kind"], hit.Fields["spec.title"])
|
||||||
|
results = append(results, val)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
func tenant(res *Resource) string {
|
func tenant(res *Resource) string {
|
||||||
return res.Metadata.Namespace
|
return res.Metadata.Namespace
|
||||||
}
|
}
|
||||||
@ -142,20 +174,31 @@ func createIndexMappings() *mapping.IndexMappingImpl {
|
|||||||
metaMapping.AddFieldMappingsAt("name", nameFieldMapping)
|
metaMapping.AddFieldMappingsAt("name", nameFieldMapping)
|
||||||
metaMapping.AddFieldMappingsAt("creationTimestamp", creationTimestampFieldMapping)
|
metaMapping.AddFieldMappingsAt("creationTimestamp", creationTimestampFieldMapping)
|
||||||
metaMapping.Dynamic = false
|
metaMapping.Dynamic = false
|
||||||
|
metaMapping.Enabled = true
|
||||||
|
|
||||||
|
specMapping := bleve.NewDocumentMapping()
|
||||||
|
specMapping.AddFieldMappingsAt("title", nameFieldMapping)
|
||||||
|
specMapping.Dynamic = false
|
||||||
|
specMapping.Enabled = true
|
||||||
|
|
||||||
//Create a sub-document mapping for the metadata field
|
//Create a sub-document mapping for the metadata field
|
||||||
objectMapping := bleve.NewDocumentMapping()
|
objectMapping := bleve.NewDocumentMapping()
|
||||||
objectMapping.AddSubDocumentMapping("metadata", metaMapping)
|
objectMapping.AddSubDocumentMapping("metadata", metaMapping)
|
||||||
|
objectMapping.AddSubDocumentMapping("spec", specMapping)
|
||||||
|
objectMapping.Dynamic = false
|
||||||
|
objectMapping.Enabled = true
|
||||||
|
|
||||||
|
// a generic reusable mapping for english text
|
||||||
|
englishTextFieldMapping := bleve.NewTextFieldMapping()
|
||||||
|
englishTextFieldMapping.Analyzer = en.AnalyzerName
|
||||||
|
|
||||||
// Map top level fields - just kind for now
|
// Map top level fields - just kind for now
|
||||||
kindFieldMapping := bleve.NewTextFieldMapping()
|
objectMapping.AddFieldMappingsAt("kind", englishTextFieldMapping)
|
||||||
objectMapping.AddFieldMappingsAt("kind", kindFieldMapping)
|
|
||||||
objectMapping.Dynamic = false
|
objectMapping.Dynamic = false
|
||||||
|
|
||||||
// Create the index mapping
|
// Create the index mapping
|
||||||
indexMapping := bleve.NewIndexMapping()
|
indexMapping := bleve.NewIndexMapping()
|
||||||
indexMapping.DefaultMapping = objectMapping
|
indexMapping.DefaultMapping = objectMapping
|
||||||
indexMapping.DefaultMapping.Dynamic = false
|
|
||||||
|
|
||||||
return indexMapping
|
return indexMapping
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,14 @@ type IndexServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (is IndexServer) Search(ctx context.Context, req *SearchRequest) (*SearchResponse, error) {
|
func (is IndexServer) Search(ctx context.Context, req *SearchRequest) (*SearchResponse, error) {
|
||||||
|
results, err := is.index.Search(ctx, req.Tenant, req.Query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
res := &SearchResponse{}
|
res := &SearchResponse{}
|
||||||
|
for _, r := range results {
|
||||||
|
res.Items = append(res.Items, &ResourceWrapper{Value: []byte(r)})
|
||||||
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1620,6 +1620,7 @@ type SearchRequest struct {
|
|||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`
|
Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`
|
||||||
|
Tenant string `protobuf:"bytes,2,opt,name=tenant,proto3" json:"tenant,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SearchRequest) Reset() {
|
func (x *SearchRequest) Reset() {
|
||||||
@ -1661,6 +1662,13 @@ func (x *SearchRequest) GetQuery() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *SearchRequest) GetTenant() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Tenant
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type SearchResponse struct {
|
type SearchResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -2441,135 +2449,136 @@ var file_resource_proto_rawDesc = []byte{
|
|||||||
0x09, 0x0a, 0x05, 0x41, 0x44, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f,
|
0x09, 0x0a, 0x05, 0x41, 0x44, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f,
|
||||||
0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45,
|
0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45,
|
||||||
0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52,
|
0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52,
|
||||||
0x4b, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x22, 0x25,
|
0x4b, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x22, 0x3d,
|
||||||
0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||||
0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
||||||
0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x41, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52,
|
0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18,
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x22, 0x41, 0x0a,
|
||||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65,
|
0x2f, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19,
|
||||||
0x72, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x9a, 0x01, 0x0a, 0x0e, 0x48, 0x69, 0x73,
|
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e,
|
0x63, 0x65, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
|
||||||
0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01,
|
0x22, 0x9a, 0x01, 0x0a, 0x0e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f,
|
0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65,
|
||||||
0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01,
|
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65,
|
||||||
0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79,
|
0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69,
|
||||||
0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b,
|
0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15,
|
||||||
0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74,
|
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x65,
|
0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x68,
|
||||||
0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xbf, 0x01, 0x0a, 0x0f, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72,
|
0x6f, 0x77, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
|
||||||
0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x69, 0x74, 0x65,
|
0x52, 0x0b, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xbf, 0x01,
|
||||||
0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
0x0a, 0x0f, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61,
|
0x65, 0x12, 0x2c, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f,
|
0x32, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f,
|
||||||
0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12,
|
||||||
0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
|
0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b,
|
||||||
0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73,
|
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||||
0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72,
|
0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f,
|
0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
|
0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||||
0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x8e, 0x01, 0x0a, 0x0d, 0x4f, 0x72, 0x69, 0x67,
|
0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72,
|
||||||
0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78,
|
0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22,
|
||||||
0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
0x8e, 0x01, 0x0a, 0x0d, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65,
|
0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74,
|
||||||
0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
|
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74,
|
||||||
0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03,
|
0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d,
|
||||||
|
0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12,
|
||||||
|
0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 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, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67,
|
||||||
|
0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
||||||
|
0x22, 0xe5, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x72, 0x69,
|
||||||
|
0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 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,
|
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,
|
0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
||||||
0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x69, 0x7a,
|
||||||
0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x22, 0xe5, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x73,
|
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12,
|
0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||||
0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72,
|
0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65,
|
||||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72,
|
||||||
0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f,
|
0x69, 0x67, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x23, 0x0a,
|
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06,
|
||||||
0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x61,
|
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74,
|
||||||
0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01,
|
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xc4, 0x01, 0x0a, 0x0e, 0x4f, 0x72, 0x69,
|
||||||
0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
|
0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x69,
|
||||||
0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12,
|
0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73,
|
||||||
0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61,
|
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x72,
|
||||||
0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
|
0x69, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12,
|
||||||
0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b,
|
||||||
0x22, 0xc4, 0x01, 0x0a, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03,
|
0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||||
0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65,
|
0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f,
|
0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||||
0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f,
|
0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||||
0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72,
|
||||||
0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
|
0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22,
|
||||||
0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73,
|
0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65,
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||||
0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22,
|
||||||
0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f,
|
0xab, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
||||||
0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a,
|
0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65,
|
||||||
0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c,
|
0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x0d,
|
||||||
0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a,
|
||||||
0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45,
|
||||||
0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53,
|
||||||
0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53,
|
0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56,
|
||||||
0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
|
0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x2a, 0x33, 0x0a,
|
||||||
0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53,
|
0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e,
|
0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65,
|
||||||
0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12,
|
0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74,
|
||||||
0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02,
|
0x10, 0x01, 0x32, 0xed, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53,
|
||||||
0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e,
|
0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72,
|
||||||
0x4f, 0x57, 0x4e, 0x10, 0x03, 0x2a, 0x33, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a,
|
0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52,
|
||||||
0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, 0x12,
|
0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43,
|
||||||
0x09, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x01, 0x32, 0xed, 0x02, 0x0a, 0x0d, 0x52,
|
0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04,
|
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18,
|
||||||
0x52, 0x65, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
|
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||||
0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65,
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61,
|
||||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e,
|
0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65,
|
||||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52,
|
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12,
|
||||||
0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||||
0x12, 0x3b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73,
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
|
0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55,
|
0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73,
|
||||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a,
|
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73,
|
||||||
0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74,
|
||||||
0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65,
|
0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61,
|
||||||
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69,
|
0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73,
|
||||||
0x73, 0x74, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69,
|
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||||
0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f,
|
0x30, 0x01, 0x32, 0xc9, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x6e, 0x64, 0x65, 0x78, 0x12, 0x3b, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x17,
|
||||||
0x65, 0x12, 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73,
|
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
|
||||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61,
|
0x63, 0x65, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0xc9, 0x01, 0x0a, 0x0d, 0x52,
|
0x65, 0x12, 0x3e, 0x0a, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x2e, 0x72,
|
||||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3b, 0x0a, 0x06,
|
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52,
|
||||||
0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||||
0x65, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
0x65, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63,
|
0x65, 0x12, 0x3b, 0x0a, 0x06, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x17, 0x2e, 0x72, 0x65,
|
||||||
0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x48, 0x69, 0x73,
|
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71,
|
||||||
0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
|
0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
|
||||||
0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19,
|
0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x57,
|
||||||
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72,
|
0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a,
|
||||||
0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x4f, 0x72, 0x69,
|
0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x73,
|
||||||
0x67, 0x69, 0x6e, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4f,
|
0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63,
|
||||||
0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72,
|
0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65,
|
0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72,
|
||||||
0x68, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65,
|
0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||||
0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c,
|
0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -326,6 +326,7 @@ message WatchEvent {
|
|||||||
|
|
||||||
message SearchRequest {
|
message SearchRequest {
|
||||||
string query = 1;
|
string query = 1;
|
||||||
|
string tenant = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SearchResponse {
|
message SearchResponse {
|
||||||
|
@ -15,8 +15,10 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/searchV2"
|
"github.com/grafana/grafana/pkg/services/searchV2"
|
||||||
"github.com/grafana/grafana/pkg/services/store"
|
"github.com/grafana/grafana/pkg/services/store"
|
||||||
|
"github.com/grafana/grafana/pkg/services/unifiedSearch"
|
||||||
testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource"
|
testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,15 +53,17 @@ var (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideService(search searchV2.SearchService, store store.StorageService) *Service {
|
func ProvideService(search searchV2.SearchService, searchNext unifiedSearch.SearchService, store store.StorageService, features featuremgmt.FeatureToggles) *Service {
|
||||||
return newService(search, store)
|
return newService(search, searchNext, store, features)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newService(search searchV2.SearchService, store store.StorageService) *Service {
|
func newService(search searchV2.SearchService, searchNext unifiedSearch.SearchService, store store.StorageService, features featuremgmt.FeatureToggles) *Service {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
search: search,
|
search: search,
|
||||||
|
searchNext: searchNext,
|
||||||
store: store,
|
store: store,
|
||||||
log: log.New("grafanads"),
|
log: log.New("grafanads"),
|
||||||
|
features: features,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
@ -68,8 +72,10 @@ func newService(search searchV2.SearchService, store store.StorageService) *Serv
|
|||||||
// Service exists regardless of user settings
|
// Service exists regardless of user settings
|
||||||
type Service struct {
|
type Service struct {
|
||||||
search searchV2.SearchService
|
search searchV2.SearchService
|
||||||
|
searchNext unifiedSearch.SearchService
|
||||||
store store.StorageService
|
store store.StorageService
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
features featuremgmt.FeatureToggles
|
||||||
}
|
}
|
||||||
|
|
||||||
func DataSourceModel(orgId int64) *datasources.DataSource {
|
func DataSourceModel(orgId int64) *datasources.DataSource {
|
||||||
@ -95,7 +101,7 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
|||||||
response.Responses[q.RefID] = s.doListQuery(ctx, q)
|
response.Responses[q.RefID] = s.doListQuery(ctx, q)
|
||||||
case queryTypeRead:
|
case queryTypeRead:
|
||||||
response.Responses[q.RefID] = s.doReadQuery(ctx, q)
|
response.Responses[q.RefID] = s.doReadQuery(ctx, q)
|
||||||
case queryTypeSearch:
|
case queryTypeSearch, queryTypeSearchNext:
|
||||||
response.Responses[q.RefID] = s.doSearchQuery(ctx, req, q)
|
response.Responses[q.RefID] = s.doSearchQuery(ctx, req, q)
|
||||||
default:
|
default:
|
||||||
response.Responses[q.RefID] = backend.DataResponse{
|
response.Responses[q.RefID] = backend.DataResponse{
|
||||||
@ -177,6 +183,18 @@ func (s *Service) doRandomWalk(query backend.DataQuery) backend.DataResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) doSearchQuery(ctx context.Context, req *backend.QueryDataRequest, query backend.DataQuery) backend.DataResponse {
|
func (s *Service) doSearchQuery(ctx context.Context, req *backend.QueryDataRequest, query backend.DataQuery) backend.DataResponse {
|
||||||
|
m := requestModel{}
|
||||||
|
err := json.Unmarshal(query.JSON, &m)
|
||||||
|
if err != nil {
|
||||||
|
return backend.DataResponse{
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.features.IsEnabled(ctx, featuremgmt.FlagUnifiedStorageSearch) {
|
||||||
|
return *s.searchNext.DoQuery(ctx, req.PluginContext.User, req.PluginContext.OrgID, m.SearchNext)
|
||||||
|
}
|
||||||
|
|
||||||
searchReadinessCheckResp := s.search.IsReady(ctx, req.PluginContext.OrgID)
|
searchReadinessCheckResp := s.search.IsReady(ctx, req.PluginContext.OrgID)
|
||||||
if !searchReadinessCheckResp.IsReady {
|
if !searchReadinessCheckResp.IsReady {
|
||||||
dashboardSearchNotServedRequestsCounter.With(prometheus.Labels{
|
dashboardSearchNotServedRequestsCounter.With(prometheus.Labels{
|
||||||
@ -192,17 +210,11 @@ func (s *Service) doSearchQuery(ctx context.Context, req *backend.QueryDataReque
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m := requestModel{}
|
|
||||||
err := json.Unmarshal(query.JSON, &m)
|
|
||||||
if err != nil {
|
|
||||||
return backend.DataResponse{
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *s.search.DoDashboardQuery(ctx, req.PluginContext.User, req.PluginContext.OrgID, m.Search)
|
return *s.search.DoDashboardQuery(ctx, req.PluginContext.User, req.PluginContext.OrgID, m.Search)
|
||||||
}
|
}
|
||||||
|
|
||||||
type requestModel struct {
|
type requestModel struct {
|
||||||
QueryType string `json:"queryType"`
|
QueryType string `json:"queryType"`
|
||||||
Search searchV2.DashboardQuery `json:"search,omitempty"`
|
Search searchV2.DashboardQuery `json:"search,omitempty"`
|
||||||
|
SearchNext unifiedSearch.Query `json:"searchNext,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ const (
|
|||||||
// QueryTypeList will list the files in a folder
|
// QueryTypeList will list the files in a folder
|
||||||
queryTypeSearch = "search"
|
queryTypeSearch = "search"
|
||||||
|
|
||||||
|
// queryTypeSearchNext will perform a search query using the next generation search service
|
||||||
|
queryTypeSearchNext = "searchNext"
|
||||||
|
|
||||||
// QueryTypeList will list the files in a folder
|
// QueryTypeList will list the files in a folder
|
||||||
queryTypeList = "list"
|
queryTypeList = "list"
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { BlugeSearcher } from './bluge';
|
|||||||
import { FrontendSearcher } from './frontend';
|
import { FrontendSearcher } from './frontend';
|
||||||
import { SQLSearcher } from './sql';
|
import { SQLSearcher } from './sql';
|
||||||
import { GrafanaSearcher } from './types';
|
import { GrafanaSearcher } from './types';
|
||||||
|
import { UnifiedSearcher } from './unified';
|
||||||
|
|
||||||
let searcher: GrafanaSearcher | undefined = undefined;
|
let searcher: GrafanaSearcher | undefined = undefined;
|
||||||
|
|
||||||
@ -13,6 +14,11 @@ export function getGrafanaSearcher(): GrafanaSearcher {
|
|||||||
const useBluge = config.featureToggles.panelTitleSearch;
|
const useBluge = config.featureToggles.panelTitleSearch;
|
||||||
searcher = useBluge ? new BlugeSearcher(sqlSearcher) : sqlSearcher;
|
searcher = useBluge ? new BlugeSearcher(sqlSearcher) : sqlSearcher;
|
||||||
|
|
||||||
|
const useUnified = config.featureToggles.unifiedStorageSearch;
|
||||||
|
if (useUnified) {
|
||||||
|
searcher = new UnifiedSearcher(sqlSearcher);
|
||||||
|
}
|
||||||
|
|
||||||
if (useBluge && location.search.includes('do-frontend-query')) {
|
if (useBluge && location.search.includes('do-frontend-query')) {
|
||||||
searcher = new FrontendSearcher(searcher);
|
searcher = new FrontendSearcher(searcher);
|
||||||
}
|
}
|
||||||
|
265
public/app/features/search/service/unified.ts
Normal file
265
public/app/features/search/service/unified.ts
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
// TODO: fix - copied from bluge.ts
|
||||||
|
import {
|
||||||
|
DataFrame,
|
||||||
|
DataFrameJSON,
|
||||||
|
DataFrameView,
|
||||||
|
getDisplayProcessor,
|
||||||
|
SelectableValue,
|
||||||
|
toDataFrame,
|
||||||
|
} from '@grafana/data';
|
||||||
|
import { config, getBackendSrv } from '@grafana/runtime';
|
||||||
|
import { TermCount } from 'app/core/components/TagFilter/TagFilter';
|
||||||
|
|
||||||
|
import { replaceCurrentFolderQuery } from './utils';
|
||||||
|
|
||||||
|
import { DashboardQueryResult, GrafanaSearcher, QueryResponse, SearchQuery } from '.';
|
||||||
|
|
||||||
|
// The backend returns an empty frame with a special name to indicate that the indexing engine is being rebuilt,
|
||||||
|
// and that it can not serve any search requests. We are temporarily using the old SQL Search API as a fallback when that happens.
|
||||||
|
const loadingFrameName = 'Loading';
|
||||||
|
|
||||||
|
const searchURI = 'api/unified-search';
|
||||||
|
|
||||||
|
type SearchAPIResponse = {
|
||||||
|
frames: DataFrameJSON[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const folderViewSort = 'name_sort';
|
||||||
|
|
||||||
|
export class UnifiedSearcher implements GrafanaSearcher {
|
||||||
|
constructor(private fallbackSearcher: GrafanaSearcher) {}
|
||||||
|
|
||||||
|
async search(query: SearchQuery): Promise<QueryResponse> {
|
||||||
|
if (query.facet?.length) {
|
||||||
|
throw new Error('facets not supported!');
|
||||||
|
}
|
||||||
|
return this.doSearchQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fix - copied from bluge.ts
|
||||||
|
async starred(query: SearchQuery): Promise<QueryResponse> {
|
||||||
|
if (query.facet?.length) {
|
||||||
|
throw new Error('facets not supported!');
|
||||||
|
}
|
||||||
|
// get the starred dashboards
|
||||||
|
const starsUIDS = await getBackendSrv().get('api/user/stars');
|
||||||
|
if (starsUIDS?.length) {
|
||||||
|
return this.doSearchQuery({
|
||||||
|
uid: starsUIDS,
|
||||||
|
query: query.query ?? '*',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Nothing is starred
|
||||||
|
return {
|
||||||
|
view: new DataFrameView({ length: 0, fields: [] }),
|
||||||
|
totalRows: 0,
|
||||||
|
loadMoreItems: async (startIndex: number, stopIndex: number): Promise<void> => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
isItemLoaded: (index: number): boolean => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fix - copied from bluge.ts
|
||||||
|
async tags(query: SearchQuery): Promise<TermCount[]> {
|
||||||
|
const req = {
|
||||||
|
...query,
|
||||||
|
query: query.query ?? '*',
|
||||||
|
sort: undefined, // no need to sort the initial query results (not used)
|
||||||
|
facet: [{ field: 'tag' }],
|
||||||
|
limit: 1, // 0 would be better, but is ignored by the backend
|
||||||
|
};
|
||||||
|
|
||||||
|
const resp = await getBackendSrv().post<SearchAPIResponse>(searchURI, req);
|
||||||
|
const frames = resp.frames.map((f) => toDataFrame(f));
|
||||||
|
|
||||||
|
if (frames[0]?.name === loadingFrameName) {
|
||||||
|
return this.fallbackSearcher.tags(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const frame of frames) {
|
||||||
|
if (frame.fields[0].name === 'tag') {
|
||||||
|
return getTermCountsFrom(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fix - copied from bluge.ts
|
||||||
|
getSortOptions(): Promise<SelectableValue[]> {
|
||||||
|
const opts: SelectableValue[] = [
|
||||||
|
{ value: folderViewSort, label: 'Alphabetically (A-Z)' },
|
||||||
|
{ value: '-name_sort', label: 'Alphabetically (Z-A)' },
|
||||||
|
];
|
||||||
|
|
||||||
|
if (config.licenseInfo.enabledFeatures.analytics) {
|
||||||
|
for (const sf of sortFields) {
|
||||||
|
opts.push({ value: `-${sf.name}`, label: `${sf.display} (most)` });
|
||||||
|
opts.push({ value: `${sf.name}`, label: `${sf.display} (least)` });
|
||||||
|
}
|
||||||
|
for (const sf of sortTimeFields) {
|
||||||
|
opts.push({ value: `-${sf.name}`, label: `${sf.display} (recent)` });
|
||||||
|
opts.push({ value: `${sf.name}`, label: `${sf.display} (oldest)` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: update - copied from bluge.ts
|
||||||
|
async doSearchQuery(query: SearchQuery): Promise<QueryResponse> {
|
||||||
|
query = await replaceCurrentFolderQuery(query);
|
||||||
|
const req = {
|
||||||
|
...query,
|
||||||
|
query: query.query ?? '*',
|
||||||
|
limit: query.limit ?? firstPageSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rsp = await getBackendSrv().post<SearchAPIResponse>(searchURI, req);
|
||||||
|
const frames = rsp.frames.map((f) => toDataFrame(f));
|
||||||
|
|
||||||
|
const first = frames.length ? toDataFrame(frames[0]) : { fields: [], length: 0 };
|
||||||
|
|
||||||
|
if (first.name === loadingFrameName) {
|
||||||
|
return this.fallbackSearcher.search(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const field of first.fields) {
|
||||||
|
field.display = getDisplayProcessor({ field, theme: config.theme2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the object exists
|
||||||
|
if (!first.meta?.custom) {
|
||||||
|
first.meta = {
|
||||||
|
...first.meta,
|
||||||
|
custom: {
|
||||||
|
count: first.length,
|
||||||
|
max_score: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = first.meta.custom || {};
|
||||||
|
if (!meta.locationInfo) {
|
||||||
|
meta.locationInfo = {}; // always set it so we can append
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the field name to a better display name
|
||||||
|
if (meta.sortBy?.length) {
|
||||||
|
const field = first.fields.find((f) => f.name === meta.sortBy);
|
||||||
|
if (field) {
|
||||||
|
const name = getSortFieldDisplayName(field.name);
|
||||||
|
meta.sortBy = name;
|
||||||
|
field.name = name; // make it look nicer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let loadMax = 0;
|
||||||
|
let pending: Promise<void> | undefined = undefined;
|
||||||
|
const getNextPage = async () => {
|
||||||
|
while (loadMax > view.dataFrame.length) {
|
||||||
|
const from = view.dataFrame.length;
|
||||||
|
if (from >= meta.count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const resp = await getBackendSrv().post<SearchAPIResponse>(searchURI, {
|
||||||
|
...(req ?? {}),
|
||||||
|
from,
|
||||||
|
limit: nextPageSizes,
|
||||||
|
});
|
||||||
|
const frame = toDataFrame(resp.frames[0]);
|
||||||
|
|
||||||
|
if (!frame) {
|
||||||
|
console.log('no results', frame);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (frame.fields.length !== view.dataFrame.fields.length) {
|
||||||
|
console.log('invalid shape', frame, view.dataFrame);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the raw values to the same array buffer
|
||||||
|
const length = frame.length + view.dataFrame.length;
|
||||||
|
for (let i = 0; i < frame.fields.length; i++) {
|
||||||
|
const values = view.dataFrame.fields[i].values;
|
||||||
|
values.push(...frame.fields[i].values);
|
||||||
|
}
|
||||||
|
view.dataFrame.length = length;
|
||||||
|
|
||||||
|
// Add all the location lookup info
|
||||||
|
const submeta = frame.meta?.custom;
|
||||||
|
if (submeta?.locationInfo && meta) {
|
||||||
|
for (const [key, value] of Object.entries(submeta.locationInfo)) {
|
||||||
|
meta.locationInfo[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const view = new DataFrameView<DashboardQueryResult>(first);
|
||||||
|
return {
|
||||||
|
totalRows: meta.count ?? first.length,
|
||||||
|
view,
|
||||||
|
loadMoreItems: async (startIndex: number, stopIndex: number): Promise<void> => {
|
||||||
|
loadMax = Math.max(loadMax, stopIndex);
|
||||||
|
if (!pending) {
|
||||||
|
pending = getNextPage();
|
||||||
|
}
|
||||||
|
return pending;
|
||||||
|
},
|
||||||
|
isItemLoaded: (index: number): boolean => {
|
||||||
|
return index < view.dataFrame.length;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getFolderViewSort(): string {
|
||||||
|
return 'name_sort';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstPageSize = 50;
|
||||||
|
const nextPageSizes = 100;
|
||||||
|
|
||||||
|
function getTermCountsFrom(frame: DataFrame): TermCount[] {
|
||||||
|
const keys = frame.fields[0].values;
|
||||||
|
const vals = frame.fields[1].values;
|
||||||
|
const counts: TermCount[] = [];
|
||||||
|
for (let i = 0; i < frame.length; i++) {
|
||||||
|
counts.push({ term: keys[i], count: vals[i] });
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enterprise only sort field values for dashboards
|
||||||
|
const sortFields = [
|
||||||
|
{ name: 'views_total', display: 'Views total' },
|
||||||
|
{ name: 'views_last_30_days', display: 'Views 30 days' },
|
||||||
|
{ name: 'errors_total', display: 'Errors total' },
|
||||||
|
{ name: 'errors_last_30_days', display: 'Errors 30 days' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Enterprise only time sort field values for dashboards
|
||||||
|
const sortTimeFields = [
|
||||||
|
{ name: 'created_at', display: 'Created time' },
|
||||||
|
{ name: 'updated_at', display: 'Updated time' },
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Given the internal field name, this gives a reasonable display name for the table colum header */
|
||||||
|
function getSortFieldDisplayName(name: string) {
|
||||||
|
for (const sf of sortFields) {
|
||||||
|
if (sf.name === name) {
|
||||||
|
return sf.display;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const sf of sortTimeFields) {
|
||||||
|
if (sf.name === name) {
|
||||||
|
return sf.display;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
@ -82,6 +82,13 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
|
|||||||
description: 'Search for grafana resources',
|
description: 'Search for grafana resources',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (config.featureToggles.unifiedStorageSearch) {
|
||||||
|
this.queryTypes.push({
|
||||||
|
label: 'Search (experimental)',
|
||||||
|
value: GrafanaQueryType.SearchNext,
|
||||||
|
description: 'Search for grafana resources',
|
||||||
|
});
|
||||||
|
}
|
||||||
if (config.featureToggles.editPanelCSVDragAndDrop) {
|
if (config.featureToggles.editPanelCSVDragAndDrop) {
|
||||||
this.queryTypes.push({
|
this.queryTypes.push({
|
||||||
label: 'Spreadsheet or snapshot',
|
label: 'Spreadsheet or snapshot',
|
||||||
@ -432,6 +439,16 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
|
|||||||
onRunQuery();
|
onRunQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onSearchNextChange = (search: SearchQuery) => {
|
||||||
|
const { query, onChange, onRunQuery } = this.props;
|
||||||
|
|
||||||
|
onChange({
|
||||||
|
...query,
|
||||||
|
searchNext: search,
|
||||||
|
});
|
||||||
|
onRunQuery();
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const query = {
|
const query = {
|
||||||
...defaultQuery,
|
...defaultQuery,
|
||||||
@ -475,6 +492,9 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
|
|||||||
{queryType === GrafanaQueryType.Search && (
|
{queryType === GrafanaQueryType.Search && (
|
||||||
<SearchEditor value={query.search ?? {}} onChange={this.onSearchChange} />
|
<SearchEditor value={query.search ?? {}} onChange={this.onSearchChange} />
|
||||||
)}
|
)}
|
||||||
|
{queryType === GrafanaQueryType.SearchNext && (
|
||||||
|
<SearchEditor value={query.searchNext ?? {}} onChange={this.onSearchNextChange} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ export enum GrafanaQueryType {
|
|||||||
List = 'list',
|
List = 'list',
|
||||||
Read = 'read',
|
Read = 'read',
|
||||||
Search = 'search',
|
Search = 'search',
|
||||||
|
SearchNext = 'searchNext',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GrafanaQuery extends DataQuery {
|
export interface GrafanaQuery extends DataQuery {
|
||||||
@ -28,6 +29,7 @@ export interface GrafanaQuery extends DataQuery {
|
|||||||
buffer?: number;
|
buffer?: number;
|
||||||
path?: string; // for list and read
|
path?: string; // for list and read
|
||||||
search?: SearchQuery;
|
search?: SearchQuery;
|
||||||
|
searchNext?: SearchQuery;
|
||||||
snapshot?: DataFrameJSON[];
|
snapshot?: DataFrameJSON[];
|
||||||
timeRegion?: TimeRegionConfig;
|
timeRegion?: TimeRegionConfig;
|
||||||
file?: GrafanaQueryFile;
|
file?: GrafanaQueryFile;
|
||||||
|
Loading…
Reference in New Issue
Block a user