diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index 8dc9d75e58..96c13fddc5 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -94,7 +94,7 @@ jobs: - name: Build and install run: make install - - name: Docker-compose + - name: Launch the containers env: ENV_UP_FLAGS: "--detach" run: make env-up diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index 0aaae32482..fd70397013 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1 + uses: dependabot/fetch-metadata@v2 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/release-doc.yml b/.github/workflows/release-doc.yml index 3e941c10b0..b60835675d 100644 --- a/.github/workflows/release-doc.yml +++ b/.github/workflows/release-doc.yml @@ -25,7 +25,7 @@ jobs: grep -rl '!!! note alert alert-primary' ${{ github.workspace }}-CHANGELOG.txt | xargs --no-run-if-empty sed -i 's/\!\!\! note alert alert-primary "\(.*\)"/\> \:memo\: **\1**/g' grep -rl '!!! note alert alert-primary' ${{ github.workspace }}-CHANGELOG.txt | xargs --no-run-if-empty sed -i 's/\!\!\! note alert alert-primary/\> \:memo\: **Note**/g' - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: body_path: ${{ github.workspace }}-CHANGELOG.txt draft: true diff --git a/admin/commands/base/setup.go b/admin/commands/base/setup.go index 8248c7c0a7..f64d384ee1 100644 --- a/admin/commands/base/setup.go +++ b/admin/commands/base/setup.go @@ -88,8 +88,13 @@ func SetupClients(ctx context.Context, globalFlags *flags.GlobalFlags) { // use JSON APIs over HTTP/1.1 transport := httptransport.New(globalFlags.ServerURL.Host, globalFlags.ServerURL.Path, []string{globalFlags.ServerURL.Scheme}) if u := globalFlags.ServerURL.User; u != nil { + user := u.Username() password, _ := u.Password() - transport.DefaultAuthentication = httptransport.BasicAuth(u.Username(), password) + if user == "service_token" || user == "api_key" { + transport.DefaultAuthentication = httptransport.BearerToken(password) + } else { + transport.DefaultAuthentication = httptransport.BasicAuth(user, password) + } } transport.SetLogger(logrus.WithField("component", "server-transport")) transport.SetDebug(globalFlags.EnableDebug || globalFlags.EnableTrace) diff --git a/admin/commands/management/unregister.go b/admin/commands/management/unregister.go index d2db97d997..b126ba868a 100644 --- a/admin/commands/management/unregister.go +++ b/admin/commands/management/unregister.go @@ -15,14 +15,16 @@ package management import ( - "github.com/AlekSi/pointer" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/percona/pmm/admin/agentlocal" "github.com/percona/pmm/admin/commands" "github.com/percona/pmm/admin/helpers" "github.com/percona/pmm/api/inventory/v1/json/client" nodes "github.com/percona/pmm/api/inventory/v1/json/client/nodes_service" + managementClient "github.com/percona/pmm/api/management/v1/json/client" + mservice "github.com/percona/pmm/api/management/v1/json/client/management_service" ) type unregisterResult struct { @@ -77,17 +79,23 @@ func (cmd *UnregisterCommand) RunCmd() (commands.Result, error) { } } - params := &nodes.RemoveNodeParams{ - NodeID: nodeID, - Force: pointer.ToBool(cmd.Force), + params := &mservice.UnregisterNodeParams{ + Body: mservice.UnregisterNodeBody{ + NodeID: nodeID, + Force: cmd.Force, + }, Context: commands.Ctx, } - _, err = client.Default.NodesService.RemoveNode(params) + res, err := managementClient.Default.ManagementService.UnregisterNode(params) if err != nil { return nil, err } + if res.Payload.Warning != "" { + logrus.Warning(res.Payload.Warning) + } + return &unregisterResult{ NodeID: nodeID, NodeName: nodeName, diff --git a/agent/Makefile b/agent/Makefile index 34921df996..2507f82fcb 100644 --- a/agent/Makefile +++ b/agent/Makefile @@ -110,10 +110,10 @@ env-up: ## Start development environment mkdir -p testdata/mysql/slowlogs chmod -R 0777 testdata - docker-compose up $(ENV_UP_FLAGS) + docker compose up $(ENV_UP_FLAGS) env-down: ## Stop development environment - docker-compose down --volumes --remove-orphans + docker compose down --volumes --remove-orphans setup-dev: install ## Run pmm-agent setup in development environment pmm-agent setup $(RUN_FLAGS) --server-insecure-tls --server-address=127.0.0.1:${PMM_DEV_SERVER_PORT} --server-username=admin --server-password=admin --paths-exporters_base=$(GOPATH)/bin --force @@ -128,13 +128,13 @@ env-psql: ## Run psql client docker exec -ti pmm-agent_postgres env PGPASSWORD=pmm-agent-password psql --username=pmm-agent env-sysbench-prepare: - docker-compose exec --workdir=/sysbench/sysbench-tpcc sysbench ./tpcc.lua \ + docker compose exec --workdir=/sysbench/sysbench-tpcc sysbench ./tpcc.lua \ --db-driver=pgsql --pgsql-host=postgres --pgsql-user=pmm-agent --pgsql-password=pmm-agent-password --pgsql-db=pmm-agent \ --threads=1 --time=0 --report-interval=10 \ --tables=1 --scale=10 --use_fk=0 --enable_purge=yes prepare env-sysbench-run: - docker-compose exec --workdir=/sysbench/sysbench-tpcc sysbench ./tpcc.lua \ + docker compose exec --workdir=/sysbench/sysbench-tpcc sysbench ./tpcc.lua \ --db-driver=pgsql --pgsql-host=postgres --pgsql-user=pmm-agent --pgsql-password=pmm-agent-password --pgsql-db=pmm-agent \ --threads=4 --time=0 --rate=10 --report-interval=10 --percentile=99 \ --tables=1 --scale=10 --use_fk=0 --enable_purge=yes run diff --git a/agent/client/basic_auth.go b/agent/client/basic_auth.go index 2984533215..c6716a64e7 100644 --- a/agent/client/basic_auth.go +++ b/agent/client/basic_auth.go @@ -17,6 +17,7 @@ package client import ( "context" "encoding/base64" + "fmt" "google.golang.org/grpc/credentials" ) @@ -31,7 +32,7 @@ func (b *basicAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[ auth := b.username + ":" + b.password enc := base64.StdEncoding.EncodeToString([]byte(auth)) return map[string]string{ - "authorization": "Basic " + enc, + "Authorization": fmt.Sprintf("Basic %s", enc), }, nil } diff --git a/agent/client/client.go b/agent/client/client.go index bb77115718..3a44fd1974 100644 --- a/agent/client/client.go +++ b/agent/client/client.go @@ -748,10 +748,16 @@ func dial(dialCtx context.Context, cfg *config.Config, l *logrus.Entry) (*dialRe } if cfg.Server.Username != "" { - opts = append(opts, grpc.WithPerRPCCredentials(&basicAuth{ - username: cfg.Server.Username, - password: cfg.Server.Password, - })) + if cfg.Server.Username == "service_token" || cfg.Server.Username == "api_key" { + opts = append(opts, grpc.WithPerRPCCredentials(&tokenAuth{ + token: cfg.Server.Password, + })) + } else { + opts = append(opts, grpc.WithPerRPCCredentials(&basicAuth{ + username: cfg.Server.Username, + password: cfg.Server.Password, + })) + } } l.Infof("Connecting to %s ...", cfg.Server.FilteredURL()) diff --git a/agent/client/token_auth.go b/agent/client/token_auth.go new file mode 100644 index 0000000000..2204f9cab8 --- /dev/null +++ b/agent/client/token_auth.go @@ -0,0 +1,43 @@ +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package client + +import ( + "context" + "fmt" + + "google.golang.org/grpc/credentials" +) + +type tokenAuth struct { + token string +} + +// GetRequestMetadata implements credentials.PerRPCCredentials interface. +func (t *tokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { //nolint:revive + return map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", t.token), + }, nil +} + +// RequireTransportSecurity implements credentials.PerRPCCredentials interface. +func (*tokenAuth) RequireTransportSecurity() bool { + return false +} + +// check interfaces. +var ( + _ credentials.PerRPCCredentials = (*tokenAuth)(nil) +) diff --git a/agent/commands/clients.go b/agent/commands/clients.go index 68fb1c6bab..e8c0b7b98d 100644 --- a/agent/commands/clients.go +++ b/agent/commands/clients.go @@ -104,8 +104,13 @@ func setServerTransport(u *url.URL, insecureTLS bool, l *logrus.Entry) { // use JSON APIs over HTTP/1.1 transport := httptransport.New(u.Host, u.Path, []string{u.Scheme}) if u.User != nil { + user := u.User.Username() password, _ := u.User.Password() - transport.DefaultAuthentication = httptransport.BasicAuth(u.User.Username(), password) + if user == "service_token" || user == "api_key" { + transport.DefaultAuthentication = httptransport.BearerToken(password) + } else { + transport.DefaultAuthentication = httptransport.BasicAuth(user, password) + } } transport.SetLogger(l) transport.SetDebug(l.Logger.GetLevel() >= logrus.DebugLevel) diff --git a/agent/commands/setup.go b/agent/commands/setup.go index 93c4c6f4f6..243b899b7d 100644 --- a/agent/commands/setup.go +++ b/agent/commands/setup.go @@ -160,10 +160,10 @@ func register(cfg *config.Config, l *logrus.Entry) { } cfg.ID = agentID if token != "" { - cfg.Server.Username = "api_key" + cfg.Server.Username = "service_token" cfg.Server.Password = token } else { - l.Info("PMM Server responded with an empty api key token. Consider upgrading PMM Server to the latest version.") + l.Info("PMM Server responded with an empty service token. Consider upgrading PMM Server to the latest version.") } fmt.Printf("Registered.\n") } diff --git a/agent/config/config.go b/agent/config/config.go index 0add35a143..3f18aaaf5f 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -18,7 +18,6 @@ package config import ( "fmt" "io/fs" - "log" "net" "net/url" "os" @@ -414,10 +413,11 @@ func Application(cfg *Config) (*kingpin.Application, *string) { }).Bool() app.Flag("version", "Show application version").Short('v').Action(func(*kingpin.ParseContext) error { + // We use fmt instead of log package to provide proper output for --json flag. if *jsonF { - log.Println(version.FullInfoJSON()) + fmt.Println(version.FullInfoJSON()) //nolint:forbidigo } else { - log.Println(version.FullInfo()) + fmt.Println(version.FullInfo()) //nolint:forbidigo } os.Exit(0) diff --git a/agent/serviceinfobroker/service_info_broker.go b/agent/serviceinfobroker/service_info_broker.go index 92879e3e28..c514cd6064 100644 --- a/agent/serviceinfobroker/service_info_broker.go +++ b/agent/serviceinfobroker/service_info_broker.go @@ -237,7 +237,7 @@ func (sib *ServiceInfoBroker) getPostgreSQLInfo(ctx context.Context, dsn string, if err != nil && !errors.Is(err, sql.ErrNoRows) { res.Error = err.Error() } - res.PgsmVersion = pgsmVersion + res.PgsmVersion = &pgsmVersion return &res } diff --git a/agent/serviceinfobroker/service_info_broker_test.go b/agent/serviceinfobroker/service_info_broker_test.go index 2a163d56a4..c02af68145 100644 --- a/agent/serviceinfobroker/service_info_broker_test.go +++ b/agent/serviceinfobroker/service_info_broker_test.go @@ -260,7 +260,7 @@ func TestServiceInfoBroker(t *testing.T) { }, 0) require.NotNil(t, resp) assert.Equal(t, []string{"postgres", "pmm-agent"}, resp.DatabaseList) - assert.Equal(t, "", resp.PgsmVersion) + assert.Equal(t, "", *resp.PgsmVersion) }) t.Run("MongoDBWithSSL", func(t *testing.T) { diff --git a/api-tests/backup/backups_test.go b/api-tests/backup/backups_test.go index e97734ca64..9d1f5abef6 100644 --- a/api-tests/backup/backups_test.go +++ b/api-tests/backup/backups_test.go @@ -40,7 +40,7 @@ func TestScheduleBackup(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer management.RemovePMMAgentWithSubAgents(t, pmmAgentID) mongo1Name := pmmapitests.TestString(t, "mongo") mongo2Name := pmmapitests.TestString(t, "mongo") diff --git a/api-tests/helpers.go b/api-tests/helpers.go index f6ed5dbb56..2549d43b7d 100644 --- a/api-tests/helpers.go +++ b/api-tests/helpers.go @@ -17,8 +17,10 @@ package apitests import ( "context" + "crypto/rand" "fmt" - "math/rand" + "math" + "math/big" "reflect" "testing" @@ -31,6 +33,8 @@ import ( agents "github.com/percona/pmm/api/inventory/v1/json/client/agents_service" nodes "github.com/percona/pmm/api/inventory/v1/json/client/nodes_service" services "github.com/percona/pmm/api/inventory/v1/json/client/services_service" + managementClient "github.com/percona/pmm/api/management/v1/json/client" + mservice "github.com/percona/pmm/api/management/v1/json/client/management_service" ) // ErrorResponse represents the response structure for error scenarios. @@ -50,7 +54,10 @@ type TestingT interface { func TestString(t TestingT, name string) string { t.Helper() - n := rand.Int() //nolint:gosec + // Without proper seed parallel tests can generate same "random" number. + n, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt32)) + require.NoError(t, err) + return fmt.Sprintf("pmm-api-tests/%s/%s/%s/%d", Hostname, t.Name(), name, n) } @@ -131,6 +138,26 @@ func (tt *expectedFailureTestingT) Check() { tt.t.Fatalf("%s expected to fail, but didn't: %s", tt.Name(), tt.link) } +// UnregisterNodes unregister specified nodes. +func UnregisterNodes(t TestingT, nodeIDs ...string) { + t.Helper() + + for _, nodeID := range nodeIDs { + params := &mservice.UnregisterNodeParams{ + Body: mservice.UnregisterNodeBody{ + NodeID: nodeID, + }, + Context: context.Background(), + } + + res, err := managementClient.Default.ManagementService.UnregisterNode(params) + require.NoError(t, err) + assert.NotNil(t, res) + assert.NotNil(t, res.Payload) + assert.Empty(t, res.Payload.Warning) + } +} + // RemoveNodes removes specified nodes. func RemoveNodes(t TestingT, nodeIDs ...string) { t.Helper() diff --git a/api-tests/inventory/nodes_test.go b/api-tests/inventory/nodes_test.go index 606c6fe4a6..6230e8c94c 100644 --- a/api-tests/inventory/nodes_test.go +++ b/api-tests/inventory/nodes_test.go @@ -33,7 +33,6 @@ import ( ) func TestNodes(t *testing.T) { - t.Parallel() t.Run("List", func(t *testing.T) { t.Parallel() @@ -103,7 +102,6 @@ func TestNodes(t *testing.T) { } func TestGetNode(t *testing.T) { - t.Parallel() t.Run("Basic", func(t *testing.T) { t.Parallel() @@ -157,7 +155,6 @@ func TestGetNode(t *testing.T) { } func TestGenericNode(t *testing.T) { - t.Parallel() t.Run("Basic", func(t *testing.T) { t.Parallel() @@ -222,7 +219,6 @@ func TestGenericNode(t *testing.T) { } func TestContainerNode(t *testing.T) { - t.Parallel() t.Run("Basic", func(t *testing.T) { t.Parallel() @@ -292,7 +288,6 @@ func TestContainerNode(t *testing.T) { } func TestRemoteNode(t *testing.T) { - t.Parallel() t.Run("Basic", func(t *testing.T) { t.Parallel() @@ -361,7 +356,6 @@ func TestRemoteNode(t *testing.T) { } func TestRemoveNode(t *testing.T) { - t.Parallel() t.Run("Basic", func(t *testing.T) { t.Parallel() diff --git a/api-tests/management/haproxy_test.go b/api-tests/management/haproxy_test.go index 8771eeeba2..ae338b8846 100644 --- a/api-tests/management/haproxy_test.go +++ b/api-tests/management/haproxy_test.go @@ -40,7 +40,7 @@ func TestAddHAProxy(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -105,7 +105,7 @@ func TestAddHAProxy(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -249,7 +249,7 @@ func TestAddHAProxy(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-the-same-name") diff --git a/api-tests/management/helpers.go b/api-tests/management/helpers.go index aeca07a57b..fb054e8ef6 100644 --- a/api-tests/management/helpers.go +++ b/api-tests/management/helpers.go @@ -49,6 +49,7 @@ func RegisterGenericNode(t pmmapitests.TestingT, body mservice.RegisterNodeBody) require.NotNil(t, registerOK.Payload.PMMAgent.AgentID) require.NotNil(t, registerOK.Payload.GenericNode) require.NotNil(t, registerOK.Payload.GenericNode.NodeID) + return registerOK.Payload.GenericNode.NodeID, registerOK.Payload.PMMAgent.AgentID } @@ -66,6 +67,7 @@ func registerContainerNode(t pmmapitests.TestingT, body mservice.RegisterNodeBod require.NotNil(t, registerOK.Payload.PMMAgent.AgentID) require.NotNil(t, registerOK.Payload.ContainerNode) require.NotNil(t, registerOK.Payload.ContainerNode.NodeID) + return registerOK.Payload.ContainerNode.NodeID, registerOK.Payload.PMMAgent.AgentID } diff --git a/api-tests/management/mongodb_test.go b/api-tests/management/mongodb_test.go index cc1616a24a..aff5326a21 100644 --- a/api-tests/management/mongodb_test.go +++ b/api-tests/management/mongodb_test.go @@ -39,7 +39,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-basic-name") @@ -112,7 +112,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-all-fields") @@ -203,7 +203,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-all-fields") @@ -262,7 +262,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-the-same-name") @@ -312,7 +312,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) nodeNameAddNode := pmmapitests.TestString(t, "node-for-add-node-name") @@ -433,7 +433,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) remoteNodeOKBody := pmmapitests.AddRemoteNode(t, pmmapitests.TestString(t, "Remote Node for wrong type test")) @@ -466,7 +466,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) params := &mservice.AddServiceParams{ @@ -488,7 +488,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -513,7 +513,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -539,7 +539,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -565,7 +565,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -595,7 +595,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-mongo-socket-name") @@ -665,7 +665,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-basic-name") @@ -738,7 +738,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-basic-name") @@ -810,7 +810,7 @@ func TestAddMongoDB(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name-for-basic-name") @@ -915,7 +915,7 @@ func TestRemoveMongoDB(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-name") nodeName := pmmapitests.TestString(t, "node-remove-by-name") nodeID, pmmAgentID, serviceID := addMongoDB(t, serviceName, nodeName, true) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -942,7 +942,7 @@ func TestRemoveMongoDB(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-id") nodeName := pmmapitests.TestString(t, "node-remove-by-id") nodeID, pmmAgentID, serviceID := addMongoDB(t, serviceName, nodeName, true) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -969,7 +969,7 @@ func TestRemoveMongoDB(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-wrong-type") nodeName := pmmapitests.TestString(t, "node-remove-wrong-type") nodeID, pmmAgentID, serviceID := addMongoDB(t, serviceName, nodeName, false) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer pmmapitests.RemoveServices(t, serviceID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) diff --git a/api-tests/management/mysql_test.go b/api-tests/management/mysql_test.go index f426b355fa..ddd58952c1 100644 --- a/api-tests/management/mysql_test.go +++ b/api-tests/management/mysql_test.go @@ -39,7 +39,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -114,7 +114,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -223,7 +223,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -284,7 +284,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-the-same-name") @@ -336,7 +336,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) nodeNameAddNode := pmmapitests.TestString(t, "node-for-add-node-name") @@ -461,7 +461,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) remoteNodeOKBody := pmmapitests.AddRemoteNode(t, pmmapitests.TestString(t, "Remote Node for wrong type test")) @@ -495,7 +495,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) params := &mservice.AddServiceParams{ @@ -517,7 +517,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -544,7 +544,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -572,7 +572,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -602,7 +602,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -628,7 +628,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -655,7 +655,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -730,7 +730,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -804,7 +804,7 @@ func TestAddMySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -912,7 +912,7 @@ func TestRemoveMySQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-name") nodeName := pmmapitests.TestString(t, "node-remove-by-name") nodeID, pmmAgentID, serviceID := addMySQL(t, serviceName, nodeName, true) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -939,7 +939,7 @@ func TestRemoveMySQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-id") nodeName := pmmapitests.TestString(t, "node-remove-by-id") nodeID, pmmAgentID, serviceID := addMySQL(t, serviceName, nodeName, true) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -966,7 +966,7 @@ func TestRemoveMySQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-wrong-type") nodeName := pmmapitests.TestString(t, "node-remove-wrong-type") nodeID, pmmAgentID, serviceID := addMySQL(t, serviceName, nodeName, false) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer pmmapitests.RemoveServices(t, serviceID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) diff --git a/api-tests/management/nodes_test.go b/api-tests/management/nodes_test.go index 482e92e6a8..3632cca9e8 100644 --- a/api-tests/management/nodes_test.go +++ b/api-tests/management/nodes_test.go @@ -40,7 +40,7 @@ func TestNodeRegister(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) // Check Node is created assertNodeCreated(t, nodeID, nodes.GetNodeOKBody{ @@ -66,7 +66,7 @@ func TestNodeRegister(t *testing.T) { Address: "node-address-1", Region: "region-1", }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) body := mservice.RegisterNodeBody{ @@ -109,8 +109,9 @@ func TestNodeRegister(t *testing.T) { node, err := client.Default.ManagementService.RegisterNode(¶ms) assert.NoError(t, err) - defer pmmapitests.RemoveNodes(t, node.Payload.GenericNode.NodeID) + defer pmmapitests.UnregisterNodes(t, node.Payload.GenericNode.NodeID) defer RemovePMMAgentWithSubAgents(t, node.Payload.PMMAgent.AgentID) + assertNodeExporterCreated(t, node.Payload.PMMAgent.AgentID) }) @@ -122,7 +123,7 @@ func TestNodeRegister(t *testing.T) { Address: "node-address-3", Region: "region-3", }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) body := mservice.RegisterNodeBody{ @@ -148,9 +149,9 @@ func TestNodeRegister(t *testing.T) { Address: "node-address-4", Region: "region-4", }) - assert.NotEmpty(t, nodeID) assert.NotEmpty(t, pmmAgentID) + pmmapitests.UnregisterNodes(t, nodeID) body := mservice.RegisterNodeBody{ NodeName: nodeName + "_new", @@ -166,7 +167,7 @@ func TestNodeRegister(t *testing.T) { node, err := client.Default.ManagementService.RegisterNode(¶ms) assert.NoError(t, err) - defer pmmapitests.RemoveNodes(t, node.Payload.GenericNode.NodeID) + defer pmmapitests.UnregisterNodes(t, node.Payload.GenericNode.NodeID) _, ok := assertNodeExporterCreated(t, node.Payload.PMMAgent.AgentID) if ok { defer RemovePMMAgentWithSubAgents(t, node.Payload.PMMAgent.AgentID) @@ -190,7 +191,7 @@ func TestNodeRegister(t *testing.T) { DisableCollectors: []string{"diskstats", "filesystem", "standard.process"}, } nodeID, pmmAgentID := RegisterGenericNode(t, body) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) // Check Node is created @@ -298,7 +299,7 @@ func TestNodeRegister(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPECONTAINERNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) // Check Node is created @@ -337,7 +338,7 @@ func TestNodeRegister(t *testing.T) { CustomLabels: map[string]string{"foo": "bar"}, } nodeID, pmmAgentID := registerContainerNode(t, body) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) // Check Node is created diff --git a/api-tests/management/postgresql_test.go b/api-tests/management/postgresql_test.go index a5a151159c..204a47c82e 100644 --- a/api-tests/management/postgresql_test.go +++ b/api-tests/management/postgresql_test.go @@ -41,7 +41,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -120,7 +120,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -231,7 +231,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -288,7 +288,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-the-same-name") @@ -341,7 +341,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) nodeNameAddNode := pmmapitests.TestString(t, "node-for-add-node-name") @@ -469,7 +469,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) remoteNodeOKBody := pmmapitests.AddRemoteNode(t, pmmapitests.TestString(t, "Remote Node for wrong type test")) @@ -503,7 +503,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) params := &mservice.AddServiceParams{ @@ -525,7 +525,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -551,7 +551,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -578,7 +578,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -604,7 +604,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -634,7 +634,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -710,7 +710,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -785,7 +785,7 @@ func TestAddPostgreSQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -894,7 +894,7 @@ func TestRemovePostgreSQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-name") nodeName := pmmapitests.TestString(t, "node-remove-by-name") nodeID, pmmAgentID, serviceID := addPostgreSQL(t, serviceName, nodeName, true) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -921,7 +921,7 @@ func TestRemovePostgreSQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-id") nodeName := pmmapitests.TestString(t, "node-remove-by-id") nodeID, pmmAgentID, serviceID := addPostgreSQL(t, serviceName, nodeName, true) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -948,7 +948,7 @@ func TestRemovePostgreSQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-wrong-type") nodeName := pmmapitests.TestString(t, "node-remove-wrong-type") nodeID, pmmAgentID, serviceID := addPostgreSQL(t, serviceName, nodeName, false) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer pmmapitests.RemoveServices(t, serviceID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) diff --git a/api-tests/management/proxysql_test.go b/api-tests/management/proxysql_test.go index bbdcdebba1..240e2fb4c0 100644 --- a/api-tests/management/proxysql_test.go +++ b/api-tests/management/proxysql_test.go @@ -39,7 +39,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-basic-name") @@ -113,7 +113,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -189,7 +189,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-all-fields-name") @@ -250,7 +250,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-for-the-same-name") @@ -302,7 +302,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) nodeNameAddNode := pmmapitests.TestString(t, "node-for-add-node-name") @@ -426,7 +426,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) remoteNodeOKBody := pmmapitests.AddRemoteNode(t, pmmapitests.TestString(t, "Remote Node for wrong type test")) @@ -460,7 +460,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) params := &mservice.AddServiceParams{ @@ -482,7 +482,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -508,7 +508,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -535,7 +535,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -565,7 +565,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -591,7 +591,7 @@ func TestAddProxySQL(t *testing.T) { NodeName: nodeName, NodeType: pointer.ToString(mservice.RegisterNodeBodyNodeTypeNODETYPEGENERICNODE), }) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) serviceName := pmmapitests.TestString(t, "service-name") @@ -649,7 +649,7 @@ func TestRemoveProxySQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-name") nodeName := pmmapitests.TestString(t, "node-remove-by-name") nodeID, pmmAgentID, serviceID := addProxySQL(t, serviceName, nodeName) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -676,7 +676,7 @@ func TestRemoveProxySQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-by-id") nodeName := pmmapitests.TestString(t, "node-remove-by-id") nodeID, pmmAgentID, serviceID := addProxySQL(t, serviceName, nodeName) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) removeServiceOK, err := client.Default.ManagementService.RemoveService(&mservice.RemoveServiceParams{ @@ -703,7 +703,7 @@ func TestRemoveProxySQL(t *testing.T) { serviceName := pmmapitests.TestString(t, "service-remove-wrong-type") nodeName := pmmapitests.TestString(t, "node-remove-wrong-type") nodeID, pmmAgentID, serviceID := addProxySQL(t, serviceName, nodeName) - defer pmmapitests.RemoveNodes(t, nodeID) + defer pmmapitests.UnregisterNodes(t, nodeID) defer pmmapitests.RemoveServices(t, serviceID) defer RemovePMMAgentWithSubAgents(t, pmmAgentID) diff --git a/api-tests/server/advisors_test.go b/api-tests/server/advisors_test.go index fba6696a47..0c6f90b4c6 100644 --- a/api-tests/server/advisors_test.go +++ b/api-tests/server/advisors_test.go @@ -162,7 +162,7 @@ func TestChangeAdvisorChecks(t *testing.T) { } }) - t.Run("change interval error", func(t *testing.T) { + t.Run("unrecognized interval is ignored", func(t *testing.T) { t.Cleanup(func() { restoreCheckIntervalDefaults(t) }) resp, err := advisorClient.Default.AdvisorService.ListAdvisorChecks(nil) diff --git a/api-tests/server/auth_test.go b/api-tests/server/auth_test.go index 6888979305..60f1ea906a 100644 --- a/api-tests/server/auth_test.go +++ b/api-tests/server/auth_test.go @@ -38,6 +38,11 @@ import ( server "github.com/percona/pmm/api/server/v1/json/client/server_service" ) +const ( + pmmServiceTokenName = "pmm-agent-service-token" //nolint:gosec + pmmServiceAccountName = "pmm-agent-service-account" //nolint:gosec +) + func TestAuth(t *testing.T) { t.Run("AuthErrors", func(t *testing.T) { for user, code := range map[*url.Userinfo]int{ @@ -235,7 +240,20 @@ func TestSwagger(t *testing.T) { } } -func TestPermissions(t *testing.T) { +func doRequest(tb testing.TB, client *http.Client, req *http.Request) (*http.Response, []byte) { + tb.Helper() + resp, err := client.Do(req) + require.NoError(tb, err) + + defer resp.Body.Close() //nolint:errcheck + + b, err := io.ReadAll(resp.Body) + require.NoError(tb, err) + + return resp, b +} + +func TestBasicAuthPermissions(t *testing.T) { ts := strconv.FormatInt(time.Now().Unix(), 10) none := "none-" + ts viewer := "viewer-" + ts @@ -254,13 +272,12 @@ func TestPermissions(t *testing.T) { adminID := createUserWithRole(t, admin, "Admin") defer deleteUser(t, adminID) - viewerAPIKeyID, viewerAPIKey := createAPIKeyWithRole(t, "api-"+viewer, "Viewer") + const apiPrefix = "api" + viewerAPIKeyID, viewerAPIKey := createAPIKeyWithRole(t, fmt.Sprintf("%s-%s", apiPrefix, viewer), "Viewer") defer deleteAPIKey(t, viewerAPIKeyID) - - editorAPIKeyID, editorAPIKey := createAPIKeyWithRole(t, "api-"+editor, "Editor") + editorAPIKeyID, editorAPIKey := createAPIKeyWithRole(t, fmt.Sprintf("%s-%s", apiPrefix, editor), "Editor") defer deleteAPIKey(t, editorAPIKeyID) - - adminAPIKeyID, adminAPIKey := createAPIKeyWithRole(t, "api-"+admin, "Admin") + adminAPIKeyID, adminAPIKey := createAPIKeyWithRole(t, fmt.Sprintf("%s-%s", apiPrefix, admin), "Admin") defer deleteAPIKey(t, adminAPIKeyID) type userCase struct { @@ -358,19 +375,6 @@ func TestPermissions(t *testing.T) { } } -func doRequest(tb testing.TB, client *http.Client, req *http.Request) (*http.Response, []byte) { - tb.Helper() - resp, err := client.Do(req) - require.NoError(tb, err) - - defer resp.Body.Close() //nolint:gosec,errcheck,nolintlint - - b, err := io.ReadAll(resp.Body) - require.NoError(tb, err) - - return resp, b -} - func createUserWithRole(t *testing.T, login, role string) int { t.Helper() userID := createUser(t, login) @@ -444,19 +448,99 @@ func setRole(t *testing.T, userID int, role string) { require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to set role for user, response: %s", b) } -func deleteAPIKey(t *testing.T, apiKeyID int) { - t.Helper() - // https://grafana.com/docs/grafana/latest/http_api/auth/#delete-api-key - u, err := url.Parse(pmmapitests.BaseURL.String()) - require.NoError(t, err) - u.Path = "/graph/api/auth/keys/" + strconv.Itoa(apiKeyID) +func TestServiceAccountPermissions(t *testing.T) { + // service account role options: viewer, editor, admin + // service token role options: editor, admin + // basic auth format is skipped, endpoint /auth/serviceaccount (to get info about currently used token in request) requires Bearer authorization + // service_token:token format could be used in pmm-agent and pmm-admin (its transformed into Bearer authorization) + nodeName := "test-node" + + viewerNodeName := fmt.Sprintf("%s-viewer", nodeName) + viewerAccountID := createServiceAccountWithRole(t, "Viewer", viewerNodeName) + viewerTokenID, viewerToken := createServiceToken(t, viewerAccountID, viewerNodeName) + defer deleteServiceAccount(t, viewerAccountID) + defer deleteServiceToken(t, viewerAccountID, viewerTokenID) + + editorNodeName := fmt.Sprintf("%s-editor", nodeName) + editorAccountID := createServiceAccountWithRole(t, "Editor", editorNodeName) + editorTokenID, editorToken := createServiceToken(t, editorAccountID, editorNodeName) + defer deleteServiceAccount(t, editorAccountID) + defer deleteServiceToken(t, editorAccountID, editorTokenID) + + adminNodeName := fmt.Sprintf("%s-admin", nodeName) + adminAccountID := createServiceAccountWithRole(t, "Admin", adminNodeName) + adminTokenID, adminToken := createServiceToken(t, adminAccountID, adminNodeName) + defer deleteServiceAccount(t, adminAccountID) + defer deleteServiceToken(t, adminAccountID, adminTokenID) - req, err := http.NewRequestWithContext(pmmapitests.Context, http.MethodDelete, u.String(), nil) - require.NoError(t, err) + type userCase struct { + userType string + serviceToken string + statusCode int + } - resp, b := doRequest(t, http.DefaultClient, req) //nolint:bodyclose + tests := []struct { + name string + url string + method string + userCase []userCase + }{ + {name: "settings", url: "/v1/Settings/Get", method: "POST", userCase: []userCase{ + {userType: "default", statusCode: 401}, + {userType: "viewer", serviceToken: viewerToken, statusCode: 401}, + {userType: "editor", serviceToken: editorToken, statusCode: 401}, + {userType: "admin", serviceToken: adminToken, statusCode: 200}, + }}, + {name: "platform-connect", url: "/v1/Platform/Connect", method: "POST", userCase: []userCase{ + {userType: "default", statusCode: 401}, + {userType: "viewer", serviceToken: viewerToken, statusCode: 401}, + {userType: "editor", serviceToken: editorToken, statusCode: 401}, + {userType: "admin", serviceToken: adminToken, statusCode: 400}, // We send bad request, but have access to endpoint + }}, + } - require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to delete API Key, status code: %d, response: %s", resp.StatusCode, b) + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + for _, user := range test.userCase { + user := user + t.Run(fmt.Sprintf("Service Token auth %s", user.userType), func(t *testing.T) { + // make a BaseURL without authentication + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.User = nil + u.Path = test.url + + req, err := http.NewRequestWithContext(pmmapitests.Context, test.method, u.String(), nil) + require.NoError(t, err) + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", user.serviceToken)) + + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() //nolint:errcheck + + assert.Equal(t, user.statusCode, resp.StatusCode) + }) + + t.Run(fmt.Sprintf("Basic auth with Service Token %s", user.userType), func(t *testing.T) { + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.User = url.UserPassword("service_token", user.serviceToken) + u.Path = test.url + + req, err := http.NewRequestWithContext(pmmapitests.Context, test.method, u.String(), nil) + require.NoError(t, err) + + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() //nolint:errcheck + + assert.Equal(t, user.statusCode, resp.StatusCode) + }) + } + }) + } } func createAPIKeyWithRole(t *testing.T, name, role string) (int, string) { @@ -504,3 +588,125 @@ func createAPIKeyWithRole(t *testing.T, name, role string) (int, string) { return apiKeyID, apiKey } + +func deleteAPIKey(t *testing.T, apiKeyID int) { + t.Helper() + // https://grafana.com/docs/grafana/latest/http_api/auth/#delete-api-key + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.Path = "/graph/api/auth/keys/" + strconv.Itoa(apiKeyID) + + req, err := http.NewRequestWithContext(pmmapitests.Context, http.MethodDelete, u.String(), nil) + require.NoError(t, err) + + resp, b := doRequest(t, http.DefaultClient, req) + defer resp.Body.Close() //nolint:gosec,errcheck,nolintlint + + require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to delete API Key, status code: %d, response: %s", resp.StatusCode, b) +} + +func createServiceAccountWithRole(t *testing.T, role, nodeName string) int { + t.Helper() + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.Path = "/graph/api/serviceaccounts" + + name := fmt.Sprintf("%s-%s", pmmServiceAccountName, nodeName) + data, err := json.Marshal(map[string]string{ + "name": name, + "role": role, + }) + require.NoError(t, err) + + req, err := http.NewRequestWithContext(pmmapitests.Context, http.MethodPost, u.String(), bytes.NewReader(data)) + require.NoError(t, err) + + req.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp, b := doRequest(t, http.DefaultClient, req) + defer resp.Body.Close() //nolint:errcheck + + require.Equalf(t, http.StatusCreated, resp.StatusCode, "failed to create Service account, status code: %d, response: %s", resp.StatusCode, b) + + var m map[string]interface{} + err = json.Unmarshal(b, &m) + require.NoError(t, err) + + serviceAccountID := int(m["id"].(float64)) + u.Path = fmt.Sprintf("/graph/api/serviceaccounts/%d", serviceAccountID) + data, err = json.Marshal(map[string]string{ + "orgId": "1", + }) + require.NoError(t, err) + + req, err = http.NewRequestWithContext(pmmapitests.Context, http.MethodPatch, u.String(), bytes.NewReader(data)) + require.NoError(t, err) + + req.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp1, b := doRequest(t, http.DefaultClient, req) + defer resp1.Body.Close() //nolint:errcheck + + require.Equalf(t, http.StatusCreated, resp.StatusCode, "failed to set orgId=1 to Service account, status code: %d, response: %s", resp.StatusCode, b) + + return serviceAccountID +} + +func deleteServiceAccount(t *testing.T, serviceAccountID int) { + t.Helper() + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.Path = fmt.Sprintf("/graph/api/serviceaccounts/%d", serviceAccountID) + + req, err := http.NewRequestWithContext(pmmapitests.Context, http.MethodDelete, u.String(), nil) + require.NoError(t, err) + + resp, b := doRequest(t, http.DefaultClient, req) + defer resp.Body.Close() //nolint:gosec,errcheck,nolintlint + + require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to delete service account, status code: %d, response: %s", resp.StatusCode, b) +} + +func createServiceToken(t *testing.T, serviceAccountID int, nodeName string) (int, string) { + t.Helper() + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.Path = fmt.Sprintf("/graph/api/serviceaccounts/%d/tokens", serviceAccountID) + + name := fmt.Sprintf("%s-%s", pmmServiceTokenName, nodeName) + data, err := json.Marshal(map[string]string{ + "name": name, + }) + require.NoError(t, err) + + req, err := http.NewRequestWithContext(pmmapitests.Context, http.MethodPost, u.String(), bytes.NewReader(data)) + require.NoError(t, err) + + req.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp, b := doRequest(t, http.DefaultClient, req) + defer resp.Body.Close() //nolint:gosec,errcheck,nolintlint + + require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to create Service account, status code: %d, response: %s", resp.StatusCode, b) + + var m map[string]interface{} + err = json.Unmarshal(b, &m) + require.NoError(t, err) + + return int(m["id"].(float64)), m["key"].(string) +} + +func deleteServiceToken(t *testing.T, serviceAccountID, serviceTokenID int) { + t.Helper() + u, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + u.Path = fmt.Sprintf("/graph/api/serviceaccounts/%d/tokens/%d", serviceAccountID, serviceTokenID) + + req, err := http.NewRequestWithContext(pmmapitests.Context, http.MethodDelete, u.String(), nil) + require.NoError(t, err) + + resp, b := doRequest(t, http.DefaultClient, req) + defer resp.Body.Close() //nolint:errcheck + + require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to delete service token, status code: %d, response: %s", resp.StatusCode, b) +} diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index 73bc76e1cf..21b8346e4b 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -2070,7 +2070,7 @@ type ServiceInfoResponse struct { // A list of PostgreSQL databases. DatabaseList []string `protobuf:"bytes,4,rep,name=database_list,json=databaseList,proto3" json:"database_list,omitempty"` // A version of pg_stat_monitor, empty if unavailable. - PgsmVersion string `protobuf:"bytes,5,opt,name=pgsm_version,json=pgsmVersion,proto3" json:"pgsm_version,omitempty"` + PgsmVersion *string `protobuf:"bytes,5,opt,name=pgsm_version,json=pgsmVersion,proto3,oneof" json:"pgsm_version,omitempty"` } func (x *ServiceInfoResponse) Reset() { @@ -2134,8 +2134,8 @@ func (x *ServiceInfoResponse) GetDatabaseList() []string { } func (x *ServiceInfoResponse) GetPgsmVersion() string { - if x != nil { - return x.PgsmVersion + if x != nil && x.PgsmVersion != nil { + return *x.PgsmVersion } return "" } @@ -7233,7 +7233,7 @@ var file_agent_v1_agent_proto_rawDesc = []byte{ 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x09, 0x74, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6c, 0x73, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x74, 0x6c, 0x73, 0x53, - 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x22, 0xae, 0x01, 0x0a, 0x13, 0x53, 0x65, + 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, @@ -7242,101 +7242,129 @@ var file_agent_v1_agent_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x67, 0x73, 0x6d, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, - 0x67, 0x73, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x0a, 0x10, 0x4a, 0x6f, - 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, - 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x29, 0x0a, 0x11, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, - 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, - 0x22, 0xb2, 0x01, 0x0a, 0x10, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, - 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, - 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x0a, 0x18, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xd3, 0x0d, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, - 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, - 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x12, 0x60, 0x0a, 0x14, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, - 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x12, 0x50, 0x0a, 0x0e, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x66, 0x0a, 0x16, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, + 0x61, 0x73, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x67, 0x73, 0x6d, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x0b, 0x70, 0x67, 0x73, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, + 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x67, 0x73, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x22, 0x29, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x29, 0x0a, 0x11, 0x4a, + 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x22, 0xb2, 0x01, 0x0a, 0x10, 0x53, 0x33, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x0a, 0x18, 0x46, + 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xd3, 0x0d, 0x0a, 0x0f, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6d, + 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, + 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x79, 0x73, 0x71, + 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x60, 0x0a, 0x14, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x14, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x96, 0x02, - 0x0a, 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x0a, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x63, - 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 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, 0x12, + 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x50, 0x0a, 0x0e, 0x6d, 0x6f, 0x6e, + 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, + 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x6f, + 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x66, 0x0a, 0x16, 0x6d, + 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x14, 0x6d, + 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x1a, 0x96, 0x02, 0x0a, 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 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, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0xc6, 0x01, 0x0a, + 0x12, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x39, + 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, + 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x0b, + 0x10, 0x0c, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0xf8, 0x02, 0x0a, 0x0d, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, + 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x6e, 0x12, 0x32, 0x0a, 0x0a, 0x74, 0x65, 0x78, + 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x52, 0x09, 0x74, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x74, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x69, 0x74, 0x72, 0x12, 0x33, 0x0a, 0x0a, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, + 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, - 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, - 0x0b, 0x10, 0x0c, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0xc6, 0x01, 0x0a, 0x12, 0x4d, 0x79, 0x53, 0x51, 0x4c, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x52, 0x11, 0x66, 0x69, - 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, - 0xf8, 0x02, 0x0a, 0x0d, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x64, 0x73, 0x6e, 0x12, 0x32, 0x0a, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x09, 0x74, 0x65, - 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, - 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, - 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x69, - 0x74, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x50, 0x69, 0x74, 0x72, 0x12, 0x33, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, - 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, - 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x33, 0x5f, + 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x51, 0x0a, 0x11, 0x66, 0x69, + 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x10, 0x66, 0x69, 0x6c, + 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, + 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x1a, 0xa7, 0x03, 0x0a, 0x14, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x6e, 0x12, 0x32, 0x0a, 0x0a, 0x74, + 0x65, 0x78, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x46, + 0x69, 0x6c, 0x65, 0x73, 0x52, 0x09, 0x74, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x70, + 0x62, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x62, + 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, 0x62, 0x6d, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x69, 0x74, 0x72, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x69, 0x74, 0x72, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, @@ -7346,329 +7374,303 @@ var file_agent_v1_agent_proto_rawDesc = []byte{ 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0xa7, 0x03, 0x0a, 0x14, 0x4d, - 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x64, 0x73, 0x6e, 0x12, 0x32, 0x0a, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x66, 0x69, - 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x09, - 0x74, 0x65, 0x78, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, - 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x70, 0x62, 0x6d, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x62, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, 0x62, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x69, 0x74, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x51, - 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, - 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x42, 0x05, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x28, 0x0a, 0x10, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x27, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x11, - 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0xea, 0x05, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, - 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x31, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x0c, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, - 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x79, - 0x73, 0x71, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x5a, 0x0a, 0x14, 0x6d, 0x79, 0x73, - 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, 0x79, 0x53, - 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, - 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x4a, 0x0a, 0x0e, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, - 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x05, 0x0a, 0x03, 0x6a, 0x6f, + 0x62, 0x22, 0x28, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x27, 0x0a, 0x0e, 0x53, + 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, + 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, + 0x6f, 0x62, 0x49, 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x05, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x31, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x0c, 0x6d, 0x79, 0x73, + 0x71, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, + 0x5a, 0x0a, 0x14, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x12, 0x60, 0x0a, 0x16, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x72, 0x65, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x14, 0x6d, - 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x1a, 0x21, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x6e, 0x0a, 0x0d, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, - 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x73, 0x5f, 0x73, 0x68, - 0x61, 0x72, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x53, 0x68, 0x61, 0x72, 0x64, 0x65, 0x64, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3e, 0x0a, 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x14, 0x0a, 0x12, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, - 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x16, 0x0a, 0x14, - 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xb0, - 0x03, 0x0a, 0x0b, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x15, - 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x46, 0x0a, 0x0c, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x79, 0x53, - 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x79, 0x73, 0x71, - 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x5c, 0x0a, 0x14, 0x6d, 0x79, 0x73, 0x71, 0x6c, - 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x79, 0x53, - 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, - 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x30, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, - 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x48, - 0x00, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x1a, 0x0d, 0x0a, 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x14, 0x0a, 0x12, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, - 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x49, 0x0a, 0x04, - 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0xb2, 0x04, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x09, 0x73, 0x6f, 0x66, 0x74, - 0x77, 0x61, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x52, 0x09, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x73, 0x1a, 0x08, 0x0a, - 0x06, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x64, 0x1a, 0x0c, 0x0a, 0x0a, 0x58, 0x74, 0x72, 0x61, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x09, 0x0a, 0x07, 0x58, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, - 0x1a, 0x08, 0x0a, 0x06, 0x51, 0x70, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x09, 0x0a, 0x07, 0x4d, 0x6f, - 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x1a, 0x05, 0x0a, 0x03, 0x50, 0x42, 0x4d, 0x1a, 0x97, 0x03, 0x0a, - 0x08, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x6d, 0x79, 0x73, - 0x71, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x64, 0x48, 0x00, - 0x52, 0x06, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x64, 0x12, 0x49, 0x0a, 0x0a, 0x78, 0x74, 0x72, 0x61, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x58, 0x74, 0x72, 0x61, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0a, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x12, 0x40, 0x0a, 0x07, 0x78, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x58, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x48, 0x00, 0x52, 0x07, 0x78, 0x62, - 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x12, 0x3d, 0x0a, 0x06, 0x71, 0x70, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x51, 0x70, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x06, 0x71, 0x70, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x0a, 0x06, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x6f, - 0x6e, 0x67, 0x6f, 0x64, 0x12, 0x34, 0x0a, 0x03, 0x70, 0x62, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x6c, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x4a, 0x0a, 0x0e, 0x6d, + 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, + 0x62, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x60, 0x0a, 0x16, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, + 0x64, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, + 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x48, 0x00, 0x52, 0x14, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x21, 0x0a, 0x05, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x6e, 0x0a, 0x0d, + 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2c, 0x0a, + 0x12, 0x69, 0x73, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x53, 0x68, 0x61, + 0x72, 0x64, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3e, 0x0a, 0x0b, + 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x14, 0x0a, 0x12, + 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x1a, 0x16, 0x0a, 0x14, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x22, 0xb0, 0x03, 0x0a, 0x0b, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x46, 0x0a, 0x0c, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, + 0x73, 0x73, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, + 0x52, 0x0b, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x5c, 0x0a, + 0x14, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, + 0x73, 0x73, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x30, 0x0a, 0x04, 0x6c, + 0x6f, 0x67, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, + 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x1a, 0x0d, 0x0a, + 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x14, 0x0a, 0x12, + 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x1a, 0x49, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, + 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x68, + 0x75, 0x6e, 0x6b, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x42, 0x08, 0x0a, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xb2, 0x04, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, + 0x0a, 0x09, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x50, 0x42, 0x4d, 0x48, 0x00, 0x52, 0x03, 0x70, 0x62, 0x6d, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x6f, - 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, - 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x1a, 0x39, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xb2, 0x09, 0x0a, - 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0xff, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x70, 0x69, - 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x44, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x0b, 0x71, 0x61, 0x6e, 0x5f, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x41, 0x4e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x71, 0x61, 0x6e, 0x43, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x44, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x34, 0x0a, 0x0a, - 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x12, 0x3a, 0x0a, 0x0c, 0x6a, 0x6f, 0x62, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x48, - 0x00, 0x52, 0x0b, 0x6a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, - 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, - 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x42, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x70, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6a, 0x6f, - 0x62, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x12, - 0x36, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x1a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, - 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x07, - 0x73, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x12, 0x3c, 0x0a, 0x0a, 0x6a, 0x6f, 0x62, 0x5f, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, + 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x52, 0x09, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x73, 0x1a, 0x08, 0x0a, 0x06, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x64, 0x1a, 0x0c, 0x0a, + 0x0a, 0x58, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, 0x09, 0x0a, 0x07, 0x58, + 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x1a, 0x08, 0x0a, 0x06, 0x51, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x1a, 0x09, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x1a, 0x05, 0x0a, 0x03, 0x50, + 0x42, 0x4d, 0x1a, 0x97, 0x03, 0x0a, 0x08, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x12, + 0x3d, 0x0a, 0x06, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x79, + 0x53, 0x51, 0x4c, 0x64, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x64, 0x12, 0x49, + 0x0a, 0x0a, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x2e, 0x58, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0a, 0x78, + 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x40, 0x0a, 0x07, 0x78, 0x62, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x58, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x48, 0x00, 0x52, 0x07, 0x78, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x12, 0x3d, 0x0a, 0x06, 0x71, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x65, - 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x0f, 0x70, 0x62, 0x6d, - 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5f, 0x70, 0x69, 0x74, 0x72, 0x18, 0x1d, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x42, - 0x4d, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x50, 0x49, 0x54, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x62, 0x6d, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, - 0x50, 0x69, 0x74, 0x72, 0x12, 0x3c, 0x0a, 0x0a, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, - 0x67, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, - 0x67, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x22, 0xb9, 0x08, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x51, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x48, 0x00, 0x52, 0x06, 0x71, 0x70, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x0a, 0x06, 0x6d, 0x6f, + 0x6e, 0x67, 0x6f, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, + 0x48, 0x00, 0x52, 0x06, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x12, 0x34, 0x0a, 0x03, 0x70, 0x62, + 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x42, 0x4d, 0x48, 0x00, 0x52, 0x03, 0x70, 0x62, 0x6d, + 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22, 0x93, 0x01, 0x0a, + 0x13, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x39, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x22, 0xb2, 0x09, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0xff, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x24, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x48, 0x00, - 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x45, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x12, 0x24, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x48, 0x00, + 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x44, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x3f, 0x0a, - 0x0b, 0x71, 0x61, 0x6e, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x41, - 0x4e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x48, 0x00, 0x52, 0x0a, 0x71, 0x61, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x45, - 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x73, - 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x08, 0x73, 0x65, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x0b, + 0x71, 0x61, 0x6e, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x41, 0x4e, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x0a, 0x71, 0x61, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x44, 0x0a, 0x0d, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x09, 0x6a, + 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3a, 0x0a, 0x0c, 0x6a, 0x6f, 0x62, 0x5f, + 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x0b, 0x6a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, + 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x65, + 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x73, 0x65, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x42, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x70, - 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, - 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x18, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, - 0x62, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x1a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x07, 0x73, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x12, 0x3b, 0x0a, 0x0a, 0x6a, 0x6f, 0x62, 0x5f, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x41, 0x0a, 0x0c, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x65, 0x74, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x48, 0x0a, 0x0f, 0x70, 0x62, 0x6d, 0x5f, - 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5f, 0x70, 0x69, 0x74, 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x42, 0x4d, - 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x50, 0x49, 0x54, 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x62, 0x6d, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x50, 0x69, - 0x74, 0x72, 0x12, 0x3b, 0x0a, 0x0a, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, - 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x00, 0x52, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, - 0x41, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2a, 0xc8, 0x01, - 0x0a, 0x18, 0x4d, 0x79, 0x73, 0x71, 0x6c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x2b, 0x0a, 0x27, 0x4d, 0x59, - 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x50, - 0x55, 0x54, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x59, 0x53, 0x51, 0x4c, - 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, - 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x01, - 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0b, 0x73, 0x74, 0x6f, + 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, + 0x73, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x10, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x18, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, + 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x36, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x6a, 0x6f, + 0x62, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x12, 0x3c, 0x0a, + 0x0a, 0x6a, 0x6f, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, + 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x67, + 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x48, 0x00, 0x52, 0x0b, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x49, 0x0a, 0x0f, 0x70, 0x62, 0x6d, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5f, 0x70, 0x69, + 0x74, 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x42, 0x4d, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x50, 0x49, 0x54, + 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x62, 0x6d, + 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x50, 0x69, 0x74, 0x72, 0x12, 0x3c, 0x0a, 0x0a, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4c, + 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x09, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, + 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x09, 0x0a, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xb9, 0x08, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0xff, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x6f, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x45, 0x0a, 0x0d, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x12, 0x3f, 0x0a, 0x0b, 0x71, 0x61, 0x6e, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x41, 0x4e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x71, 0x61, 0x6e, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x12, 0x45, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x70, + 0x69, 0x6e, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, + 0x67, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x15, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x08, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, + 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x17, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, + 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, + 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x08, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x70, 0x5f, + 0x6a, 0x6f, 0x62, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x12, 0x3b, + 0x0a, 0x0a, 0x6a, 0x6f, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x1b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, + 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x41, 0x0a, 0x0c, 0x67, + 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x0b, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x48, + 0x0a, 0x0f, 0x70, 0x62, 0x6d, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5f, 0x70, 0x69, 0x74, + 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x42, 0x4d, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x50, 0x49, 0x54, 0x52, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x62, 0x6d, 0x53, 0x77, + 0x69, 0x74, 0x63, 0x68, 0x50, 0x69, 0x74, 0x72, 0x12, 0x3b, 0x0a, 0x0a, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x09, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x2a, 0xc8, 0x01, 0x0a, 0x18, 0x4d, 0x79, 0x73, 0x71, 0x6c, 0x45, 0x78, 0x70, + 0x6c, 0x61, 0x69, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x12, 0x2b, 0x0a, 0x27, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, - 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x27, 0x0a, + 0x23, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x5f, 0x4f, + 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x44, 0x45, 0x46, + 0x41, 0x55, 0x4c, 0x54, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x46, - 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x54, 0x52, 0x41, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x41, - 0x4c, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x03, 0x32, 0x4e, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x12, 0x16, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x88, 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x08, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x14, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x09, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, + 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x5f, 0x4f, 0x55, + 0x54, 0x50, 0x55, 0x54, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x54, 0x52, 0x41, 0x44, + 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x03, 0x32, 0x4e, + 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, + 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x16, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x88, + 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, + 0x0a, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, + 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, + 0x76, 0x31, 0x3b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, + 0xaa, 0x02, 0x08, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x08, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x14, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x09, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -9018,6 +9020,7 @@ func file_agent_v1_agent_proto_init() { (*StartActionRequest_MongodbQueryGetdiagnosticdataParams)(nil), (*StartActionRequest_RestartSysServiceParams)(nil), } + file_agent_v1_agent_proto_msgTypes[27].OneofWrappers = []interface{}{} file_agent_v1_agent_proto_msgTypes[32].OneofWrappers = []interface{}{ (*StartJobRequest_MysqlBackup)(nil), (*StartJobRequest_MysqlRestoreBackup)(nil), diff --git a/api/agent/v1/agent.pb.validate.go b/api/agent/v1/agent.pb.validate.go index 81ecc497d6..a6fb4bda41 100644 --- a/api/agent/v1/agent.pb.validate.go +++ b/api/agent/v1/agent.pb.validate.go @@ -4443,7 +4443,9 @@ func (m *ServiceInfoResponse) validate(all bool) error { // no validation rules for Version - // no validation rules for PgsmVersion + if m.PgsmVersion != nil { + // no validation rules for PgsmVersion + } if len(errors) > 0 { return ServiceInfoResponseMultiError(errors) diff --git a/api/agent/v1/agent.proto b/api/agent/v1/agent.proto index 482ae810ad..718eeb0802 100644 --- a/api/agent/v1/agent.proto +++ b/api/agent/v1/agent.proto @@ -471,7 +471,7 @@ message ServiceInfoResponse { // A list of PostgreSQL databases. repeated string database_list = 4; // A version of pg_stat_monitor, empty if unavailable. - string pgsm_version = 5; + optional string pgsm_version = 5; } // JobStatusRequest is a ServerMessage asking pmm-agent for job status. diff --git a/api/management/v1/json/client/management_service/management_service_client.go b/api/management/v1/json/client/management_service/management_service_client.go index 5e0c2a738b..22fb58f103 100644 --- a/api/management/v1/json/client/management_service/management_service_client.go +++ b/api/management/v1/json/client/management_service/management_service_client.go @@ -38,6 +38,8 @@ type ClientService interface { RemoveService(params *RemoveServiceParams, opts ...ClientOption) (*RemoveServiceOK, error) + UnregisterNode(params *UnregisterNodeParams, opts ...ClientOption) (*UnregisterNodeOK, error) + SetTransport(transport runtime.ClientTransport) } @@ -236,6 +238,45 @@ func (a *Client) RemoveService(params *RemoveServiceParams, opts ...ClientOption return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +UnregisterNode unregisters node + +Unregisters a Node and pmm-agent +*/ +func (a *Client) UnregisterNode(params *UnregisterNodeParams, opts ...ClientOption) (*UnregisterNodeOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewUnregisterNodeParams() + } + op := &runtime.ClientOperation{ + ID: "UnregisterNode", + Method: "POST", + PathPattern: "/v1/management/Node/Unregister", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &UnregisterNodeReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*UnregisterNodeOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*UnregisterNodeDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport diff --git a/api/management/v1/json/client/management_service/unregister_node_parameters.go b/api/management/v1/json/client/management_service/unregister_node_parameters.go new file mode 100644 index 0000000000..e1e2684fdc --- /dev/null +++ b/api/management/v1/json/client/management_service/unregister_node_parameters.go @@ -0,0 +1,144 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package management_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewUnregisterNodeParams creates a new UnregisterNodeParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewUnregisterNodeParams() *UnregisterNodeParams { + return &UnregisterNodeParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUnregisterNodeParamsWithTimeout creates a new UnregisterNodeParams object +// with the ability to set a timeout on a request. +func NewUnregisterNodeParamsWithTimeout(timeout time.Duration) *UnregisterNodeParams { + return &UnregisterNodeParams{ + timeout: timeout, + } +} + +// NewUnregisterNodeParamsWithContext creates a new UnregisterNodeParams object +// with the ability to set a context for a request. +func NewUnregisterNodeParamsWithContext(ctx context.Context) *UnregisterNodeParams { + return &UnregisterNodeParams{ + Context: ctx, + } +} + +// NewUnregisterNodeParamsWithHTTPClient creates a new UnregisterNodeParams object +// with the ability to set a custom HTTPClient for a request. +func NewUnregisterNodeParamsWithHTTPClient(client *http.Client) *UnregisterNodeParams { + return &UnregisterNodeParams{ + HTTPClient: client, + } +} + +/* +UnregisterNodeParams contains all the parameters to send to the API endpoint + + for the unregister node operation. + + Typically these are written to a http.Request. +*/ +type UnregisterNodeParams struct { + // Body. + Body UnregisterNodeBody + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the unregister node params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UnregisterNodeParams) WithDefaults() *UnregisterNodeParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the unregister node params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UnregisterNodeParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the unregister node params +func (o *UnregisterNodeParams) WithTimeout(timeout time.Duration) *UnregisterNodeParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the unregister node params +func (o *UnregisterNodeParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the unregister node params +func (o *UnregisterNodeParams) WithContext(ctx context.Context) *UnregisterNodeParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the unregister node params +func (o *UnregisterNodeParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the unregister node params +func (o *UnregisterNodeParams) WithHTTPClient(client *http.Client) *UnregisterNodeParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the unregister node params +func (o *UnregisterNodeParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the unregister node params +func (o *UnregisterNodeParams) WithBody(body UnregisterNodeBody) *UnregisterNodeParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the unregister node params +func (o *UnregisterNodeParams) SetBody(body UnregisterNodeBody) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *UnregisterNodeParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/management/v1/json/client/management_service/unregister_node_responses.go b/api/management/v1/json/client/management_service/unregister_node_responses.go new file mode 100644 index 0000000000..434c3d1343 --- /dev/null +++ b/api/management/v1/json/client/management_service/unregister_node_responses.go @@ -0,0 +1,337 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package management_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// UnregisterNodeReader is a Reader for the UnregisterNode structure. +type UnregisterNodeReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UnregisterNodeReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewUnregisterNodeOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewUnregisterNodeDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewUnregisterNodeOK creates a UnregisterNodeOK with default headers values +func NewUnregisterNodeOK() *UnregisterNodeOK { + return &UnregisterNodeOK{} +} + +/* +UnregisterNodeOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type UnregisterNodeOK struct { + Payload *UnregisterNodeOKBody +} + +func (o *UnregisterNodeOK) Error() string { + return fmt.Sprintf("[POST /v1/management/Node/Unregister][%d] unregisterNodeOk %+v", 200, o.Payload) +} + +func (o *UnregisterNodeOK) GetPayload() *UnregisterNodeOKBody { + return o.Payload +} + +func (o *UnregisterNodeOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UnregisterNodeOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewUnregisterNodeDefault creates a UnregisterNodeDefault with default headers values +func NewUnregisterNodeDefault(code int) *UnregisterNodeDefault { + return &UnregisterNodeDefault{ + _statusCode: code, + } +} + +/* +UnregisterNodeDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type UnregisterNodeDefault struct { + _statusCode int + + Payload *UnregisterNodeDefaultBody +} + +// Code gets the status code for the unregister node default response +func (o *UnregisterNodeDefault) Code() int { + return o._statusCode +} + +func (o *UnregisterNodeDefault) Error() string { + return fmt.Sprintf("[POST /v1/management/Node/Unregister][%d] UnregisterNode default %+v", o._statusCode, o.Payload) +} + +func (o *UnregisterNodeDefault) GetPayload() *UnregisterNodeDefaultBody { + return o.Payload +} + +func (o *UnregisterNodeDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UnregisterNodeDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +/* +UnregisterNodeBody unregister node body +swagger:model UnregisterNodeBody +*/ +type UnregisterNodeBody struct { + // Node_id to be unregistered. + NodeID string `json:"node_id,omitempty"` + + // Force delete node, related service account, even if it has more service tokens attached. + Force bool `json:"force,omitempty"` +} + +// Validate validates this unregister node body +func (o *UnregisterNodeBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this unregister node body based on context it is used +func (o *UnregisterNodeBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UnregisterNodeBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UnregisterNodeBody) UnmarshalBinary(b []byte) error { + var res UnregisterNodeBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UnregisterNodeDefaultBody unregister node default body +swagger:model UnregisterNodeDefaultBody +*/ +type UnregisterNodeDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*UnregisterNodeDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this unregister node default body +func (o *UnregisterNodeDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UnregisterNodeDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("UnregisterNode default" + "." + "details" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("UnregisterNode default" + "." + "details" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this unregister node default body based on the context it is used +func (o *UnregisterNodeDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UnregisterNodeDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("UnregisterNode default" + "." + "details" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("UnregisterNode default" + "." + "details" + "." + strconv.Itoa(i)) + } + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UnregisterNodeDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UnregisterNodeDefaultBody) UnmarshalBinary(b []byte) error { + var res UnregisterNodeDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UnregisterNodeDefaultBodyDetailsItems0 unregister node default body details items0 +swagger:model UnregisterNodeDefaultBodyDetailsItems0 +*/ +type UnregisterNodeDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` +} + +// Validate validates this unregister node default body details items0 +func (o *UnregisterNodeDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this unregister node default body details items0 based on context it is used +func (o *UnregisterNodeDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UnregisterNodeDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UnregisterNodeDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res UnregisterNodeDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UnregisterNodeOKBody unregister node OK body +swagger:model UnregisterNodeOKBody +*/ +type UnregisterNodeOKBody struct { + // Warning message if there are more service tokens attached to service account. + Warning string `json:"warning,omitempty"` +} + +// Validate validates this unregister node OK body +func (o *UnregisterNodeOKBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this unregister node OK body based on context it is used +func (o *UnregisterNodeOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UnregisterNodeOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UnregisterNodeOKBody) UnmarshalBinary(b []byte) error { + var res UnregisterNodeOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/management/v1/json/v1.json b/api/management/v1/json/v1.json index b8fc9a2b14..6a486aeee8 100644 --- a/api/management/v1/json/v1.json +++ b/api/management/v1/json/v1.json @@ -15,6 +15,84 @@ "version": "v1" }, "paths": { + "/v1/management/Node/Unregister": { + "post": { + "description": "Unregisters a Node and pmm-agent", + "tags": [ + "ManagementService" + ], + "summary": "Unregister Node", + "operationId": "UnregisterNode", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "force": { + "description": "Force delete node, related service account, even if it has more service tokens attached.", + "type": "boolean", + "x-order": 1 + }, + "node_id": { + "description": "Node_id to be unregistered.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "warning": { + "description": "Warning message if there are more service tokens attached to service account.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + }, + "message": { + "type": "string", + "x-order": 1 + } + } + } + } + } + } + }, "/v1/management/annotations": { "post": { "description": "Adds an annotation.", diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index c99b5d7fae..dbcd6293b8 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -422,6 +422,111 @@ func (*RemoveServiceResponse) Descriptor() ([]byte, []int) { return file_management_v1_service_proto_rawDescGZIP(), []int{3} } +type UnregisterNodeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Node_id to be unregistered. + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // Force delete node, related service account, even if it has more service tokens attached. + Force bool `protobuf:"varint,2,opt,name=force,proto3" json:"force,omitempty"` +} + +func (x *UnregisterNodeRequest) Reset() { + *x = UnregisterNodeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_management_v1_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnregisterNodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnregisterNodeRequest) ProtoMessage() {} + +func (x *UnregisterNodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_management_v1_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnregisterNodeRequest.ProtoReflect.Descriptor instead. +func (*UnregisterNodeRequest) Descriptor() ([]byte, []int) { + return file_management_v1_service_proto_rawDescGZIP(), []int{4} +} + +func (x *UnregisterNodeRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *UnregisterNodeRequest) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + +type UnregisterNodeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Warning message if there are more service tokens attached to service account. + Warning string `protobuf:"bytes,1,opt,name=warning,proto3" json:"warning,omitempty"` +} + +func (x *UnregisterNodeResponse) Reset() { + *x = UnregisterNodeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_management_v1_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnregisterNodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnregisterNodeResponse) ProtoMessage() {} + +func (x *UnregisterNodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_management_v1_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnregisterNodeResponse.ProtoReflect.Descriptor instead. +func (*UnregisterNodeResponse) Descriptor() ([]byte, []int) { + return file_management_v1_service_proto_rawDescGZIP(), []int{5} +} + +func (x *UnregisterNodeResponse) GetWarning() string { + if x != nil { + return x.Warning + } + return "" +} + var File_management_v1_service_proto protoreflect.FileDescriptor var file_management_v1_service_proto_rawDesc = []byte{ @@ -521,77 +626,97 @@ var file_management_v1_service_proto_rawDesc = []byte{ 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xa9, 0x07, 0x0a, 0x11, 0x4d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0xac, 0x01, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x50, 0x92, 0x41, - 0x28, 0x12, 0x11, 0x41, 0x64, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x41, 0x64, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6e, - 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, - 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0xb3, - 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, - 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x92, 0x41, 0x38, 0x12, 0x0f, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x25, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, - 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x6d, 0x6d, 0x2d, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, - 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x6e, - 0x6f, 0x64, 0x65, 0x73, 0x12, 0xb2, 0x01, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x92, 0x41, 0x3a, 0x12, 0x0d, 0x41, - 0x64, 0x64, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x29, 0x41, 0x64, - 0x64, 0x73, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x20, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, - 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0xaf, 0x01, 0x0a, 0x0b, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x59, 0x92, 0x41, 0x28, 0x12, 0x0c, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x20, - 0x52, 0x44, 0x53, 0x1a, 0x18, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x20, 0x52, - 0x44, 0x53, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x28, 0x3a, 0x01, 0x2a, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3a, - 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0xc7, 0x01, 0x0a, 0x0d, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x15, 0x55, 0x6e, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, + 0x65, 0x22, 0x32, 0x0a, 0x16, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x77, + 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x61, + 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x32, 0xea, 0x08, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xac, 0x01, 0x0a, 0x0d, + 0x41, 0x64, 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, + 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x92, 0x41, 0x3c, 0x12, 0x10, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, - 0x28, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, - 0x73, 0x20, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x2a, - 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x42, 0xad, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x35, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, - 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, 0x58, 0x58, 0xaa, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, 0x4d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x50, 0x92, 0x41, 0x28, 0x12, 0x11, 0x41, + 0x64, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x1a, 0x13, 0x41, 0x64, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, + 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x61, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0xb3, 0x01, 0x0a, 0x0c, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x92, 0x41, 0x38, 0x12, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x25, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x4e, 0x6f, 0x64, 0x65, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x6d, 0x6d, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, + 0x12, 0xbe, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, + 0x6f, 0x64, 0x65, 0x12, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, + 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x5f, 0x92, 0x41, 0x33, 0x12, 0x0f, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x20, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, + 0x6d, 0x6d, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x3a, 0x01, + 0x2a, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x2f, 0x4e, 0x6f, 0x64, 0x65, 0x2f, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x12, 0xb2, 0x01, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x92, 0x41, 0x3a, 0x12, 0x0d, 0x41, 0x64, 0x64, 0x20, + 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x29, 0x41, 0x64, 0x64, 0x73, 0x20, + 0x61, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, + 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0xaf, 0x01, 0x0a, 0x0b, 0x44, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, + 0x44, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x59, 0x92, + 0x41, 0x28, 0x12, 0x0c, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x52, 0x44, 0x53, + 0x1a, 0x18, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x20, 0x52, 0x44, 0x53, 0x20, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, + 0x3a, 0x01, 0x2a, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x64, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0xc7, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x92, 0x41, 0x3c, 0x12, 0x10, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x28, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, + 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x2a, 0x24, 0x2f, 0x76, + 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x7d, 0x42, 0xad, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, + 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x76, 0x31, 0xa2, + 0x02, 0x03, 0x4d, 0x58, 0x58, 0xaa, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x3a, + 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -607,64 +732,68 @@ func file_management_v1_service_proto_rawDescGZIP() []byte { } var ( - file_management_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4) + file_management_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) file_management_v1_service_proto_goTypes = []interface{}{ (*AddServiceRequest)(nil), // 0: management.v1.AddServiceRequest (*AddServiceResponse)(nil), // 1: management.v1.AddServiceResponse (*RemoveServiceRequest)(nil), // 2: management.v1.RemoveServiceRequest (*RemoveServiceResponse)(nil), // 3: management.v1.RemoveServiceResponse - (*AddMySQLServiceParams)(nil), // 4: management.v1.AddMySQLServiceParams - (*AddMongoDBServiceParams)(nil), // 5: management.v1.AddMongoDBServiceParams - (*AddPostgreSQLServiceParams)(nil), // 6: management.v1.AddPostgreSQLServiceParams - (*AddProxySQLServiceParams)(nil), // 7: management.v1.AddProxySQLServiceParams - (*AddHAProxyServiceParams)(nil), // 8: management.v1.AddHAProxyServiceParams - (*AddExternalServiceParams)(nil), // 9: management.v1.AddExternalServiceParams - (*AddRDSServiceParams)(nil), // 10: management.v1.AddRDSServiceParams - (*MySQLServiceResult)(nil), // 11: management.v1.MySQLServiceResult - (*MongoDBServiceResult)(nil), // 12: management.v1.MongoDBServiceResult - (*PostgreSQLServiceResult)(nil), // 13: management.v1.PostgreSQLServiceResult - (*ProxySQLServiceResult)(nil), // 14: management.v1.ProxySQLServiceResult - (*HAProxyServiceResult)(nil), // 15: management.v1.HAProxyServiceResult - (*ExternalServiceResult)(nil), // 16: management.v1.ExternalServiceResult - (*RDSServiceResult)(nil), // 17: management.v1.RDSServiceResult - (v1.ServiceType)(0), // 18: inventory.v1.ServiceType - (*AddAnnotationRequest)(nil), // 19: management.v1.AddAnnotationRequest - (*RegisterNodeRequest)(nil), // 20: management.v1.RegisterNodeRequest - (*DiscoverRDSRequest)(nil), // 21: management.v1.DiscoverRDSRequest - (*AddAnnotationResponse)(nil), // 22: management.v1.AddAnnotationResponse - (*RegisterNodeResponse)(nil), // 23: management.v1.RegisterNodeResponse - (*DiscoverRDSResponse)(nil), // 24: management.v1.DiscoverRDSResponse + (*UnregisterNodeRequest)(nil), // 4: management.v1.UnregisterNodeRequest + (*UnregisterNodeResponse)(nil), // 5: management.v1.UnregisterNodeResponse + (*AddMySQLServiceParams)(nil), // 6: management.v1.AddMySQLServiceParams + (*AddMongoDBServiceParams)(nil), // 7: management.v1.AddMongoDBServiceParams + (*AddPostgreSQLServiceParams)(nil), // 8: management.v1.AddPostgreSQLServiceParams + (*AddProxySQLServiceParams)(nil), // 9: management.v1.AddProxySQLServiceParams + (*AddHAProxyServiceParams)(nil), // 10: management.v1.AddHAProxyServiceParams + (*AddExternalServiceParams)(nil), // 11: management.v1.AddExternalServiceParams + (*AddRDSServiceParams)(nil), // 12: management.v1.AddRDSServiceParams + (*MySQLServiceResult)(nil), // 13: management.v1.MySQLServiceResult + (*MongoDBServiceResult)(nil), // 14: management.v1.MongoDBServiceResult + (*PostgreSQLServiceResult)(nil), // 15: management.v1.PostgreSQLServiceResult + (*ProxySQLServiceResult)(nil), // 16: management.v1.ProxySQLServiceResult + (*HAProxyServiceResult)(nil), // 17: management.v1.HAProxyServiceResult + (*ExternalServiceResult)(nil), // 18: management.v1.ExternalServiceResult + (*RDSServiceResult)(nil), // 19: management.v1.RDSServiceResult + (v1.ServiceType)(0), // 20: inventory.v1.ServiceType + (*AddAnnotationRequest)(nil), // 21: management.v1.AddAnnotationRequest + (*RegisterNodeRequest)(nil), // 22: management.v1.RegisterNodeRequest + (*DiscoverRDSRequest)(nil), // 23: management.v1.DiscoverRDSRequest + (*AddAnnotationResponse)(nil), // 24: management.v1.AddAnnotationResponse + (*RegisterNodeResponse)(nil), // 25: management.v1.RegisterNodeResponse + (*DiscoverRDSResponse)(nil), // 26: management.v1.DiscoverRDSResponse } ) var file_management_v1_service_proto_depIdxs = []int32{ - 4, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams - 5, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams - 6, // 2: management.v1.AddServiceRequest.postgresql:type_name -> management.v1.AddPostgreSQLServiceParams - 7, // 3: management.v1.AddServiceRequest.proxysql:type_name -> management.v1.AddProxySQLServiceParams - 8, // 4: management.v1.AddServiceRequest.haproxy:type_name -> management.v1.AddHAProxyServiceParams - 9, // 5: management.v1.AddServiceRequest.external:type_name -> management.v1.AddExternalServiceParams - 10, // 6: management.v1.AddServiceRequest.rds:type_name -> management.v1.AddRDSServiceParams - 11, // 7: management.v1.AddServiceResponse.mysql:type_name -> management.v1.MySQLServiceResult - 12, // 8: management.v1.AddServiceResponse.mongodb:type_name -> management.v1.MongoDBServiceResult - 13, // 9: management.v1.AddServiceResponse.postgresql:type_name -> management.v1.PostgreSQLServiceResult - 14, // 10: management.v1.AddServiceResponse.proxysql:type_name -> management.v1.ProxySQLServiceResult - 15, // 11: management.v1.AddServiceResponse.haproxy:type_name -> management.v1.HAProxyServiceResult - 16, // 12: management.v1.AddServiceResponse.external:type_name -> management.v1.ExternalServiceResult - 17, // 13: management.v1.AddServiceResponse.rds:type_name -> management.v1.RDSServiceResult - 18, // 14: management.v1.RemoveServiceRequest.service_type:type_name -> inventory.v1.ServiceType - 19, // 15: management.v1.ManagementService.AddAnnotation:input_type -> management.v1.AddAnnotationRequest - 20, // 16: management.v1.ManagementService.RegisterNode:input_type -> management.v1.RegisterNodeRequest - 0, // 17: management.v1.ManagementService.AddService:input_type -> management.v1.AddServiceRequest - 21, // 18: management.v1.ManagementService.DiscoverRDS:input_type -> management.v1.DiscoverRDSRequest - 2, // 19: management.v1.ManagementService.RemoveService:input_type -> management.v1.RemoveServiceRequest - 22, // 20: management.v1.ManagementService.AddAnnotation:output_type -> management.v1.AddAnnotationResponse - 23, // 21: management.v1.ManagementService.RegisterNode:output_type -> management.v1.RegisterNodeResponse - 1, // 22: management.v1.ManagementService.AddService:output_type -> management.v1.AddServiceResponse - 24, // 23: management.v1.ManagementService.DiscoverRDS:output_type -> management.v1.DiscoverRDSResponse - 3, // 24: management.v1.ManagementService.RemoveService:output_type -> management.v1.RemoveServiceResponse - 20, // [20:25] is the sub-list for method output_type - 15, // [15:20] is the sub-list for method input_type + 6, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams + 7, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams + 8, // 2: management.v1.AddServiceRequest.postgresql:type_name -> management.v1.AddPostgreSQLServiceParams + 9, // 3: management.v1.AddServiceRequest.proxysql:type_name -> management.v1.AddProxySQLServiceParams + 10, // 4: management.v1.AddServiceRequest.haproxy:type_name -> management.v1.AddHAProxyServiceParams + 11, // 5: management.v1.AddServiceRequest.external:type_name -> management.v1.AddExternalServiceParams + 12, // 6: management.v1.AddServiceRequest.rds:type_name -> management.v1.AddRDSServiceParams + 13, // 7: management.v1.AddServiceResponse.mysql:type_name -> management.v1.MySQLServiceResult + 14, // 8: management.v1.AddServiceResponse.mongodb:type_name -> management.v1.MongoDBServiceResult + 15, // 9: management.v1.AddServiceResponse.postgresql:type_name -> management.v1.PostgreSQLServiceResult + 16, // 10: management.v1.AddServiceResponse.proxysql:type_name -> management.v1.ProxySQLServiceResult + 17, // 11: management.v1.AddServiceResponse.haproxy:type_name -> management.v1.HAProxyServiceResult + 18, // 12: management.v1.AddServiceResponse.external:type_name -> management.v1.ExternalServiceResult + 19, // 13: management.v1.AddServiceResponse.rds:type_name -> management.v1.RDSServiceResult + 20, // 14: management.v1.RemoveServiceRequest.service_type:type_name -> inventory.v1.ServiceType + 21, // 15: management.v1.ManagementService.AddAnnotation:input_type -> management.v1.AddAnnotationRequest + 22, // 16: management.v1.ManagementService.RegisterNode:input_type -> management.v1.RegisterNodeRequest + 4, // 17: management.v1.ManagementService.UnregisterNode:input_type -> management.v1.UnregisterNodeRequest + 0, // 18: management.v1.ManagementService.AddService:input_type -> management.v1.AddServiceRequest + 23, // 19: management.v1.ManagementService.DiscoverRDS:input_type -> management.v1.DiscoverRDSRequest + 2, // 20: management.v1.ManagementService.RemoveService:input_type -> management.v1.RemoveServiceRequest + 24, // 21: management.v1.ManagementService.AddAnnotation:output_type -> management.v1.AddAnnotationResponse + 25, // 22: management.v1.ManagementService.RegisterNode:output_type -> management.v1.RegisterNodeResponse + 5, // 23: management.v1.ManagementService.UnregisterNode:output_type -> management.v1.UnregisterNodeResponse + 1, // 24: management.v1.ManagementService.AddService:output_type -> management.v1.AddServiceResponse + 26, // 25: management.v1.ManagementService.DiscoverRDS:output_type -> management.v1.DiscoverRDSResponse + 3, // 26: management.v1.ManagementService.RemoveService:output_type -> management.v1.RemoveServiceResponse + 21, // [21:27] is the sub-list for method output_type + 15, // [15:21] is the sub-list for method input_type 15, // [15:15] is the sub-list for extension type_name 15, // [15:15] is the sub-list for extension extendee 0, // [0:15] is the sub-list for field type_name @@ -733,6 +862,30 @@ func file_management_v1_service_proto_init() { return nil } } + file_management_v1_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnregisterNodeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_management_v1_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnregisterNodeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_management_v1_service_proto_msgTypes[0].OneofWrappers = []interface{}{ (*AddServiceRequest_Mysql)(nil), @@ -758,7 +911,7 @@ func file_management_v1_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_management_v1_service_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/api/management/v1/service.pb.gw.go b/api/management/v1/service.pb.gw.go index 02d342601c..7455dfe908 100644 --- a/api/management/v1/service.pb.gw.go +++ b/api/management/v1/service.pb.gw.go @@ -81,6 +81,30 @@ func local_request_ManagementService_RegisterNode_0(ctx context.Context, marshal return msg, metadata, err } +func request_ManagementService_UnregisterNode_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UnregisterNodeRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UnregisterNode(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_ManagementService_UnregisterNode_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UnregisterNodeRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UnregisterNode(ctx, &protoReq) + return msg, metadata, err +} + func request_ManagementService_AddService_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq AddServiceRequest var metadata runtime.ServerMetadata @@ -248,6 +272,30 @@ func RegisterManagementServiceHandlerServer(ctx context.Context, mux *runtime.Se forward_ManagementService_RegisterNode_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("POST", pattern_ManagementService_UnregisterNode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/management.v1.ManagementService/UnregisterNode", runtime.WithHTTPPathPattern("/v1/management/Node/Unregister")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ManagementService_UnregisterNode_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ManagementService_UnregisterNode_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle("POST", pattern_ManagementService_AddService_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -402,6 +450,27 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se forward_ManagementService_RegisterNode_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("POST", pattern_ManagementService_UnregisterNode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/management.v1.ManagementService/UnregisterNode", runtime.WithHTTPPathPattern("/v1/management/Node/Unregister")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ManagementService_UnregisterNode_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ManagementService_UnregisterNode_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle("POST", pattern_ManagementService_AddService_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -473,6 +542,8 @@ var ( pattern_ManagementService_RegisterNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "management", "nodes"}, "")) + pattern_ManagementService_UnregisterNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "management", "Node", "Unregister"}, "")) + pattern_ManagementService_AddService_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "management", "services"}, "")) pattern_ManagementService_DiscoverRDS_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "management", "services"}, "discoverRDS")) @@ -485,6 +556,8 @@ var ( forward_ManagementService_RegisterNode_0 = runtime.ForwardResponseMessage + forward_ManagementService_UnregisterNode_0 = runtime.ForwardResponseMessage + forward_ManagementService_AddService_0 = runtime.ForwardResponseMessage forward_ManagementService_DiscoverRDS_0 = runtime.ForwardResponseMessage diff --git a/api/management/v1/service.pb.validate.go b/api/management/v1/service.pb.validate.go index b93d85072f..11246d3539 100644 --- a/api/management/v1/service.pb.validate.go +++ b/api/management/v1/service.pb.validate.go @@ -1034,3 +1034,213 @@ var _ interface { Cause() error ErrorName() string } = RemoveServiceResponseValidationError{} + +// Validate checks the field values on UnregisterNodeRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UnregisterNodeRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UnregisterNodeRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// UnregisterNodeRequestMultiError, or nil if none found. +func (m *UnregisterNodeRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *UnregisterNodeRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for NodeId + + // no validation rules for Force + + if len(errors) > 0 { + return UnregisterNodeRequestMultiError(errors) + } + + return nil +} + +// UnregisterNodeRequestMultiError is an error wrapping multiple validation +// errors returned by UnregisterNodeRequest.ValidateAll() if the designated +// constraints aren't met. +type UnregisterNodeRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UnregisterNodeRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UnregisterNodeRequestMultiError) AllErrors() []error { return m } + +// UnregisterNodeRequestValidationError is the validation error returned by +// UnregisterNodeRequest.Validate if the designated constraints aren't met. +type UnregisterNodeRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UnregisterNodeRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UnregisterNodeRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UnregisterNodeRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UnregisterNodeRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UnregisterNodeRequestValidationError) ErrorName() string { + return "UnregisterNodeRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e UnregisterNodeRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUnregisterNodeRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = UnregisterNodeRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UnregisterNodeRequestValidationError{} + +// Validate checks the field values on UnregisterNodeResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UnregisterNodeResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UnregisterNodeResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// UnregisterNodeResponseMultiError, or nil if none found. +func (m *UnregisterNodeResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *UnregisterNodeResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Warning + + if len(errors) > 0 { + return UnregisterNodeResponseMultiError(errors) + } + + return nil +} + +// UnregisterNodeResponseMultiError is an error wrapping multiple validation +// errors returned by UnregisterNodeResponse.ValidateAll() if the designated +// constraints aren't met. +type UnregisterNodeResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UnregisterNodeResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UnregisterNodeResponseMultiError) AllErrors() []error { return m } + +// UnregisterNodeResponseValidationError is the validation error returned by +// UnregisterNodeResponse.Validate if the designated constraints aren't met. +type UnregisterNodeResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UnregisterNodeResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UnregisterNodeResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UnregisterNodeResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UnregisterNodeResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UnregisterNodeResponseValidationError) ErrorName() string { + return "UnregisterNodeResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e UnregisterNodeResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUnregisterNodeResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = UnregisterNodeResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UnregisterNodeResponseValidationError{} diff --git a/api/management/v1/service.proto b/api/management/v1/service.proto index e0896d3d8b..92b38275f9 100644 --- a/api/management/v1/service.proto +++ b/api/management/v1/service.proto @@ -48,6 +48,18 @@ message RemoveServiceRequest { message RemoveServiceResponse {} +message UnregisterNodeRequest { + // Node_id to be unregistered. + string node_id = 1; + // Force delete node, related service account, even if it has more service tokens attached. + bool force = 2; +} + +message UnregisterNodeResponse { + // Warning message if there are more service tokens attached to service account. + string warning = 1; +} + // ManagementService provides public methods for managing and querying Services. service ManagementService { // AddAnnotation adds an annotation. @@ -72,7 +84,17 @@ service ManagementService { description: "Registers a new Node and a pmm-agent." }; } - + // UnregisterNode unregisters a Node, pmm-agent and removes the service account and its token. + rpc UnregisterNode(UnregisterNodeRequest) returns (UnregisterNodeResponse) { + option (google.api.http) = { + post: "/v1/management/Node/Unregister" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Unregister Node" + description: "Unregisters a Node and pmm-agent" + }; + } // AddExternal adds external service and adds external exporter. // It automatically adds a service to inventory, which is running on provided "node_id", // then adds an "external exporter" agent to inventory, which is running on provided "runs_on_node_id". diff --git a/api/management/v1/service_grpc.pb.go b/api/management/v1/service_grpc.pb.go index 4076f364bf..b4e086e459 100644 --- a/api/management/v1/service_grpc.pb.go +++ b/api/management/v1/service_grpc.pb.go @@ -20,11 +20,12 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - ManagementService_AddAnnotation_FullMethodName = "/management.v1.ManagementService/AddAnnotation" - ManagementService_RegisterNode_FullMethodName = "/management.v1.ManagementService/RegisterNode" - ManagementService_AddService_FullMethodName = "/management.v1.ManagementService/AddService" - ManagementService_DiscoverRDS_FullMethodName = "/management.v1.ManagementService/DiscoverRDS" - ManagementService_RemoveService_FullMethodName = "/management.v1.ManagementService/RemoveService" + ManagementService_AddAnnotation_FullMethodName = "/management.v1.ManagementService/AddAnnotation" + ManagementService_RegisterNode_FullMethodName = "/management.v1.ManagementService/RegisterNode" + ManagementService_UnregisterNode_FullMethodName = "/management.v1.ManagementService/UnregisterNode" + ManagementService_AddService_FullMethodName = "/management.v1.ManagementService/AddService" + ManagementService_DiscoverRDS_FullMethodName = "/management.v1.ManagementService/DiscoverRDS" + ManagementService_RemoveService_FullMethodName = "/management.v1.ManagementService/RemoveService" ) // ManagementServiceClient is the client API for ManagementService service. @@ -35,6 +36,8 @@ type ManagementServiceClient interface { AddAnnotation(ctx context.Context, in *AddAnnotationRequest, opts ...grpc.CallOption) (*AddAnnotationResponse, error) // RegisterNode registers a new Node and a pmm-agent. RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error) + // UnregisterNode unregisters a Node, pmm-agent and removes the service account and its token. + UnregisterNode(ctx context.Context, in *UnregisterNodeRequest, opts ...grpc.CallOption) (*UnregisterNodeResponse, error) // AddService adds a Service and starts several Agents. AddService(ctx context.Context, in *AddServiceRequest, opts ...grpc.CallOption) (*AddServiceResponse, error) // DiscoverRDS discovers RDS instances. @@ -69,6 +72,15 @@ func (c *managementServiceClient) RegisterNode(ctx context.Context, in *Register return out, nil } +func (c *managementServiceClient) UnregisterNode(ctx context.Context, in *UnregisterNodeRequest, opts ...grpc.CallOption) (*UnregisterNodeResponse, error) { + out := new(UnregisterNodeResponse) + err := c.cc.Invoke(ctx, ManagementService_UnregisterNode_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *managementServiceClient) AddService(ctx context.Context, in *AddServiceRequest, opts ...grpc.CallOption) (*AddServiceResponse, error) { out := new(AddServiceResponse) err := c.cc.Invoke(ctx, ManagementService_AddService_FullMethodName, in, out, opts...) @@ -104,6 +116,8 @@ type ManagementServiceServer interface { AddAnnotation(context.Context, *AddAnnotationRequest) (*AddAnnotationResponse, error) // RegisterNode registers a new Node and a pmm-agent. RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error) + // UnregisterNode unregisters a Node, pmm-agent and removes the service account and its token. + UnregisterNode(context.Context, *UnregisterNodeRequest) (*UnregisterNodeResponse, error) // AddService adds a Service and starts several Agents. AddService(context.Context, *AddServiceRequest) (*AddServiceResponse, error) // DiscoverRDS discovers RDS instances. @@ -124,6 +138,10 @@ func (UnimplementedManagementServiceServer) RegisterNode(context.Context, *Regis return nil, status.Errorf(codes.Unimplemented, "method RegisterNode not implemented") } +func (UnimplementedManagementServiceServer) UnregisterNode(context.Context, *UnregisterNodeRequest) (*UnregisterNodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnregisterNode not implemented") +} + func (UnimplementedManagementServiceServer) AddService(context.Context, *AddServiceRequest) (*AddServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddService not implemented") } @@ -184,6 +202,24 @@ func _ManagementService_RegisterNode_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _ManagementService_UnregisterNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnregisterNodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ManagementServiceServer).UnregisterNode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ManagementService_UnregisterNode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ManagementServiceServer).UnregisterNode(ctx, req.(*UnregisterNodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _ManagementService_AddService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(AddServiceRequest) if err := dec(in); err != nil { @@ -253,6 +289,10 @@ var ManagementService_ServiceDesc = grpc.ServiceDesc{ MethodName: "RegisterNode", Handler: _ManagementService_RegisterNode_Handler, }, + { + MethodName: "UnregisterNode", + Handler: _ManagementService_UnregisterNode_Handler, + }, { MethodName: "AddService", Handler: _ManagementService_AddService_Handler, diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 7c688e093b..6a9f489592 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -17127,6 +17127,84 @@ } } }, + "/v1/management/Node/Unregister": { + "post": { + "description": "Unregisters a Node and pmm-agent", + "tags": [ + "ManagementService" + ], + "summary": "Unregister Node", + "operationId": "UnregisterNode", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "node_id": { + "description": "Node_id to be unregistered.", + "type": "string", + "x-order": 0 + }, + "force": { + "description": "Force delete node, related service account, even if it has more service tokens attached.", + "type": "boolean", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "warning": { + "description": "Warning message if there are more service tokens attached to service account.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/management/Service/List": { "post": { "description": "Returns a filtered list of Services.", diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index c8d7e7b884..2d99762336 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4689,6 +4689,84 @@ } } }, + "/v1/management/Node/Unregister": { + "post": { + "description": "Unregisters a Node and pmm-agent", + "tags": [ + "ManagementService" + ], + "summary": "Unregister Node", + "operationId": "UnregisterNode", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "node_id": { + "description": "Node_id to be unregistered.", + "type": "string", + "x-order": 0 + }, + "force": { + "description": "Force delete node, related service account, even if it has more service tokens attached.", + "type": "boolean", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "warning": { + "description": "Warning message if there are more service tokens attached to service account.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/management/annotations": { "post": { "description": "Adds an annotation.", diff --git a/build/Makefile b/build/Makefile index e88c9321b2..66da3fddb0 100644 --- a/build/Makefile +++ b/build/Makefile @@ -9,7 +9,7 @@ fetch: -o ${PACKER_CACHE_DIR}/id_rsa_vagrant chmod 600 ${PACKER_CACHE_DIR}/id_rsa_vagrant test -f ${PACKER_CACHE_DIR}/box/oracle9.ova \ - || curl -fL https://vagrantcloud.com/bento/boxes/oracle-9.0/versions/202207.20.0/providers/virtualbox.box -o ${PACKER_CACHE_DIR}/box/oracle9.ova + || curl -fL https://vagrantcloud.com/bento/boxes/oracle-9.3/versions/202401.31.0/providers/virtualbox.box -o ${PACKER_CACHE_DIR}/box/oracle9.ova # NOTE: image from vagrant registry is twice as large test -f ${PACKER_CACHE_DIR}/box/box.ovf \ @@ -24,11 +24,6 @@ pmm-ovf: fetch /usr/bin/packer build \ -only virtualbox-ovf -color=false packer/pmm.json | tee build.log -# NOTE: no difference between rc and dev-latest (i.e. pmm-ovf) ATM -pmm-ovf-rc: fetch - /usr/bin/packer build \ - -only virtualbox-ovf -color=false packer/pmm.json | tee build.log - pmm-digitalocean: packer build -only digitalocean -var 'single_disk=true' packer/pmm.json diff --git a/build/ansible/roles/initialization/tasks/main.yml b/build/ansible/roles/initialization/tasks/main.yml index 988eef564b..fdbe31c9b2 100644 --- a/build/ansible/roles/initialization/tasks/main.yml +++ b/build/ansible/roles/initialization/tasks/main.yml @@ -27,56 +27,61 @@ - name: Set need_upgrade fact set_fact: - need_upgrade: not pmm_current_version is version(pmm_image_version, '>=') + need_upgrade: "{{ pmm_current_version is version(pmm_image_version, '<') }}" - name: Print current PMM and image versions debug: msg: "Current version: {{ pmm_current_version }} Image Version: {{ pmm_image_version }}" -- name: Enable maintenance mode before upgrade - copy: - src: maintenance.html - dest: /usr/share/pmm-server/maintenance/ - owner: pmm - group: pmm - mode: 0644 - -- name: Upgrade dashboards - include_role: - name: dashboards - when: need_upgrade - -- name: Copy file with image version - copy: - src: /usr/share/percona-dashboards/VERSION - dest: /srv/grafana/PERCONA_DASHBOARDS_VERSION - owner: pmm - group: pmm - mode: 0644 - remote_src: yes - when: need_upgrade - -- name: Create a backup directory - file: - path: /srv/backup - state: directory - owner: pmm - group: pmm - mode: 0775 +- name: Print need_upgrade fact + debug: + msg: "Need upgrade: {{ need_upgrade }}" -# Note: we want to leave this for some time until we achieve stable builds -- name: Output pmm-managed logs - shell: sleep 10 && tail -n 300 /srv/logs/pmm-managed.log +- name: Perform upgrade tasks + block: + - name: Enable maintenance mode before upgrade + copy: + src: maintenance.html + dest: /usr/share/pmm-server/maintenance/ + owner: pmm + group: pmm + mode: 0644 + + - name: Upgrade dashboards + include_role: + name: dashboards + + - name: Copy file with image version + copy: + src: /usr/share/percona-dashboards/VERSION + dest: /srv/grafana/PERCONA_DASHBOARDS_VERSION + owner: pmm + group: pmm + mode: 0644 + remote_src: yes + + - name: Create a backup directory + file: + path: /srv/backup + state: directory + owner: pmm + group: pmm + mode: 0775 -- name: Wait for PMM to be ready - ansible.builtin.uri: - url: "http://127.0.0.1:7772/v1/server/readyz" - status_code: 200 - method: GET - retries: 20 - delay: 5 + # Note: we want to leave this for some time until we achieve stable builds + - name: Output pmm-managed logs + shell: sleep 10 && tail -n 300 /srv/logs/pmm-managed.log -- name: Disable maintenance mode - file: - state: absent - path: /usr/share/pmm-server/maintenance/maintenance.html + - name: Wait for PMM to be ready + ansible.builtin.uri: + url: "http://127.0.0.1:7772/v1/server/readyz" + status_code: 200 + method: GET + retries: 20 + delay: 5 + + - name: Disable maintenance mode + file: + state: absent + path: /usr/share/pmm-server/maintenance/maintenance.html + when: need_upgrade diff --git a/build/packages/rpm/server/SPECS/grafana.spec b/build/packages/rpm/server/SPECS/grafana.spec index 873df8558a..bd16ba3121 100644 --- a/build/packages/rpm/server/SPECS/grafana.spec +++ b/build/packages/rpm/server/SPECS/grafana.spec @@ -1,9 +1,9 @@ %global debug_package %{nil} -%global commit 93891204fab2b2be06011638422d3bd9869a1603 +%global commit f283b87d773da4ad61ca65660e72c084ac8f8716 %global shortcommit %(c=%{commit}; echo ${c:0:7}) %define build_timestamp %(date -u +"%y%m%d%H%M") -%define release 103 -%define grafana_version 10.2.3 +%define release 104 +%define grafana_version 10.4.0 %define full_pmm_version 2.0.0 %define full_version v%{grafana_version}-%{full_pmm_version} %define rpm_release %{release}.%{build_timestamp}.%{shortcommit}%{?dist} @@ -82,6 +82,9 @@ getent passwd pmm >/dev/null || echo "User pmm does not exist. Please create it exit 0 %changelog +* Tue Mar 12 2024 Matej Kubinec - 10.4.0-1 +- PMM-12991 Grafana 10.4.0 + * Tue Jan 16 2024 Matej Kubinec - 10.2.3-1 - PMM-12314 Grafana 10.2.3 diff --git a/build/packer/pmm.json b/build/packer/pmm.json index f243d13604..3262b48916 100644 --- a/build/packer/pmm.json +++ b/build/packer/pmm.json @@ -64,7 +64,7 @@ }, { "type": "virtualbox-ovf", - "vm_name": "PMM-Server-EL9-{{isotime \"2006-01-02-1504\"}}", + "vm_name": "PMM3-Server-{{isotime \"2006-01-02-1504\"}}", "export_opts": [ "--ovf10", "--manifest", diff --git a/build/scripts/install_tarball b/build/scripts/install_tarball index a250d8473d..4ca4ce6ba8 100755 --- a/build/scripts/install_tarball +++ b/build/scripts/install_tarball @@ -2,6 +2,31 @@ set -eu +# Usage instruction for the install_tarball script +usage () { + cat <=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -295,16 +295,63 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", "debug": "^4.3.4" }, "engines": { @@ -324,13 +371,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", + "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -341,18 +388,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz", + "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/utils": "7.3.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -367,10 +414,92 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", + "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -381,13 +510,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", + "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -433,21 +562,21 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz", + "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", "semver": "^7.5.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -457,13 +586,112 @@ "eslint": "^8.56.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", + "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.2.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2891,9 +3119,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/cli-tests/package.json b/cli-tests/package.json index f0c0b74dce..e971b719a3 100644 --- a/cli-tests/package.json +++ b/cli-tests/package.json @@ -16,16 +16,16 @@ "@types/luxon": "^3.4.0", "dotenv": "^16.4.0", "luxon": "^3.4.4", - "playwright": "^1.33.0", + "playwright": "^1.41.2", "promise-retry": "^2.0.1", "shelljs": "^0.8.5", - "typescript": "^5.3.3" + "typescript": "^5.4.2" }, "devDependencies": { "@types/promise-retry": "^1.1.3", "@types/shelljs": "^0.8.12", - "@typescript-eslint/eslint-plugin": "^7.1.0", - "@typescript-eslint/parser": "^7.1.0", + "@typescript-eslint/eslint-plugin": "^7.3.1", + "@typescript-eslint/parser": "^7.2.0", "eslint": "8.56", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^18.0.0", diff --git a/descriptor.bin b/descriptor.bin index bdfdbb1233..68df144fbe 100644 Binary files a/descriptor.bin and b/descriptor.bin differ diff --git a/docs/api/welcome/authentication.md b/docs/api/welcome/authentication.md index 6693f8765d..cec8d37873 100644 --- a/docs/api/welcome/authentication.md +++ b/docs/api/welcome/authentication.md @@ -12,7 +12,7 @@ PMM Server's user authentication is built on top of and is compatible with [Graf In this section we will talk about two main authentication mechanisms: - Basic HTTP authentication -- Bearer Authentication (Authentication with an API key) +- Bearer Authentication (Authentication with an Service Token or API key) ### Basic HTTP Authentication @@ -37,8 +37,23 @@ curl -X GET -u admin:admin -H 'Content-Type: application/json' https://127.0.0.1 ### Bearer Authentication -Bearer authentication (also called token authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The bearer token is a cryptic API key, which can be generated by the server admin from the Settings UI or via a respective API call (read more about how to generate an API key). The client must send the API key in the `Authorization` header when making requests to protected resources: +Bearer authentication (also called token authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The bearer token is a cryptic Service Token, or API key, which can be generated by the server admin from the Settings UI or via a respective API call (read more about how to generate Service token or API key). The client must send the Service Token/API key in the `Authorization` header when making requests to protected resources: +Service Token example: +```shell +curl -X GET -H 'Authorization: Bearer glsa_Fp0ggev31R58ueNJbJgYw7fIGfO3yKWH_746383ab' \ + -H 'Content-Type: application/json' https://127.0.0.1/v1/version +``` + +You can use the Service Token in basic authentication as well: + +```shell +curl -X GET -H 'Content-Type: application/json' \ + https://service_token:glsa_Fp0ggev31R58ueNJbJgYw7fIGfO3yKWH_746383ab@127.0.0.1/v1/version +``` +Service Token usually has "glsa_" prefix. If you convert it from API key, it will not change. If you use API key, then it will be automatically converted into Service Account and Service Token. + +API key example: ```shell curl -X GET -H 'Authorization: Bearer eyJrIjoiUXRkeDNMS1g1bFVyY0tUj1o0SmhBc3g4QUdTRVAwekoiLCJuIjoicG1tLXRlc3QiLCJpZCI6MX0=' \ -H 'Content-Type: application/json' https://127.0.0.1/v1/version diff --git a/go.mod b/go.mod index 55a30b8e2b..82d0df57e9 100644 --- a/go.mod +++ b/go.mod @@ -18,11 +18,11 @@ replace github.com/ClickHouse/clickhouse-go/151 => github.com/ClickHouse/clickho require ( github.com/AlekSi/pointer v1.2.0 github.com/ClickHouse/clickhouse-go/151 v0.0.0-00010101000000-000000000000 - github.com/ClickHouse/clickhouse-go/v2 v2.20.0 + github.com/ClickHouse/clickhouse-go/v2 v2.23.0 github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/alecthomas/kong v0.8.0 + github.com/alecthomas/kong v0.9.0 github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 - github.com/aws/aws-sdk-go v1.50.8 + github.com/aws/aws-sdk-go v1.51.3 github.com/blang/semver v3.5.1+incompatible github.com/brianvoe/gofakeit/v6 v6.28.0 github.com/charmbracelet/bubbles v0.18.0 @@ -39,6 +39,7 @@ require ( github.com/go-openapi/swag v0.23.0 github.com/go-openapi/validate v0.24.0 github.com/go-sql-driver/mysql v1.7.1 + github.com/gogo/status v1.1.1 github.com/golang-migrate/migrate/v4 v4.17.0 github.com/golang/protobuf v1.5.3 github.com/google/uuid v1.6.0 @@ -78,7 +79,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 google.golang.org/grpc v1.62.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.33.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/reform.v1 v1.5.1 gopkg.in/yaml.v3 v3.0.1 @@ -92,6 +93,7 @@ require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a // indirect github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/google/btree v1.0.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect @@ -118,7 +120,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect - github.com/ClickHouse/ch-go v0.61.3 // indirect + github.com/ClickHouse/ch-go v0.61.5 // indirect github.com/ClickHouse/clickhouse-go v1.5.4 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 github.com/Microsoft/go-winio v0.6.1 // indirect diff --git a/go.sum b/go.sum index aff6f48c7a..b845062ff6 100644 --- a/go.sum +++ b/go.sum @@ -48,14 +48,14 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaC github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ClickHouse/ch-go v0.61.3 h1:MmBwUhXrAOBZK7n/sWBzq6FdIQ01cuF2SaaO8KlDRzI= -github.com/ClickHouse/ch-go v0.61.3/go.mod h1:1PqXjMz/7S1ZUaKvwPA3i35W2bz2mAMFeCi6DIXgGwQ= +github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4= +github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= github.com/ClickHouse/clickhouse-go v1.5.1 h1:I8zVFZTz80crCs0FFEBJooIxsPcV0xfthzK1YrkpJTc= github.com/ClickHouse/clickhouse-go v1.5.1/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0= github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= -github.com/ClickHouse/clickhouse-go/v2 v2.20.0 h1:bvlLQ31XJfl7MxIqAq2l1G6JhHYzqEXdvfpMeU6bkKc= -github.com/ClickHouse/clickhouse-go/v2 v2.20.0/go.mod h1:VQfyA+tCwCRw2G7ogfY8V0fq/r0yJWzy8UDrjiP/Lbs= +github.com/ClickHouse/clickhouse-go/v2 v2.23.0 h1:srmRrkS0BR8gEut87u8jpcZ7geOob6nGj9ifrb+aKmg= +github.com/ClickHouse/clickhouse-go/v2 v2.23.0/go.mod h1:tBhdF3f3RdP7sS59+oBAtTyhWpy0024ZxDMhgxra0QE= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -71,12 +71,12 @@ github.com/Percona-Lab/spec v0.20.5-percona h1:ViCJVq52QIZxpP8/Nv4/nIed+WnqUirNj github.com/Percona-Lab/spec v0.20.5-percona/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0= -github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= -github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= -github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= -github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= -github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= +github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA= +github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -93,8 +93,8 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.50.8 h1:gY0WoOW+/Wz6XmYSgDH9ge3wnAevYDSQWPxxJvqAkP4= -github.com/aws/aws-sdk-go v1.50.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.51.3 h1:OqSyEXcJwf/XhZNVpMRgKlLA9nmbo5X8dwbll4RWxq8= +github.com/aws/aws-sdk-go v1.51.3/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -221,10 +221,14 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA= github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a h1:dR8+Q0uO5S2ZBcs2IH6VBKYwSxPo2vYCYq0ot0mu7xA= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= +github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU= @@ -899,6 +903,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -935,6 +940,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1: google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -962,8 +968,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/managed/models/agent_model.go b/managed/models/agent_model.go index 90fa00425f..42d37c95a3 100644 --- a/managed/models/agent_model.go +++ b/managed/models/agent_model.go @@ -124,13 +124,13 @@ func (c *AzureOptions) Scan(src interface{}) error { return jsonScan(c, src) } // PostgreSQLOptions represents structure for special PostgreSQL options. type PostgreSQLOptions struct { - SSLCa string `json:"ssl_ca"` - SSLCert string `json:"ssl_cert"` - SSLKey string `json:"ssl_key"` - AutoDiscoveryLimit int32 `json:"auto_discovery_limit"` - DatabaseCount int32 `json:"database_count"` - PGSMVersion string `json:"pgsm_version"` - MaxExporterConnections int32 `json:"max_exporter_connections"` + SSLCa string `json:"ssl_ca"` + SSLCert string `json:"ssl_cert"` + SSLKey string `json:"ssl_key"` + AutoDiscoveryLimit int32 `json:"auto_discovery_limit"` + DatabaseCount int32 `json:"database_count"` + PGSMVersion *string `json:"pgsm_version"` + MaxExporterConnections int32 `json:"max_exporter_connections"` } // Value implements database/sql/driver.Valuer interface. Should be defined on the value. diff --git a/managed/services/grafana/auth_server.go b/managed/services/grafana/auth_server.go index af647304e9..d41e6290ff 100644 --- a/managed/services/grafana/auth_server.go +++ b/managed/services/grafana/auth_server.go @@ -38,11 +38,15 @@ import ( "github.com/percona/pmm/managed/models" ) +const ( + connectionEndpoint = "/agent.v1.AgentService/Connect" +) + // rules maps original URL prefix to minimal required role. var rules = map[string]role{ // TODO https://jira.percona.com/browse/PMM-4420 - "/agent.Agent/Connect": none, // NOTE: remove before v3 GA - "/agent.v1.AgentService/Connect": none, + "/agent.Agent/Connect": none, // NOTE: remove before v3 GA + connectionEndpoint: admin, "/inventory.": admin, "/management.": admin, @@ -467,6 +471,17 @@ func nextPrefix(path string) string { return path[:i+1] } +func isLocalAgentConnection(req *http.Request) bool { + ip := strings.Split(req.RemoteAddr, ":")[0] + pmmAgent := req.Header.Get("Pmm-Agent-Id") + path := req.Header.Get("X-Original-Uri") + if ip == "127.0.0.1" && pmmAgent == "pmm-server" && path == connectionEndpoint { + return true + } + + return false +} + // authenticate checks if user has access to a specific path. // It returns user information retrieved during authentication. // Paths which require no Grafana role return zero value for @@ -506,22 +521,30 @@ func (s *AuthServer) authenticate(ctx context.Context, req *http.Request, l *log return nil, nil } - // Get authenticated user from Grafana - authUser, authErr := s.getAuthUser(ctx, req, l) - if authErr != nil { - return nil, authErr + var user *authUser + if isLocalAgentConnection(req) { + user = &authUser{ + role: rules[connectionEndpoint], + userID: 0, + } + } else { + var authErr *authError + // Get authenticated user from Grafana + user, authErr = s.getAuthUser(ctx, req, l) + if authErr != nil { + return nil, authErr + } } + l = l.WithField("role", user.role.String()) - l = l.WithField("role", authUser.role.String()) - - if authUser.role == grafanaAdmin { + if user.role == grafanaAdmin { l.Debugf("Grafana admin, allowing access.") - return authUser, nil + return user, nil } - if minRole <= authUser.role { + if minRole <= user.role { l.Debugf("Minimal required role is %q, granting access.", minRole) - return authUser, nil + return user, nil } l.Warnf("Minimal required role is %q.", minRole) @@ -536,6 +559,8 @@ func cleanPath(p string) (string, error) { cleanedPath := path.Clean(unescaped) + cleanedPath = strings.ReplaceAll(cleanedPath, "\n", " ") + u, err := url.Parse(cleanedPath) if err != nil { return "", err diff --git a/managed/services/grafana/auth_server_test.go b/managed/services/grafana/auth_server_test.go index 85fc3f37ae..6e25d55eea 100644 --- a/managed/services/grafana/auth_server_test.go +++ b/managed/services/grafana/auth_server_test.go @@ -32,6 +32,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "gopkg.in/reform.v1" "gopkg.in/reform.v1/dialects/postgresql" @@ -162,7 +163,6 @@ func TestAuthServerMustSetup(t *testing.T) { func TestAuthServerAuthenticate(t *testing.T) { t.Parallel() - // logrus.SetLevel(logrus.TraceLevel) checker := &mockAwsInstanceChecker{} checker.Test(t) @@ -199,7 +199,8 @@ func TestAuthServerAuthenticate(t *testing.T) { }) for uri, minRole := range map[string]role{ - "/agent.v1.AgentService/Connect": none, + "/agent.v1.AgentService/Connect": admin, + "/agent.Agent/Connect": admin, "/inventory.v1.Nodes/ListNodes": admin, "/actions/StartMySQLShowTableStatusAction": viewer, @@ -270,6 +271,75 @@ func TestAuthServerAuthenticate(t *testing.T) { } } +func TestServerClientConnection(t *testing.T) { + t.Parallel() + + checker := &mockAwsInstanceChecker{} + checker.Test(t) + t.Cleanup(func() { checker.AssertExpectations(t) }) + + ctx := context.Background() + c := NewClient("127.0.0.1:3000") + s := NewAuthServer(c, checker, nil) + + t.Run("Basic auth - success", func(t *testing.T) { + t.Parallel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, connectionEndpoint, nil) + require.NoError(t, err) + req.SetBasicAuth("admin", "admin") + + _, authError := s.authenticate(ctx, req, logrus.WithField("test", t.Name())) + assert.Nil(t, authError) + }) + + t.Run("Basic auth - fail", func(t *testing.T) { + t.Parallel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, connectionEndpoint, nil) + require.NoError(t, err) + req.SetBasicAuth("admin", "wrong") + + _, authError := s.authenticate(ctx, req, logrus.WithField("test", t.Name())) + assert.Equal(t, codes.Unauthenticated, authError.code) + }) + + t.Run("Token auth - success", func(t *testing.T) { + t.Parallel() + + nodeName := fmt.Sprintf("N1-%d", time.Now().UnixNano()) + headersMD := metadata.New(map[string]string{ + "Authorization": "Basic YWRtaW46YWRtaW4=", + }) + ctx := metadata.NewIncomingContext(context.Background(), headersMD) + _, serviceToken, err := c.CreateServiceAccount(ctx, nodeName, true) + require.NoError(t, err) + defer func() { + warning, err := c.DeleteServiceAccount(ctx, nodeName, true) + require.NoError(t, err) + require.Empty(t, warning) + }() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, connectionEndpoint, nil) + require.NoError(t, err) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", serviceToken)) + + _, authError := s.authenticate(ctx, req, logrus.WithField("test", t.Name())) + assert.Nil(t, authError) + }) + + t.Run("Token auth - fail", func(t *testing.T) { + t.Parallel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, connectionEndpoint, nil) + require.NoError(t, err) + req.Header.Set("Authorization", "Bearer wrong") + + _, authError := s.authenticate(ctx, req, logrus.WithField("test", t.Name())) + assert.Equal(t, codes.Unauthenticated, authError.code) + }) +} + func TestAuthServerAddVMGatewayToken(t *testing.T) { ctx := logger.Set(context.Background(), t.Name()) uuid.SetRand(&tests.IDReader{}) @@ -420,6 +490,9 @@ func Test_cleanPath(t *testing.T) { }, { "/v1/server/AWSInstanceCheck/..%2f..%2f..%2f/logs.zip", "/logs.zip", + }, { + "/graph/api/datasources/proxy/8/?query=WITH%20(%0A%20%20%20%20CASE%20%0A%20%20%20%20%20%20%20%20WHEN%20(3000%20%25%2060)%20%3D%200%20THEN%203000%0A%20%20%20%20ELSE%2060%20END%0A)%20AS%20scale%0ASELECT%0A%20%20%20%20(intDiv(toUInt32(timestamp)%2C%203000)%20*%203000)%20*%201000%20as%20t%2C%0A%20%20%20%20hostname%20h%2C%0A%20%20%20%20status%20s%2C%0A%20%20%20%20SUM(req_count)%20as%20req_count%0AFROM%20pinba.report_by_all%0AWHERE%0A%20%20%20%20timestamp%20%3E%3D%20toDateTime(1707139680)%20AND%20timestamp%20%3C%3D%20toDateTime(1707312480)%0A%20%20%20%20AND%20status%20%3E%3D%20400%0A%20%20%20%20AND%20CASE%20WHEN%20%27all%27%20%3C%3E%20%27all%27%20THEN%20schema%20%3D%20%27all%27%20ELSE%201%20END%0A%20%20%20%20AND%20CASE%20WHEN%20%27all%27%20%3C%3E%20%27all%27%20THEN%20hostname%20%3D%20%27all%27%20ELSE%201%20END%0A%20%20%20%20AND%20CASE%20WHEN%20%27all%27%20%3C%3E%20%27all%27%20THEN%20server_name%20%3D%20%27all%27%20ELSE%201%20END%0AGROUP%20BY%20t%2C%20h%2C%20s%0AORDER%20BY%20t%20FORMAT%20JSON", + "/graph/api/datasources/proxy/8/", }, } for _, tt := range tests { diff --git a/managed/services/grafana/client.go b/managed/services/grafana/client.go index 32df0a1900..82b9fa561d 100644 --- a/managed/services/grafana/client.go +++ b/managed/services/grafana/client.go @@ -19,7 +19,6 @@ package grafana import ( "bytes" "context" - "encoding/base64" "encoding/json" "fmt" "io" @@ -39,13 +38,18 @@ import ( "google.golang.org/grpc/status" "github.com/percona/pmm/managed/services" + "github.com/percona/pmm/managed/utils/auth" "github.com/percona/pmm/managed/utils/irt" ) // ErrFailedToGetToken means it failed to get user's token. Most likely due to the fact user is not logged in using Percona Account. var ErrFailedToGetToken = errors.New("failed to get token") -const defaultEvaluationInterval = time.Minute +const ( + defaultEvaluationInterval = time.Minute + pmmServiceTokenName = "pmm-agent-service-token" //nolint:gosec + pmmServiceAccountName = "pmm-agent-service-account" //nolint:gosec +) // Client represents a client for Grafana API. type Client struct { @@ -136,7 +140,7 @@ func (c *Client) do(ctx context.Context, method, path, rawQuery string, headers if err != nil { return errors.WithStack(err) } - if resp.StatusCode != 200 && resp.StatusCode != 202 { + if resp.StatusCode < 200 || resp.StatusCode > 202 { cErr := &clientError{ Method: req.Method, URL: req.URL.String(), @@ -192,7 +196,7 @@ func (r role) String() string { // GetUserID returns user ID from Grafana for the current user. func (c *Client) GetUserID(ctx context.Context) (int, error) { - authHeaders, err := c.authHeadersFromContext(ctx) + authHeaders, err := auth.GetHeadersFromContext(ctx) if err != nil { return 0, err } @@ -211,27 +215,41 @@ func (c *Client) GetUserID(ctx context.Context) (int, error) { return int(userID), nil } +var emptyUser = authUser{ + role: none, + userID: 0, +} + // getAuthUser returns grafanaAdmin if currently authenticated user is a Grafana (super) admin. // Otherwise, it returns a role in the default organization (with ID 1). // Ctx is used only for cancelation. func (c *Client) getAuthUser(ctx context.Context, authHeaders http.Header) (authUser, error) { - // Check if it's API Key - if c.IsAPIKeyAuth(authHeaders) { - role, err := c.getRoleForAPIKey(ctx, authHeaders) + // Check if API Key or Service Token is authorized. + token := auth.GetTokenFromHeaders(authHeaders) + if token != "" { + role, err := c.getRoleForServiceToken(ctx, token) + if err != nil { + if strings.Contains(err.Error(), "Auth method is not service account token") { + role, err := c.getRoleForAPIKey(ctx, authHeaders) + return authUser{ + role: role, + userID: 0, + }, err + } + + return emptyUser, err + } return authUser{ role: role, userID: 0, - }, err + }, nil } // https://grafana.com/docs/http_api/user/#actual-user - works only with Basic Auth var m map[string]interface{} err := c.do(ctx, http.MethodGet, "/api/user", "", authHeaders, nil, &m) if err != nil { - return authUser{ - role: none, - userID: 0, - }, err + return emptyUser, err } id, _ := m["id"].(float64) @@ -274,21 +292,18 @@ func (c *Client) getAuthUser(ctx context.Context, authHeaders http.Header) (auth }, nil } -// IsAPIKeyAuth checks if the request is made using an API Key. -func (c *Client) IsAPIKeyAuth(headers http.Header) bool { - authHeader := headers.Get("Authorization") - switch { - case strings.HasPrefix(authHeader, "Bearer"): - return true - case strings.HasPrefix(authHeader, "Basic"): - h := strings.TrimPrefix(authHeader, "Basic") - d, err := base64.StdEncoding.DecodeString(strings.TrimSpace(h)) - if err != nil { - return false - } - return strings.HasPrefix(string(d), "api_key:") +func (c *Client) getRoleForAPIKey(ctx context.Context, authHeaders http.Header) (role, error) { + var k map[string]interface{} + if err := c.do(ctx, http.MethodGet, "/api/auth/key", "", authHeaders, nil, &k); err != nil { + return none, err + } + + if id, _ := k["orgId"].(float64); id != 1 { + return none, nil } - return false + + role, _ := k["role"].(string) + return c.convertRole(role), nil } func (c *Client) convertRole(role string) role { @@ -312,9 +327,12 @@ type apiKey struct { Expiration *time.Time `json:"expiration,omitempty"` } -func (c *Client) getRoleForAPIKey(ctx context.Context, authHeaders http.Header) (role, error) { +func (c *Client) getRoleForServiceToken(ctx context.Context, token string) (role, error) { + header := http.Header{} + header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) + var k map[string]interface{} - if err := c.do(ctx, http.MethodGet, "/api/auth/key", "", authHeaders, nil, &k); err != nil { + if err := c.do(ctx, http.MethodGet, "/api/auth/serviceaccount", "", header, nil, &k); err != nil { return none, err } @@ -326,6 +344,54 @@ func (c *Client) getRoleForAPIKey(ctx context.Context, authHeaders http.Header) return c.convertRole(role), nil } +type serviceAccountSearch struct { + TotalCount int `json:"totalCount"` + ServiceAccounts []serviceAccount `json:"serviceAccounts"` +} + +func (c *Client) getServiceAccountIDFromName(ctx context.Context, nodeName string, authHeaders http.Header) (int, error) { + var res serviceAccountSearch + serviceAccountName := fmt.Sprintf("%s-%s", pmmServiceAccountName, nodeName) + if err := c.do(ctx, http.MethodGet, "/api/serviceaccounts/search", fmt.Sprintf("query=%s", serviceAccountName), authHeaders, nil, &res); err != nil { + return 0, err + } + for _, serviceAccount := range res.ServiceAccounts { + if serviceAccount.Name != serviceAccountName { + continue + } + return serviceAccount.ID, nil + } + + return 0, errors.Errorf("service account %s not found", serviceAccountName) +} + +func (c *Client) getNotPMMAgentTokenCountForServiceAccount(ctx context.Context, nodeName string) (int, error) { + authHeaders, err := auth.GetHeadersFromContext(ctx) + if err != nil { + return 0, err + } + + serviceAccountID, err := c.getServiceAccountIDFromName(ctx, nodeName, authHeaders) + if err != nil { + return 0, err + } + + var tokens []serviceToken + if err := c.do(ctx, http.MethodGet, fmt.Sprintf("/api/serviceaccounts/%d/tokens", serviceAccountID), "", authHeaders, nil, &tokens); err != nil { + return 0, err + } + + count := 0 + for _, token := range tokens { + serviceTokenName := fmt.Sprintf("%s-%s", pmmServiceTokenName, nodeName) + if !strings.HasPrefix(token.Name, serviceTokenName) { + count++ + } + } + + return count, nil +} + func (c *Client) testCreateUser(ctx context.Context, login string, role role, authHeaders http.Header) (int, error) { // https://grafana.com/docs/http_api/admin/#global-users b, err := json.Marshal(map[string]string{ @@ -366,50 +432,60 @@ func (c *Client) testDeleteUser(ctx context.Context, userID int, authHeaders htt return c.do(ctx, "DELETE", "/api/admin/users/"+strconv.Itoa(userID), "", authHeaders, nil, nil) } -// CreateAdminAPIKey creates API key with Admin role and provided name. -func (c *Client) CreateAdminAPIKey(ctx context.Context, name string) (int64, string, error) { - authHeaders, err := c.authHeadersFromContext(ctx) +// CreateServiceAccount creates service account and token with Admin role. +func (c *Client) CreateServiceAccount(ctx context.Context, nodeName string, reregister bool) (int, string, error) { + authHeaders, err := auth.GetHeadersFromContext(ctx) if err != nil { return 0, "", err } - return c.createAPIKey(ctx, name, admin, authHeaders) -} -// DeleteAPIKeysWithPrefix deletes all API keys with provided prefix. If there is no api key with provided prefix just ignores it. -func (c *Client) DeleteAPIKeysWithPrefix(ctx context.Context, prefix string) error { - authHeaders, err := c.authHeadersFromContext(ctx) + serviceAccountID, err := c.createServiceAccount(ctx, admin, nodeName, reregister, authHeaders) if err != nil { - return err - } - var keys []apiKey - if err := c.do(ctx, http.MethodGet, "/api/auth/keys", "", authHeaders, nil, &keys); err != nil { - return err + return 0, "", err } - for _, k := range keys { - if strings.HasPrefix(k.Name, prefix) { - err := c.deleteAPIKey(ctx, k.ID, authHeaders) - if err != nil { - return err - } - } + _, serviceToken, err := c.createServiceToken(ctx, serviceAccountID, nodeName, reregister, authHeaders) + if err != nil { + return 0, "", err } - return nil + return serviceAccountID, serviceToken, nil } -// DeleteAPIKeyByID deletes API key by ID. -func (c *Client) DeleteAPIKeyByID(ctx context.Context, id int64) error { - authHeaders, err := c.authHeadersFromContext(ctx) +// DeleteServiceAccount deletes service account by current service token. +func (c *Client) DeleteServiceAccount(ctx context.Context, nodeName string, force bool) (string, error) { + authHeaders, err := auth.GetHeadersFromContext(ctx) if err != nil { - return err + return "", err + } + + warning := "" + serviceAccountID, err := c.getServiceAccountIDFromName(ctx, nodeName, authHeaders) + if err != nil { + return warning, err + } + + customsTokensCount, err := c.getNotPMMAgentTokenCountForServiceAccount(ctx, nodeName) + if err != nil { + return warning, err + } + + if !force && customsTokensCount > 0 { + warning = "Service account wont be deleted, because there are more not PMM agent related service tokens." + err = c.deletePMMAgentServiceToken(ctx, serviceAccountID, nodeName, authHeaders) + } else { + err = c.deleteServiceAccount(ctx, serviceAccountID, authHeaders) + } + if err != nil { + return warning, err } - return c.deleteAPIKey(ctx, id, authHeaders) + + return warning, err } // CreateAlertRule creates Grafana alert rule. func (c *Client) CreateAlertRule(ctx context.Context, folderName, groupName string, rule *services.Rule) error { - authHeaders, err := c.authHeadersFromContext(ctx) + authHeaders, err := auth.GetHeadersFromContext(ctx) if err != nil { return err } @@ -539,7 +615,7 @@ func (c *Client) GetFolderByUID(ctx context.Context, uid string) (*gapi.Folder, } func (c *Client) createGrafanaClient(ctx context.Context) (*gapi.Client, error) { - authHeaders, err := c.authHeadersFromContext(ctx) + authHeaders, err := auth.GetHeadersFromContext(ctx) if err != nil { return nil, errors.WithStack(err) } @@ -557,30 +633,6 @@ func (c *Client) createGrafanaClient(ctx context.Context) (*gapi.Client, error) return grafanaClient, nil } -func (c *Client) authHeadersFromContext(ctx context.Context) (http.Header, error) { - headers, ok := metadata.FromIncomingContext(ctx) - if !ok { - return nil, fmt.Errorf("cannot get headers from metadata") - } - // get authorization from headers. - authorizationHeaders := headers.Get("Authorization") - cookieHeaders := headers.Get(grpcGatewayCookie) - if len(authorizationHeaders) == 0 && len(cookieHeaders) == 0 { - return nil, status.Error(codes.Unauthenticated, "Authorization error.") - } - - authHeaders := make(http.Header) - if len(authorizationHeaders) != 0 { - authHeaders.Add("Authorization", authorizationHeaders[0]) - } - if len(cookieHeaders) != 0 { - for _, header := range cookieHeaders { - authHeaders.Add("Cookie", header) - } - } - return authHeaders, nil -} - func (c *Client) createAPIKey(ctx context.Context, name string, role role, authHeaders http.Header) (int64, string, error) { // https://grafana.com/docs/grafana/latest/http_api/auth/#create-api-key b, err := json.Marshal(apiKey{Name: name, Role: role.String()}) @@ -610,6 +662,117 @@ func (c *Client) deleteAPIKey(ctx context.Context, apiKeyID int64, authHeaders h return c.do(ctx, "DELETE", "/api/auth/keys/"+strconv.FormatInt(apiKeyID, 10), "", authHeaders, nil, nil) } +type serviceAccount struct { + ID int `json:"id"` + Name string `json:"name"` + Role string `json:"role"` + Force bool `json:"force"` +} +type serviceToken struct { + ID int `json:"id"` + Name string `json:"name"` + Role string `json:"role"` +} + +func (c *Client) createServiceAccount(ctx context.Context, role role, nodeName string, reregister bool, authHeaders http.Header) (int, error) { + if role == none { + return 0, errors.New("you cannot create service account with empty role") + } + + // Max length of service account name is 190 chars (default limit in Grafana). In reality it is 187. + // Some test could fail if you will have name longer than 187 chars. + serviceAccountName := fmt.Sprintf("%s-%s", pmmServiceAccountName, nodeName) + b, err := json.Marshal(serviceAccount{Name: serviceAccountName, Role: role.String(), Force: reregister}) + if err != nil { + return 0, errors.WithStack(err) + } + + var m map[string]interface{} + if err = c.do(ctx, "POST", "/api/serviceaccounts", "", authHeaders, b, &m); err != nil { + return 0, err + } + + serviceAccountID := int(m["id"].(float64)) //nolint:forcetypeassert + + // orgId is ignored during creating service account and default is -1 + // orgId should be set to 1 + if err = c.do(ctx, "PATCH", fmt.Sprintf("/api/serviceaccounts/%d", serviceAccountID), "", authHeaders, []byte("{\"orgId\": 1}"), &m); err != nil { + return 0, err + } + + return serviceAccountID, nil +} + +func (c *Client) createServiceToken(ctx context.Context, serviceAccountID int, nodeName string, reregister bool, authHeaders http.Header) (int, string, error) { + serviceTokenName := fmt.Sprintf("%s-%s", pmmServiceTokenName, nodeName) + exists, err := c.serviceTokenExists(ctx, serviceAccountID, nodeName, authHeaders) + if err != nil { + return 0, "", err + } + if exists && reregister { + err := c.deletePMMAgentServiceToken(ctx, serviceAccountID, nodeName, authHeaders) + if err != nil { + return 0, "", err + } + } + + b, err := json.Marshal(serviceToken{Name: serviceTokenName, Role: admin.String()}) + if err != nil { + return 0, "", errors.WithStack(err) + } + + var m map[string]interface{} + if err = c.do(ctx, "POST", fmt.Sprintf("/api/serviceaccounts/%d/tokens", serviceAccountID), "", authHeaders, b, &m); err != nil { + return 0, "", err + } + serviceTokenID := int(m["id"].(float64)) //nolint:forcetypeassert + serviceTokenKey := m["key"].(string) //nolint:forcetypeassert + + return serviceTokenID, serviceTokenKey, nil +} + +func (c *Client) serviceTokenExists(ctx context.Context, serviceAccountID int, nodeName string, authHeaders http.Header) (bool, error) { + var tokens []serviceToken + if err := c.do(ctx, "GET", fmt.Sprintf("/api/serviceaccounts/%d/tokens", serviceAccountID), "", authHeaders, nil, &tokens); err != nil { + return false, err + } + + serviceTokenName := fmt.Sprintf("%s-%s", pmmServiceTokenName, nodeName) + for _, token := range tokens { + if !strings.HasPrefix(token.Name, serviceTokenName) { + continue + } + + return true, nil + } + + return false, nil +} + +func (c *Client) deletePMMAgentServiceToken(ctx context.Context, serviceAccountID int, nodeName string, authHeaders http.Header) error { + var tokens []serviceToken + if err := c.do(ctx, "GET", fmt.Sprintf("/api/serviceaccounts/%d/tokens", serviceAccountID), "", authHeaders, nil, &tokens); err != nil { + return err + } + + serviceTokenName := fmt.Sprintf("%s-%s", pmmServiceTokenName, nodeName) + for _, token := range tokens { + if strings.HasPrefix(token.Name, serviceTokenName) { + if err := c.do(ctx, "DELETE", fmt.Sprintf("/api/serviceaccounts/%d/tokens/%d", serviceAccountID, token.ID), "", authHeaders, nil, nil); err != nil { + return err + } + + return nil + } + } + + return nil +} + +func (c *Client) deleteServiceAccount(ctx context.Context, serviceAccountID int, authHeaders http.Header) error { + return c.do(ctx, "DELETE", fmt.Sprintf("/api/serviceaccounts/%d", serviceAccountID), "", authHeaders, nil, nil) +} + // Annotation contains grafana annotation response. type annotation struct { Time time.Time `json:"-"` diff --git a/managed/services/grafana/client_test.go b/managed/services/grafana/client_test.go index 16cbd03dc0..66963ded67 100644 --- a/managed/services/grafana/client_test.go +++ b/managed/services/grafana/client_test.go @@ -72,9 +72,6 @@ func TestClient(t *testing.T) { }) t.Run("NewUserViewerByDefault", func(t *testing.T) { - // do not run this test in parallel - they lock Grafana's sqlite3 database - // t.Parallel() - // See [users] in grafana.ini. login := fmt.Sprintf("%s-%d", none, time.Now().Nanosecond()) @@ -104,8 +101,7 @@ func TestClient(t *testing.T) { role := role t.Run(fmt.Sprintf("Basic auth %s", role.String()), func(t *testing.T) { - // do not run this test in parallel - they lock Grafana's sqlite3 database - // t.Parallel() + t.Parallel() login := fmt.Sprintf("basic-%s-%d", role, time.Now().Nanosecond()) userID, err := c.testCreateUser(ctx, login, role, authHeaders) @@ -131,8 +127,7 @@ func TestClient(t *testing.T) { }) t.Run(fmt.Sprintf("API Key auth %s", role.String()), func(t *testing.T) { - // do not run this test in parallel - they lock Grafana's sqlite3 database - // t.Parallel() + t.Parallel() login := fmt.Sprintf("api-%s-%d", role, time.Now().Nanosecond()) apiKeyID, apiKey, err := c.createAPIKey(ctx, login, role, authHeaders) @@ -155,6 +150,35 @@ func TestClient(t *testing.T) { assert.Equal(t, role, actualRole) assert.Equal(t, role.String(), actualRole.String()) }) + + t.Run(fmt.Sprintf("Service token auth %s", role.String()), func(t *testing.T) { + t.Parallel() + + nodeName := fmt.Sprintf("test-node-%s", role) + serviceAccountID, err := c.createServiceAccount(ctx, role, nodeName, true, authHeaders) + require.NoError(t, err) + defer func() { + err := c.deleteServiceAccount(ctx, serviceAccountID, authHeaders) + require.NoError(t, err) + }() + + serviceTokenID, serviceToken, err := c.createServiceToken(ctx, serviceAccountID, nodeName, true, authHeaders) + require.NoError(t, err) + require.NotZero(t, serviceTokenID) + require.NotEmpty(t, serviceToken) + defer func() { + err := c.deletePMMAgentServiceToken(ctx, serviceAccountID, nodeName, authHeaders) + require.NoError(t, err) + }() + + serviceTokenAuthHeaders := http.Header{} + serviceTokenAuthHeaders.Set("Authorization", fmt.Sprintf("Bearer %s", serviceToken)) + u, err := c.getAuthUser(ctx, serviceTokenAuthHeaders) + assert.NoError(t, err) + actualRole := u.role + assert.Equal(t, role, actualRole) + assert.Equal(t, role.String(), actualRole.String()) + }) } }) diff --git a/managed/services/management/deps.go b/managed/services/management/deps.go index a4f2ef8a55..dee58d918b 100644 --- a/managed/services/management/deps.go +++ b/managed/services/management/deps.go @@ -17,7 +17,6 @@ package management import ( "context" - "net/http" "time" "github.com/percona-platform/saas/pkg/check" @@ -67,8 +66,8 @@ type checksService interface { // We use it instead of real type for testing and to avoid dependency cycle. type grafanaClient interface { CreateAnnotation(context.Context, []string, time.Time, string, string) (string, error) - CreateAdminAPIKey(ctx context.Context, name string) (int64, string, error) - IsAPIKeyAuth(headers http.Header) bool + CreateServiceAccount(ctx context.Context, noneName string, reregister bool) (int, string, error) + DeleteServiceAccount(ctx context.Context, noneName string, force bool) (string, error) } // jobsService is a subset of methods of agents.JobsService used by this package. diff --git a/managed/services/management/mock_grafana_client_test.go b/managed/services/management/mock_grafana_client_test.go index 975d0948a3..cd58f21d8e 100644 --- a/managed/services/management/mock_grafana_client_test.go +++ b/managed/services/management/mock_grafana_client_test.go @@ -4,7 +4,6 @@ package management import ( context "context" - http "net/http" time "time" mock "github.com/stretchr/testify/mock" @@ -15,34 +14,62 @@ type mockGrafanaClient struct { mock.Mock } -// CreateAdminAPIKey provides a mock function with given fields: ctx, name -func (_m *mockGrafanaClient) CreateAdminAPIKey(ctx context.Context, name string) (int64, string, error) { - ret := _m.Called(ctx, name) +// CreateAnnotation provides a mock function with given fields: _a0, _a1, _a2, _a3, _a4 +func (_m *mockGrafanaClient) CreateAnnotation(_a0 context.Context, _a1 []string, _a2 time.Time, _a3 string, _a4 string) (string, error) { + ret := _m.Called(_a0, _a1, _a2, _a3, _a4) if len(ret) == 0 { - panic("no return value specified for CreateAdminAPIKey") + panic("no return value specified for CreateAnnotation") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []string, time.Time, string, string) (string, error)); ok { + return rf(_a0, _a1, _a2, _a3, _a4) + } + if rf, ok := ret.Get(0).(func(context.Context, []string, time.Time, string, string) string); ok { + r0 = rf(_a0, _a1, _a2, _a3, _a4) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, []string, time.Time, string, string) error); ok { + r1 = rf(_a0, _a1, _a2, _a3, _a4) + } else { + r1 = ret.Error(1) } - var r0 int64 + return r0, r1 +} + +// CreateServiceAccount provides a mock function with given fields: ctx, noneName, reregister +func (_m *mockGrafanaClient) CreateServiceAccount(ctx context.Context, noneName string, reregister bool) (int, string, error) { + ret := _m.Called(ctx, noneName, reregister) + + if len(ret) == 0 { + panic("no return value specified for CreateServiceAccount") + } + + var r0 int var r1 string var r2 error - if rf, ok := ret.Get(0).(func(context.Context, string) (int64, string, error)); ok { - return rf(ctx, name) + if rf, ok := ret.Get(0).(func(context.Context, string, bool) (int, string, error)); ok { + return rf(ctx, noneName, reregister) } - if rf, ok := ret.Get(0).(func(context.Context, string) int64); ok { - r0 = rf(ctx, name) + if rf, ok := ret.Get(0).(func(context.Context, string, bool) int); ok { + r0 = rf(ctx, noneName, reregister) } else { - r0 = ret.Get(0).(int64) + r0 = ret.Get(0).(int) } - if rf, ok := ret.Get(1).(func(context.Context, string) string); ok { - r1 = rf(ctx, name) + if rf, ok := ret.Get(1).(func(context.Context, string, bool) string); ok { + r1 = rf(ctx, noneName, reregister) } else { r1 = ret.Get(1).(string) } - if rf, ok := ret.Get(2).(func(context.Context, string) error); ok { - r2 = rf(ctx, name) + if rf, ok := ret.Get(2).(func(context.Context, string, bool) error); ok { + r2 = rf(ctx, noneName, reregister) } else { r2 = ret.Error(2) } @@ -50,27 +77,27 @@ func (_m *mockGrafanaClient) CreateAdminAPIKey(ctx context.Context, name string) return r0, r1, r2 } -// CreateAnnotation provides a mock function with given fields: _a0, _a1, _a2, _a3, _a4 -func (_m *mockGrafanaClient) CreateAnnotation(_a0 context.Context, _a1 []string, _a2 time.Time, _a3 string, _a4 string) (string, error) { - ret := _m.Called(_a0, _a1, _a2, _a3, _a4) +// DeleteServiceAccount provides a mock function with given fields: ctx, noneName, force +func (_m *mockGrafanaClient) DeleteServiceAccount(ctx context.Context, noneName string, force bool) (string, error) { + ret := _m.Called(ctx, noneName, force) if len(ret) == 0 { - panic("no return value specified for CreateAnnotation") + panic("no return value specified for DeleteServiceAccount") } var r0 string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string, time.Time, string, string) (string, error)); ok { - return rf(_a0, _a1, _a2, _a3, _a4) + if rf, ok := ret.Get(0).(func(context.Context, string, bool) (string, error)); ok { + return rf(ctx, noneName, force) } - if rf, ok := ret.Get(0).(func(context.Context, []string, time.Time, string, string) string); ok { - r0 = rf(_a0, _a1, _a2, _a3, _a4) + if rf, ok := ret.Get(0).(func(context.Context, string, bool) string); ok { + r0 = rf(ctx, noneName, force) } else { r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func(context.Context, []string, time.Time, string, string) error); ok { - r1 = rf(_a0, _a1, _a2, _a3, _a4) + if rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok { + r1 = rf(ctx, noneName, force) } else { r1 = ret.Error(1) } @@ -78,24 +105,6 @@ func (_m *mockGrafanaClient) CreateAnnotation(_a0 context.Context, _a1 []string, return r0, r1 } -// IsAPIKeyAuth provides a mock function with given fields: headers -func (_m *mockGrafanaClient) IsAPIKeyAuth(headers http.Header) bool { - ret := _m.Called(headers) - - if len(ret) == 0 { - panic("no return value specified for IsAPIKeyAuth") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(http.Header) bool); ok { - r0 = rf(headers) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - // newMockGrafanaClient creates a new instance of mockGrafanaClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func newMockGrafanaClient(t interface { diff --git a/managed/services/management/node.go b/managed/services/management/node.go index 5f72d6fa85..098144e904 100644 --- a/managed/services/management/node.go +++ b/managed/services/management/node.go @@ -17,14 +17,9 @@ package management import ( "context" - "fmt" - "math/rand" - "net/http" "github.com/AlekSi/pointer" - "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "gopkg.in/reform.v1" @@ -32,12 +27,12 @@ import ( managementv1 "github.com/percona/pmm/api/management/v1" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/services" + "github.com/percona/pmm/managed/utils/auth" ) // RegisterNode performs the registration of a new node. func (s *ManagementService) RegisterNode(ctx context.Context, req *managementv1.RegisterNodeRequest) (*managementv1.RegisterNodeResponse, error) { res := &managementv1.RegisterNodeResponse{} - e := s.db.InTransaction(func(tx *reform.TX) error { node, err := models.FindNodeByName(tx.Querier, req.NodeName) switch status.Code(err) { //nolint:exhaustive @@ -119,30 +114,44 @@ func (s *ManagementService) RegisterNode(ctx context.Context, req *managementv1. return nil, e } - l := logrus.WithField("component", "node") - // get authorization from headers. - md, ok := metadata.FromIncomingContext(ctx) - if !ok { - msg := "Couldn't create Admin API Key: cannot get headers from metadata" - l.Errorln(msg) - res.Warning = msg - return res, nil - } - authorizationHeaders := md.Get("Authorization") - if len(authorizationHeaders) == 0 { - return nil, status.Error(codes.Unauthenticated, "Authorization error.") - } - headers := make(http.Header) - headers.Set("Authorization", authorizationHeaders[0]) - if !s.grafanaClient.IsAPIKeyAuth(headers) { - apiKeyName := fmt.Sprintf("pmm-agent-%s-%d", req.NodeName, rand.Int63()) //nolint:gosec - _, res.Token, e = s.grafanaClient.CreateAdminAPIKey(ctx, apiKeyName) + authHeaders, _ := auth.GetHeadersFromContext(ctx) + token := auth.GetTokenFromHeaders(authHeaders) + if token != "" { + res.Token = token + } else { + _, res.Token, e = s.grafanaClient.CreateServiceAccount(ctx, req.NodeName, req.Reregister) if e != nil { - msg := fmt.Sprintf("Couldn't create Admin API Key: %s", e) - l.Errorln(msg) - res.Warning = msg + return nil, e } } return res, nil } + +// Unregister do unregistration of the node. +func (s *ManagementService) Unregister(ctx context.Context, req *managementv1.UnregisterNodeRequest) (*managementv1.UnregisterNodeResponse, error) { + node, err := models.FindNodeByID(s.db.Querier, req.NodeId) + if err != nil { + return nil, err + } + + err = s.db.InTransaction(func(tx *reform.TX) error { + return models.RemoveNode(tx.Querier, req.NodeId, models.RemoveCascade) + }) + if err != nil { + return nil, err + } + + warning, err := s.grafanaClient.DeleteServiceAccount(ctx, node.NodeName, req.Force) + if err != nil { + // TODO: need to pass the logger to the service + // s.l.WithError(err).Error("deleting service account") + return &managementv1.UnregisterNodeResponse{ + Warning: err.Error(), + }, nil + } + + return &managementv1.UnregisterNodeResponse{ + Warning: warning, + }, nil +} diff --git a/managed/services/management/node_test.go b/managed/services/management/node_test.go index 5a93eb156b..b8674a9cba 100644 --- a/managed/services/management/node_test.go +++ b/managed/services/management/node_test.go @@ -21,7 +21,6 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" @@ -38,7 +37,10 @@ import ( ) func TestNodeService(t *testing.T) { - t.Run("Register", func(t *testing.T) { + getTestNodeName := func() string { + return "test-node" + } + t.Run("Register/Unregister", func(t *testing.T) { setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T)) { t.Helper() @@ -61,6 +63,11 @@ func TestNodeService(t *testing.T) { vmdb := &mockPrometheusService{} vmdb.Test(t) + serviceAccountID := int(0) + nodeName := getTestNodeName() + reregister := false + force := true + state := &mockAgentsStateUpdater{} state.Test(t) @@ -76,14 +83,12 @@ func TestNodeService(t *testing.T) { vc := &mockVersionCache{} vc.Test(t) - grafanaClient := &mockGrafanaClient{} - grafanaClient.Test(t) - - grafanaClient.Test(t) - grafanaClient.On("IsAPIKeyAuth", mock.Anything).Return(false) - grafanaClient.On("CreateAdminAPIKey", ctx, mock.AnythingOfType("string")).Return(int64(0), "test-token", nil) + authProvider := &mockGrafanaClient{} + authProvider.Test(t) + authProvider.On("CreateServiceAccount", ctx, nodeName, reregister).Return(serviceAccountID, "test-token", nil) + authProvider.On("DeleteServiceAccount", ctx, nodeName, force).Return("", nil) - s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient) + s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, authProvider) return ctx, s, teardown } @@ -94,14 +99,14 @@ func TestNodeService(t *testing.T) { res, err := s.RegisterNode(ctx, &managementv1.RegisterNodeRequest{ NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, - NodeName: "node", + NodeName: "test-node", Address: "some.address.org", Region: "region", }) expected := &managementv1.RegisterNodeResponse{ GenericNode: &inventoryv1.GenericNode{ NodeId: "/node_id/00000000-0000-4000-8000-000000000005", - NodeName: "node", + NodeName: "test-node", Address: "some.address.org", Region: "region", }, @@ -118,16 +123,25 @@ func TestNodeService(t *testing.T) { t.Run("Exist", func(t *testing.T) { res, err = s.RegisterNode(ctx, &managementv1.RegisterNodeRequest{ NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, - NodeName: "node", + NodeName: "test-node", }) assert.Nil(t, res) - tests.AssertGRPCError(t, status.New(codes.AlreadyExists, `Node with name "node" already exists.`), err) + tests.AssertGRPCError(t, status.New(codes.AlreadyExists, `Node with name "test-node" already exists.`), err) }) t.Run("Reregister", func(t *testing.T) { + serviceAccountID := int(0) + nodeName := getTestNodeName() + reregister := true + + authProvider := &mockGrafanaClient{} + authProvider.Test(t) + authProvider.On("CreateServiceAccount", ctx, nodeName, reregister).Return(serviceAccountID, "test-token", nil) + s.grafanaClient = authProvider + res, err = s.RegisterNode(ctx, &managementv1.RegisterNodeRequest{ NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, - NodeName: "node", + NodeName: "test-node", Address: "some.address.org", Region: "region", Reregister: true, @@ -135,7 +149,7 @@ func TestNodeService(t *testing.T) { expected := &managementv1.RegisterNodeResponse{ GenericNode: &inventoryv1.GenericNode{ NodeId: "/node_id/00000000-0000-4000-8000-000000000008", - NodeName: "node", + NodeName: "test-node", Address: "some.address.org", Region: "region", }, @@ -149,10 +163,20 @@ func TestNodeService(t *testing.T) { assert.Equal(t, expected, res) assert.NoError(t, err) }) + t.Run("Reregister-force", func(t *testing.T) { + serviceAccountID := int(0) + nodeName := "test-node-new" + reregister := true + + authProvider := &mockGrafanaClient{} + authProvider.Test(t) + authProvider.On("CreateServiceAccount", ctx, nodeName, reregister).Return(serviceAccountID, "test-token", nil) + s.grafanaClient = authProvider + res, err = s.RegisterNode(ctx, &managementv1.RegisterNodeRequest{ NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, - NodeName: "node-name-new", + NodeName: "test-node-new", Address: "some.address.org", Region: "region", Reregister: true, @@ -160,7 +184,7 @@ func TestNodeService(t *testing.T) { expected := &managementv1.RegisterNodeResponse{ GenericNode: &inventoryv1.GenericNode{ NodeId: "/node_id/00000000-0000-4000-8000-00000000000b", - NodeName: "node-name-new", + NodeName: "test-node-new", Address: "some.address.org", Region: "region", }, @@ -174,6 +198,51 @@ func TestNodeService(t *testing.T) { assert.Equal(t, expected, res) assert.NoError(t, err) }) + + t.Run("Unregister", func(t *testing.T) { + serviceAccountID := int(0) + nodeName := getTestNodeName() + reregister := true + force := true + + authProvider := &mockGrafanaClient{} + authProvider.Test(t) + authProvider.On("CreateServiceAccount", ctx, nodeName, reregister).Return(serviceAccountID, "test-token", nil) + authProvider.On("DeleteServiceAccount", ctx, nodeName, force).Return("", nil) + s.grafanaClient = authProvider + + resRegister, err := s.RegisterNode(ctx, &managementv1.RegisterNodeRequest{ + NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, + NodeName: "test-node", + Address: "some.address.org", + Region: "region", + Reregister: true, + }) + assert.NoError(t, err) + + expected := &managementv1.RegisterNodeResponse{ + GenericNode: &inventoryv1.GenericNode{ + NodeId: "/node_id/00000000-0000-4000-8000-00000000000e", + NodeName: "test-node", + Address: "some.address.org", + Region: "region", + }, + ContainerNode: (*inventoryv1.ContainerNode)(nil), + PmmAgent: &inventoryv1.PMMAgent{ + AgentId: "/agent_id/00000000-0000-4000-8000-00000000000f", + RunsOnNodeId: "/node_id/00000000-0000-4000-8000-00000000000e", + }, + Token: "test-token", + } + assert.Equal(t, expected, resRegister) + + res, err := s.Unregister(ctx, &managementv1.UnregisterNodeRequest{ + NodeId: resRegister.GenericNode.NodeId, + Force: true, + }) + assert.NoError(t, err) + assert.Equal(t, "", res.Warning) + }) }) }) } diff --git a/managed/services/management/postgresql.go b/managed/services/management/postgresql.go index 98dbd88e69..94ccff5845 100644 --- a/managed/services/management/postgresql.go +++ b/managed/services/management/postgresql.go @@ -92,9 +92,9 @@ func (s *ManagementService) addPostgreSQL(ctx context.Context, req *managementv1 return err } - // In case PGSM extension is unavailable, it will switch to PGSS. - if req.QanPostgresqlPgstatmonitorAgent && row.PostgreSQLOptions.PGSMVersion == "" { - postgres.Warning = "Could not to detect pg_stat_monitor extension on your system. Falling back to pg_stat_statements." + // In case of not available PGSM extension it is switch to PGSS. + if req.QanPostgresqlPgstatmonitorAgent && row.PostgreSQLOptions.PGSMVersion != nil && *row.PostgreSQLOptions.PGSMVersion == "" { + postgres.Warning = "Could not to detect the pg_stat_monitor extension on your system. Falling back to the pg_stat_statements." req.QanPostgresqlPgstatementsAgent = true req.QanPostgresqlPgstatmonitorAgent = false } diff --git a/managed/utils/auth/token.go b/managed/utils/auth/token.go new file mode 100644 index 0000000000..43fd2b6635 --- /dev/null +++ b/managed/utils/auth/token.go @@ -0,0 +1,78 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Package auth contains functions to work with auth tokens and headers. +package auth + +import ( + "context" + "encoding/base64" + "fmt" + "net/http" + "strings" + + "github.com/gogo/status" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// GetTokenFromHeaders returns authorization token if it is found in provided HTTP headers. +func GetTokenFromHeaders(authHeaders http.Header) string { + authHeader := authHeaders.Get("Authorization") + switch { + case strings.HasPrefix(authHeader, "Bearer"): + return strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer")) + case strings.HasPrefix(authHeader, "Basic"): + h := strings.TrimPrefix(authHeader, "Basic") + t, err := base64.StdEncoding.DecodeString(strings.TrimSpace(h)) + if err != nil { + logrus.Debugf("cannot decode basic authorization header: %s", err) + return "" + } + tk := string(t) + if strings.HasPrefix(tk, "api_key:") || strings.HasPrefix(tk, "service_token:") { + return strings.Split(tk, ":")[1] + } + } + + return "" +} + +// GetHeadersFromContext returns authorization headers if they are found in provided context. +func GetHeadersFromContext(ctx context.Context) (http.Header, error) { + headers, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, fmt.Errorf("cannot get headers from metadata") + } + + authorizationHeaders := headers.Get("Authorization") + cookieHeaders := headers.Get("grpcgateway-cookie") + if len(authorizationHeaders) == 0 && len(cookieHeaders) == 0 { + return nil, status.Error(codes.Unauthenticated, "Authorization error.") + } + + authHeaders := make(http.Header) + if len(authorizationHeaders) != 0 { + authHeaders.Add("Authorization", authorizationHeaders[0]) + } + if len(cookieHeaders) != 0 { + for _, header := range cookieHeaders { + authHeaders.Add("Cookie", header) + } + } + + return authHeaders, nil +} diff --git a/tools/go.mod b/tools/go.mod index fafc812c0b..5ec37a3308 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -69,7 +69,7 @@ require ( github.com/distribution/reference v0.5.0 // indirect github.com/docker/cli v24.0.7+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v25.0.0+incompatible // indirect + github.com/docker/docker v25.0.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index 6c994fc892..8dfef95ea4 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -169,8 +169,8 @@ github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1x github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= -github.com/docker/docker v25.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= +github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=