diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c83c7c24..a944634a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,23 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. ### Security -* Boundary now uses Go's execabs package for execution of binaries in `boundary - connect`. This is for defense-in-depth rather than a specific issue. See the - [Go blog post](https://blog.golang.org/path-security) for more details. - ([PR](https://github.com/hashicorp/boundary/pull/873)) +* Boundary now uses Go's new execabs package for execution of binaries in + `boundary connect`. This is for defense-in-depth rather than a specific + issue. See the [Go blog post](https://blog.golang.org/path-security) for more + details. ([PR](https://github.com/hashicorp/boundary/pull/873)) + +### Changes/Deprecations + +* controller/worker: Require names to be all lowercase. This removes ambiguity + or accidental mismatching when using upcoming filtering features. ### New and Improved +* targets: You can now specify a Boolean-expression filter against worker tags + to control which workers are allowed to handle any given target's sessions + ([PR](https://github.com/hashicorp/boundary/pull/862)) * api/cli: On listing/reading, return a list of actions the user is authorized - to perform on the identified resources + to perform on the identified resources or their associated collections ([PR](https://github.com/hashicorp/boundary/pull/870)) ### Bug Fixes diff --git a/Makefile b/Makefile index 50aa400b4..d5166c6b8 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,7 @@ CGO_ENABLED?=0 export GEN_BASEPATH := $(shell pwd) -api: apigen fmt -apigen: +api: $(MAKE) --environment-overrides -C internal/api/genapi api tools: diff --git a/api/targets/option.gen.go b/api/targets/option.gen.go index fe410d36f..fab0672df 100644 --- a/api/targets/option.gen.go +++ b/api/targets/option.gen.go @@ -158,3 +158,15 @@ func DefaultSessionMaxSeconds() Option { o.postMap["session_max_seconds"] = nil } } + +func WithWorkerFilter(inWorkerFilter string) Option { + return func(o *options) { + o.postMap["worker_filter"] = inWorkerFilter + } +} + +func DefaultWorkerFilter() Option { + return func(o *options) { + o.postMap["worker_filter"] = nil + } +} diff --git a/api/targets/target.gen.go b/api/targets/target.gen.go index 3bc18de76..76905db41 100644 --- a/api/targets/target.gen.go +++ b/api/targets/target.gen.go @@ -27,6 +27,7 @@ type Target struct { HostSets []*HostSet `json:"host_sets,omitempty"` SessionMaxSeconds uint32 `json:"session_max_seconds,omitempty"` SessionConnectionLimit int32 `json:"session_connection_limit,omitempty"` + WorkerFilter string `json:"worker_filter,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` AuthorizedActions []string `json:"authorized_actions,omitempty"` diff --git a/go.mod b/go.mod index 06a41f12d..64c6724fc 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/hashicorp/boundary/sdk v0.0.1 github.com/hashicorp/dbassert v0.0.0-20200930125617-6218396928df github.com/hashicorp/errwrap v1.1.0 + github.com/hashicorp/go-bexpr v0.1.4 github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-hclog v0.15.0 github.com/hashicorp/go-kms-wrapping v0.5.16 @@ -43,6 +44,7 @@ require ( github.com/mitchellh/cli v1.1.2 github.com/mitchellh/go-wordwrap v1.0.1 github.com/mitchellh/gox v1.0.1 + github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 github.com/oligot/go-mod-upgrade v0.3.0 github.com/ory/dockertest/v3 v3.6.0 diff --git a/go.sum b/go.sum index 485b0325d..745ea9fee 100644 --- a/go.sum +++ b/go.sum @@ -544,6 +544,8 @@ github.com/hashicorp/dbassert v0.0.0-20200930125617-6218396928df/go.mod h1:+B5eZ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-bexpr v0.1.4 h1:vyQpuKqqc+Ywb8tf6vZSlkf5qhYkgrNSWURtQggCfLE= +github.com/hashicorp/go-bexpr v0.1.4/go.mod h1:ey7VZGNrY1PnLlYp6Nf3RLEizPo0B9W4yw2MnDkcK3M= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -846,6 +848,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.1.0 h1:6RI+cKHSIOOuMhKALJyMIpGOHsmBGGwS0ZSMCPFn/jM= +github.com/mitchellh/pointerstructure v1.1.0/go.mod h1:zoQzmW5t87ncZZuJWXEyhr0///POW/WQEeFG4RRVKEs= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/internal/api/genapi/Makefile b/internal/api/genapi/Makefile index 7051f247c..b406e9421 100644 --- a/internal/api/genapi/Makefile +++ b/internal/api/genapi/Makefile @@ -7,5 +7,6 @@ export API_GEN_BASEPATH := ${GEN_BASEPATH}/api api: go run . goimports -w ${API_GEN_BASEPATH} + gofumpt -w ${API_GEN_BASEPATH} .PHONY: api diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index 5d064fb70..0632c2c31 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -544,7 +544,7 @@ func (c *Command) WaitForInterrupt() int { shutdownTriggered = true case <-c.SighupCh: - c.UI.Output("==> Boundary controller reload triggered") + c.UI.Output("==> Boundary server reload triggered") // Check for new log level var level hclog.Level @@ -589,7 +589,7 @@ func (c *Command) WaitForInterrupt() int { RUNRELOADFUNCS: if err := c.Reload(); err != nil { - c.UI.Error(fmt.Errorf("Error(s) were encountered during controller reload: %w", err).Error()) + c.UI.Error(fmt.Errorf("Error(s) were encountered during server reload: %w", err).Error()) } case <-c.SigUSR2Ch: diff --git a/internal/cmd/commands/targets/funcs.go b/internal/cmd/commands/targets/funcs.go index f2f806088..016e2e76b 100644 --- a/internal/cmd/commands/targets/funcs.go +++ b/internal/cmd/commands/targets/funcs.go @@ -41,6 +41,9 @@ func generateTargetTableOutput(in *targets.Target) string { if in.Description != "" { nonAttributeMap["Description"] = in.Description } + if in.WorkerFilter != "" { + nonAttributeMap["Worker Filter"] = in.WorkerFilter + } maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap) diff --git a/internal/cmd/commands/targets/tcp.go b/internal/cmd/commands/targets/tcp.go index 5d9cc5d1a..6c8d0daba 100644 --- a/internal/cmd/commands/targets/tcp.go +++ b/internal/cmd/commands/targets/tcp.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/cmd/common" "github.com/hashicorp/boundary/sdk/strutil" + "github.com/hashicorp/go-bexpr" "github.com/mitchellh/cli" "github.com/posener/complete" ) @@ -27,6 +28,7 @@ type TcpCommand struct { flagDefaultPort string flagSessionMaxSeconds string flagSessionConnectionLimit string + flagWorkerFilter string } func (c *TcpCommand) Synopsis() string { @@ -34,8 +36,8 @@ func (c *TcpCommand) Synopsis() string { } var tcpFlagsMap = map[string][]string{ - "create": {"scope-id", "name", "description", "default-port", "session-max-seconds", "session-connection-limit"}, - "update": {"id", "name", "description", "version", "default-port", "session-max-seconds", "session-connection-limit"}, + "create": {"scope-id", "name", "description", "default-port", "session-max-seconds", "session-connection-limit", "worker-filter"}, + "update": {"id", "name", "description", "version", "default-port", "session-max-seconds", "session-connection-limit", "worker-filter"}, } func (c *TcpCommand) Help() string { @@ -91,6 +93,12 @@ func (c *TcpCommand) Flags() *base.FlagSets { Target: &c.flagSessionConnectionLimit, Usage: "The maximum number of connections allowed for a session. -1 means unlimited.", }) + case "worker-filter": + f.StringVar(&base.StringVar{ + Name: "worker-filter", + Target: &c.flagWorkerFilter, + Usage: "A boolean expression to filter which workers can handle sessions for this target.", + }) } } @@ -196,6 +204,18 @@ func (c *TcpCommand) Run(args []string) int { opts = append(opts, targets.WithSessionConnectionLimit(int32(limit))) } + switch c.flagWorkerFilter { + case "": + case "null": + opts = append(opts, targets.DefaultWorkerFilter()) + default: + if _, err := bexpr.CreateEvaluator(c.flagWorkerFilter); err != nil { + c.UI.Error(fmt.Sprintf("Unable to successfully parse filter expression: %s", err)) + return 1 + } + opts = append(opts, targets.WithWorkerFilter(c.flagWorkerFilter)) + } + targetClient := targets.NewClient(client) // Perform check-and-set when needed diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index 574cfae74..edc40e9ad 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -13,10 +13,12 @@ import ( "strings" "time" + "github.com/hashicorp/boundary/sdk/strutil" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/hcl" "github.com/hashicorp/shared-secure-libs/configutil" "github.com/hashicorp/vault/sdk/helper/parseutil" + "github.com/mitchellh/mapstructure" ) const ( @@ -77,6 +79,9 @@ worker { name = "dev-worker" description = "A default worker created in dev mode" controllers = ["127.0.0.1"] + tags { + type = ["dev", "local"] + } } ` ) @@ -117,6 +122,12 @@ type Worker struct { Description string `hcl:"description"` Controllers []string `hcl:"controllers"` PublicAddr string `hcl:"public_addr"` + + // We use a raw interface for parsing so that people can use JSON-like + // syntax that maps directly to the filter input or possibly more familiar + // key=value syntax. This is trued up in the Parse function below. + TagsRaw interface{} `hcl:"tags"` + Tags map[string][]string `hcl:"-"` } type Database struct { @@ -224,6 +235,12 @@ func Parse(d string) (*Config, error) { // Perform controller configuration overrides for auth token settings if result.Controller != nil { + if result.Controller.Name != strings.ToLower(result.Controller.Name) { + return nil, errors.New("Controller name must be all lower-case") + } + if !strutil.Printable(result.Controller.Name) { + return nil, errors.New("Controller name contains non-printable characters") + } if result.Controller.AuthTokenTimeToLive != "" { t, err := parseutil.ParseDurationSecond(result.Controller.AuthTokenTimeToLive) if err != nil { @@ -241,6 +258,69 @@ func Parse(d string) (*Config, error) { } } + // Parse worker tags + if result.Worker != nil { + if result.Worker.Name != strings.ToLower(result.Worker.Name) { + return nil, errors.New("Worker name must be all lower-case") + } + if !strutil.Printable(result.Worker.Name) { + return nil, errors.New("Worker name contains non-printable characters") + } + if result.Worker.TagsRaw != nil { + switch t := result.Worker.TagsRaw.(type) { + // HCL allows multiple labeled blocks with the same name, turning it + // into a slice of maps, hence the slice here. This format is the + // one that ends up matching the JSON that we use in the expression. + case []map[string]interface{}: + if err := mapstructure.WeakDecode(t, &result.Worker.Tags); err != nil { + return nil, fmt.Errorf("Error decoding the worker's %q section: %w", "tags", err) + } + + // However for those that are used to other systems, we also accept + // key=value pairs + case []interface{}: + var strs []string + if err := mapstructure.WeakDecode(t, &strs); err != nil { + return nil, fmt.Errorf("Error decoding the worker's %q section: %w", "tags", err) + } + result.Worker.Tags = make(map[string][]string, len(strs)) + // Aggregate the values by key. We care about the first equal + // sign only, to allow equals to be in values if needed. This + // also means we don't support equal signs in keys. + for _, str := range strs { + splitStr := strings.SplitN(str, "=", 2) + switch len(splitStr) { + case 1: + return nil, fmt.Errorf("Error decoding tag %q from string: must be in key = value format", str) + case 2: + key := splitStr[0] + v := result.Worker.Tags[key] + if len(v) == 0 { + v = make([]string, 0, 1) + } + result.Worker.Tags[key] = append(v, splitStr[1]) + } + } + } + } + for k, v := range result.Worker.Tags { + if k != strings.ToLower(k) { + return nil, fmt.Errorf("Tag key %q is not all lower-case letters", k) + } + if !strutil.Printable(k) { + return nil, fmt.Errorf("Tag key %q contains non-printable characters", k) + } + for _, val := range v { + if val != strings.ToLower(val) { + return nil, fmt.Errorf("Tag value %q for tag key %q is not all lower-case letters", val, k) + } + if !strutil.Printable(k) { + return nil, fmt.Errorf("Tag value %q for tag key %q contains non-printable characters", v, k) + } + } + } + } + sharedConfig, err := configutil.ParseConfig(d) if err != nil { return nil, err diff --git a/internal/cmd/config/config_test.go b/internal/cmd/config/config_test.go index e3aa06014..7092cc7cc 100644 --- a/internal/cmd/config/config_test.go +++ b/internal/cmd/config/config_test.go @@ -108,10 +108,84 @@ func TestDevWorker(t *testing.T) { Name: "dev-worker", Description: "A default worker created in dev mode", Controllers: []string{"127.0.0.1"}, + Tags: map[string][]string{ + "type": {"dev", "local"}, + }, }, } exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig - + exp.Worker.TagsRaw = actual.Worker.TagsRaw assert.Equal(t, exp, actual) + + // Redo it with key=value syntax for tags + devWorkerKeyValueConfig := ` + listener "tcp" { + purpose = "proxy" + } + + worker { + name = "dev-worker" + description = "A default worker created in dev mode" + controllers = ["127.0.0.1"] + tags = ["type=dev", "type=local"] + } + ` + + actual, err = Parse(devConfig + devWorkerKeyValueConfig) + assert.NoError(t, err) + exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig + exp.Worker.TagsRaw = actual.Worker.TagsRaw + assert.Equal(t, exp, actual) + + // Redo it with non-lower-cased keys + devWorkerKeyValueConfig = ` + listener "tcp" { + purpose = "proxy" + } + + worker { + name = "dev-worker" + description = "A default worker created in dev mode" + controllers = ["127.0.0.1"] + tags = ["tyPe=dev", "type=local"] + } + ` + + _, err = Parse(devConfig + devWorkerKeyValueConfig) + assert.Error(t, err) + + // Redo it with non-lower-cased values + devWorkerKeyValueConfig = ` + listener "tcp" { + purpose = "proxy" + } + + worker { + name = "dev-worker" + description = "A default worker created in dev mode" + controllers = ["127.0.0.1"] + tags = ["type=dev", "type=loCal"] + } + ` + + _, err = Parse(devConfig + devWorkerKeyValueConfig) + assert.Error(t, err) + + // Redo with non-printable characters to validate the strutil function + devWorkerKeyValueConfig = ` + listener "tcp" { + purpose = "proxy" + } + + worker { + name = "dev-work\u0000er" + description = "A default worker created in dev mode" + controllers = ["127.0.0.1"] + tags = ["type=dev", "type=local"] + } + ` + + _, err = Parse(devConfig + devWorkerKeyValueConfig) + assert.Error(t, err) } diff --git a/internal/db/domains_test.go b/internal/db/domains_test.go index 9ce7136fc..22a9c007f 100644 --- a/internal/db/domains_test.go +++ b/internal/db/domains_test.go @@ -95,6 +95,148 @@ returning id; } } +func TestDomain_TagPairs(t *testing.T) { + const ( + createTable = ` +create table if not exists test_table ( + pair wt_tagpair primary key +); +` + insert = ` +insert into test_table +values ($1); +` + ) + + conn, _ := TestSetup(t, "postgres") + db := conn.DB() + + if _, err := db.Exec(createTable); err != nil { + t.Fatalf("query: \n%s\n error: %s", createTable, err) + } + + tests := []struct { + value string + fail bool + }{ + { + " ", + true, + }, + { + "00000009", + false, + }, + { + "ABC123", + true, + }, + { + "092h3oiuansdfh98wh3piornasiopudhfp98aw384rhfaouisdhnfios", + false, + }, + { + strings.Repeat("1234567890", 51), + false, + }, + { + strings.Repeat("1234567890", 52), + true, + }, + } + for _, tt := range tests { + t.Run(tt.value, func(t *testing.T) { + // t.Logf("insert value: %q", tt.value) + _, err := db.Query(insert, tt.value) + switch { + case err == nil && tt.fail: + t.Errorf("want error, got no error for inserting value: %s", tt.value) + case err == nil && !tt.fail: + // All good + case err != nil && tt.fail: + // All good + default: + t.Errorf("expected no error, got error: %s", err) + } + }) + } + t.Run("null", func(t *testing.T) { + _, err := db.Query("insert into test_table values (null);") + assert.Contains(t, err.Error(), "violates check constraint") + }) +} + +func TestDomain_Bexprfilter(t *testing.T) { + const ( + createTable = ` +create table if not exists test_table ( + filter wt_bexprfilter +); +` + insert = ` +insert into test_table +values ($1); +` + ) + + conn, _ := TestSetup(t, "postgres") + db := conn.DB() + + if _, err := db.Exec(createTable); err != nil { + t.Fatalf("query: \n%s\n error: %s", createTable, err) + } + + tests := []struct { + value string + fail bool + }{ + { + " ", + true, + }, + { + "00000009", + false, + }, + { + "ABC123", + false, + }, + { + `"/foo/bar" in "/values"`, + false, + }, + { + strings.Repeat("1234567890", 204), + false, + }, + { + strings.Repeat("1234567890", 205), + true, + }, + } + for _, tt := range tests { + t.Run(tt.value, func(t *testing.T) { + // t.Logf("insert value: %q", tt.value) + _, err := db.Query(insert, tt.value) + switch { + case err == nil && tt.fail: + t.Errorf("want error, got no error for inserting value: %s", tt.value) + case err == nil && !tt.fail: + // All good + case err != nil && tt.fail: + // All good + default: + t.Errorf("expected no error, got error: %s", err) + } + }) + } + t.Run("null", func(t *testing.T) { + _, err := db.Query("insert into test_table values (null);") + assert.NoError(t, err) + }) +} + func TestDomain_Timestamp(t *testing.T) { const ( createTable = ` diff --git a/internal/db/read_writer.go b/internal/db/read_writer.go index 6bb5eb4ca..4ceabd217 100644 --- a/internal/db/read_writer.go +++ b/internal/db/read_writer.go @@ -1054,9 +1054,8 @@ func filterPaths(paths []string) []string { } func setFieldsToNil(i interface{}, fieldNames []string) { - if err := Clear(i, fieldNames, 2); err != nil { - // do nothing - } + // Note: error cases are not handled + _ = Clear(i, fieldNames, 2) } func isNil(i interface{}) bool { diff --git a/internal/db/schema/migrations/generate/Makefile b/internal/db/schema/migrations/generate/Makefile index 4e51dea15..d067e6c6f 100644 --- a/internal/db/schema/migrations/generate/Makefile +++ b/internal/db/schema/migrations/generate/Makefile @@ -4,5 +4,6 @@ THIS_FILE := $(lastword $(MAKEFILE_LIST)) migrations: go run . goimports -w ${GEN_BASEPATH}/internal/db/schema + gofumpt -w ${GEN_BASEPATH}/internal/db/schema .PHONY: migrations diff --git a/internal/db/schema/migrations/postgres/0/41_targets.up.sql b/internal/db/schema/migrations/postgres/0/41_targets.up.sql index 0720b5d92..13ebfd80f 100644 --- a/internal/db/schema/migrations/postgres/0/41_targets.up.sql +++ b/internal/db/schema/migrations/postgres/0/41_targets.up.sql @@ -154,6 +154,7 @@ before insert on target_tcp -- target_all_subtypes is a union of all target subtypes +-- NOTE: this is replaced in 100 to add worker_filter create view target_all_subtypes as select diff --git a/internal/db/schema/migrations/postgres/0/50_session.up.sql b/internal/db/schema/migrations/postgres/0/50_session.up.sql index 0e92f7c94..f43b34403 100644 --- a/internal/db/schema/migrations/postgres/0/50_session.up.sql +++ b/internal/db/schema/migrations/postgres/0/50_session.up.sql @@ -158,6 +158,7 @@ begin; endpoint text -- not part of the warehouse, used to send info to the worker ); + -- Replaced in 100 to add worker_filter create trigger immutable_columns before @@ -453,6 +454,7 @@ begin; create trigger insert_session_state before insert on session_state for each row execute procedure insert_session_state(); + -- Replaced in 100 to add worker_filter create view session_with_state as select s.public_id, diff --git a/internal/db/schema/migrations/postgres/dev/01_server_tags_migrations.down.sql b/internal/db/schema/migrations/postgres/dev/01_server_tags_migrations.down.sql new file mode 100644 index 000000000..71a055d92 --- /dev/null +++ b/internal/db/schema/migrations/postgres/dev/01_server_tags_migrations.down.sql @@ -0,0 +1,8 @@ +begin; + +drop domain wt_bexprfilter; + +drop table server_tag; +drop domain wt_tagpair; + +commit; \ No newline at end of file diff --git a/internal/db/schema/migrations/postgres/dev/01_server_tags_migrations.up.sql b/internal/db/schema/migrations/postgres/dev/01_server_tags_migrations.up.sql new file mode 100644 index 000000000..202e3c9fe --- /dev/null +++ b/internal/db/schema/migrations/postgres/dev/01_server_tags_migrations.up.sql @@ -0,0 +1,123 @@ +begin; + +-- This series of expressions fixes the primary key on the server table +alter table session + drop constraint session_server_id_server_type_fkey; +alter table server + drop constraint server_pkey; +alter table server + drop column name; +alter table server + add primary key (private_id); +alter table server + add constraint server_id_must_not_be_empty + check(length(trim(private_id)) > 0); +alter table session + add constraint session_server_id_fkey + foreign key (server_id) + references server(private_id) + on delete set null + on update cascade; + +create domain wt_bexprfilter as text +check( + value is null + or + ( + length(trim(value)) > 0 + and + length(trim(value)) <= 2048 + ) +); +comment on domain wt_bexprfilter is + 'Text field with constraints for go-bexpr filters'; + +-- Add the worker filter to the target_tcp table and session table +alter table target_tcp + add column worker_filter wt_bexprfilter; +alter table session + add column worker_filter wt_bexprfilter; + +-- Replace the immutable columns trigger from 50 to add worker_filter +drop trigger immutable_columns on session; +create trigger immutable_columns + before update on session + for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint', 'worker_filter'); + +-- Replaces the view created in 41 to include worker_filter +drop view target_all_subtypes; +create view target_all_subtypes +as +select + public_id, + scope_id, + name, + description, + default_port, + session_max_seconds, + session_connection_limit, + version, + create_time, + update_time, + worker_filter, + 'tcp' as type +from target_tcp; + +-- Replaces the view created in 50 to include worker_filter +drop view session_with_state; +create view session_with_state as + select + s.public_id, + s.user_id, + s.host_id, + s.server_id, + s.server_type, + s.target_id, + s.host_set_id, + s.auth_token_id, + s.scope_id, + s.certificate, + s.expiration_time, + s.connection_limit, + s.tofu_token, + s.key_id, + s.termination_reason, + s.version, + s.create_time, + s.update_time, + s.endpoint, + s.worker_filter, + ss.state, + ss.previous_end_time, + ss.start_time, + ss.end_time + from + session s, + session_state ss + where + s.public_id = ss.session_id; + +create domain wt_tagpair as text +check( + value is not null + and + length(trim(value)) > 0 + and + length(trim(value)) <= 512 + and + lower(trim(value)) = value +); +comment on domain wt_tagpair is + 'Text field with constraints for key/value pairs'; + +create table server_tag ( + server_id text + references server(private_id) + on delete cascade + on update cascade, + key wt_tagpair, + value wt_tagpair, + primary key(server_id, key, value) +); + +commit; \ No newline at end of file diff --git a/internal/db/schema/postgres_migration.gen.go b/internal/db/schema/postgres_migration.gen.go index 054957de8..c8ca26165 100644 --- a/internal/db/schema/postgres_migration.gen.go +++ b/internal/db/schema/postgres_migration.gen.go @@ -4,8 +4,8 @@ package schema func init() { migrationStates["postgres"] = migrationState{ - devMigration: false, - binarySchemaVersion: 69, + devMigration: true, + binarySchemaVersion: 1001, upMigrations: map[int][]byte{ 1: []byte(` begin; @@ -2930,6 +2930,7 @@ before insert on target_tcp -- target_all_subtypes is a union of all target subtypes +-- NOTE: this is replaced in 100 to add worker_filter create view target_all_subtypes as select @@ -3127,6 +3128,7 @@ begin; endpoint text -- not part of the warehouse, used to send info to the worker ); + -- Replaced in 100 to add worker_filter create trigger immutable_columns before @@ -3422,6 +3424,7 @@ begin; create trigger insert_session_state before insert on session_state for each row execute procedure insert_session_state(); + -- Replaced in 100 to add worker_filter create view session_with_state as select s.public_id, @@ -4861,6 +4864,131 @@ begin; commit; +`), + 1001: []byte(` +begin; + +-- This series of expressions fixes the primary key on the server table +alter table session + drop constraint session_server_id_server_type_fkey; +alter table server + drop constraint server_pkey; +alter table server + drop column name; +alter table server + add primary key (private_id); +alter table server + add constraint server_id_must_not_be_empty + check(length(trim(private_id)) > 0); +alter table session + add constraint session_server_id_fkey + foreign key (server_id) + references server(private_id) + on delete set null + on update cascade; + +create domain wt_bexprfilter as text +check( + value is null + or + ( + length(trim(value)) > 0 + and + length(trim(value)) <= 2048 + ) +); +comment on domain wt_bexprfilter is + 'Text field with constraints for go-bexpr filters'; + +-- Add the worker filter to the target_tcp table and session table +alter table target_tcp + add column worker_filter wt_bexprfilter; +alter table session + add column worker_filter wt_bexprfilter; + +-- Replace the immutable columns trigger from 50 to add worker_filter +drop trigger immutable_columns on session; +create trigger immutable_columns + before update on session + for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint', 'worker_filter'); + +-- Replaces the view created in 41 to include worker_filter +drop view target_all_subtypes; +create view target_all_subtypes +as +select + public_id, + scope_id, + name, + description, + default_port, + session_max_seconds, + session_connection_limit, + version, + create_time, + update_time, + worker_filter, + 'tcp' as type +from target_tcp; + +-- Replaces the view created in 50 to include worker_filter +drop view session_with_state; +create view session_with_state as + select + s.public_id, + s.user_id, + s.host_id, + s.server_id, + s.server_type, + s.target_id, + s.host_set_id, + s.auth_token_id, + s.scope_id, + s.certificate, + s.expiration_time, + s.connection_limit, + s.tofu_token, + s.key_id, + s.termination_reason, + s.version, + s.create_time, + s.update_time, + s.endpoint, + s.worker_filter, + ss.state, + ss.previous_end_time, + ss.start_time, + ss.end_time + from + session s, + session_state ss + where + s.public_id = ss.session_id; + +create domain wt_tagpair as text +check( + value is not null + and + length(trim(value)) > 0 + and + length(trim(value)) <= 512 + and + lower(trim(value)) = value +); +comment on domain wt_tagpair is + 'Text field with constraints for key/value pairs'; + +create table server_tag ( + server_id text + references server(private_id) + on delete cascade + on update cascade, + key wt_tagpair, + value wt_tagpair, + primary key(server_id, key, value) +); + +commit; `), }, downMigrations: map[int][]byte{ @@ -5216,6 +5344,16 @@ begin; commit; +`), + 1001: []byte(` +begin; + +drop domain wt_bexprfilter; + +drop table server_tag; +drop domain wt_tagpair; + +commit; `), }, } diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index 1cdb02065..d2d0f1983 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -3344,6 +3344,10 @@ "format": "int32", "description": "Maximum number of connections allowed in a Session. Unlimited is indicated by the value -1." }, + "worker_filter": { + "type": "string", + "description": "Optional boolean expression to filter the workers that are allowed to satisfy this request." + }, "attributes": { "type": "object", "description": "The attributes that are applicable for the specific Target." diff --git a/internal/gen/controller/api/resources/targets/target.pb.go b/internal/gen/controller/api/resources/targets/target.pb.go index 692248287..b2ac2dd48 100644 --- a/internal/gen/controller/api/resources/targets/target.pb.go +++ b/internal/gen/controller/api/resources/targets/target.pb.go @@ -115,6 +115,8 @@ type Target struct { SessionMaxSeconds *wrappers.UInt32Value `protobuf:"bytes,120,opt,name=session_max_seconds,proto3" json:"session_max_seconds,omitempty"` // Maximum number of connections allowed in a Session. Unlimited is indicated by the value -1. SessionConnectionLimit *wrappers.Int32Value `protobuf:"bytes,130,opt,name=session_connection_limit,proto3" json:"session_connection_limit,omitempty"` + // Optional boolean expression to filter the workers that are allowed to satisfy this request. + WorkerFilter *wrappers.StringValue `protobuf:"bytes,140,opt,name=worker_filter,proto3" json:"worker_filter,omitempty"` // The attributes that are applicable for the specific Target. Attributes *_struct.Struct `protobuf:"bytes,200,opt,name=attributes,proto3" json:"attributes,omitempty"` // Output only. The available actions on this resource for this user. @@ -244,6 +246,13 @@ func (x *Target) GetSessionConnectionLimit() *wrappers.Int32Value { return nil } +func (x *Target) GetWorkerFilter() *wrappers.StringValue { + if x != nil { + return x.WorkerFilter + } + return nil +} + func (x *Target) GetAttributes() *_struct.Struct { if x != nil { return x.Attributes @@ -649,7 +658,7 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, - 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x22, 0xce, 0x07, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, + 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x22, 0xba, 0x08, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x43, @@ -703,58 +712,34 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, - 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x12, 0x70, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, - 0x72, 0x74, 0x22, 0x26, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x18, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 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, 0x0c, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, - 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0b, - 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x82, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x08, 0x65, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x8d, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, - 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x96, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x77, - 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x91, 0x03, 0x0a, 0x14, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x6a, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x25, 0xa0, + 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1d, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x26, + 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, @@ -766,24 +751,55 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 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, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, - 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x46, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x30, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x64, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x55, - 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x5a, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, + 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x68, + 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, + 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x8d, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x18, 0x96, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x91, 0x03, 0x0a, 0x14, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, + 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x28, 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, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x32, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, + 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, 0x13, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x55, 0x5a, 0x53, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -822,18 +838,19 @@ var file_controller_api_resources_targets_v1_target_proto_depIdxs = []int32{ 0, // 5: controller.api.resources.targets.v1.Target.host_sets:type_name -> controller.api.resources.targets.v1.HostSet 9, // 6: controller.api.resources.targets.v1.Target.session_max_seconds:type_name -> google.protobuf.UInt32Value 10, // 7: controller.api.resources.targets.v1.Target.session_connection_limit:type_name -> google.protobuf.Int32Value - 11, // 8: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct - 9, // 9: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value - 6, // 10: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 8, // 11: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp - 3, // 12: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo - 6, // 13: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 8, // 14: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp - 15, // [15:15] is the sub-list for method output_type - 15, // [15:15] 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 + 7, // 8: controller.api.resources.targets.v1.Target.worker_filter:type_name -> google.protobuf.StringValue + 11, // 9: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct + 9, // 10: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value + 6, // 11: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 8, // 12: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp + 3, // 13: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo + 6, // 14: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 8, // 15: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp + 16, // [16:16] is the sub-list for method output_type + 16, // [16:16] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name } func init() { file_controller_api_resources_targets_v1_target_proto_init() } diff --git a/internal/gen/controller/servers/services/server_coordination_service.pb.go b/internal/gen/controller/servers/services/server_coordination_service.pb.go index 0424c5f70..6bf2e2bf6 100644 --- a/internal/gen/controller/servers/services/server_coordination_service.pb.go +++ b/internal/gen/controller/servers/services/server_coordination_service.pb.go @@ -474,6 +474,11 @@ type StatusRequest struct { Worker *servers.Server `protobuf:"bytes,10,opt,name=worker,proto3" json:"worker,omitempty"` // Jobs which this worker wants to report the status. Jobs []*JobStatus `protobuf:"bytes,20,rep,name=jobs,proto3" json:"jobs,omitempty"` + // Whether to update tags from the Server block on this RPC. We only need to + // do this at startup or (at some point) SIGHUP, so specifying when it's + // changed allows us to avoid constant database operations for something that + // won't change very often, if ever. + UpdateTags bool `protobuf:"varint,30,opt,name=update_tags,json=updateTags,proto3" json:"update_tags,omitempty"` } func (x *StatusRequest) Reset() { @@ -522,6 +527,13 @@ func (x *StatusRequest) GetJobs() []*JobStatus { return nil } +func (x *StatusRequest) GetUpdateTags() bool { + if x != nil { + return x.UpdateTags + } + return false +} + type JobChangeRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -687,7 +699,7 @@ var file_controller_servers_services_v1_server_coordination_service_proto_rawDes 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, - 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x85, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0xa6, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, @@ -695,69 +707,71 @@ var file_controller_servers_services_v1_server_coordination_service_proto_rawDes 0x3d, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, - 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x98, - 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x4d, 0x0a, 0x0c, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x52, 0x0b, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0xa8, 0x01, 0x0a, 0x0e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x12, 0x55, 0x0a, - 0x0d, 0x6a, 0x6f, 0x62, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x14, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0c, 0x6a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x73, 0x2a, 0x92, 0x01, 0x0a, 0x10, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, - 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e, - 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1f, 0x0a, 0x1b, 0x43, - 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, - 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, - 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x9e, 0x01, 0x0a, 0x0d, 0x53, 0x45, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x1d, 0x0a, 0x19, 0x53, - 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, - 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, - 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, - 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, 0x45, - 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x37, 0x0a, 0x07, 0x4a, 0x4f, - 0x42, 0x54, 0x59, 0x50, 0x45, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, - 0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, - 0x4e, 0x10, 0x01, 0x2a, 0x45, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, - 0x45, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, - 0x17, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, - 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x01, 0x32, 0x86, 0x01, 0x0a, 0x19, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x1f, + 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x1e, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x67, 0x73, 0x22, + 0x98, 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, - 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x4d, 0x0a, 0x0c, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x52, 0x0b, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0xa8, 0x01, 0x0a, 0x0e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, + 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x12, 0x55, + 0x0a, 0x0d, 0x6a, 0x6f, 0x62, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, + 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0c, 0x6a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x2a, 0x92, 0x01, 0x0a, 0x10, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, + 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1f, 0x0a, 0x1b, + 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1e, 0x0a, + 0x1a, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1b, 0x0a, + 0x17, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x9e, 0x01, 0x0a, 0x0d, 0x53, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x1d, 0x0a, 0x19, + 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, + 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, + 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, + 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x1c, 0x0a, + 0x18, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, + 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x37, 0x0a, 0x07, 0x4a, + 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x13, 0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, + 0x4f, 0x4e, 0x10, 0x01, 0x2a, 0x45, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, + 0x50, 0x45, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, + 0x0a, 0x17, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x01, 0x32, 0x86, 0x01, 0x0a, 0x19, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x06, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, + 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/gen/controller/servers/services/session_service.pb.go b/internal/gen/controller/servers/services/session_service.pb.go index 27caab49a..52a423bc4 100644 --- a/internal/gen/controller/servers/services/session_service.pb.go +++ b/internal/gen/controller/servers/services/session_service.pb.go @@ -30,6 +30,9 @@ type LookupSessionRequest struct { // The session ID from the client SessionId string `protobuf:"bytes,10,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // The name of the requesting worker, used for filtering to ensure this + // worker is allowed to handle this session. + ServerId string `protobuf:"bytes,20,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` } func (x *LookupSessionRequest) Reset() { @@ -71,6 +74,13 @@ func (x *LookupSessionRequest) GetSessionId() string { return "" } +func (x *LookupSessionRequest) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + // LookupSessionResponse contains information necessary for a client to // establish a session. type LookupSessionResponse struct { @@ -912,204 +922,206 @@ var file_controller_servers_services_v1_session_service_proto_rawDesc = []byte{ 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x35, 0x0a, 0x14, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x22, 0x52, 0x0a, 0x14, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x99, 0x04, 0x0a, 0x15, 0x4c, 0x6f, 0x6f, 0x6b, - 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x63, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x32, 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, 0x0a, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, - 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x46, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x50, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x4c, 0x65, 0x66, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, - 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x64, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, - 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x22, 0xd4, 0x01, 0x0a, 0x16, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, - 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x5f, 0x69, 0x64, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x32, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x60, 0x0a, 0x17, 0x41, 0x63, - 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x35, 0x0a, 0x14, - 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x22, 0x5e, 0x0a, 0x15, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x3b, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x49, 0x64, 0x22, 0x99, 0x04, 0x0a, 0x15, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, + 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1e, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x32, 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, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x3c, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x46, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x65, 0x66, + 0x74, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x5a, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, + 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x22, 0xd4, 0x01, 0x0a, 0x16, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, + 0x66, 0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x74, 0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x60, 0x0a, 0x17, 0x41, 0x63, 0x74, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x22, 0xb7, 0x01, 0x0a, 0x1b, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, - 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, - 0x65, 0x66, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x87, 0x02, 0x0a, 0x18, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x54, 0x63, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x1e, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x50, 0x6f, - 0x72, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, - 0x63, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x12, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x65, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, - 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x1a, - 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x18, 0x14, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x55, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x22, 0x82, 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x68, 0x0a, 0x12, - 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x10, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8c, 0x01, 0x0a, 0x1b, 0x43, 0x6c, 0x6f, 0x73, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, - 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x17, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6b, 0x0a, 0x13, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, + 0x22, 0x5e, 0x0a, 0x15, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, + 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x22, 0x3b, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, + 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xb7, 0x01, + 0x0a, 0x1b, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, + 0x18, 0x1e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x87, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x63, 0x70, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, + 0x30, 0x0a, 0x14, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x63, + 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x65, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x11, 0x63, 0x6c, 0x6f, - 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x32, 0xbe, - 0x06, 0x0a, 0x0e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x7e, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x1a, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x55, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x82, + 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x68, 0x0a, 0x12, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x10, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, + 0x61, 0x74, 0x61, 0x22, 0x8c, 0x01, 0x0a, 0x1b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x17, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, + 0x0a, 0x13, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x11, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x32, 0xbe, 0x06, 0x0a, 0x0e, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, + 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, + 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, 0x13, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, 0x13, 0x41, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8a, 0x01, 0x0a, 0x11, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8a, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, - 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, - 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, - 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/proto/local/controller/api/resources/targets/v1/target.proto b/internal/proto/local/controller/api/resources/targets/v1/target.proto index 8ec11e1c9..64ad58274 100644 --- a/internal/proto/local/controller/api/resources/targets/v1/target.proto +++ b/internal/proto/local/controller/api/resources/targets/v1/target.proto @@ -42,7 +42,7 @@ message Target { google.protobuf.Timestamp updated_time = 70 [json_name="updated_time"]; // Version is used in mutation requests, after the initial creation, to ensure this resource has not changed. - // The mutation will fail if the version does not match the latest known good version. + // The mutation will fail if the version does not match the latest known good version. uint32 version = 80; // The type of the Target. @@ -55,10 +55,13 @@ message Target { repeated HostSet host_sets = 110 [json_name="host_sets"]; // Maximum total lifetime of a created Session, in seconds. - google.protobuf.UInt32Value session_max_seconds = 120 [json_name="session_max_seconds", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"session_max_seconds" that: "SessionMaxSeconds"}]; + google.protobuf.UInt32Value session_max_seconds = 120 [json_name="session_max_seconds", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this: "session_max_seconds" that: "SessionMaxSeconds"}]; // Maximum number of connections allowed in a Session. Unlimited is indicated by the value -1. - google.protobuf.Int32Value session_connection_limit = 130 [json_name="session_connection_limit", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"session_connection_limit" that: "SessionConnectionLimit"}]; + google.protobuf.Int32Value session_connection_limit = 130 [json_name="session_connection_limit", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this: "session_connection_limit" that: "SessionConnectionLimit"}]; + + // Optional boolean expression to filter the workers that are allowed to satisfy this request. + google.protobuf.StringValue worker_filter = 140 [json_name="worker_filter", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this: "worker_filter" that: "WorkerFilter"}]; // The attributes that are applicable for the specific Target. google.protobuf.Struct attributes = 200 [(custom_options.v1.generate_sdk_option) = true]; @@ -70,7 +73,7 @@ message Target { // TcpTargetAttributes contains attributes relevant to Targets of type "tcp" message TcpTargetAttributes { // The default TCP port that will be used when connecting to the endpoint unless overridden by a Host Set or Host. - google.protobuf.UInt32Value default_port = 10 [json_name="default_port", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"attributes.default_port" that: "DefaultPort"}]; + google.protobuf.UInt32Value default_port = 10 [json_name="default_port", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this: "attributes.default_port" that: "DefaultPort"}]; } // WorkerInfo contains information about workers, returned in to the client in SessionAuthorization diff --git a/internal/proto/local/controller/servers/services/v1/server_coordination_service.proto b/internal/proto/local/controller/servers/services/v1/server_coordination_service.proto index 51b06f7c7..2925bb5e5 100644 --- a/internal/proto/local/controller/servers/services/v1/server_coordination_service.proto +++ b/internal/proto/local/controller/servers/services/v1/server_coordination_service.proto @@ -65,6 +65,12 @@ message StatusRequest { // Jobs which this worker wants to report the status. repeated JobStatus jobs = 20; + + // Whether to update tags from the Server block on this RPC. We only need to + // do this at startup or (at some point) SIGHUP, so specifying when it's + // changed allows us to avoid constant database operations for something that + // won't change very often, if ever. + bool update_tags = 30; } enum CHANGETYPE { diff --git a/internal/proto/local/controller/servers/services/v1/session_service.proto b/internal/proto/local/controller/servers/services/v1/session_service.proto index a3a18f5fd..67a83d7ed 100644 --- a/internal/proto/local/controller/servers/services/v1/session_service.proto +++ b/internal/proto/local/controller/servers/services/v1/session_service.proto @@ -33,6 +33,9 @@ service SessionService { message LookupSessionRequest { // The session ID from the client string session_id = 10; + // The name of the requesting worker, used for filtering to ensure this + // worker is allowed to handle this session. + string server_id = 20; } // LookupSessionResponse contains information necessary for a client to diff --git a/internal/proto/local/controller/servers/v1/servers.proto b/internal/proto/local/controller/servers/v1/servers.proto index 45d251bd5..cc02349f3 100644 --- a/internal/proto/local/controller/servers/v1/servers.proto +++ b/internal/proto/local/controller/servers/v1/servers.proto @@ -13,8 +13,11 @@ message Server { // Type of the resource (controller, worker) string type = 20; - // Name of the resource - string name = 30; + // Name of the resource. This is deprecated because we ended up setting the + // private ID and name to be identical, and there is currently no reason we + // can think of to allow a given server's name to match another within the + // same cluster. So we simply use the private ID and deprecate this. + string name = 30 [deprecated = true]; // Description of the resource string description = 40; @@ -27,4 +30,13 @@ message Server { // Last time there was an update storage.timestamp.v1.Timestamp update_time = 70; + + // Tags for workers + map tags = 80; } + +// TagValues is used because map fields cannot be repeated but can be a +// message +message TagValues { + repeated string values = 10; +} \ No newline at end of file diff --git a/internal/proto/local/controller/storage/target/store/v1/target.proto b/internal/proto/local/controller/storage/target/store/v1/target.proto index 56234c01a..b66b6e4d4 100644 --- a/internal/proto/local/controller/storage/target/store/v1/target.proto +++ b/internal/proto/local/controller/storage/target/store/v1/target.proto @@ -53,6 +53,10 @@ message TargetView { // Maximum number of connections in a session // @inject_tag: `gorm:"default:null"` int32 session_connection_limit = 110; + + // A boolean expression that allows filtering the workers that can handle a session + // @inject_tag: `gorm:"default:null"` + string worker_filter = 120; } message TargetHostSet { @@ -124,4 +128,11 @@ message TcpTarget { this: "SessionConnectionLimit" that: "session_connection_limit" }]; + + // A boolean expression that allows filtering the workers that can handle a session + // @inject_tag: `gorm:"default:null"` + string worker_filter = 120 [(custom_options.v1.mask_mapping) = { + this: "WorkerFilter" + that: "worker_filter" + }]; } \ No newline at end of file diff --git a/internal/servers/controller/handlers/targets/target_service.go b/internal/servers/controller/handlers/targets/target_service.go index 0c9466766..b6e0e033e 100644 --- a/internal/servers/controller/handlers/targets/target_service.go +++ b/internal/servers/controller/handlers/targets/target_service.go @@ -28,6 +28,7 @@ import ( "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/types/scope" "github.com/hashicorp/boundary/sdk/strutil" + "github.com/hashicorp/go-bexpr" "github.com/mr-tron/base58" "google.golang.org/grpc/codes" "google.golang.org/protobuf/proto" @@ -418,6 +419,7 @@ HostSetIterationLoop: Endpoint: endpointUrl.String(), ExpirationTime: ×tamp.Timestamp{Timestamp: expTime}, ConnectionLimit: t.GetSessionConnectionLimit(), + WorkerFilter: t.GetWorkerFilter(), } sess, err := session.New(sessionComposition) @@ -433,15 +435,77 @@ HostSetIterationLoop: return nil, err } + // WorkerInfo only contains the address; worker IDs below is used to contain + // their IDs in the same order. This is used to fetch tags for filtering. + // But we avoid allocation unless we actually need it. var workers []*pb.WorkerInfo + var workerIds []string + hasWorkerFilter := len(t.GetWorkerFilter()) > 0 servers, err := serversRepo.ListServers(ctx, servers.ServerTypeWorker) if err != nil { return nil, err } for _, v := range servers { + if hasWorkerFilter { + workerIds = append(workerIds, v.GetPrivateId()) + } workers = append(workers, &pb.WorkerInfo{Address: v.Address}) } + if hasWorkerFilter && len(workerIds) > 0 { + finalWorkers := make([]*pb.WorkerInfo, 0, len(workers)) + // Fetch the tags for the given worker IDs + tags, err := serversRepo.ListTagsForServers(ctx, workerIds) + if err != nil { + return nil, err + } + // Build the map for filtering. This is similar to the filter map we + // built from the worker config, but with one extra level: a map of the + // worker's ID to its filter map. + tagMap := make(map[string]map[string][]string) + for _, tag := range tags { + currWorkerMap := tagMap[tag.ServerId] + if currWorkerMap == nil { + currWorkerMap = make(map[string][]string) + tagMap[tag.ServerId] = currWorkerMap + } + currWorkerMap[tag.Key] = append(currWorkerMap[tag.Key], tag.Value) + // We don't need to reinsert after the fact because maps are + // reference types, so we don't need to re-insert into tagMap + } + + // Create the evaluator + eval, err := bexpr.CreateEvaluator(t.GetWorkerFilter()) + if err != nil { + return nil, err + } + + // Iterate through the known worker IDs, and evaluate. If evaluation + // returns true, add to the final worker slice, which is assigned back + // to workers after this. + for i, worker := range workerIds { + filterInput := map[string]interface{}{ + "name": worker, + "tags": tagMap[worker], + } + ok, err := eval.Evaluate(filterInput) + if err != nil { + return nil, handlers.ApiErrorWithCodeAndMessage( + codes.FailedPrecondition, + fmt.Sprintf("Worker filter expression evaluation resulted in error: %s", err)) + } + if ok { + finalWorkers = append(finalWorkers, workers[i]) + } + } + workers = finalWorkers + } + if len(workers) == 0 { + return nil, handlers.ApiErrorWithCodeAndMessage( + codes.FailedPrecondition, + "No workers are available to handle this session, or all have been filtered.") + } + sad := &pb.SessionAuthorizationData{ SessionId: sess.PublicId, TargetId: t.GetPublicId(), @@ -505,6 +569,9 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (*pb.Target, if item.GetSessionConnectionLimit() != nil { opts = append(opts, target.WithSessionConnectionLimit(item.GetSessionConnectionLimit().GetValue())) } + if item.GetWorkerFilter() != nil { + opts = append(opts, target.WithWorkerFilter(item.GetWorkerFilter().GetValue())) + } tcpAttrs := &pb.TcpTargetAttributes{} if err := handlers.StructToProto(item.GetAttributes(), tcpAttrs); err != nil { return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "Provided attributes don't match expected format.") @@ -544,6 +611,9 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st if item.GetSessionConnectionLimit() != nil { opts = append(opts, target.WithSessionConnectionLimit(item.GetSessionConnectionLimit().GetValue())) } + if filter := item.GetWorkerFilter(); filter != nil { + opts = append(opts, target.WithWorkerFilter(item.GetWorkerFilter().GetValue())) + } tcpAttrs := &pb.TcpTargetAttributes{} if err := handlers.StructToProto(item.GetAttributes(), tcpAttrs); err != nil { return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "Provided attributes don't match expected format.") @@ -737,6 +807,9 @@ func toProto(in target.Target, m []*target.TargetSet) (*pb.Target, error) { if in.GetName() != "" { out.Name = wrapperspb.String(in.GetName()) } + if in.GetWorkerFilter() != "" { + out.WorkerFilter = wrapperspb.String(in.GetWorkerFilter()) + } attrs := &pb.TcpTargetAttributes{} if in.GetDefaultPort() > 0 { attrs.DefaultPort = &wrappers.UInt32Value{Value: in.GetDefaultPort()} @@ -803,6 +876,11 @@ func validateCreateRequest(req *pbs.CreateTargetRequest) error { default: badFields["type"] = "Unknown type provided." } + if filter := req.GetItem().GetWorkerFilter(); filter != nil { + if _, err := bexpr.CreateEvaluator(filter.GetValue()); err != nil { + badFields["worker_filter"] = "Unable to successfully parse filter expression." + } + } return badFields }) } @@ -838,6 +916,11 @@ func validateUpdateRequest(req *pbs.UpdateTargetRequest) error { badFields["attributes.default_port"] = "This optional field cannot be set to 0." } } + if filter := req.GetItem().GetWorkerFilter(); filter != nil { + if _, err := bexpr.CreateEvaluator(filter.GetValue()); err != nil { + badFields["worker_filter"] = "Unable to successfully parse filter expression." + } + } return badFields }) } diff --git a/internal/servers/controller/handlers/workers/worker_service.go b/internal/servers/controller/handlers/workers/worker_service.go index 8e5157022..17da40184 100644 --- a/internal/servers/controller/handlers/workers/worker_service.go +++ b/internal/servers/controller/handlers/workers/worker_service.go @@ -2,15 +2,19 @@ package workers import ( "context" + "fmt" "sync" "time" "github.com/hashicorp/boundary/internal/gen/controller/api/resources/targets" pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services" "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/boundary/internal/servers/controller/common" + "github.com/hashicorp/boundary/internal/servers/controller/handlers" "github.com/hashicorp/boundary/internal/session" "github.com/hashicorp/boundary/internal/types/resource" + "github.com/hashicorp/go-bexpr" "github.com/hashicorp/go-hclog" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -48,15 +52,15 @@ var ( ) func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) { - ws.logger.Trace("got status request from worker", "name", req.Worker.Name, "address", req.Worker.Address, "jobs", req.GetJobs()) - ws.updateTimes.Store(req.Worker.Name, time.Now()) + ws.logger.Trace("got status request from worker", "name", req.Worker.PrivateId, "address", req.Worker.Address, "jobs", req.GetJobs()) + ws.updateTimes.Store(req.Worker.PrivateId, time.Now()) repo, err := ws.serversRepoFn() if err != nil { ws.logger.Error("error getting servers repo", "error", err) return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error aqcuiring repo to store worker status: %v", err) } req.Worker.Type = resource.Worker.String() - controllers, _, err := repo.UpsertServer(ctx, req.Worker) + controllers, _, err := repo.UpsertServer(ctx, req.Worker, servers.WithUpdateTags(req.GetUpdateTags())) if err != nil { ws.logger.Error("error storing worker status", "error", err) return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error storing worker status: %v", err) @@ -149,6 +153,51 @@ func (ws *workerServiceServer) LookupSession(ctx context.Context, req *pbs.Looku return nil, status.Error(codes.Internal, "Empty session states during lookup.") } + if sessionInfo.WorkerFilter != "" { + if req.ServerId == "" { + ws.logger.Error("worker filter enabled for session but got no server ID from worker") + return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Did not receive server ID when looking up session but filtering is enabled: %v", err) + } + serversRepo, err := ws.serversRepoFn() + if err != nil { + ws.logger.Error("error getting servers repo", "error", err) + return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error acquiring server repo when looking up session: %v", err) + } + tags, err := serversRepo.ListTagsForServers(ctx, []string{req.ServerId}) + if err != nil { + ws.logger.Error("error looking up tags for server", "error", err, "server_id", req.ServerId) + return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error looking up tags for server: %v", err) + } + // Build the map for filtering. + tagMap := make(map[string][]string) + for _, tag := range tags { + tagMap[tag.Key] = append(tagMap[tag.Key], tag.Value) + // We don't need to reinsert after the fact because maps are + // reference types, so we don't need to re-insert into tagMap + } + + // Create the evaluator + eval, err := bexpr.CreateEvaluator(sessionInfo.WorkerFilter) + if err != nil { + ws.logger.Error("error creating worker filter evaluator", "error", err, "server_id", req.ServerId) + return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error creating worker filter evaluator: %v", err) + } + filterInput := map[string]interface{}{ + "name": req.ServerId, + "tags": tagMap, + } + ok, err := eval.Evaluate(filterInput) + if err != nil { + return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, + fmt.Sprintf("Worker filter expression evaluation resulted in error: %s", err)) + } + if !ok { + return nil, handlers.ApiErrorWithCodeAndMessage( + codes.FailedPrecondition, + "Worker filter expression precludes this worker from serving this session") + } + } + resp := &pbs.LookupSessionResponse{ Authorization: &targets.SessionAuthorizationData{ SessionId: sessionInfo.GetPublicId(), diff --git a/internal/servers/controller/testing.go b/internal/servers/controller/testing.go index 330fc5a23..01b10fa32 100644 --- a/internal/servers/controller/testing.go +++ b/internal/servers/controller/testing.go @@ -305,6 +305,9 @@ type TestControllerOpts struct { // generated, unless provided in a non-nil Config Name string + // The suffix to use for initial resources + InitialResourcesSuffix string + // The logger to use, or one will be created Logger hclog.Logger } @@ -383,6 +386,18 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController { } tc.name = opts.Config.Controller.Name + if opts.InitialResourcesSuffix != "" { + suffix := opts.InitialResourcesSuffix + tc.b.DevAuthMethodId = "ampw_" + suffix + tc.b.DevHostCatalogId = "hcst_" + suffix + tc.b.DevHostId = "hst_" + suffix + tc.b.DevHostSetId = "hsst_" + suffix + tc.b.DevOrgId = "o_" + suffix + tc.b.DevProjectId = "p_" + suffix + tc.b.DevTargetId = "ttcp_" + suffix + tc.b.DevUserId = "u_" + suffix + } + // Set up KMSes switch { case opts.RootKms != nil && opts.WorkerAuthKms != nil: diff --git a/internal/servers/options.go b/internal/servers/options.go index 114f983e0..6c2b0cf51 100644 --- a/internal/servers/options.go +++ b/internal/servers/options.go @@ -16,8 +16,9 @@ type Option func(*options) // options = how options are represented type options struct { - withLimit int - withLiveness time.Duration + withLimit int + withLiveness time.Duration + withUpdateTags bool } func getDefaultOptions() options { @@ -43,3 +44,12 @@ func WithLiveness(liveness time.Duration) Option { o.withLiveness = liveness } } + +// WithUpdateTags indicates that we should perform tag updates in the DB. +// This would happen on first sync from a worker after startup or (eventually, +// perhaps), after a SIGHUP. +func WithUpdateTags(updateTags bool) Option { + return func(o *options) { + o.withUpdateTags = updateTags + } +} diff --git a/internal/servers/options_test.go b/internal/servers/options_test.go new file mode 100644 index 000000000..6ceedfc52 --- /dev/null +++ b/internal/servers/options_test.go @@ -0,0 +1,27 @@ +package servers + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +// Test_GetOpts provides unit tests for GetOpts and all the options +func Test_GetOpts(t *testing.T) { + t.Parallel() + opts := getOpts() + assert.Equal(t, options{}, opts) + + opts = getOpts( + WithLimit(5), + WithLiveness(time.Hour), + WithUpdateTags(true), + ) + exp := options{ + withLimit: 5, + withLiveness: time.Hour, + withUpdateTags: true, + } + assert.Equal(t, exp, opts) +} diff --git a/internal/servers/query.go b/internal/servers/query.go index a2a60c07e..6f6268e74 100644 --- a/internal/servers/query.go +++ b/internal/servers/query.go @@ -1,5 +1,18 @@ package servers const ( - deleteWhereSql = `create_time < $1` + serverUpsertQuery = ` + insert into server + (private_id, type, description, address, update_time) + values + ($1, $2, $3, $4, $5) + on conflict on constraint server_pkey + do update set + type = $2, + description = $3, + address = $4, + update_time = $5; + ` + deleteWhereCreateTimeSql = `create_time < $1` + deleteTagsSql = `server_id = $1` ) diff --git a/internal/servers/repository.go b/internal/servers/repository.go index 3759dcaa3..d59a0776f 100644 --- a/internal/servers/repository.go +++ b/internal/servers/repository.go @@ -2,12 +2,12 @@ package servers import ( "context" - "errors" "fmt" "time" "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/types/resource" ) @@ -37,14 +37,15 @@ type Repository struct { // NewRepository creates a new servers Repository. Supports the options: WithLimit // which sets a default limit on results returned by repo operations. func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms) (*Repository, error) { + const op = "servers.NewRepository" if r == nil { - return nil, errors.New("error creating server repository with nil reader") + return nil, errors.New(errors.InvalidParameter, op, "nil reader") } if w == nil { - return nil, errors.New("error creating server repository with nil writer") + return nil, errors.New(errors.InvalidParameter, op, "nil writer") } if kms == nil { - return nil, errors.New("error creating server repository with nil kms") + return nil, errors.New(errors.InvalidParameter, op, "nil kms") } return &Repository{ reader: r, @@ -53,9 +54,16 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms) (*Repository, error) }, nil } -// list will return a listing of resources and honor the WithLimit option or the -// repo defaultLimit +// ListServers is a passthrough to listServersWithReader that uses the repo's +// normal reader. func (r *Repository) ListServers(ctx context.Context, serverType ServerType, opt ...Option) ([]*Server, error) { + return r.listServersWithReader(ctx, r.reader, serverType, opt...) +} + +// listServersWithReader will return a listing of resources and honor the +// WithLimit option or the repo defaultLimit. It accepts a reader, allowing it +// to be used within a transaction or without. +func (r *Repository) listServersWithReader(ctx context.Context, reader db.Reader, serverType ServerType, opt ...Option) ([]*Server, error) { opts := getOpts(opt...) liveness := opts.withLiveness if liveness == 0 { @@ -63,58 +71,128 @@ func (r *Repository) ListServers(ctx context.Context, serverType ServerType, opt } updateTime := time.Now().Add(-1 * liveness) var servers []*Server - if err := r.reader.SearchWhere( + if err := reader.SearchWhere( ctx, &servers, "type = $1 and update_time > $2", []interface{}{serverType, updateTime.Format(time.RFC3339)}, db.WithLimit(-1), ); err != nil { - return nil, fmt.Errorf("error listing servers: %w", err) + return nil, errors.Wrap(err, "servers.listServersWithReader") } return servers, nil } +// ServerTag holds the information for the server_tag table for Gorm. +type ServerTag struct { + ServerId string + Key string + Value string +} + +// TableName overrides the table name used by ServerTag to `server_tag` +func (ServerTag) TableName() string { + return "server_tag" +} + +// ListTagsForServers pulls out tag tuples into ServerTag structs for the +// given server ID values. +func (r *Repository) ListTagsForServers(ctx context.Context, serverIds []string, opt ...Option) ([]*ServerTag, error) { + var serverTags []*ServerTag + if err := r.reader.SearchWhere( + ctx, + &serverTags, + "server_id in (?)", + []interface{}{serverIds}, + db.WithLimit(-1), + ); err != nil { + return nil, errors.Wrap(err, "servers.ListTagsForServers", errors.WithMsg(fmt.Sprintf("server IDs %v", serverIds))) + } + return serverTags, nil +} + // UpsertServer adds or updates a server in the DB func (r *Repository) UpsertServer(ctx context.Context, server *Server, opt ...Option) ([]*Server, int, error) { - if server == nil { - return nil, db.NoRowsAffected, errors.New("cannot update server that is nil") - } - // Ensure, for now at least, the private ID is always equivalent to the name - server.PrivateId = server.Name - // Build query - q := ` - insert into server - (private_id, type, name, description, address, update_time) - values - ($1, $2, $3, $4, $5, $6) - on conflict on constraint server_pkey - do update set - name = $3, - description = $4, - address = $5, - update_time = $6; - ` + const op = "servers.UpsertServer" - rowsAffected, err := r.writer.Exec(ctx, q, - []interface{}{ - server.PrivateId, - server.Type, - server.Name, - server.Description, - server.Address, - time.Now().Format(time.RFC3339), - }) + if server == nil { + return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "server is nil") + } + + opts := getOpts(opt...) + + var rowsUpdated int + var controllers []*Server + _, err := r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(read db.Reader, w db.Writer) error { + var err error + rowsUpdated, err = w.Exec(ctx, + serverUpsertQuery, + []interface{}{ + server.PrivateId, + server.Type, + server.Description, + server.Address, + time.Now().Format(time.RFC3339), + }) + if err != nil { + return errors.Wrap(err, op+":Upsert") + } + + // If it's a worker, fetch the current controllers to feed to them + if server.Type == resource.Worker.String() { + // Fetch current controllers to feed to the workers + controllers, err = r.listServersWithReader(ctx, read, ServerTypeController) + if err != nil { + return errors.Wrap(err, op+":ListServer") + } + } + + // If we've been told to update tags, we need to clean out old + // ones and add new ones. Within the current transaction, simply + // delete all tags for the given worker, then add the new ones + // we've been sent. + if opts.withUpdateTags { + _, err = w.Delete(ctx, &ServerTag{}, db.WithWhere(deleteTagsSql, server.PrivateId)) + if err != nil { + return errors.Wrap(err, op+":DeleteTags", errors.WithMsg(server.PrivateId)) + } + + // If tags were cleared out entirely, then we'll have nothing + // to do here, e.g., it will result in deletion of all tags. + // Otherwise, go through and stage each tuple for insertion + // below. + if len(server.Tags) > 0 { + tags := make([]interface{}, 0, len(server.Tags)) + for k, v := range server.Tags { + if v == nil { + return errors.New(errors.InvalidParameter, op+":RangeTags", fmt.Sprintf("found nil tag value for worker %s and key %s", server.PrivateId, k)) + } + for _, val := range v.Values { + tags = append(tags, ServerTag{ + ServerId: server.PrivateId, + Key: k, + Value: val, + }) + } + } + if err = w.CreateItems(ctx, tags); err != nil { + return errors.Wrap(err, op+":CreateTags", errors.WithMsg(server.PrivateId)) + } + } + } + + return nil + }, + ) if err != nil { - return nil, db.NoRowsAffected, fmt.Errorf("error performing status upsert: %w", err) + return nil, db.NoRowsAffected, err } - // If updating a controller, done - if server.Type == resource.Controller.String() { - return nil, int(rowsAffected), nil - } - // Fetch current controllers to feed to the workers - controllers, err := r.ListServers(ctx, ServerTypeController) - return controllers, len(controllers), err + + return controllers, rowsUpdated, nil } type RecoveryNonce struct { @@ -123,12 +201,13 @@ type RecoveryNonce struct { // AddRecoveryNonce adds a nonce func (r *Repository) AddRecoveryNonce(ctx context.Context, nonce string, opt ...Option) error { + const op = "servers.AddRecoveryNonce" if nonce == "" { - return errors.New("empty nonce provided") + return errors.New(errors.InvalidParameter, op, "empty nonce") } rn := &RecoveryNonce{Nonce: nonce} if err := r.writer.Create(ctx, rn); err != nil { - return fmt.Errorf("error performing nonce insertion: %w", err) + return errors.Wrap(err, op+":Insertion") } return nil } @@ -138,9 +217,9 @@ func (r *Repository) CleanupNonces(ctx context.Context, opt ...Option) (int, err // If something was inserted before 3x the actual validity period, clean it out endTime := time.Now().Add(-3 * globals.RecoveryTokenValidityPeriod) - rows, err := r.writer.Delete(ctx, &RecoveryNonce{}, db.WithWhere(deleteWhereSql, endTime)) + rows, err := r.writer.Delete(ctx, &RecoveryNonce{}, db.WithWhere(deleteWhereCreateTimeSql, endTime)) if err != nil { - return db.NoRowsAffected, fmt.Errorf("error performing nonce cleanup: %w", err) + return db.NoRowsAffected, errors.Wrap(err, "servers.CleanupNonces") } return rows, nil } @@ -149,7 +228,7 @@ func (r *Repository) CleanupNonces(ctx context.Context, opt ...Option) (int, err func (r *Repository) ListNonces(ctx context.Context, opt ...Option) ([]*RecoveryNonce, error) { var nonces []*RecoveryNonce if err := r.reader.SearchWhere(ctx, &nonces, "", nil, db.WithLimit(-1)); err != nil { - return nil, fmt.Errorf("error listing nonces: %w", err) + return nil, errors.Wrap(err, "servers.ListNonces") } return nonces, nil } diff --git a/internal/servers/repository_test.go b/internal/servers/repository_test.go index 0b052f7f9..f58736f0c 100644 --- a/internal/servers/repository_test.go +++ b/internal/servers/repository_test.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/boundary/api/roles" "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/boundary/internal/servers/controller" "github.com/hashicorp/boundary/internal/types/scope" "github.com/hashicorp/boundary/sdk/recovery" @@ -78,3 +79,104 @@ func TestRecoveryNonces(t *testing.T) { assert.Len(nonces, 0) } } + +func TestTagUpdatingListing(t *testing.T) { + require := require.New(t) + + wrapper := db.TestWrapper(t) + tc := controller.NewTestController(t, &controller.TestControllerOpts{ + RecoveryKms: wrapper, + }) + defer tc.Shutdown() + + repo := tc.ServersRepo() + srv := &servers.Server{ + PrivateId: "test1", + Type: "worker", + Address: "127.0.0.1", + Tags: map[string]*servers.TagValues{ + "tag1": { + Values: []string{"value1", "value2"}, + }, + }, + } + _, _, err := repo.UpsertServer(tc.Context(), srv, servers.WithUpdateTags(true)) + require.NoError(err) + + srv = &servers.Server{ + PrivateId: "test2", + Type: "worker", + Address: "127.0.0.1", + Tags: map[string]*servers.TagValues{ + "tag2": { + Values: []string{"value1", "value2"}, + }, + }, + } + _, _, err = repo.UpsertServer(tc.Context(), srv, servers.WithUpdateTags(true)) + require.NoError(err) + + tags, err := repo.ListTagsForServers(tc.Context(), []string{"test1", "test2"}) + require.NoError(err) + + // Base case + exp := []*servers.ServerTag{ + { + ServerId: "test1", + Key: "tag1", + Value: "value1", + }, + { + ServerId: "test1", + Key: "tag1", + Value: "value2", + }, + { + ServerId: "test2", + Key: "tag2", + Value: "value1", + }, + { + ServerId: "test2", + Key: "tag2", + Value: "value2", + }, + } + require.Equal(exp, tags) + + // Update without saying to update tags + srv = &servers.Server{ + PrivateId: "test2", + Type: "worker", + Address: "192.168.1.1", + Tags: map[string]*servers.TagValues{ + "tag22": { + Values: []string{"value21", "value22"}, + }, + }, + } + _, _, err = repo.UpsertServer(tc.Context(), srv) + require.NoError(err) + tags, err = repo.ListTagsForServers(tc.Context(), []string{"test1", "test2"}) + require.NoError(err) + require.Equal(exp, tags) + + // Update tags and test again + _, _, err = repo.UpsertServer(tc.Context(), srv, servers.WithUpdateTags(true)) + require.NoError(err) + tags, err = repo.ListTagsForServers(tc.Context(), []string{"test1", "test2"}) + require.NoError(err) + require.NotEqual(exp, tags) + // Update and try again + exp[2] = &servers.ServerTag{ + ServerId: "test2", + Key: "tag22", + Value: "value21", + } + exp[3] = &servers.ServerTag{ + ServerId: "test2", + Key: "tag22", + Value: "value22", + } + require.Equal(exp, tags) +} diff --git a/internal/servers/servers.pb.go b/internal/servers/servers.pb.go index 16d634639..3de0b88a3 100644 --- a/internal/servers/servers.pb.go +++ b/internal/servers/servers.pb.go @@ -31,7 +31,12 @@ type Server struct { PrivateId string `protobuf:"bytes,10,opt,name=private_id,json=privateId,proto3" json:"private_id,omitempty"` // Type of the resource (controller, worker) Type string `protobuf:"bytes,20,opt,name=type,proto3" json:"type,omitempty"` - // Name of the resource + // Name of the resource. This is deprecated because we ended up setting the + // private ID and name to be identical, and there is currently no reason we + // can think of to allow a given server's name to match another within the + // same cluster. So we simply use the private ID and deprecate this. + // + // Deprecated: Do not use. Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty"` // Description of the resource Description string `protobuf:"bytes,40,opt,name=description,proto3" json:"description,omitempty"` @@ -41,6 +46,8 @@ type Server struct { CreateTime *timestamp.Timestamp `protobuf:"bytes,60,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` // Last time there was an update UpdateTime *timestamp.Timestamp `protobuf:"bytes,70,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + // Tags for workers + Tags map[string]*TagValues `protobuf:"bytes,80,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Server) Reset() { @@ -89,6 +96,7 @@ func (x *Server) GetType() string { return "" } +// Deprecated: Do not use. func (x *Server) GetName() string { if x != nil { return x.Name @@ -124,6 +132,62 @@ func (x *Server) GetUpdateTime() *timestamp.Timestamp { return nil } +func (x *Server) GetTags() map[string]*TagValues { + if x != nil { + return x.Tags + } + return nil +} + +// TagValues is used because map fields cannot be repeated but can be a +// message +type TagValues struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []string `protobuf:"bytes,10,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *TagValues) Reset() { + *x = TagValues{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_v1_servers_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TagValues) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TagValues) ProtoMessage() {} + +func (x *TagValues) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_v1_servers_proto_msgTypes[1] + 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 TagValues.ProtoReflect.Descriptor instead. +func (*TagValues) Descriptor() ([]byte, []int) { + return file_controller_servers_v1_servers_proto_rawDescGZIP(), []int{1} +} + +func (x *TagValues) GetValues() []string { + if x != nil { + return x.Values + } + return nil +} + var File_controller_servers_v1_servers_proto protoreflect.FileDescriptor var file_controller_servers_v1_servers_proto_rawDesc = []byte{ @@ -133,30 +197,42 @@ var file_controller_servers_v1_servers_proto_rawDesc = []byte{ 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, 0x02, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc1, 0x03, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x28, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x32, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x4b, 0x0a, 0x0b, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x61, 0x67, + 0x73, 0x18, 0x50, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x59, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x23, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -171,19 +247,23 @@ func file_controller_servers_v1_servers_proto_rawDescGZIP() []byte { return file_controller_servers_v1_servers_proto_rawDescData } -var file_controller_servers_v1_servers_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_controller_servers_v1_servers_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_controller_servers_v1_servers_proto_goTypes = []interface{}{ (*Server)(nil), // 0: controller.servers.v1.Server - (*timestamp.Timestamp)(nil), // 1: controller.storage.timestamp.v1.Timestamp + (*TagValues)(nil), // 1: controller.servers.v1.TagValues + nil, // 2: controller.servers.v1.Server.TagsEntry + (*timestamp.Timestamp)(nil), // 3: controller.storage.timestamp.v1.Timestamp } var file_controller_servers_v1_servers_proto_depIdxs = []int32{ - 1, // 0: controller.servers.v1.Server.create_time:type_name -> controller.storage.timestamp.v1.Timestamp - 1, // 1: controller.servers.v1.Server.update_time:type_name -> controller.storage.timestamp.v1.Timestamp - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 3, // 0: controller.servers.v1.Server.create_time:type_name -> controller.storage.timestamp.v1.Timestamp + 3, // 1: controller.servers.v1.Server.update_time:type_name -> controller.storage.timestamp.v1.Timestamp + 2, // 2: controller.servers.v1.Server.tags:type_name -> controller.servers.v1.Server.TagsEntry + 1, // 3: controller.servers.v1.Server.TagsEntry.value:type_name -> controller.servers.v1.TagValues + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_controller_servers_v1_servers_proto_init() } @@ -204,6 +284,18 @@ func file_controller_servers_v1_servers_proto_init() { return nil } } + file_controller_servers_v1_servers_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TagValues); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -211,7 +303,7 @@ func file_controller_servers_v1_servers_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_servers_v1_servers_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/servers/worker/session.go b/internal/servers/worker/session.go index 11d3ed066..13e9f2071 100644 --- a/internal/servers/worker/session.go +++ b/internal/servers/worker/session.go @@ -67,6 +67,7 @@ func (w *Worker) getSessionTls(hello *tls.ClientHelloInfo) (*tls.Config, error) w.logger.Trace("looking up session", "session_id", sessionId) resp, err := conn.LookupSession(timeoutContext, &pbs.LookupSessionRequest{ + ServerId: w.conf.RawConfig.Worker.Name, SessionId: sessionId, }) if err != nil { diff --git a/internal/servers/worker/status.go b/internal/servers/worker/status.go index be1c1cb07..32270fc94 100644 --- a/internal/servers/worker/status.go +++ b/internal/servers/worker/status.go @@ -45,143 +45,160 @@ func (w *Worker) startStatusTicking(cancelCtx context.Context) { return case <-timer.C: - // First send info as-is. We'll perform cleanup duties after we - // get cancel/job change info back. - var activeJobs []*pbs.JobStatus - w.sessionInfoMap.Range(func(key, value interface{}) bool { - var jobInfo pbs.SessionJobInfo - sessionId := key.(string) - si := value.(*sessionInfo) - si.RLock() - status := si.status - connections := make([]*pbs.Connection, 0, len(si.connInfoMap)) - for k, v := range si.connInfoMap { - connections = append(connections, &pbs.Connection{ - ConnectionId: k, - Status: v.status, - }) - } - si.RUnlock() - jobInfo.SessionId = sessionId - activeJobs = append(activeJobs, &pbs.JobStatus{ - Job: &pbs.Job{ - Type: pbs.JOBTYPE_JOBTYPE_SESSION, - JobInfo: &pbs.Job_SessionInfo{ - SessionInfo: &pbs.SessionJobInfo{ - SessionId: sessionId, - Status: status, - Connections: connections, - }, - }, - }, - }) - return true - }) - client := w.controllerStatusConn.Load().(pbs.ServerCoordinationServiceClient) - result, err := client.Status(cancelCtx, &pbs.StatusRequest{ - Jobs: activeJobs, - Worker: &servers.Server{ - PrivateId: w.conf.RawConfig.Worker.Name, - Name: w.conf.RawConfig.Worker.Name, - Type: resource.Worker.String(), - Description: w.conf.RawConfig.Worker.Description, - Address: w.conf.RawConfig.Worker.PublicAddr, - }, - }) - if err != nil { - w.logger.Error("error making status request to controller", "error", err) - } else { - w.logger.Trace("successfully sent status to controller") - addrs := make([]resolver.Address, 0, len(result.Controllers)) - strAddrs := make([]string, 0, len(result.Controllers)) - for _, v := range result.Controllers { - addrs = append(addrs, resolver.Address{Addr: v.Address}) - strAddrs = append(strAddrs, v.Address) - } - w.logger.Trace("found controllers", "addresses", strAddrs) - switch len(strAddrs) { - case 0: - w.logger.Warn("got no controller addresses from controller; possibly prior to first status save, not persisting") - default: - w.Resolver().UpdateState(resolver.State{Addresses: addrs}) - } - w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now()}) - - for _, request := range result.GetJobsRequests() { - switch request.GetRequestType() { - case pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE: - switch request.GetJob().GetType() { - case pbs.JOBTYPE_JOBTYPE_SESSION: - sessInfo := request.GetJob().GetSessionInfo() - sessionId := sessInfo.GetSessionId() - siRaw, ok := w.sessionInfoMap.Load(sessionId) - if !ok { - w.logger.Warn("asked to cancel session but could not find a local information for it", "session_id", sessionId) - continue - } - si := siRaw.(*sessionInfo) - si.Lock() - si.status = sessInfo.GetStatus() - si.Unlock() - } - } - } - } - - // Cleanup: Run through current jobs. Cancel connections for any - // canceling session or any session that is expired. Clear out - // sessions that are canceled or expired with all connections - // marked as closed. Close any that aren't marked as such. - closeInfo := make(map[string]string) - cleanSessionIds := make([]string, 0) - w.sessionInfoMap.Range(func(key, value interface{}) bool { - si := value.(*sessionInfo) - si.Lock() - switch { - case si.status == pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING, - si.status == pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED, - time.Until(si.lookupSessionResponse.Expiration.AsTime()) < 0: - var toClose int - for k, v := range si.connInfoMap { - if v.closeTime.IsZero() { - toClose++ - v.connCancel() - w.logger.Info("terminated connection due to cancelation or expiration", "session_id", si.id, "connection_id", k) - closeInfo[k] = si.id - } - } - // closeTime is marked by closeConnections iff the - // status is returned for that connection as closed. If - // the session is no longer valid and all connections - // are marked closed, clean up the session. - if toClose == 0 { - cleanSessionIds = append(cleanSessionIds, si.id) - } - } - si.Unlock() - return true - }) - - // Note that we won't clean these from the info map until the - // next time we run this function - if len(closeInfo) > 0 { - if err := w.closeConnections(cancelCtx, closeInfo); err != nil { - w.logger.Error("error marking connections closed", "error", err) - } - } - - // Forget sessions where the session is expired/canceled and all - // connections are canceled and marked closed - for _, v := range cleanSessionIds { - w.sessionInfoMap.Delete(v) - } - + w.sendWorkerStatus(cancelCtx) timer.Reset(getRandomInterval()) } } }() } +// LastStatusSuccess is used in tests (it's exported for tests in other +// packages) to verify the last time we sent status func (w *Worker) LastStatusSuccess() *LastStatusInformation { return w.lastStatusSuccess.Load().(*LastStatusInformation) } + +func (w *Worker) sendWorkerStatus(cancelCtx context.Context) { + // First send info as-is. We'll perform cleanup duties after we + // get cancel/job change info back. + var activeJobs []*pbs.JobStatus + + // Range over known sessions and collect info + w.sessionInfoMap.Range(func(key, value interface{}) bool { + var jobInfo pbs.SessionJobInfo + sessionId := key.(string) + si := value.(*sessionInfo) + si.RLock() + status := si.status + connections := make([]*pbs.Connection, 0, len(si.connInfoMap)) + for k, v := range si.connInfoMap { + connections = append(connections, &pbs.Connection{ + ConnectionId: k, + Status: v.status, + }) + } + si.RUnlock() + jobInfo.SessionId = sessionId + activeJobs = append(activeJobs, &pbs.JobStatus{ + Job: &pbs.Job{ + Type: pbs.JOBTYPE_JOBTYPE_SESSION, + JobInfo: &pbs.Job_SessionInfo{ + SessionInfo: &pbs.SessionJobInfo{ + SessionId: sessionId, + Status: status, + Connections: connections, + }, + }, + }, + }) + return true + }) + + // Send status information + client := w.controllerStatusConn.Load().(pbs.ServerCoordinationServiceClient) + var tags map[string]*servers.TagValues + // If we're not going to request a tag update, no reason to have these + // marshaled on every status call. + if w.updateTags.Load() { + tags = w.tags.Load().(map[string]*servers.TagValues) + } + result, err := client.Status(cancelCtx, &pbs.StatusRequest{ + Jobs: activeJobs, + Worker: &servers.Server{ + PrivateId: w.conf.RawConfig.Worker.Name, + Type: resource.Worker.String(), + Description: w.conf.RawConfig.Worker.Description, + Address: w.conf.RawConfig.Worker.PublicAddr, + Tags: tags, + }, + UpdateTags: w.updateTags.Load(), + }) + if err != nil { + w.logger.Error("error making status request to controller", "error", err) + } else { + w.logger.Trace("successfully sent status to controller") + w.updateTags.Store(false) + addrs := make([]resolver.Address, 0, len(result.Controllers)) + strAddrs := make([]string, 0, len(result.Controllers)) + for _, v := range result.Controllers { + addrs = append(addrs, resolver.Address{Addr: v.Address}) + strAddrs = append(strAddrs, v.Address) + } + w.logger.Trace("found controllers", "addresses", strAddrs) + switch len(strAddrs) { + case 0: + w.logger.Warn("got no controller addresses from controller; possibly prior to first status save, not persisting") + default: + w.Resolver().UpdateState(resolver.State{Addresses: addrs}) + } + w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now()}) + + for _, request := range result.GetJobsRequests() { + switch request.GetRequestType() { + case pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE: + switch request.GetJob().GetType() { + case pbs.JOBTYPE_JOBTYPE_SESSION: + sessInfo := request.GetJob().GetSessionInfo() + sessionId := sessInfo.GetSessionId() + siRaw, ok := w.sessionInfoMap.Load(sessionId) + if !ok { + w.logger.Warn("asked to cancel session but could not find a local information for it", "session_id", sessionId) + continue + } + si := siRaw.(*sessionInfo) + si.Lock() + si.status = sessInfo.GetStatus() + si.Unlock() + } + } + } + } + + // Cleanup: Run through current jobs. Cancel connections for any + // canceling session or any session that is expired. Clear out + // sessions that are canceled or expired with all connections + // marked as closed. Close any that aren't marked as such. + closeInfo := make(map[string]string) + cleanSessionIds := make([]string, 0) + w.sessionInfoMap.Range(func(key, value interface{}) bool { + si := value.(*sessionInfo) + si.Lock() + switch { + case si.status == pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING, + si.status == pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED, + time.Until(si.lookupSessionResponse.Expiration.AsTime()) < 0: + var toClose int + for k, v := range si.connInfoMap { + if v.closeTime.IsZero() { + toClose++ + v.connCancel() + w.logger.Info("terminated connection due to cancelation or expiration", "session_id", si.id, "connection_id", k) + closeInfo[k] = si.id + } + } + // closeTime is marked by closeConnections iff the + // status is returned for that connection as closed. If + // the session is no longer valid and all connections + // are marked closed, clean up the session. + if toClose == 0 { + cleanSessionIds = append(cleanSessionIds, si.id) + } + } + si.Unlock() + return true + }) + + // Note that we won't clean these from the info map until the + // next time we run this function + if len(closeInfo) > 0 { + if err := w.closeConnections(cancelCtx, closeInfo); err != nil { + w.logger.Error("error marking connections closed", "error", err) + } + } + + // Forget sessions where the session is expired/canceled and all + // connections are canceled and marked closed + for _, v := range cleanSessionIds { + w.sessionInfoMap.Delete(v) + } +} diff --git a/internal/servers/worker/worker.go b/internal/servers/worker/worker.go index acc4d4a85..0ff5858a0 100644 --- a/internal/servers/worker/worker.go +++ b/internal/servers/worker/worker.go @@ -10,6 +10,7 @@ import ( "time" "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/sdk/helper/base62" "github.com/hashicorp/vault/sdk/helper/mlock" @@ -33,6 +34,14 @@ type Worker struct { controllerSessionConn *atomic.Value sessionInfoMap *sync.Map + + // We store the current set in an atomic value so that we can add + // reload-on-sighup behavior later + tags *atomic.Value + // This stores whether or not to send updated tags on the next status + // request. It can be set via startup in New below, or (eventually) via + // SIGHUP. + updateTags ua.Bool } func New(conf *Config) (*Worker, error) { @@ -44,12 +53,15 @@ func New(conf *Config) (*Worker, error) { controllerResolver: new(atomic.Value), controllerSessionConn: new(atomic.Value), sessionInfoMap: new(sync.Map), + tags: new(atomic.Value), } w.lastStatusSuccess.Store((*LastStatusInformation)(nil)) - w.started.Store(false) w.controllerResolver.Store((*manual.Resolver)(nil)) + w.parseAndStoreTags(conf.RawConfig.Worker.Tags) + w.updateTags.Store(true) + if conf.SecureRandomReader == nil { conf.SecureRandomReader = rand.Reader } @@ -135,3 +147,17 @@ func (w *Worker) Resolver() *manual.Resolver { } return raw.(*manual.Resolver) } + +func (w *Worker) parseAndStoreTags(incoming map[string][]string) { + if len(incoming) == 0 { + w.tags.Store(map[string]*servers.TagValues{}) + return + } + tags := make(map[string]*servers.TagValues, len(incoming)) + for k, v := range incoming { + tags[k] = &servers.TagValues{ + Values: append(make([]string, 0, len(v)), v...), + } + } + w.tags.Store(tags) +} diff --git a/internal/session/session.go b/internal/session/session.go index 704a55b0c..87b364cc0 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -45,6 +45,11 @@ type ComposedOf struct { ExpirationTime *timestamp.Timestamp // Max connections for the session ConnectionLimit int32 + // Worker filter. Active filter when the session was created, used to + // validate the session via the same set of rules at consumption time as + // existed at creation time. Round tripping it through here saves a lookup + // in the DB. It is not stored in the warehouse. + WorkerFilter string } // Session contains information about a user's session with a target @@ -89,6 +94,8 @@ type Session struct { Endpoint string `json:"-" gorm:"default:null"` // Maximum number of connections in a session ConnectionLimit int32 `json:"connection_limit,omitempty" gorm:"default:null"` + // Worker filter + WorkerFilter string `json:"-" gorm:"default:null"` // key_id is the key ID that was used for the encryption operation. It can be // used to identify a specific version of the key needed to decrypt the value, @@ -123,6 +130,7 @@ func New(c ComposedOf, opt ...Option) (*Session, error) { Endpoint: c.Endpoint, ExpirationTime: c.ExpirationTime, ConnectionLimit: c.ConnectionLimit, + WorkerFilter: c.WorkerFilter, } if err := s.validateNewSession("new session:"); err != nil { return nil, err @@ -151,6 +159,7 @@ func (s *Session) Clone() interface{} { Version: s.Version, Endpoint: s.Endpoint, ConnectionLimit: s.ConnectionLimit, + WorkerFilter: s.WorkerFilter, } if len(s.States) > 0 { clone.States = make([]*State, 0, len(s.States)) @@ -239,6 +248,8 @@ func (s *Session) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType return fmt.Errorf("session vet for write: expiration time is immutable: %w", errors.ErrInvalidParameter) case contains(opts.WithFieldMaskPaths, "ConnectionLimit"): return fmt.Errorf("session vet for write: connection limit is immutable: %w", errors.ErrInvalidParameter) + case contains(opts.WithFieldMaskPaths, "WorkerFilter"): + return fmt.Errorf("session vet for write: worker filter is immutable: %w", errors.ErrInvalidParameter) case contains(opts.WithFieldMaskPaths, "TerminationReason"): if _, err := convertToReason(s.TerminationReason); err != nil { return fmt.Errorf("session vet for write: termination reason '%s' is invalid: %w", s.TerminationReason, errors.ErrInvalidParameter) @@ -304,6 +315,7 @@ func (s *Session) validateNewSession(errorPrefix string) error { if s.CtTofuToken != nil { return fmt.Errorf("%s ct must be empty: %w", errorPrefix, errors.ErrInvalidParameter) } + // It is okay for the worker filter to be empty, so it is not checked here. return nil } diff --git a/internal/session/testing.go b/internal/session/testing.go index 6dd6b92f0..b17dd98ca 100644 --- a/internal/session/testing.go +++ b/internal/session/testing.go @@ -180,7 +180,7 @@ func TestWorker(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper) *servers. id, err := uuid.GenerateUUID() require.NoError(t, err) worker := &servers.Server{ - Name: "test-session-worker-" + id, + PrivateId: "test-session-worker-" + id, Type: servers.ServerTypeWorker.String(), Description: "Test Session Worker", Address: "127.0.0.1", diff --git a/internal/target/options.go b/internal/target/options.go index f2c308841..9dd77cc01 100644 --- a/internal/target/options.go +++ b/internal/target/options.go @@ -28,6 +28,7 @@ type options struct { withSessionMaxSeconds uint32 withSessionConnectionLimit int32 withPublicId string + withWorkerFilter string } func getDefaultOptions() options { @@ -44,6 +45,7 @@ func getDefaultOptions() options { withSessionMaxSeconds: uint32((8 * time.Hour).Seconds()), withSessionConnectionLimit: 1, withPublicId: "", + withWorkerFilter: "", } } @@ -130,3 +132,10 @@ func WithPublicId(id string) Option { o.withPublicId = id } } + +// WithWorkerFilter provides an optional worker filter +func WithWorkerFilter(filter string) Option { + return func(o *options) { + o.withWorkerFilter = filter + } +} diff --git a/internal/target/options_test.go b/internal/target/options_test.go index dd81b677a..293e4128b 100644 --- a/internal/target/options_test.go +++ b/internal/target/options_test.go @@ -97,4 +97,11 @@ func Test_GetOpts(t *testing.T) { testOpts.withHostSets = []string{"alice", "bob"} assert.Equal(opts, testOpts) }) + t.Run("WithWorkerFilter", func(t *testing.T) { + assert := assert.New(t) + opts := getOpts(WithWorkerFilter(`"/foo" == "bar"`)) + testOpts := getDefaultOptions() + testOpts.withWorkerFilter = `"/foo" == "bar"` + assert.Equal(opts, testOpts) + }) } diff --git a/internal/target/repository_tcp_target.go b/internal/target/repository_tcp_target.go index 39a35b369..8563a5e39 100644 --- a/internal/target/repository_tcp_target.go +++ b/internal/target/repository_tcp_target.go @@ -108,9 +108,9 @@ func (r *Repository) CreateTcpTarget(ctx context.Context, target *TcpTarget, opt // UpdateTcpTarget will update a target in the repository and return the written // target. fieldMaskPaths provides field_mask.proto paths for fields that should // be updated. Fields will be set to NULL if the field is a zero value and -// included in fieldMask. Name and Description are the only updatable fields, -// If no updatable fields are included in the fieldMaskPaths, then an error is -// returned. +// included in fieldMask. Name, Description, and WorkerFilter are the only +// updatable fields. If no updatable fields are included in the fieldMaskPaths, +// then an error is returned. func (r *Repository) UpdateTcpTarget(ctx context.Context, target *TcpTarget, version uint32, fieldMaskPaths []string, opt ...Option) (Target, []*TargetSet, int, error) { if target == nil { return nil, nil, db.NoRowsAffected, fmt.Errorf("update tcp target: missing target %w", errors.ErrInvalidParameter) @@ -128,6 +128,7 @@ func (r *Repository) UpdateTcpTarget(ctx context.Context, target *TcpTarget, ver case strings.EqualFold("defaultport", f): case strings.EqualFold("sessionmaxseconds", f): case strings.EqualFold("sessionconnectionlimit", f): + case strings.EqualFold("workerfilter", f): default: return nil, nil, db.NoRowsAffected, fmt.Errorf("update tcp target: field: %s: %w", f, errors.ErrInvalidFieldMask) } @@ -140,6 +141,7 @@ func (r *Repository) UpdateTcpTarget(ctx context.Context, target *TcpTarget, ver "DefaultPort": target.DefaultPort, "SessionMaxSeconds": target.SessionMaxSeconds, "SessionConnectionLimit": target.SessionConnectionLimit, + "WorkerFilter": target.WorkerFilter, }, fieldMaskPaths, []string{"SessionMaxSeconds", "SessionConnectionLimit"}, diff --git a/internal/target/store/target.pb.go b/internal/target/store/target.pb.go index a33d92d52..eaf0c6f53 100644 --- a/internal/target/store/target.pb.go +++ b/internal/target/store/target.pb.go @@ -63,6 +63,9 @@ type TargetView struct { // Maximum number of connections in a session // @inject_tag: `gorm:"default:null"` SessionConnectionLimit int32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"` + // A boolean expression that allows filtering the workers that can handle a session + // @inject_tag: `gorm:"default:null"` + WorkerFilter string `protobuf:"bytes,120,opt,name=worker_filter,json=workerFilter,proto3" json:"worker_filter,omitempty" gorm:"default:null"` } func (x *TargetView) Reset() { @@ -174,6 +177,13 @@ func (x *TargetView) GetSessionConnectionLimit() int32 { return 0 } +func (x *TargetView) GetWorkerFilter() string { + if x != nil { + return x.WorkerFilter + } + return "" +} + type TargetHostSet struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -280,6 +290,9 @@ type TcpTarget struct { // Maximum number of connections in a session // @inject_tag: `gorm:"default:null"` SessionConnectionLimit int32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"` + // A boolean expression that allows filtering the workers that can handle a session + // @inject_tag: `gorm:"default:null"` + WorkerFilter string `protobuf:"bytes,120,opt,name=worker_filter,json=workerFilter,proto3" json:"worker_filter,omitempty" gorm:"default:null"` } func (x *TcpTarget) Reset() { @@ -384,6 +397,13 @@ func (x *TcpTarget) GetSessionConnectionLimit() int32 { return 0 } +func (x *TcpTarget) GetWorkerFilter() string { + if x != nil { + return x.WorkerFilter + } + return "" +} + var File_controller_storage_target_store_v1_target_proto protoreflect.FileDescriptor var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ @@ -398,7 +418,7 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xcf, 0x03, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x69, 0x65, + 0x74, 0x6f, 0x22, 0xf4, 0x03, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, @@ -427,61 +447,68 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x22, 0x99, 0x01, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, - 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, - 0x74, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, + 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x99, 0x01, 0x0a, 0x0d, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, + 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x68, + 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xc6, 0x05, 0x0a, 0x09, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x22, 0xfe, 0x04, 0x0a, 0x09, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, - 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, - 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1e, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, - 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x32, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, - 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x0b, - 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, - 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, - 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2c, - 0xc2, 0xdd, 0x29, 0x28, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, - 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x52, 0x11, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, - 0x70, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, - 0x05, 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, - 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, - 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2, + 0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20, + 0x01, 0x28, 0x0d, 0x42, 0x2c, 0xc2, 0xdd, 0x29, 0x28, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x13, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x52, 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x70, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x18, 0x6e, 0x20, 0x01, 0x28, 0x05, 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x46, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xc2, + 0xdd, 0x29, 0x1d, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x12, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x3b, + 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/internal/target/target.go b/internal/target/target.go index e2631138f..5660e32fa 100644 --- a/internal/target/target.go +++ b/internal/target/target.go @@ -21,6 +21,7 @@ type Target interface { GetUpdateTime() *timestamp.Timestamp GetSessionMaxSeconds() uint32 GetSessionConnectionLimit() int32 + GetWorkerFilter() string oplog(op oplog.OpType) oplog.Metadata } @@ -92,6 +93,7 @@ func (t *targetView) targetSubType() (Target, error) { tcpTarget.Version = t.Version tcpTarget.SessionMaxSeconds = t.SessionMaxSeconds tcpTarget.SessionConnectionLimit = t.SessionConnectionLimit + tcpTarget.WorkerFilter = t.WorkerFilter return &tcpTarget, nil } return nil, fmt.Errorf("%s is an unknown target subtype of %s", t.PublicId, t.Type) diff --git a/internal/target/tcp_target.go b/internal/target/tcp_target.go index 533afe265..86054171d 100644 --- a/internal/target/tcp_target.go +++ b/internal/target/tcp_target.go @@ -41,6 +41,7 @@ func NewTcpTarget(scopeId string, opt ...Option) (*TcpTarget, error) { DefaultPort: opts.withDefaultPort, SessionConnectionLimit: opts.withSessionConnectionLimit, SessionMaxSeconds: opts.withSessionMaxSeconds, + WorkerFilter: opts.withWorkerFilter, }, } return t, nil diff --git a/internal/tests/cluster/multi_controller_worker_test.go b/internal/tests/cluster/multi_controller_worker_test.go index a76fcc3be..63d3c6672 100644 --- a/internal/tests/cluster/multi_controller_worker_test.go +++ b/internal/tests/cluster/multi_controller_worker_test.go @@ -8,12 +8,11 @@ import ( "github.com/hashicorp/boundary/internal/servers/controller" "github.com/hashicorp/boundary/internal/servers/worker" "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestMultiControllerMultiWorkerConnections(t *testing.T) { - assert, require := assert.New(t), require.New(t) + require := require.New(t) amId := "ampw_1234567890" user := "user" password := "passpass" @@ -38,29 +37,8 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { }) defer c2.Shutdown() - expectWorkers := func(c *controller.TestController, workers ...*worker.TestWorker) { - updateTimes := c.Controller().WorkerStatusUpdateTimes() - workerMap := map[string]*worker.TestWorker{} - for _, w := range workers { - workerMap[w.Name()] = w - } - updateTimes.Range(func(k, v interface{}) bool { - require.NotNil(k) - require.NotNil(v) - if workerMap[k.(string)] == nil { - // We don't remove from updateTimes currently so if we're not - // expecting it we'll see an out-of-date entry - return true - } - assert.WithinDuration(time.Now(), v.(time.Time), 30*time.Second) - delete(workerMap, k.(string)) - return true - }) - assert.Empty(workerMap) - } - - expectWorkers(c1) - expectWorkers(c2) + expectWorkers(t, c1) + expectWorkers(t, c2) w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ WorkerAuthKms: c1.Config().WorkerAuthKms, @@ -70,8 +48,8 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { defer w1.Shutdown() time.Sleep(10 * time.Second) - expectWorkers(c1, w1) - expectWorkers(c2, w1) + expectWorkers(t, c1, w1) + expectWorkers(t, c2, w1) w2 := w1.AddClusterWorkerMember(t, &worker.TestWorkerOpts{ Logger: logger.Named("w2"), @@ -79,25 +57,25 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { defer w2.Shutdown() time.Sleep(10 * time.Second) - expectWorkers(c1, w1, w2) - expectWorkers(c2, w1, w2) + expectWorkers(t, c1, w1, w2) + expectWorkers(t, c2, w1, w2) require.NoError(w1.Worker().Shutdown(true)) time.Sleep(10 * time.Second) - expectWorkers(c1, w2) - expectWorkers(c2, w2) + expectWorkers(t, c1, w2) + expectWorkers(t, c2, w2) require.NoError(w1.Worker().Start()) time.Sleep(10 * time.Second) - expectWorkers(c1, w1, w2) - expectWorkers(c2, w1, w2) + expectWorkers(t, c1, w1, w2) + expectWorkers(t, c2, w1, w2) require.NoError(c1.Controller().Shutdown(true)) time.Sleep(10 * time.Second) - expectWorkers(c2, w1, w2) + expectWorkers(t, c2, w1, w2) require.NoError(c1.Controller().Start()) time.Sleep(10 * time.Second) - expectWorkers(c1, w1, w2) - expectWorkers(c2, w1, w2) + expectWorkers(t, c1, w1, w2) + expectWorkers(t, c2, w1, w2) } diff --git a/internal/tests/cluster/util.go b/internal/tests/cluster/util.go new file mode 100644 index 000000000..00949bb20 --- /dev/null +++ b/internal/tests/cluster/util.go @@ -0,0 +1,32 @@ +package cluster + +import ( + "testing" + "time" + + "github.com/hashicorp/boundary/internal/servers/controller" + "github.com/hashicorp/boundary/internal/servers/worker" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func expectWorkers(t *testing.T, c *controller.TestController, workers ...*worker.TestWorker) { + updateTimes := c.Controller().WorkerStatusUpdateTimes() + workerMap := map[string]*worker.TestWorker{} + for _, w := range workers { + workerMap[w.Name()] = w + } + updateTimes.Range(func(k, v interface{}) bool { + require.NotNil(t, k) + require.NotNil(t, v) + if workerMap[k.(string)] == nil { + // We don't remove from updateTimes currently so if we're not + // expecting it we'll see an out-of-date entry + return true + } + assert.WithinDuration(t, time.Now(), v.(time.Time), 30*time.Second) + delete(workerMap, k.(string)) + return true + }) + assert.Empty(t, workerMap) +} diff --git a/internal/tests/cluster/worker_tagging_test.go b/internal/tests/cluster/worker_tagging_test.go new file mode 100644 index 000000000..7dc916752 --- /dev/null +++ b/internal/tests/cluster/worker_tagging_test.go @@ -0,0 +1,154 @@ +package cluster + +import ( + "testing" + "time" + + "github.com/hashicorp/boundary/api/targets" + "github.com/hashicorp/boundary/internal/cmd/config" + pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/targets" + "github.com/hashicorp/boundary/internal/servers/controller" + "github.com/hashicorp/boundary/internal/servers/worker" + "github.com/hashicorp/go-hclog" + "github.com/mr-tron/base58" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +func TestWorkerTagging(t *testing.T) { + amId := "ampw_1234567890" + user := "user" + password := "passpass" + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + }) + + conf, err := config.DevController() + require.NoError(t, err) + + c1 := controller.NewTestController(t, &controller.TestControllerOpts{ + Config: conf, + DefaultAuthMethodId: amId, + DefaultLoginName: user, + DefaultPassword: password, + InitialResourcesSuffix: "1234567890", + Logger: logger.Named("c1"), + }) + defer c1.Shutdown() + + ctx := c1.Context() + + // No workers yet + expectWorkers(t, c1) + + // Ensure target is valid + client := c1.Client() + client.SetToken(c1.Token().Token) + tcl := targets.NewClient(client) + tgt, err := tcl.Read(ctx, "ttcp_1234567890") + require.NoError(t, err) + require.NotNil(t, tgt) + + // Worker 1 + conf, err = config.DevWorker() + require.NoError(t, err) + conf.Worker.Name = "w1" + conf.Worker.Tags = map[string][]string{ + "region": {"east"}, + } + w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ + Config: conf, + WorkerAuthKms: c1.Config().WorkerAuthKms, + InitialControllers: c1.ClusterAddrs(), + Logger: logger.Named("w1"), + }) + defer w1.Shutdown() + w1Addr := w1.ProxyAddrs()[0] + + // Worker 2 + conf, err = config.DevWorker() + require.NoError(t, err) + conf.Worker.Name = "w2" + conf.Worker.Tags = map[string][]string{ + "region": {"west"}, + "az": {"one", "two", "three"}, + } + w2 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ + Config: conf, + WorkerAuthKms: c1.Config().WorkerAuthKms, + InitialControllers: c1.ClusterAddrs(), + Logger: logger.Named("w2"), + }) + defer w2.Shutdown() + w2Addr := w2.ProxyAddrs()[0] + + // Worker 3 + conf, err = config.DevWorker() + require.NoError(t, err) + conf.Worker.Name = "w3" + conf.Worker.Tags = map[string][]string{ + "region": {"west"}, + "az": {"one", "three"}, + } + w3 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ + Config: conf, + WorkerAuthKms: c1.Config().WorkerAuthKms, + InitialControllers: c1.ClusterAddrs(), + Logger: logger.Named("w3"), + }) + defer w3.Shutdown() + w3Addr := w3.ProxyAddrs()[0] + + time.Sleep(10 * time.Second) + expectWorkers(t, c1, w1, w2, w3) + + cases := []struct { + name string + filter string + expWorkers []string + }{ + { + name: "base case", + expWorkers: []string{w1Addr, w2Addr, w3Addr}, + }, + { + name: "name and region", + filter: `"/name" matches "w[13]" and "west" in "/tags/region"`, + expWorkers: []string{w3Addr}, + }, + { + name: "name and az", + filter: `"/name" matches "w[23]" and "three" in "/tags/az"`, + expWorkers: []string{w2Addr, w3Addr}, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + require, assert := require.New(t), assert.New(t) + + opts := []targets.Option{targets.WithAutomaticVersioning(true), targets.WithDescription(tc.name)} + if tc.filter != "" { + opts = append(opts, targets.WithWorkerFilter(tc.filter)) + } + tgt, err := tcl.Update(ctx, "ttcp_1234567890", 0, opts...) + require.NoError(err) + require.NotNil(tgt) + + // Fetch the session and decode the token + sar, err := tcl.AuthorizeSession(ctx, "ttcp_1234567890") + require.NoError(err) + sat := sar.GetItem().(*targets.SessionAuthorization).AuthorizationToken + decodedSat, err := base58.FastBase58Decoding(sat) + require.NoError(err) + var sad pb.SessionAuthorizationData + require.NoError(proto.Unmarshal(decodedSat, &sad)) + + var addrs []string + for _, worker := range sad.GetWorkerInfo() { + addrs = append(addrs, worker.GetAddress()) + } + assert.ElementsMatch(tc.expWorkers, addrs) + }) + } +} diff --git a/sdk/strutil/strutil.go b/sdk/strutil/strutil.go index 9688bbe9a..16b3a8598 100644 --- a/sdk/strutil/strutil.go +++ b/sdk/strutil/strutil.go @@ -6,6 +6,7 @@ import ( "fmt" "sort" "strings" + "unicode" "github.com/hashicorp/errwrap" glob "github.com/ryanuber/go-glob" @@ -446,6 +447,16 @@ func Difference(a, b []string, lowercase bool) []string { return items } +// Printable returns true if all characters in the string are printable +// according to Unicode +func Printable(s string) bool { + return strings.IndexFunc(s, func(c rune) bool { + return !unicode.IsPrint(c) + }) == -1 +} + +// StringListToInterfaceList simply takes a []string and turns it into a +// []interface{} to satisfy the input requirements for other library functions func StringListToInterfaceList(in []string) []interface{} { ret := make([]interface{}, len(in)) for i, v := range in { diff --git a/sdk/strutil/strutil_test.go b/sdk/strutil/strutil_test.go index 9da041b47..977213150 100644 --- a/sdk/strutil/strutil_test.go +++ b/sdk/strutil/strutil_test.go @@ -3,8 +3,11 @@ package strutil import ( "encoding/base64" "encoding/json" + "fmt" "reflect" "testing" + + "github.com/stretchr/testify/require" ) func TestStrUtil_StrListDelete(t *testing.T) { @@ -598,3 +601,35 @@ func TestStrUtil_EqualStringMaps(t *testing.T) { } } } + +func TestPrintable(t *testing.T) { + cases := []struct { + input string + err bool + }{ + { + input: "/valid", + }, + { + input: "foobarvalid", + }, + { + input: "/invalid\u000A", + err: true, + }, + { + input: "/invalid\u000D", + err: true, + }, + { + input: "/invalid\u0000", + err: true, + }, + } + + for i, tc := range cases { + t.Run(fmt.Sprint(i), func(t *testing.T) { + require.True(t, Printable(tc.input) != tc.err) + }) + } +}