Add controller-led worker auth flow (#2413)

This adds an action to the API that allows pulling out an activation
token that can be given to a worker in its config (directly or via env
or file). The worker can pass this along with its normal request in
place of its normal nonce and the server will automatically accept it.

Co-authored-by: Irena Rindos <irenarindos@users.noreply.github.com>
This commit is contained in:
Jeff MitchellandIrena Rindos authored and GitHub committed 2022-09-02 14:32:41 -04:00
1 parent a1be125f5b
commit 01fb949d0b
55 files changed
+2728 -625

No files matched your search

+46 -6
View File
@@ -4,9 +4,49 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
## Next
### New and Improved
* Controller-led worker authorization: This is a second authorization option for
the workers using PKI-based authentication that was introduced in Boundary
0.10. In 0.10, the only mode available was "worker-led", in which a worker
generates an authorization request which can be submitted to a controller to
authorize the worker. With this new controller-led flow, a worker can be
created via the controller API first and return a one-time-use authorization
token. This token can then be made available to the worker at startup time via
its configuration file, env var, or a file with the value. If the worker is
not authorized and this token is provided, it will use the token to authorize
itself to the controller and set up PKI-based authentication.
([PR](https://github.com/hashicorp/boundary/pull/2413))
* Initial upstreams reloading on `SIGHUP`: Workers will now re-read the
`initial_upstreams` value from the configuration file when given a SIGHUP.
This allows a worker to reconnect to controllers if the full set of
controllers has been changed over at the same time, without having to restart
the worker. ([PR](https://github.com/hashicorp/boundary/pull/2417))
### Bug Fixes
* Sessions: Fix an issue where sessions could not have more than one connection
([Issue](https://github.com/hashicorp/boundary/issues/2362)), ([PR](https://github.com/hashicorp/boundary/pull/2369))
* aws host catalog: Fix an issue where the request to list hosts could timeout
on a large number of hosts
([Issue](https://github.com/hashicorp/boundary/issues/2224),
[PR](https://github.com/hashicorp/boundary-plugin-host-aws/pull/17))
* aws host catalog: Fix an issue where filters could become unreadable in the UI
if only one filter was created and was set by the CLI or directly via the API
([PR1](https://github.com/hashicorp/boundary/pull/2376),
[PR2](https://github.com/hashicorp/boundary-plugin-host-aws/pull/16))
* azure host catalog: Fix hosts not being found depending on the exact filter
used because different filters return values with different casing
([PR](https://github.com/hashicorp/boundary-plugin-host-azure/pull/8))
* sessions: Fix an issue where sessions could not have more than one connection
([Issue](https://github.com/hashicorp/boundary/issues/2362)),
([PR](https://github.com/hashicorp/boundary/pull/2369))
* workers: Fix repeating error in logs when connected to HCP Boundary about an
unimplemented HcpbWorkers call
([PR](https://github.com/hashicorp/boundary/pull/2361))
* workers: Fix a panic that could occur when `workers:create:worker-led` (e.g.
via `boundary workers create worker-led`) was given an invalid token
([PR](https://github.com/hashicorp/boundary/pull/2388))
* workers: Add the ability to set API-based worker tags via the CLI
([PR](https://github.com/hashicorp/boundary/pull/2266))
## 0.10.3 (2022/08/30)
@@ -33,15 +73,15 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
credential libraries or static credentials.
([Issue](https://github.com/hashicorp/boundary/issues/2349)),
([PR](https://github.com/hashicorp/boundary/pull/2351)).
* Managed Groups: Fix an issue where the `filter` field is not sent by
* managed groups: Fix an issue where the `filter` field is not sent by
admin UI ([PR](https://github.com/hashicorp/boundary-ui/pull/1238)).
* Host Sets: Fix an issue causing host sets to not display in UI when using the aws plugin
* host sets: Fix an issue causing host sets to not display in UI when using the aws plugin
([PR](https://github.com/hashicorp/boundary-ui/pull/1251))
* Plugins: Fixes regression from 0.9.0 causing a failure to start when using
* plugins: Fixes regression from 0.9.0 causing a failure to start when using
multiple KMS blocks of the same type
([PR1](https://github.com/hashicorp/go-secure-stdlib/pull/43),
[PR2](https://github.com/hashicorp/boundary/pull/2346))
* CLI: Fixed errors related to URL detection when passing in `-attr` or
* cli: Fixed errors related to URL detection when passing in `-attr` or
`-secret` values that contained colons
([PR](https://github.com/hashicorp/boundary/pull/2353))
+62 -17
View File
@@ -13,23 +13,24 @@ import (
)
type Worker struct {
Id string `json:"id,omitempty"`
ScopeId string `json:"scope_id,omitempty"`
Scope *scopes.ScopeInfo `json:"scope,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
CreatedTime time.Time `json:"created_time,omitempty"`
UpdatedTime time.Time `json:"updated_time,omitempty"`
Version uint32 `json:"version,omitempty"`
Address string `json:"address,omitempty"`
CanonicalTags map[string][]string `json:"canonical_tags,omitempty"`
ConfigTags map[string][]string `json:"config_tags,omitempty"`
LastStatusTime time.Time `json:"last_status_time,omitempty"`
WorkerGeneratedAuthToken string `json:"worker_generated_auth_token,omitempty"`
ActiveConnectionCount uint32 `json:"active_connection_count,omitempty"`
Type string `json:"type,omitempty"`
ApiTags map[string][]string `json:"api_tags,omitempty"`
AuthorizedActions []string `json:"authorized_actions,omitempty"`
Id string `json:"id,omitempty"`
ScopeId string `json:"scope_id,omitempty"`
Scope *scopes.ScopeInfo `json:"scope,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
CreatedTime time.Time `json:"created_time,omitempty"`
UpdatedTime time.Time `json:"updated_time,omitempty"`
Version uint32 `json:"version,omitempty"`
Address string `json:"address,omitempty"`
CanonicalTags map[string][]string `json:"canonical_tags,omitempty"`
ConfigTags map[string][]string `json:"config_tags,omitempty"`
LastStatusTime time.Time `json:"last_status_time,omitempty"`
WorkerGeneratedAuthToken string `json:"worker_generated_auth_token,omitempty"`
ControllerGeneratedActivationToken string `json:"controller_generated_activation_token,omitempty"`
ActiveConnectionCount uint32 `json:"active_connection_count,omitempty"`
Type string `json:"type,omitempty"`
ApiTags map[string][]string `json:"api_tags,omitempty"`
AuthorizedActions []string `json:"authorized_actions,omitempty"`
response *api.Response
}
@@ -143,6 +144,50 @@ func (c *Client) CreateWorkerLed(ctx context.Context, workerGeneratedAuthToken s
return target, nil
}
func (c *Client) CreateControllerLed(ctx context.Context, scopeId string, opt ...Option) (*WorkerCreateResult, error) {
if scopeId == "" {
return nil, fmt.Errorf("empty scopeId value passed into CreateControllerLed request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "workers:create:controller-led", opts.postMap, apiOpts...)
if err != nil {
return nil, fmt.Errorf("error creating CreateControllerLed request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, fmt.Errorf("error performing client request during CreateControllerLed call: %w", err)
}
target := new(WorkerCreateResult)
target.Item = new(Worker)
apiErr, err := resp.Decode(target.Item)
if err != nil {
return nil, fmt.Errorf("error decoding CreateControllerLed response: %w", err)
}
if apiErr != nil {
return nil, apiErr
}
target.response = resp
return target, nil
}
func (c *Client) Read(ctx context.Context, id string, opt ...Option) (*WorkerReadResult, error) {
if id == "" {
return nil, fmt.Errorf("empty id value passed into Read request")
+1
View File
@@ -84,4 +84,5 @@ const (
WorkerGeneratedAuthTokenField = "worker_generated_auth_token"
WorkerProvidedConfigurationField = "worker_provided_configuration"
ActiveConnectionCountField = "active_connection_count"
ControllerGeneratedActivationToken = "controller_generated_activation_token"
)
+1 -1
View File
@@ -92,7 +92,7 @@ require github.com/hashicorp/go-dbw v0.0.0-20220725170111-b7cb3aa3d628
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20220711120347-32232bae6803
github.com/hashicorp/nodeenrollment v0.1.13
github.com/hashicorp/nodeenrollment v0.1.16
)
require (
+2 -2
View File
@@ -743,8 +743,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/nodeenrollment v0.1.13 h1:h830EbaWqt1wyRi3DERDtUHLW3tXl4cLfbVkPeD5Twc=
github.com/hashicorp/nodeenrollment v0.1.13/go.mod h1:LIPKi+g0g/vl3xhpbzugCalHSxX1PMeqnatkAsxRgyM=
github.com/hashicorp/nodeenrollment v0.1.16 h1:TZ+lN7uvkW733OZE25Wo1FgkC0zwcQo1eo3NtEnHLkw=
github.com/hashicorp/nodeenrollment v0.1.16/go.mod h1:N5gYsm8mWiDfIw/j+1IQ6NBO1cWCmhPpvQ9GB1QUnsU=
github.com/hashicorp/vault/api v1.3.1 h1:pkDkcgTh47PRjY1NEFeofqR4W/HkNUi9qIakESO2aRM=
github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFywzhptMsTIUw=
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
+128 -55
View File
@@ -95,9 +95,6 @@ type structInfo struct {
// useful to avoid collisions
nameOverride string
// extraRequiredParams allows adding extra required parameters to templates
extraRequiredParams []requiredParam
// recursiveListing indicates that the collection supports recursion when
// listing
recursiveListing bool
@@ -308,20 +305,32 @@ var inputStructs = []*structInfo{
outFile: "authmethods/authmethods.gen.go",
templates: []*template.Template{
clientTemplate,
commonCreateTemplate,
template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
"funcName": func() string {
return "Create"
},
"apiAction": func() string {
return ""
},
"extraRequiredParams": func() []requiredParam {
return []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
}
},
},
).Parse(createTemplateStr)),
readTemplate,
updateTemplate,
deleteTemplate,
listTemplate,
},
pluralResourceName: "auth-methods",
extraRequiredParams: []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
},
pluralResourceName: "auth-methods",
versionEnabled: true,
createResponseTypes: true,
recursiveListing: true,
@@ -422,21 +431,33 @@ var inputStructs = []*structInfo{
outFile: "credentialstores/credential_store.gen.go",
templates: []*template.Template{
clientTemplate,
commonCreateTemplate,
template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
"funcName": func() string {
return "Create"
},
"apiAction": func() string {
return ""
},
"extraRequiredParams": func() []requiredParam {
return []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
}
},
},
).Parse(createTemplateStr)),
readTemplate,
updateTemplate,
deleteTemplate,
listTemplate,
},
pluralResourceName: "credential-stores",
parentTypeName: "scope",
extraRequiredParams: []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
},
pluralResourceName: "credential-stores",
parentTypeName: "scope",
versionEnabled: true,
createResponseTypes: true,
recursiveListing: true,
@@ -525,19 +546,31 @@ var inputStructs = []*structInfo{
outFile: "credentials/credential.gen.go",
templates: []*template.Template{
clientTemplate,
commonCreateTemplate,
template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
"funcName": func() string {
return "Create"
},
"apiAction": func() string {
return ""
},
"extraRequiredParams": func() []requiredParam {
return []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
}
},
},
).Parse(createTemplateStr)),
readTemplate,
updateTemplate,
deleteTemplate,
listTemplate,
},
extraRequiredParams: []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
},
pluralResourceName: "credentials",
parentTypeName: "credential-store",
versionEnabled: true,
@@ -550,7 +583,26 @@ var inputStructs = []*structInfo{
outFile: "hostcatalogs/host_catalog.gen.go",
templates: []*template.Template{
clientTemplate,
commonCreateTemplate,
template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
"funcName": func() string {
return "Create"
},
"apiAction": func() string {
return ""
},
"extraRequiredParams": func() []requiredParam {
return []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
}
},
},
).Parse(createTemplateStr)),
readTemplate,
updateTemplate,
deleteTemplate,
@@ -571,14 +623,7 @@ var inputStructs = []*structInfo{
SkipDefault: true,
},
},
pluralResourceName: "host-catalogs",
extraRequiredParams: []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
},
pluralResourceName: "host-catalogs",
versionEnabled: true,
createResponseTypes: true,
recursiveListing: true,
@@ -689,7 +734,26 @@ var inputStructs = []*structInfo{
outFile: "targets/target.gen.go",
templates: []*template.Template{
clientTemplate,
commonCreateTemplate,
template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
"funcName": func() string {
return "Create"
},
"apiAction": func() string {
return ""
},
"extraRequiredParams": func() []requiredParam {
return []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
}
},
},
).Parse(createTemplateStr)),
readTemplate,
updateTemplate,
deleteTemplate,
@@ -742,14 +806,7 @@ var inputStructs = []*structInfo{
FieldType: "[]string",
},
},
versionEnabled: true,
extraRequiredParams: []requiredParam{
{
Name: "resourceType",
Typ: "string",
PostType: "type",
},
},
versionEnabled: true,
createResponseTypes: true,
recursiveListing: true,
},
@@ -796,6 +853,29 @@ var inputStructs = []*structInfo{
"apiAction": func() string {
return ":create:worker-led"
},
"extraRequiredParams": func() []requiredParam {
return []requiredParam{
{
Name: "workerGeneratedAuthToken",
Typ: "string",
PostType: "worker_generated_auth_token",
},
}
},
},
).Parse(createTemplateStr)),
template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
"funcName": func() string {
return "CreateControllerLed"
},
"apiAction": func() string {
return ":create:controller-led"
},
"extraRequiredParams": func() []requiredParam {
return nil
},
},
).Parse(createTemplateStr)),
readTemplate,
@@ -803,13 +883,6 @@ var inputStructs = []*structInfo{
deleteTemplate,
listTemplate,
},
extraRequiredParams: []requiredParam{
{
Name: "workerGeneratedAuthToken",
Typ: "string",
PostType: "worker_generated_auth_token",
},
},
pluralResourceName: "workers",
sliceSubtypes: map[string]sliceSubtypeInfo{
"WorkerTags": {
+5 -4
View File
@@ -46,7 +46,6 @@ type templateInput struct {
SliceSubtypes map[string]sliceSubtypeInfo
ExtraFields []fieldInfo
VersionEnabled bool
ExtraRequiredParams []requiredParam
CreateResponseTypes bool
RecursiveListing bool
}
@@ -65,7 +64,6 @@ func fillTemplates() {
ParentTypeName: in.parentTypeName,
ExtraFields: in.extraFields,
VersionEnabled: in.versionEnabled,
ExtraRequiredParams: in.extraRequiredParams,
CreateResponseTypes: in.createResponseTypes,
RecursiveListing: in.recursiveListing,
}
@@ -347,7 +345,7 @@ func (c *Client) Delete(ctx context.Context, id string, opt... Option) (*{{ .Nam
`))
const createTemplateStr = `
func (c *Client) {{ funcName }} (ctx context.Context, {{ range .ExtraRequiredParams }} {{ .Name }} {{ .Typ }}, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}CreateResult, error) {
func (c *Client) {{ funcName }} (ctx context.Context, {{ range extraRequiredParams }} {{ .Name }} {{ .Typ }}, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}CreateResult, error) {
if {{ .CollectionFunctionArg }} == "" {
return nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into {{ funcName }} request")
}
@@ -357,7 +355,7 @@ func (c *Client) {{ funcName }} (ctx context.Context, {{ range .ExtraRequiredPar
if c.client == nil {
return nil, fmt.Errorf("nil client")
}
{{ range .ExtraRequiredParams }} if {{ .Name }} == "" {
{{ range extraRequiredParams }} if {{ .Name }} == "" {
return nil, fmt.Errorf("empty {{ .Name }} value passed into {{ funcName }} request")
} else {
opts.postMap["{{ .PostType }}"] = {{ .Name }}
@@ -408,6 +406,9 @@ var commonCreateTemplate = template.Must(template.New("").Funcs(
"apiAction": func() string {
return ""
},
"extraRequiredParams": func() []requiredParam {
return nil
},
},
).Parse(createTemplateStr))
+6
View File
@@ -1114,6 +1114,12 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
Func: "create",
}, nil
},
"workers create controller-led": func() (cli.Command, error) {
return &workerscmd.ControllerLedCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"workers read": func() (cli.Command, error) {
return &workerscmd.Command{
Command: base.NewCommand(ui),
+89 -37
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"net"
"os"
"os/signal"
@@ -90,7 +91,7 @@ type Command struct {
flagEveryEventDenyFilters []string
flagCreateLoopbackHostPlugin bool
flagPluginExecutionDir string
flagUseKmsWorkerAuthMethod bool
flagWorkerAuthMethod string
flagWorkerAuthStorageDir string
flagWorkerAuthStorageSkipCleanup bool
flagWorkerAuthRotationInterval time.Duration
@@ -337,10 +338,11 @@ func (c *Command) Flags() *base.FlagSets {
EnvVar: "BOUNDARY_DEV_PLUGIN_EXECUTION_DIR",
Usage: "Specifies where Boundary should write plugins that it is executing; if not set defaults to system temp directory.",
})
f.BoolVar(&base.BoolVar{
Name: "use-kms-worker-auth-method",
Target: &c.flagUseKmsWorkerAuthMethod,
Usage: "If set, the original KMS-based method of worker auth will be used to connect the initial dev worker to the controller.",
f.StringVar(&base.StringVar{
Name: "worker-auth-method",
Target: &c.flagWorkerAuthMethod,
Default: "random-pki",
Usage: `Allows specifying how the generated worker will authenticate to the controller. Valid values are "kms" for the KMS-based mechanism; "pki-controller-led" for the PKI mechanism via the server-led authorization flow; "pki-worker-led" for the PKI mechanism via the worker-led authorization flow; and "random-pki" to randomly choose one of the PKI methods.`,
})
f.StringVar(&base.StringVar{
@@ -598,7 +600,7 @@ func (c *Command) Run(args []string) int {
c.InfoKeys = append(c.InfoKeys, "[Worker-Auth] AEAD Key Bytes")
c.Info["[Worker-Auth] AEAD Key Bytes"] = c.Config.DevWorkerAuthKey
if !c.flagUseKmsWorkerAuthMethod {
if c.flagWorkerAuthMethod != "kms" {
c.DevUsePkiForUpstream = true
// These must be unset for PKI
c.Config.Worker.Name = ""
@@ -701,6 +703,54 @@ func (c *Command) Run(args []string) int {
c.worker.TestOverrideAuthRotationPeriod = c.flagWorkerAuthRotationInterval
}
// Note: this should be done before starting the worker so that the
// activation token is populated
var useWorkerLed bool
if c.flagWorkerAuthMethod != "kms" {
// Flip a coin. Use one method or the other; it's transparent to
// users, but keeps both exercised.
if c.flagWorkerAuthMethod == "random-pki" {
randPki := rand.New(rand.NewSource(time.Now().UnixMicro())).Intn(2)
if randPki == 0 {
c.flagWorkerAuthMethod = "pki-controller-led"
} else {
c.flagWorkerAuthMethod = "pki-worker-led"
}
}
switch c.flagWorkerAuthMethod {
case "pki-controller-led":
// Controller-led
serversRepo, err := c.controller.ServersRepoFn()
if err != nil {
c.UI.Error(fmt.Errorf("Error instantiating server repo: %w", err).Error())
if err := c.controller.Shutdown(); err != nil {
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
}
return base.CommandCliError
}
// Create the worker in the database and fetch an activation token
worker, err := serversRepo.CreateWorker(c.Context, &server.Worker{
Worker: &store.Worker{
ScopeId: scope.Global.String(),
},
}, server.WithCreateControllerLedActivationToken(true))
if err != nil {
c.UI.Error(fmt.Errorf("Error creating worker in database: %w", err).Error())
if err := c.controller.Shutdown(); err != nil {
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
}
return base.CommandCliError
}
// Set the activation token in the config
conf.RawConfig.Worker.ControllerGeneratedActivationToken = worker.ControllerGeneratedActivationToken
default:
useWorkerLed = true
}
}
if err := c.worker.Start(); err != nil {
retErr := fmt.Errorf("Error starting worker: %w", err)
if err := c.worker.Shutdown(); err != nil {
@@ -714,46 +764,48 @@ func (c *Command) Run(args []string) int {
return base.CommandCliError
}
if !c.flagUseKmsWorkerAuthMethod {
req := c.worker.WorkerAuthRegistrationRequest
if req == "" {
c.UI.Error("No worker auth registration request found at worker start time")
return base.CommandCliError
}
c.InfoKeys = append(c.InfoKeys, "worker auth registration request")
c.Info["worker auth registration request"] = req
if c.flagWorkerAuthMethod != "kms" {
c.InfoKeys = append(c.InfoKeys, "worker auth current key id")
c.Info["worker auth current key id"] = c.worker.WorkerAuthCurrentKeyId.Load()
c.InfoKeys = append(c.InfoKeys, "worker auth storage path")
c.Info["worker auth storage path"] = c.worker.WorkerAuthStorage.BaseDir()
if err := c.StoreWorkerAuthReq(c.worker.WorkerAuthRegistrationRequest, c.worker.WorkerAuthStorage.BaseDir()); err != nil {
// Shutdown on failure
retErr := fmt.Errorf("Error storing worker auth request: %w", err)
if err := c.worker.Shutdown(); err != nil {
if useWorkerLed {
req := c.worker.WorkerAuthRegistrationRequest
if req == "" {
c.UI.Error("No worker auth registration request found at worker start time")
return base.CommandCliError
}
if err := c.StoreWorkerAuthReq(c.worker.WorkerAuthRegistrationRequest, c.worker.WorkerAuthStorage.BaseDir()); err != nil {
// Shutdown on failure
retErr := fmt.Errorf("Error storing worker auth request: %w", err)
if err := c.worker.Shutdown(); err != nil {
c.UI.Error(retErr.Error())
retErr = fmt.Errorf("Error shutting down worker: %w", err)
}
c.UI.Error(retErr.Error())
retErr = fmt.Errorf("Error shutting down worker: %w", err)
if err := c.controller.Shutdown(); err != nil {
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
}
return base.CommandCliError
}
c.UI.Error(retErr.Error())
if err := c.controller.Shutdown(); err != nil {
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
}
return base.CommandCliError
}
go func() {
for {
select {
case <-c.Context.Done():
return
case <-time.After(time.Second):
if err := authorizeWorker(c.Context, c.controller, req); err != nil {
c.UI.Error(fmt.Errorf("Error authorizing node: %w", err).Error())
errorEncountered.Store(true)
go func() {
for {
select {
case <-c.Context.Done():
return
case <-time.After(time.Second):
if err := authorizeWorker(c.Context, c.controller, req); err != nil {
c.UI.Error(fmt.Errorf("Error authorizing node: %w", err).Error())
errorEncountered.Store(true)
return
}
return
}
return
}
}
}()
}()
}
}
}
+1 -1
View File
@@ -64,7 +64,7 @@ func TestCommand_Flags(t *testing.T) {
assert.Contains(completions, "-event-allow-filter")
assert.Contains(completions, "-event-deny-filter")
assert.Contains(completions, "-plugin-execution-dir")
assert.Contains(completions, "-use-kms-worker-auth-method")
assert.Contains(completions, "-worker-auth-method")
assert.Contains(completions, "-worker-auth-storage-dir")
assert.Contains(completions, "-worker-auth-storage-skip-cleanup")
+4
View File
@@ -210,6 +210,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("Worker is using KMS auth but has no name set. It must be the unique name of this instance.")
return base.CommandUserError
}
if c.Config.Worker.ControllerGeneratedActivationToken != "" {
c.UI.Error("Worker has KMS auth info but also has a controller-generated activation token set, which is incompatible.")
return base.CommandUserError
}
}
}
@@ -0,0 +1,40 @@
package workerscmd
import (
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func init() {
executeExtraControllerLedActions = executeExtraControllerLedActionsImpl
}
func (c *ControllerLedCommand) extraControllerLedHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary workers create controller-led [options] [args]",
"",
" Create a worker using the controller-led approach, receiving an activation token for a worker. Example:",
"",
` $ boundary workers create controller-led -name us-east-1-1 "`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func executeExtraControllerLedActionsImpl(c *ControllerLedCommand, origResp *api.Response, origItem *workers.Worker, origError error, workerClient *workers.Client, version uint32, opts []workers.Option) (*api.Response, *workers.Worker, error) {
switch c.Func {
case "create":
result, err := workerClient.CreateControllerLed(c.Context, c.FlagScopeId, opts...)
if err != nil {
return nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil
}
return origResp, origItem, origError
}
@@ -0,0 +1,247 @@
// Code generated by "make cli"; DO NOT EDIT.
package workerscmd
import (
"errors"
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initControllerLedFlags() {
flagsOnce.Do(func() {
extraFlags := extraControllerLedActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsControllerLedMap[k] = append(flagsControllerLedMap[k], v...)
}
})
}
var (
_ cli.Command = (*ControllerLedCommand)(nil)
_ cli.CommandAutocomplete = (*ControllerLedCommand)(nil)
)
type ControllerLedCommand struct {
*base.Command
Func string
plural string
}
func (c *ControllerLedCommand) AutocompleteArgs() complete.Predictor {
initControllerLedFlags()
return complete.PredictAnything
}
func (c *ControllerLedCommand) AutocompleteFlags() complete.Flags {
initControllerLedFlags()
return c.Flags().Completions()
}
func (c *ControllerLedCommand) Synopsis() string {
if extra := extraControllerLedSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "worker"
synopsisStr = fmt.Sprintf("%s %s", "controller-led-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *ControllerLedCommand) Help() string {
initControllerLedFlags()
var helpStr string
helpMap := common.HelpMap("worker")
switch c.Func {
default:
helpStr = c.extraControllerLedHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsControllerLedMap = map[string][]string{
"create": {"scope-id", "name", "description"},
}
func (c *ControllerLedCommand) Flags() *base.FlagSets {
if len(flagsControllerLedMap[c.Func]) == 0 {
return c.FlagSet(base.FlagSetNone)
}
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "controller-led-type worker", flagsControllerLedMap, c.Func)
extraControllerLedFlagsFunc(c, set, f)
return set
}
func (c *ControllerLedCommand) Run(args []string) int {
initControllerLedFlags()
switch c.Func {
case "":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}
c.plural = "controller-led-type worker"
switch c.Func {
case "list":
c.plural = "controller-led-type workers"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
if strutil.StrListContains(flagsControllerLedMap[c.Func], "id") && c.FlagId == "" {
c.PrintCliError(errors.New("ID is required but not passed in via -id"))
return base.CommandUserError
}
var opts []workers.Option
if strutil.StrListContains(flagsControllerLedMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.PrintCliError(errors.New("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID"))
return base.CommandUserError
}
}
}
client, err := c.Client()
if c.WrapperCleanupFunc != nil {
defer func() {
if err := c.WrapperCleanupFunc(); err != nil {
c.PrintCliError(fmt.Errorf("Error cleaning kms wrapper: %w", err))
}
}()
}
if err != nil {
c.PrintCliError(fmt.Errorf("Error creating API client: %w", err))
return base.CommandCliError
}
workersClient := workers.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, workers.DefaultName())
default:
opts = append(opts, workers.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, workers.DefaultDescription())
default:
opts = append(opts, workers.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, workers.WithRecursive(true))
}
if c.FlagFilter != "" {
opts = append(opts, workers.WithFilter(c.FlagFilter))
}
var version uint32
if ok := extraControllerLedFlagsHandlingFunc(c, f, &opts); !ok {
return base.CommandUserError
}
var resp *api.Response
var item *workers.Worker
switch c.Func {
}
resp, item, err = executeExtraControllerLedActions(c, resp, item, err, workersClient, version, opts)
if exitCode := c.checkFuncError(err); exitCode > 0 {
return exitCode
}
output, err := printCustomControllerLedActionOutput(c)
if err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
if output {
return base.CommandSuccess
}
switch c.Func {
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item, resp))
case "json":
if ok := c.PrintJsonItem(resp); !ok {
return base.CommandCliError
}
}
return base.CommandSuccess
}
func (c *ControllerLedCommand) checkFuncError(err error) int {
if err == nil {
return 0
}
if apiErr := api.AsServerError(err); apiErr != nil {
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural))
return base.CommandApiError
}
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return base.CommandCliError
}
var (
extraControllerLedActionsFlagsMapFunc = func() map[string][]string { return nil }
extraControllerLedSynopsisFunc = func(*ControllerLedCommand) string { return "" }
extraControllerLedFlagsFunc = func(*ControllerLedCommand, *base.FlagSets, *base.FlagSet) {}
extraControllerLedFlagsHandlingFunc = func(*ControllerLedCommand, *base.FlagSets, *[]workers.Option) bool { return true }
executeExtraControllerLedActions = func(_ *ControllerLedCommand, inResp *api.Response, inItem *workers.Worker, inErr error, _ *workers.Client, _ uint32, _ []workers.Option) (*api.Response, *workers.Worker, error) {
return inResp, inItem, inErr
}
printCustomControllerLedActionOutput = func(*ControllerLedCommand) (bool, error) { return false, nil }
)
@@ -261,6 +261,9 @@ func printItemTable(item *workers.Worker, resp *api.Response) string {
if !item.LastStatusTime.IsZero() {
nonAttributeMap["Last Status Time"] = item.LastStatusTime
}
if item.ControllerGeneratedActivationToken != "" {
nonAttributeMap["Controller-Generated Activation Token"] = item.ControllerGeneratedActivationToken
}
resultMap := resp.Map
if count, ok := resultMap[globals.ActiveConnectionCountField]; ok {
+10
View File
@@ -212,6 +212,11 @@ type Worker struct {
// AuthStoragePath represents the location a worker stores its node credentials, if set
AuthStoragePath string `hcl:"auth_storage_path"`
// ControllerGeneratedActivationToken is a controller-generated activation
// token used to register this worker to the cluster. It can be a path, env
// var, or direct value.
ControllerGeneratedActivationToken string `hcl:"controller_generated_activation_token"`
}
type Database struct {
@@ -454,6 +459,11 @@ func Parse(d string) (*Config, error) {
return nil, errors.New("Worker description contains non-printable characters")
}
result.Worker.ControllerGeneratedActivationToken, err = parseutil.ParsePath(result.Worker.ControllerGeneratedActivationToken)
if err != nil && !errors.Is(err, parseutil.ErrNotAUrl) {
return nil, fmt.Errorf("Error parsing worker activation token: %w", err)
}
if result.Worker.TagsRaw != nil {
switch t := result.Worker.TagsRaw.(type) {
// We allow `tags` to be a simple string containing a URL with schema.
+18
View File
@@ -301,6 +301,24 @@ func TestDevWorker(t *testing.T) {
_, err = Parse(devConfig + devWorkerKeyValueConfig)
assert.Error(t, err)
// Check activation token parsing
devWorkerActivationTokenConfig := `
listener "tcp" {
purpose = "proxy"
}
worker {
name = "dev-worker"
description = "A default worker created in dev mode"
initial_upstreams = ["127.0.0.1"]
controller_generated_activation_token = "foobar"
}
`
actual, err = Parse(devConfig + devWorkerActivationTokenConfig)
require.NoError(t, err)
assert.Equal(t, "foobar", actual.Worker.ControllerGeneratedActivationToken)
}
func TestDevCombined(t *testing.T) {
+14
View File
@@ -552,5 +552,19 @@ var inputStructs = map[string][]*cmdInfo{
NeedsSubtypeInCreate: true,
SkipClientCallActions: []string{"create"},
},
{
ResourceType: resource.Worker.String(),
Pkg: "workers",
StdActions: []string{"create"},
SubActionPrefix: "controller-led",
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
Container: "Scope",
HasDescription: true,
NeedsSubtypeInCreate: true,
SkipClientCallActions: []string{"create"},
},
},
}
@@ -2,6 +2,7 @@ package handlers_test
import (
"context"
"crypto/rand"
"fmt"
"sync"
"testing"
@@ -20,6 +21,7 @@ import (
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh/testdata"
@@ -206,16 +208,17 @@ func TestHcpbWorkers(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
serversRepoFn := func() (*server.Repository, error) {
return server.NewRepository(rw, rw, kms)
return server.NewRepository(rw, rw, kmsCache)
}
sessionRepoFn := func() (*session.Repository, error) {
return session.NewRepository(rw, rw, kms)
return session.NewRepository(rw, rw, kmsCache)
}
connectionRepoFn := func() (*session.ConnectionRepository, error) {
return session.NewConnectionRepository(ctx, rw, rw, kms)
return session.NewConnectionRepository(ctx, rw, rw, kmsCache)
}
for i := 0; i < 3; i++ {
@@ -228,7 +231,7 @@ func TestHcpbWorkers(t *testing.T) {
server.TestPkiWorker(t, conn, wrapper, opt...)
}
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, new(sync.Map), kms)
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, new(sync.Map), kmsCache)
require.NotNil(t, s)
res, err := s.ListHcpbWorkers(ctx, &pbs.ListHcpbWorkersRequest{})
@@ -97,6 +97,7 @@ var globalAuthorizedCollectionActions = map[string]*structpb.ListValue{
},
"workers": {
Values: []*structpb.Value{
structpb.NewStringValue("create:controller-led"),
structpb.NewStringValue("create:worker-led"),
structpb.NewStringValue("list"),
},
@@ -1,10 +1,13 @@
package targets
import (
"context"
"crypto/rand"
"fmt"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/server"
"github.com/hashicorp/boundary/internal/types/scope"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
@@ -35,6 +38,8 @@ func TestWorkerList_Addresses(t *testing.T) {
func TestWorkerList_Filter(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
var workers []*server.Worker
for i := 0; i < 5; i++ {
switch {
@@ -19,6 +19,7 @@ import (
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/internal/util"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/nodeenrollment/types"
@@ -52,6 +53,7 @@ var (
// CollectionActions contains the set of actions that can be performed on
// this collection
CollectionActions = action.ActionSet{
action.CreateControllerLed,
action.CreateWorkerLed,
action.List,
}
@@ -199,18 +201,20 @@ func (s Service) GetWorker(ctx context.Context, req *pbs.GetWorkerRequest) (*pbs
return &pbs.GetWorkerResponse{Item: item}, nil
}
// CreateWorker implements the interface pbs.WorkerServiceServer.
// CreateWorkerLed implements the interface pbs.WorkerServiceServer and handles
// a request to create a new worker and consume a worker-generated authorization
// request
func (s Service) CreateWorkerLed(ctx context.Context, req *pbs.CreateWorkerLedRequest) (*pbs.CreateWorkerLedResponse, error) {
const op = "workers.(Service).CreateWorkerLed"
if err := validateCreateRequest(req); err != nil {
act := action.CreateWorkerLed
item := req.GetItem()
if err := validateCreateRequest(item, act); err != nil {
return nil, err
}
authResults := s.authResult(ctx, req.GetItem().GetScopeId(), action.CreateWorkerLed)
if authResults.Error != nil {
return nil, authResults.Error
}
reqBytes, err := base58.FastBase58Decoding(req.GetItem().WorkerGeneratedAuthToken.GetValue())
reqBytes, err := base58.FastBase58Decoding(item.WorkerGeneratedAuthToken.GetValue())
if err != nil {
return nil, fmt.Errorf("%s: error decoding node_credentials_token: %w", op, err)
}
@@ -219,7 +223,43 @@ func (s Service) CreateWorkerLed(ctx context.Context, req *pbs.CreateWorkerLedRe
if err := proto.Unmarshal(reqBytes, creds); err != nil {
return nil, fmt.Errorf("%s: error unmarshaling node_credentials_token: %w", op, err)
}
created, err := s.createInRepo(ctx, req.GetItem(), creds)
out, err := s.createCommon(ctx, item, act, server.WithFetchNodeCredentialsRequest(creds))
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
return &pbs.CreateWorkerLedResponse{Item: out}, nil
}
// CreateControllerLed implements the interface pbs.WorkerServiceServer and handles
// a request to create a new worker, generating and returning an activation
// token
func (s Service) CreateControllerLed(ctx context.Context, req *pbs.CreateControllerLedRequest) (*pbs.CreateControllerLedResponse, error) {
const op = "workers.(Service).CreateControllerLed"
act := action.CreateControllerLed
if err := validateCreateRequest(req.GetItem(), act); err != nil {
return nil, err
}
out, err := s.createCommon(ctx, req.GetItem(), act, server.WithCreateControllerLedActivationToken(true))
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
return &pbs.CreateControllerLedResponse{Item: out}, nil
}
func (s Service) createCommon(ctx context.Context, in *pb.Worker, act action.Type, opt ...server.Option) (*pb.Worker, error) {
const op = "workers.(Service).createCommon"
authResults := s.authResult(ctx, in.GetScopeId(), act)
if authResults.Error != nil {
return nil, authResults.Error
}
created, err := s.createInRepo(ctx, in, opt...)
if err != nil {
return nil, fmt.Errorf("%s: error creating worker: %w", op, err)
}
@@ -243,7 +283,7 @@ func (s Service) CreateWorkerLed(ctx context.Context, req *pbs.CreateWorkerLedRe
return nil, err
}
return &pbs.CreateWorkerLedResponse{Item: item}, nil
return item, nil
}
// DeleteWorker implements the interface pbs.WorkerServiceServer.
@@ -438,7 +478,7 @@ func (s Service) getFromRepo(ctx context.Context, id string) (*server.Worker, er
return w, nil
}
func (s Service) createInRepo(ctx context.Context, worker *pb.Worker, creds *types.FetchNodeCredentialsRequest) (*server.Worker, error) {
func (s Service) createInRepo(ctx context.Context, worker *pb.Worker, opt ...server.Option) (*server.Worker, error) {
const op = "workers.(Service).createInRepo"
repo, err := s.repoFn()
if err != nil {
@@ -449,7 +489,7 @@ func (s Service) createInRepo(ctx context.Context, worker *pb.Worker, creds *typ
server.WithName(worker.GetName().GetValue()),
server.WithDescription(worker.GetDescription().GetValue()),
)
retWorker, err := repo.CreateWorker(ctx, newWorker, server.WithFetchNodeCredentialsRequest(creds))
retWorker, err := repo.CreateWorker(ctx, newWorker, opt...)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create worker"))
}
@@ -593,7 +633,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.
var parentId string
opts := []auth.Option{auth.WithType(resource.Worker), auth.WithAction(a)}
switch a {
case action.List, action.CreateWorkerLed:
case action.List, action.CreateWorkerLed, action.CreateControllerLed:
parentId = id
default:
w, err := repo.LookupWorker(ctx, id)
@@ -670,6 +710,9 @@ func toProto(ctx context.Context, in *server.Worker, opt ...handlers.Option) (*p
if outputFields.Has(globals.ActiveConnectionCountField) {
out.ActiveConnectionCount = &wrapperspb.UInt32Value{Value: in.ActiveConnectionCount()}
}
if outputFields.Has(globals.ControllerGeneratedActivationToken) && in.ControllerGeneratedActivationToken != "" {
out.ControllerGeneratedActivationToken = &wrapperspb.StringValue{Value: in.ControllerGeneratedActivationToken}
}
if outputFields.Has(globals.ConfigTagsField) && len(in.GetConfigTags()) > 0 {
var err error
out.ConfigTags, err = tagsToMapProto(in.GetConfigTags())
@@ -769,45 +812,57 @@ func validateUpdateRequest(req *pbs.UpdateWorkerRequest) error {
}, server.WorkerPrefix)
}
func validateCreateRequest(req *pbs.CreateWorkerLedRequest) error {
return handlers.ValidateCreateRequest(req.GetItem(), func() map[string]string {
func validateCreateRequest(item *pb.Worker, act action.Type) error {
if util.IsNil(item) {
return handlers.InvalidArgumentErrorf("Request item is nil", nil)
}
switch act {
case action.CreateWorkerLed:
case action.CreateControllerLed:
default:
// This shouldn't happen because we shouldn't be routed to one of the
// handlers if it's the wrong action, but check anyways.
return handlers.InvalidArgumentErrorf("Invalid action", nil)
}
return handlers.ValidateCreateRequest(item, func() map[string]string {
const (
mustBeGlobalMsg = "Must be 'global'"
cannotBeEmptyMsg = "Cannot be empty."
readOnlyFieldMsg = "This is a read only field."
)
badFields := map[string]string{}
if scope.Global.String() != req.GetItem().GetScopeId() {
if scope.Global.String() != item.GetScopeId() {
badFields[globals.ScopeIdField] = mustBeGlobalMsg
}
// FIXME: in the future, we won't require this token since we'll support
// the server led flow where a token is returned when a worker is created.
if req.GetItem().WorkerGeneratedAuthToken == nil {
switch {
case act == action.CreateWorkerLed && item.WorkerGeneratedAuthToken == nil:
badFields[globals.WorkerGeneratedAuthTokenField] = cannotBeEmptyMsg
case act == action.CreateControllerLed && item.WorkerGeneratedAuthToken != nil:
badFields[globals.WorkerGeneratedAuthTokenField] = "Worker-generated auth tokens are not used with the controller-led creation flow."
}
if req.GetItem().Address != "" {
if item.Address != "" {
badFields[globals.CanonicalAddressField] = readOnlyFieldMsg
}
if req.GetItem().CanonicalTags != nil {
if item.CanonicalTags != nil {
badFields[globals.CanonicalTagsField] = readOnlyFieldMsg
}
if req.GetItem().ConfigTags != nil {
if item.ConfigTags != nil {
badFields[globals.ConfigTagsField] = readOnlyFieldMsg
}
if req.GetItem().LastStatusTime != nil {
if item.LastStatusTime != nil {
badFields[globals.LastStatusTimeField] = readOnlyFieldMsg
}
if req.GetItem().AuthorizedActions != nil {
if item.AuthorizedActions != nil {
badFields[globals.AuthorizedActionsField] = readOnlyFieldMsg
}
nameString := req.GetItem().GetName().String()
nameString := item.GetName().String()
if !strutil.Printable(nameString) {
badFields[globals.NameField] = "Name contains non-printable characters."
}
if strings.ToLower(nameString) != nameString {
badFields[globals.NameField] = "Name must be all lowercase."
}
descriptionString := req.GetItem().GetDescription().String()
descriptionString := item.GetDescription().String()
if !strutil.Printable(descriptionString) {
badFields[globals.DescriptionField] = "Description contains non-printable characters."
}
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"sort"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -22,6 +23,7 @@ import (
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/rotation"
"github.com/hashicorp/nodeenrollment/storage/file"
"github.com/hashicorp/nodeenrollment/types"
@@ -1316,6 +1318,350 @@ func TestCreateWorkerLed(t *testing.T) {
}
}
func TestCreateControllerLed(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
testRootWrapper := db.TestWrapper(t)
iamRepo := iam.TestRepo(t, conn, testRootWrapper)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
rw := db.New(conn)
testKms := kms.TestKms(t, conn, testRootWrapper)
repoFn := func() (*server.Repository, error) {
return server.NewRepository(rw, rw, testKms)
}
testCtx := context.Background()
testSrv, err := NewService(testCtx, repoFn, iamRepoFn)
require.NoError(t, err, "Error when getting new worker service.")
// Get an initial set of authorized node credentials
rootStorage, err := server.NewRepositoryStorage(testCtx, rw, rw, testKms)
require.NoError(t, err)
_, err = rotation.RotateRootCertificates(testCtx, rootStorage)
require.NoError(t, err)
fetchReqFn := func() string {
// This happens on the worker
fileStorage, err := file.New(testCtx)
require.NoError(t, err)
defer fileStorage.Cleanup()
nodeCreds, err := types.NewNodeCredentials(testCtx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(testCtx)
require.NoError(t, err)
fetchEncoded, err := proto.Marshal(fetchReq)
require.NoError(t, err)
return base58.Encode(fetchEncoded)
}
tests := []struct {
name string
scopeId string
service Service
req *pbs.CreateControllerLedRequest
res *pbs.CreateControllerLedResponse
wantErr bool
wantErrIs error
wantErrContains string
}{
{
name: "invalid-scope",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: "invalid-scope",
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: "Must be 'global'",
},
{
name: "supplied-node-auth-request",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
WorkerGeneratedAuthToken: &wrapperspb.StringValue{Value: fetchReqFn()},
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.WorkerGeneratedAuthTokenField,
},
{
name: "invalid-id",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Id: "invalid-id",
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.IdField,
},
{
name: "invalid-address",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Address: "invalid-address",
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.AddressField,
},
{
name: "invalid-config-tags",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
ConfigTags: map[string]*structpb.ListValue{
"invalid": {Values: []*structpb.Value{
structpb.NewStringValue("invalid-tags"),
}},
},
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.ConfigTagsField,
},
{
name: "invalid-canonical-tags",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
CanonicalTags: map[string]*structpb.ListValue{
"invalid": {Values: []*structpb.Value{
structpb.NewStringValue("invalid-canonical-tags"),
}},
},
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.CanonicalTagsField,
},
{
name: "invalid-last-status-time",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
LastStatusTime: timestamppb.Now(),
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.LastStatusTimeField,
},
{
name: "invalid-authorized-actions",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
AuthorizedActions: []string{"invalid-authorized-actions"},
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.AuthorizedActionsField,
},
{
name: "invalid-create-time",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
CreatedTime: timestamppb.Now(),
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.CreatedTimeField,
},
{
name: "invalid-update-time",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
UpdatedTime: timestamppb.Now(),
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.UpdatedTimeField,
},
{
name: "invalid-version",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Version: 1,
},
},
wantErr: true,
wantErrIs: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: globals.VersionField,
},
{
name: "invalid-auth",
service: testSrv,
scopeId: "splat-auth-scope",
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
},
},
wantErr: true,
wantErrContains: "non-existent scope \"splat-auth-scope\"",
},
{
name: "create-error",
service: func() Service {
repoFn := func() (*server.Repository, error) {
return server.NewRepository(rw, &db.Db{}, testKms)
}
testSrv, err := NewService(testCtx, repoFn, iamRepoFn)
require.NoError(t, err, "Error when getting new worker service.")
return testSrv
}(),
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: "success"},
Description: &wrapperspb.StringValue{Value: "success-description"},
},
},
wantErr: true,
wantErrContains: "error creating worker",
},
{
name: "bad-repo-function-in-create",
service: func() Service {
// var cnt gives us a way for the repoFn to fail the 2nd time
// it's called so we can get past the AuthRequest check in
// CreateWorker(...) and test the createInRepo(...) failure
// path if the repoFn returns and err.
cnt := 0
repoFn := func() (*server.Repository, error) {
cnt = cnt + 1
switch {
case cnt > 1:
return nil, errors.New(testCtx, errors.Internal, "bad-repo-function", "error creating repo")
default:
return server.NewRepository(rw, rw, testKms)
}
}
testSrv, err := NewService(testCtx, repoFn, iamRepoFn)
require.NoError(t, err, "Error when getting new worker service.")
return testSrv
}(),
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: "success"},
Description: &wrapperspb.StringValue{Value: "success-description"},
},
},
wantErr: true,
wantErrContains: "error creating worker: bad-repo-function: error creating repo",
},
{
name: "success",
service: testSrv,
scopeId: scope.Global.String(),
req: &pbs.CreateControllerLedRequest{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: "success"},
Description: &wrapperspb.StringValue{Value: "success-description"},
},
},
res: &pbs.CreateControllerLedResponse{
Item: &workers.Worker{
ScopeId: scope.Global.String(),
Name: &wrapperspb.StringValue{Value: "success"},
Description: &wrapperspb.StringValue{Value: "success-description"},
ActiveConnectionCount: &wrapperspb.UInt32Value{Value: 0},
Version: 1,
Type: PkiWorkerType,
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
got, err := tc.service.CreateControllerLed(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), tc.req)
if tc.wantErr {
require.Error(err)
assert.Nil(got)
if tc.wantErrIs != nil {
assert.ErrorIs(err, tc.wantErrIs)
}
if tc.wantErrContains != "" {
assert.Contains(err.Error(), tc.wantErrContains)
}
return
}
require.NoError(err)
require.NotNil(got)
{
// we only need to check that these "read-only" fields were set
// outbound. Other portions of the domain is responsible for
// testing that these values are correct and there's no reason
// to repeat those tests here.
assert.NotEmpty(got.GetItem().GetId())
assert.NotEmpty(got.GetItem().CreatedTime)
assert.NotEmpty(got.GetItem().UpdatedTime)
assert.NotEmpty(got.GetItem().Scope)
assert.NotEmpty(got.GetItem().AuthorizedActions)
assert.NotEmpty(got.GetItem().ControllerGeneratedActivationToken)
assert.True(strings.HasPrefix(got.GetItem().ControllerGeneratedActivationToken.GetValue(), nodeenrollment.ServerLedActivationTokenPrefix))
{
tc.res.Item.Id = got.GetItem().GetId()
tc.res.Item.CreatedTime = got.GetItem().GetCreatedTime()
tc.res.Item.UpdatedTime = got.GetItem().GetUpdatedTime()
tc.res.Item.Scope = got.GetItem().Scope
tc.res.Item.AuthorizedActions = got.GetItem().GetAuthorizedActions()
tc.res.Item.ControllerGeneratedActivationToken = got.GetItem().GetControllerGeneratedActivationToken()
}
}
assert.Equal(tc.res, got)
})
}
}
func TestService_AddWorkerTags(t *testing.T) {
t.Parallel()
assert, require := assert.New(t), require.New(t)
@@ -1662,8 +2008,9 @@ func TestService_RemoveWorkerTags(t *testing.T) {
name: "remove-valid-tag",
req: func() *pbs.RemoveWorkerTagsRequest {
worker := server.TestKmsWorker(t, conn, wrapper)
s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
_, err := s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
worker.Version, map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}})
require.NoError(err)
return &pbs.RemoveWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version + 1,
@@ -1676,7 +2023,7 @@ func TestService_RemoveWorkerTags(t *testing.T) {
name: "remove-many-valid-tags",
req: func() *pbs.RemoveWorkerTagsRequest {
worker := server.TestKmsWorker(t, conn, wrapper)
s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
_, err := s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
worker.Version, map[string]*structpb.ListValue{
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value1")}},
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
@@ -1685,6 +2032,7 @@ func TestService_RemoveWorkerTags(t *testing.T) {
"key5": {Values: []*structpb.Value{structpb.NewStringValue("value5")}},
"key6": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
})
require.NoError(err)
return &pbs.RemoveWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version + 1,
@@ -1738,7 +2086,7 @@ func TestService_RemoveWorkerTags(t *testing.T) {
name: "remove-nonexistent-tags",
req: func() *pbs.RemoveWorkerTagsRequest {
worker := server.TestKmsWorker(t, conn, wrapper)
s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
_, err := s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
worker.Version, map[string]*structpb.ListValue{
"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
@@ -1747,6 +2095,7 @@ func TestService_RemoveWorkerTags(t *testing.T) {
"key5": {Values: []*structpb.Value{structpb.NewStringValue("value5")}},
"key6": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
})
require.NoError(err)
return &pbs.RemoveWorkerTagsRequest{
Id: worker.PublicId,
Version: worker.Version + 1,
@@ -86,7 +86,16 @@ func (w *Worker) controllerDialerFunc(extraAlpnProtos ...string) func(context.Co
case w.conf.WorkerAuthKms != nil && !w.conf.DevUsePkiForUpstream:
conn, err = w.v1KmsAuthDialFn(ctx, addr, extraAlpnProtos...)
default:
conn, err = protocol.Dial(ctx, w.WorkerAuthStorage, addr, nodeenrollment.WithWrapper(w.conf.WorkerAuthStorageKms), nodeenrollment.WithExtraAlpnProtos(extraAlpnProtos))
conn, err = protocol.Dial(
ctx,
w.WorkerAuthStorage,
addr,
nodeenrollment.WithWrapper(w.conf.WorkerAuthStorageKms),
nodeenrollment.WithExtraAlpnProtos(extraAlpnProtos),
// If the activation token hasn't been populated, this won't do
// anything, and it won't do anything if it's already been used
nodeenrollment.WithActivationToken(w.conf.RawConfig.Worker.ControllerGeneratedActivationToken),
)
// No error and a valid connection means the WorkerAuthRegistrationRequest was populated
// We can remove the stored workerAuthRequest file
if err == nil && conn != nil {
@@ -97,13 +106,23 @@ func (w *Worker) controllerDialerFunc(extraAlpnProtos ...string) func(context.Co
}
}
}
switch err {
case nil:
case nodeenrollment.ErrNotAuthorized:
// We don't event in this case, because the function retries often
// and will spam the logs. The status function will event indicating
// that it can't send status because it's not authorized, so that
// will be a fine hint to the user as to the issue.
switch {
case err == nil:
// Nothing
case errors.Is(err, nodeenrollment.ErrNotAuthorized):
switch w.conf.RawConfig.Worker.ControllerGeneratedActivationToken {
case "":
// We don't event in this case, because the function retries
// often and will spam the logs while waiting on the user to
// transfer the worker-generated request over
default:
// In this case, event, so that the operator can understand that
// it was rejected
event.WriteError(ctx, op, fmt.Errorf("controller rejected activation token as invalid"))
}
default:
event.WriteError(ctx, op, err)
}
+13
View File
@@ -251,6 +251,10 @@ func (w *Worker) Start() error {
// the controller, we don't want to invalidate that request on restart
// by generating a new set of credentials. However it's safe to output a
// new fetch request so we do in fact do that.
//
// Note that if a controller-generated activation token has been
// supplied, we do not output a fetch request; we attempt to use that
// directly later.
var err error
w.WorkerAuthStorage, err = nodeefile.New(w.baseContext,
nodeefile.WithBaseDirectory(w.conf.RawConfig.Worker.AuthStoragePath))
@@ -311,6 +315,15 @@ func (w *Worker) Start() error {
return fmt.Errorf("error loading worker auth creds: %w", err)
}
// Don't output a fetch request if an activation token has been
// provided. Technically we _could_ still output a fetch request, and it
// would be valid to do so, but if a token was provided it may well be
// confusing to a user if it seems like it was ignored because a fetch
// request was still output.
if actToken := w.conf.RawConfig.Worker.ControllerGeneratedActivationToken; actToken != "" {
createFetchRequest = false
}
// NOTE: this block _must_ be before the `if createFetchRequest` block
// or the fetch request may have no credentials to work with
if createNodeAuthCreds {
@@ -0,0 +1,30 @@
begin;
create table worker_auth_server_led_activation_token(
worker_id wt_public_id primary key
constraint server_worker_fkey
references server_worker (public_id)
on delete cascade
on update cascade,
token_id text not null
constraint token_id_must_not_be_empty
check(length(trim(token_id)) > 0),
creation_time_encrypted bytea not null
constraint creation_time_encrypted_must_not_be_empty
check(length(creation_time_encrypted) > 0),
key_id kms_private_id not null
constraint kms_data_key_version_fkey
references kms_data_key_version (private_id)
on delete restrict
on update cascade,
constraint worker_auth_server_led_activation_token_token_id_uq -- only one valid token at a time for a given worker
unique(token_id)
);
comment on table worker_auth_server_led_activation_token is
'worker_auth_server_led_activation_token is a table where each row represents an activation token for a worker. Only one activation token is allowed per worker.';
create trigger immutable_columns before update on worker_auth_server_led_activation_token
for each row execute procedure immutable_columns('worker_id', 'token_id', 'creation_time_encrypted');
commit;
+43
View File
@@ -3961,6 +3961,33 @@
]
}
},
"/v1/workers:create:controller-led": {
"post": {
"summary": "Creates a single Worker.",
"operationId": "WorkerService_CreateControllerLed",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
}
}
},
"parameters": [
{
"name": "item",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
}
}
],
"tags": [
"controller.api.services.v1.WorkerService"
]
}
},
"/v1/workers:create:worker-led": {
"post": {
"summary": "Creates a single Worker.",
@@ -5790,6 +5817,11 @@
"type": "string",
"title": "worker_generated_auth_token is input only. Supports the worker led node\nenrollment flow where this credentials token is produced by a worker. This\ntoken is a base58 encoded types.FetchNodeCredentialsRequest from\nhttps://github.com/hashicorp/nodeenrollment"
},
"controller_generated_activation_token": {
"type": "string",
"description": "Output only. An activation token that can be given to a worker to correlate\nit to the created resource.",
"readOnly": true
},
"active_connection_count": {
"type": "integer",
"format": "int64",
@@ -5966,6 +5998,17 @@
}
}
},
"controller.api.services.v1.CreateControllerLedResponse": {
"type": "object",
"properties": {
"uri": {
"type": "string"
},
"item": {
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
}
}
},
"controller.api.services.v1.CreateCredentialLibraryResponse": {
"type": "object",
"properties": {
@@ -331,6 +331,108 @@ func (x *CreateWorkerLedResponse) GetItem() *workers.Worker {
return nil
}
type CreateControllerLedRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Item *workers.Worker `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"`
}
func (x *CreateControllerLedRequest) Reset() {
*x = CreateControllerLedRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CreateControllerLedRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateControllerLedRequest) ProtoMessage() {}
func (x *CreateControllerLedRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[6]
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 CreateControllerLedRequest.ProtoReflect.Descriptor instead.
func (*CreateControllerLedRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{6}
}
func (x *CreateControllerLedRequest) GetItem() *workers.Worker {
if x != nil {
return x.Item
}
return nil
}
type CreateControllerLedResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty" class:"public"` // @gotags: `class:"public"`
Item *workers.Worker `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"`
}
func (x *CreateControllerLedResponse) Reset() {
*x = CreateControllerLedResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CreateControllerLedResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateControllerLedResponse) ProtoMessage() {}
func (x *CreateControllerLedResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[7]
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 CreateControllerLedResponse.ProtoReflect.Descriptor instead.
func (*CreateControllerLedResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{7}
}
func (x *CreateControllerLedResponse) GetUri() string {
if x != nil {
return x.Uri
}
return ""
}
func (x *CreateControllerLedResponse) GetItem() *workers.Worker {
if x != nil {
return x.Item
}
return nil
}
type UpdateWorkerRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -344,7 +446,7 @@ type UpdateWorkerRequest struct {
func (x *UpdateWorkerRequest) Reset() {
*x = UpdateWorkerRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[6]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -357,7 +459,7 @@ func (x *UpdateWorkerRequest) String() string {
func (*UpdateWorkerRequest) ProtoMessage() {}
func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[6]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -370,7 +472,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead.
func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{6}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{8}
}
func (x *UpdateWorkerRequest) GetId() string {
@@ -405,7 +507,7 @@ type UpdateWorkerResponse struct {
func (x *UpdateWorkerResponse) Reset() {
*x = UpdateWorkerResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[7]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -418,7 +520,7 @@ func (x *UpdateWorkerResponse) String() string {
func (*UpdateWorkerResponse) ProtoMessage() {}
func (x *UpdateWorkerResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[7]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -431,7 +533,7 @@ func (x *UpdateWorkerResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use UpdateWorkerResponse.ProtoReflect.Descriptor instead.
func (*UpdateWorkerResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{7}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{9}
}
func (x *UpdateWorkerResponse) GetItem() *workers.Worker {
@@ -452,7 +554,7 @@ type DeleteWorkerRequest struct {
func (x *DeleteWorkerRequest) Reset() {
*x = DeleteWorkerRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[8]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -465,7 +567,7 @@ func (x *DeleteWorkerRequest) String() string {
func (*DeleteWorkerRequest) ProtoMessage() {}
func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[8]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -478,7 +580,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead.
func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{8}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{10}
}
func (x *DeleteWorkerRequest) GetId() string {
@@ -497,7 +599,7 @@ type DeleteWorkerResponse struct {
func (x *DeleteWorkerResponse) Reset() {
*x = DeleteWorkerResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[9]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -510,7 +612,7 @@ func (x *DeleteWorkerResponse) String() string {
func (*DeleteWorkerResponse) ProtoMessage() {}
func (x *DeleteWorkerResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[9]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -523,7 +625,7 @@ func (x *DeleteWorkerResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeleteWorkerResponse.ProtoReflect.Descriptor instead.
func (*DeleteWorkerResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{9}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{11}
}
type AddWorkerTagsRequest struct {
@@ -541,7 +643,7 @@ type AddWorkerTagsRequest struct {
func (x *AddWorkerTagsRequest) Reset() {
*x = AddWorkerTagsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[10]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -554,7 +656,7 @@ func (x *AddWorkerTagsRequest) String() string {
func (*AddWorkerTagsRequest) ProtoMessage() {}
func (x *AddWorkerTagsRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[10]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -567,7 +669,7 @@ func (x *AddWorkerTagsRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use AddWorkerTagsRequest.ProtoReflect.Descriptor instead.
func (*AddWorkerTagsRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{10}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{12}
}
func (x *AddWorkerTagsRequest) GetId() string {
@@ -602,7 +704,7 @@ type AddWorkerTagsResponse struct {
func (x *AddWorkerTagsResponse) Reset() {
*x = AddWorkerTagsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[11]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -615,7 +717,7 @@ func (x *AddWorkerTagsResponse) String() string {
func (*AddWorkerTagsResponse) ProtoMessage() {}
func (x *AddWorkerTagsResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[11]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -628,7 +730,7 @@ func (x *AddWorkerTagsResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use AddWorkerTagsResponse.ProtoReflect.Descriptor instead.
func (*AddWorkerTagsResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{11}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{13}
}
func (x *AddWorkerTagsResponse) GetItem() *workers.Worker {
@@ -653,7 +755,7 @@ type SetWorkerTagsRequest struct {
func (x *SetWorkerTagsRequest) Reset() {
*x = SetWorkerTagsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[12]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -666,7 +768,7 @@ func (x *SetWorkerTagsRequest) String() string {
func (*SetWorkerTagsRequest) ProtoMessage() {}
func (x *SetWorkerTagsRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[12]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -679,7 +781,7 @@ func (x *SetWorkerTagsRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SetWorkerTagsRequest.ProtoReflect.Descriptor instead.
func (*SetWorkerTagsRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{12}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{14}
}
func (x *SetWorkerTagsRequest) GetId() string {
@@ -714,7 +816,7 @@ type SetWorkerTagsResponse struct {
func (x *SetWorkerTagsResponse) Reset() {
*x = SetWorkerTagsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[13]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -727,7 +829,7 @@ func (x *SetWorkerTagsResponse) String() string {
func (*SetWorkerTagsResponse) ProtoMessage() {}
func (x *SetWorkerTagsResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[13]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -740,7 +842,7 @@ func (x *SetWorkerTagsResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SetWorkerTagsResponse.ProtoReflect.Descriptor instead.
func (*SetWorkerTagsResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{13}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{15}
}
func (x *SetWorkerTagsResponse) GetItem() *workers.Worker {
@@ -765,7 +867,7 @@ type RemoveWorkerTagsRequest struct {
func (x *RemoveWorkerTagsRequest) Reset() {
*x = RemoveWorkerTagsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[14]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -778,7 +880,7 @@ func (x *RemoveWorkerTagsRequest) String() string {
func (*RemoveWorkerTagsRequest) ProtoMessage() {}
func (x *RemoveWorkerTagsRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[14]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -791,7 +893,7 @@ func (x *RemoveWorkerTagsRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use RemoveWorkerTagsRequest.ProtoReflect.Descriptor instead.
func (*RemoveWorkerTagsRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{14}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{16}
}
func (x *RemoveWorkerTagsRequest) GetId() string {
@@ -826,7 +928,7 @@ type RemoveWorkerTagsResponse struct {
func (x *RemoveWorkerTagsResponse) Reset() {
*x = RemoveWorkerTagsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[15]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -839,7 +941,7 @@ func (x *RemoveWorkerTagsResponse) String() string {
func (*RemoveWorkerTagsResponse) ProtoMessage() {}
func (x *RemoveWorkerTagsResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[15]
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -852,7 +954,7 @@ func (x *RemoveWorkerTagsResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use RemoveWorkerTagsResponse.ProtoReflect.Descriptor instead.
func (*RemoveWorkerTagsResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{15}
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{17}
}
func (x *RemoveWorkerTagsResponse) GetItem() *workers.Worker {
@@ -914,191 +1016,218 @@ var file_controller_api_services_v1_worker_service_proto_rawDesc = []byte{
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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x22, 0xa4, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x6d, 0x22, 0x5d, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x22, 0x70, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x6c, 0x65, 0x72, 0x4c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72,
0x69, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x22, 0xa4, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, 0x0b, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, 0x75, 0x70,
0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x57, 0x0a, 0x14, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x22, 0x25, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70,
0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, 0x75, 0x70, 0x64,
0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x57, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0xf3, 0x01, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54,
0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, 0x69, 0x54, 0x61, 0x67, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x1a,
0x56, 0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b,
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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x22, 0x25, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0xf3, 0x01, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61,
0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, 0x69, 0x54, 0x61, 0x67, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x56,
0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x22, 0xf3, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61,
0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, 0x69, 0x54, 0x61, 0x67, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x56,
0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x22, 0xf9, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61,
0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70,
0x69, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69, 0x5f,
0x74, 0x61, 0x67, 0x73, 0x1a, 0x56, 0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5b, 0x0a, 0x18,
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0xfd, 0x0b, 0x0a, 0x0d, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa2, 0x01, 0x0a, 0x09,
0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x6d, 0x22, 0xf3, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54,
0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, 0x69, 0x54, 0x61, 0x67, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x1a,
0x56, 0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b,
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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x22, 0xf9, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74,
0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x92, 0x41, 0x17, 0x12, 0x15, 0x47, 0x65, 0x74,
0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x12, 0x9a, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73,
0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x2a, 0x92, 0x41, 0x14, 0x12, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c,
0x6c, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d,
0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0xca, 0x01,
0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x65,
0x64, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x65, 0x64, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c,
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x92, 0x41, 0x1a, 0x12,
0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c,
0x65, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22,
0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x3a, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x3a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0x6c, 0x65, 0x64, 0x3a, 0x04,
0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xad, 0x01, 0x0a, 0x0c, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x2f, 0x2e, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a,
0x92, 0x41, 0x13, 0x12, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x10, 0x2f, 0x76,
0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04,
0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xa1, 0x01, 0x0a, 0x0c, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x2f, 0x2e, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e,
0x92, 0x41, 0x13, 0x12, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x2a, 0x10, 0x2f, 0x76,
0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xd0,
0x01, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73,
0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64,
0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41,
0x70, 0x69, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69,
0x5f, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x56, 0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c,
0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5b, 0x0a,
0x18, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0xda, 0x0d, 0x0a, 0x0d, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa2, 0x01, 0x0a,
0x09, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x2c, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x92, 0x41, 0x17, 0x12, 0x15, 0x47, 0x65,
0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x12, 0x9a, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x2a, 0x92, 0x41, 0x14, 0x12, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61,
0x6c, 0x6c, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0xca,
0x01, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c,
0x65, 0x64, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x92, 0x41, 0x26, 0x12, 0x24, 0x41, 0x64, 0x64, 0x73,
0x20, 0x61, 0x70, 0x69, 0x20, 0x74, 0x61, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20,
0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x77, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x2d, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x12, 0xd1, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54,
0x61, 0x67, 0x73, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x65, 0x64, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x4c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x92, 0x41, 0x1a,
0x12, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67,
0x6c, 0x65, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b,
0x22, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x3a, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x3a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0x6c, 0x65, 0x64, 0x3a,
0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xda, 0x01, 0x0a, 0x13,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x4c, 0x65, 0x64, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x4c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x1a, 0x12, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2d, 0x6c, 0x65, 0x64, 0x3a, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xad, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x92, 0x41,
0x13, 0x12, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x10, 0x2f, 0x76, 0x31, 0x2f,
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xa1, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x92, 0x41,
0x13, 0x12, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x2a, 0x10, 0x2f, 0x76, 0x31, 0x2f,
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xd0, 0x01, 0x0a,
0x0d, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x12, 0x30,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64,
0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x5a, 0x92, 0x41, 0x26, 0x12, 0x24, 0x41, 0x64, 0x64, 0x73, 0x20, 0x61,
0x70, 0x69, 0x20, 0x74, 0x61, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78,
0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x2b, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x77, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x2d, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12,
0xd1, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67,
0x73, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
0x2e, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x92, 0x41, 0x27, 0x12, 0x25, 0x53,
0x65, 0x74, 0x73, 0x20, 0x61, 0x70, 0x69, 0x20, 0x74, 0x61, 0x67, 0x73, 0x20, 0x66, 0x6f, 0x72,
0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f,
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74,
0x2d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x62,
0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xe1, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d,
0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x62, 0x92, 0x41, 0x2b, 0x12, 0x29, 0x52, 0x65, 0x6d, 0x6f,
0x76, 0x65, 0x73, 0x20, 0x61, 0x70, 0x69, 0x20, 0x74, 0x61, 0x67, 0x73, 0x20, 0x66, 0x72, 0x6f,
0x6d, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x22, 0x23, 0x2f, 0x76, 0x31,
0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65,
0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0x74, 0x61, 0x67, 0x73,
0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x4d, 0x5a, 0x4b, 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, 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,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x92, 0x41, 0x27, 0x12, 0x25, 0x53, 0x65, 0x74,
0x73, 0x20, 0x61, 0x70, 0x69, 0x20, 0x74, 0x61, 0x67, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61,
0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x65,
0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69,
0x74, 0x65, 0x6d, 0x12, 0xe1, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f,
0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e,
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76,
0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x62, 0x92, 0x41, 0x2b, 0x12, 0x29, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
0x73, 0x20, 0x61, 0x70, 0x69, 0x20, 0x74, 0x61, 0x67, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20,
0x61, 0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f,
0x76, 0x65, 0x2d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x01,
0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x4d, 0x5a, 0x4b, 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, 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 (
@@ -1113,69 +1242,75 @@ func file_controller_api_services_v1_worker_service_proto_rawDescGZIP() []byte {
return file_controller_api_services_v1_worker_service_proto_rawDescData
}
var file_controller_api_services_v1_worker_service_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
var file_controller_api_services_v1_worker_service_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
var file_controller_api_services_v1_worker_service_proto_goTypes = []interface{}{
(*GetWorkerRequest)(nil), // 0: controller.api.services.v1.GetWorkerRequest
(*GetWorkerResponse)(nil), // 1: controller.api.services.v1.GetWorkerResponse
(*ListWorkersRequest)(nil), // 2: controller.api.services.v1.ListWorkersRequest
(*ListWorkersResponse)(nil), // 3: controller.api.services.v1.ListWorkersResponse
(*CreateWorkerLedRequest)(nil), // 4: controller.api.services.v1.CreateWorkerLedRequest
(*CreateWorkerLedResponse)(nil), // 5: controller.api.services.v1.CreateWorkerLedResponse
(*UpdateWorkerRequest)(nil), // 6: controller.api.services.v1.UpdateWorkerRequest
(*UpdateWorkerResponse)(nil), // 7: controller.api.services.v1.UpdateWorkerResponse
(*DeleteWorkerRequest)(nil), // 8: controller.api.services.v1.DeleteWorkerRequest
(*DeleteWorkerResponse)(nil), // 9: controller.api.services.v1.DeleteWorkerResponse
(*AddWorkerTagsRequest)(nil), // 10: controller.api.services.v1.AddWorkerTagsRequest
(*AddWorkerTagsResponse)(nil), // 11: controller.api.services.v1.AddWorkerTagsResponse
(*SetWorkerTagsRequest)(nil), // 12: controller.api.services.v1.SetWorkerTagsRequest
(*SetWorkerTagsResponse)(nil), // 13: controller.api.services.v1.SetWorkerTagsResponse
(*RemoveWorkerTagsRequest)(nil), // 14: controller.api.services.v1.RemoveWorkerTagsRequest
(*RemoveWorkerTagsResponse)(nil), // 15: controller.api.services.v1.RemoveWorkerTagsResponse
nil, // 16: controller.api.services.v1.AddWorkerTagsRequest.ApiTagsEntry
nil, // 17: controller.api.services.v1.SetWorkerTagsRequest.ApiTagsEntry
nil, // 18: controller.api.services.v1.RemoveWorkerTagsRequest.ApiTagsEntry
(*workers.Worker)(nil), // 19: controller.api.resources.workers.v1.Worker
(*fieldmaskpb.FieldMask)(nil), // 20: google.protobuf.FieldMask
(*structpb.ListValue)(nil), // 21: google.protobuf.ListValue
(*GetWorkerRequest)(nil), // 0: controller.api.services.v1.GetWorkerRequest
(*GetWorkerResponse)(nil), // 1: controller.api.services.v1.GetWorkerResponse
(*ListWorkersRequest)(nil), // 2: controller.api.services.v1.ListWorkersRequest
(*ListWorkersResponse)(nil), // 3: controller.api.services.v1.ListWorkersResponse
(*CreateWorkerLedRequest)(nil), // 4: controller.api.services.v1.CreateWorkerLedRequest
(*CreateWorkerLedResponse)(nil), // 5: controller.api.services.v1.CreateWorkerLedResponse
(*CreateControllerLedRequest)(nil), // 6: controller.api.services.v1.CreateControllerLedRequest
(*CreateControllerLedResponse)(nil), // 7: controller.api.services.v1.CreateControllerLedResponse
(*UpdateWorkerRequest)(nil), // 8: controller.api.services.v1.UpdateWorkerRequest
(*UpdateWorkerResponse)(nil), // 9: controller.api.services.v1.UpdateWorkerResponse
(*DeleteWorkerRequest)(nil), // 10: controller.api.services.v1.DeleteWorkerRequest
(*DeleteWorkerResponse)(nil), // 11: controller.api.services.v1.DeleteWorkerResponse
(*AddWorkerTagsRequest)(nil), // 12: controller.api.services.v1.AddWorkerTagsRequest
(*AddWorkerTagsResponse)(nil), // 13: controller.api.services.v1.AddWorkerTagsResponse
(*SetWorkerTagsRequest)(nil), // 14: controller.api.services.v1.SetWorkerTagsRequest
(*SetWorkerTagsResponse)(nil), // 15: controller.api.services.v1.SetWorkerTagsResponse
(*RemoveWorkerTagsRequest)(nil), // 16: controller.api.services.v1.RemoveWorkerTagsRequest
(*RemoveWorkerTagsResponse)(nil), // 17: controller.api.services.v1.RemoveWorkerTagsResponse
nil, // 18: controller.api.services.v1.AddWorkerTagsRequest.ApiTagsEntry
nil, // 19: controller.api.services.v1.SetWorkerTagsRequest.ApiTagsEntry
nil, // 20: controller.api.services.v1.RemoveWorkerTagsRequest.ApiTagsEntry
(*workers.Worker)(nil), // 21: controller.api.resources.workers.v1.Worker
(*fieldmaskpb.FieldMask)(nil), // 22: google.protobuf.FieldMask
(*structpb.ListValue)(nil), // 23: google.protobuf.ListValue
}
var file_controller_api_services_v1_worker_service_proto_depIdxs = []int32{
19, // 0: controller.api.services.v1.GetWorkerResponse.item:type_name -> controller.api.resources.workers.v1.Worker
19, // 1: controller.api.services.v1.ListWorkersResponse.items:type_name -> controller.api.resources.workers.v1.Worker
19, // 2: controller.api.services.v1.CreateWorkerLedRequest.item:type_name -> controller.api.resources.workers.v1.Worker
19, // 3: controller.api.services.v1.CreateWorkerLedResponse.item:type_name -> controller.api.resources.workers.v1.Worker
19, // 4: controller.api.services.v1.UpdateWorkerRequest.item:type_name -> controller.api.resources.workers.v1.Worker
20, // 5: controller.api.services.v1.UpdateWorkerRequest.update_mask:type_name -> google.protobuf.FieldMask
19, // 6: controller.api.services.v1.UpdateWorkerResponse.item:type_name -> controller.api.resources.workers.v1.Worker
16, // 7: controller.api.services.v1.AddWorkerTagsRequest.api_tags:type_name -> controller.api.services.v1.AddWorkerTagsRequest.ApiTagsEntry
19, // 8: controller.api.services.v1.AddWorkerTagsResponse.item:type_name -> controller.api.resources.workers.v1.Worker
17, // 9: controller.api.services.v1.SetWorkerTagsRequest.api_tags:type_name -> controller.api.services.v1.SetWorkerTagsRequest.ApiTagsEntry
19, // 10: controller.api.services.v1.SetWorkerTagsResponse.item:type_name -> controller.api.resources.workers.v1.Worker
18, // 11: controller.api.services.v1.RemoveWorkerTagsRequest.api_tags:type_name -> controller.api.services.v1.RemoveWorkerTagsRequest.ApiTagsEntry
19, // 12: controller.api.services.v1.RemoveWorkerTagsResponse.item:type_name -> controller.api.resources.workers.v1.Worker
21, // 13: controller.api.services.v1.AddWorkerTagsRequest.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
21, // 14: controller.api.services.v1.SetWorkerTagsRequest.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
21, // 15: controller.api.services.v1.RemoveWorkerTagsRequest.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
0, // 16: controller.api.services.v1.WorkerService.GetWorker:input_type -> controller.api.services.v1.GetWorkerRequest
2, // 17: controller.api.services.v1.WorkerService.ListWorkers:input_type -> controller.api.services.v1.ListWorkersRequest
4, // 18: controller.api.services.v1.WorkerService.CreateWorkerLed:input_type -> controller.api.services.v1.CreateWorkerLedRequest
6, // 19: controller.api.services.v1.WorkerService.UpdateWorker:input_type -> controller.api.services.v1.UpdateWorkerRequest
8, // 20: controller.api.services.v1.WorkerService.DeleteWorker:input_type -> controller.api.services.v1.DeleteWorkerRequest
10, // 21: controller.api.services.v1.WorkerService.AddWorkerTags:input_type -> controller.api.services.v1.AddWorkerTagsRequest
12, // 22: controller.api.services.v1.WorkerService.SetWorkerTags:input_type -> controller.api.services.v1.SetWorkerTagsRequest
14, // 23: controller.api.services.v1.WorkerService.RemoveWorkerTags:input_type -> controller.api.services.v1.RemoveWorkerTagsRequest
1, // 24: controller.api.services.v1.WorkerService.GetWorker:output_type -> controller.api.services.v1.GetWorkerResponse
3, // 25: controller.api.services.v1.WorkerService.ListWorkers:output_type -> controller.api.services.v1.ListWorkersResponse
5, // 26: controller.api.services.v1.WorkerService.CreateWorkerLed:output_type -> controller.api.services.v1.CreateWorkerLedResponse
7, // 27: controller.api.services.v1.WorkerService.UpdateWorker:output_type -> controller.api.services.v1.UpdateWorkerResponse
9, // 28: controller.api.services.v1.WorkerService.DeleteWorker:output_type -> controller.api.services.v1.DeleteWorkerResponse
11, // 29: controller.api.services.v1.WorkerService.AddWorkerTags:output_type -> controller.api.services.v1.AddWorkerTagsResponse
13, // 30: controller.api.services.v1.WorkerService.SetWorkerTags:output_type -> controller.api.services.v1.SetWorkerTagsResponse
15, // 31: controller.api.services.v1.WorkerService.RemoveWorkerTags:output_type -> controller.api.services.v1.RemoveWorkerTagsResponse
24, // [24:32] is the sub-list for method output_type
16, // [16:24] 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
21, // 0: controller.api.services.v1.GetWorkerResponse.item:type_name -> controller.api.resources.workers.v1.Worker
21, // 1: controller.api.services.v1.ListWorkersResponse.items:type_name -> controller.api.resources.workers.v1.Worker
21, // 2: controller.api.services.v1.CreateWorkerLedRequest.item:type_name -> controller.api.resources.workers.v1.Worker
21, // 3: controller.api.services.v1.CreateWorkerLedResponse.item:type_name -> controller.api.resources.workers.v1.Worker
21, // 4: controller.api.services.v1.CreateControllerLedRequest.item:type_name -> controller.api.resources.workers.v1.Worker
21, // 5: controller.api.services.v1.CreateControllerLedResponse.item:type_name -> controller.api.resources.workers.v1.Worker
21, // 6: controller.api.services.v1.UpdateWorkerRequest.item:type_name -> controller.api.resources.workers.v1.Worker
22, // 7: controller.api.services.v1.UpdateWorkerRequest.update_mask:type_name -> google.protobuf.FieldMask
21, // 8: controller.api.services.v1.UpdateWorkerResponse.item:type_name -> controller.api.resources.workers.v1.Worker
18, // 9: controller.api.services.v1.AddWorkerTagsRequest.api_tags:type_name -> controller.api.services.v1.AddWorkerTagsRequest.ApiTagsEntry
21, // 10: controller.api.services.v1.AddWorkerTagsResponse.item:type_name -> controller.api.resources.workers.v1.Worker
19, // 11: controller.api.services.v1.SetWorkerTagsRequest.api_tags:type_name -> controller.api.services.v1.SetWorkerTagsRequest.ApiTagsEntry
21, // 12: controller.api.services.v1.SetWorkerTagsResponse.item:type_name -> controller.api.resources.workers.v1.Worker
20, // 13: controller.api.services.v1.RemoveWorkerTagsRequest.api_tags:type_name -> controller.api.services.v1.RemoveWorkerTagsRequest.ApiTagsEntry
21, // 14: controller.api.services.v1.RemoveWorkerTagsResponse.item:type_name -> controller.api.resources.workers.v1.Worker
23, // 15: controller.api.services.v1.AddWorkerTagsRequest.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
23, // 16: controller.api.services.v1.SetWorkerTagsRequest.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
23, // 17: controller.api.services.v1.RemoveWorkerTagsRequest.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
0, // 18: controller.api.services.v1.WorkerService.GetWorker:input_type -> controller.api.services.v1.GetWorkerRequest
2, // 19: controller.api.services.v1.WorkerService.ListWorkers:input_type -> controller.api.services.v1.ListWorkersRequest
4, // 20: controller.api.services.v1.WorkerService.CreateWorkerLed:input_type -> controller.api.services.v1.CreateWorkerLedRequest
6, // 21: controller.api.services.v1.WorkerService.CreateControllerLed:input_type -> controller.api.services.v1.CreateControllerLedRequest
8, // 22: controller.api.services.v1.WorkerService.UpdateWorker:input_type -> controller.api.services.v1.UpdateWorkerRequest
10, // 23: controller.api.services.v1.WorkerService.DeleteWorker:input_type -> controller.api.services.v1.DeleteWorkerRequest
12, // 24: controller.api.services.v1.WorkerService.AddWorkerTags:input_type -> controller.api.services.v1.AddWorkerTagsRequest
14, // 25: controller.api.services.v1.WorkerService.SetWorkerTags:input_type -> controller.api.services.v1.SetWorkerTagsRequest
16, // 26: controller.api.services.v1.WorkerService.RemoveWorkerTags:input_type -> controller.api.services.v1.RemoveWorkerTagsRequest
1, // 27: controller.api.services.v1.WorkerService.GetWorker:output_type -> controller.api.services.v1.GetWorkerResponse
3, // 28: controller.api.services.v1.WorkerService.ListWorkers:output_type -> controller.api.services.v1.ListWorkersResponse
5, // 29: controller.api.services.v1.WorkerService.CreateWorkerLed:output_type -> controller.api.services.v1.CreateWorkerLedResponse
7, // 30: controller.api.services.v1.WorkerService.CreateControllerLed:output_type -> controller.api.services.v1.CreateControllerLedResponse
9, // 31: controller.api.services.v1.WorkerService.UpdateWorker:output_type -> controller.api.services.v1.UpdateWorkerResponse
11, // 32: controller.api.services.v1.WorkerService.DeleteWorker:output_type -> controller.api.services.v1.DeleteWorkerResponse
13, // 33: controller.api.services.v1.WorkerService.AddWorkerTags:output_type -> controller.api.services.v1.AddWorkerTagsResponse
15, // 34: controller.api.services.v1.WorkerService.SetWorkerTags:output_type -> controller.api.services.v1.SetWorkerTagsResponse
17, // 35: controller.api.services.v1.WorkerService.RemoveWorkerTags:output_type -> controller.api.services.v1.RemoveWorkerTagsResponse
27, // [27:36] is the sub-list for method output_type
18, // [18:27] is the sub-list for method input_type
18, // [18:18] is the sub-list for extension type_name
18, // [18:18] is the sub-list for extension extendee
0, // [0:18] is the sub-list for field type_name
}
func init() { file_controller_api_services_v1_worker_service_proto_init() }
@@ -1257,7 +1392,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UpdateWorkerRequest); i {
switch v := v.(*CreateControllerLedRequest); i {
case 0:
return &v.state
case 1:
@@ -1269,7 +1404,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UpdateWorkerResponse); i {
switch v := v.(*CreateControllerLedResponse); i {
case 0:
return &v.state
case 1:
@@ -1281,7 +1416,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteWorkerRequest); i {
switch v := v.(*UpdateWorkerRequest); i {
case 0:
return &v.state
case 1:
@@ -1293,7 +1428,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteWorkerResponse); i {
switch v := v.(*UpdateWorkerResponse); i {
case 0:
return &v.state
case 1:
@@ -1305,7 +1440,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddWorkerTagsRequest); i {
switch v := v.(*DeleteWorkerRequest); i {
case 0:
return &v.state
case 1:
@@ -1317,7 +1452,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddWorkerTagsResponse); i {
switch v := v.(*DeleteWorkerResponse); i {
case 0:
return &v.state
case 1:
@@ -1329,7 +1464,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SetWorkerTagsRequest); i {
switch v := v.(*AddWorkerTagsRequest); i {
case 0:
return &v.state
case 1:
@@ -1341,7 +1476,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SetWorkerTagsResponse); i {
switch v := v.(*AddWorkerTagsResponse); i {
case 0:
return &v.state
case 1:
@@ -1353,7 +1488,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveWorkerTagsRequest); i {
switch v := v.(*SetWorkerTagsRequest); i {
case 0:
return &v.state
case 1:
@@ -1365,6 +1500,30 @@ func file_controller_api_services_v1_worker_service_proto_init() {
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SetWorkerTagsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveWorkerTagsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_worker_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveWorkerTagsResponse); i {
case 0:
return &v.state
@@ -1383,7 +1542,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_api_services_v1_worker_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 19,
NumMessages: 21,
NumExtensions: 0,
NumServices: 1,
},
@@ -153,6 +153,40 @@ func local_request_WorkerService_CreateWorkerLed_0(ctx context.Context, marshale
}
func request_WorkerService_CreateControllerLed_0(ctx context.Context, marshaler runtime.Marshaler, client WorkerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CreateControllerLedRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.CreateControllerLed(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WorkerService_CreateControllerLed_0(ctx context.Context, marshaler runtime.Marshaler, server WorkerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CreateControllerLedRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.CreateControllerLed(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_WorkerService_UpdateWorker_0 = &utilities.DoubleArray{Encoding: map[string]int{"item": 0, "id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
@@ -590,6 +624,31 @@ func RegisterWorkerServiceHandlerServer(ctx context.Context, mux *runtime.ServeM
})
mux.Handle("POST", pattern_WorkerService_CreateControllerLed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/CreateControllerLed", runtime.WithHTTPPathPattern("/v1/workers:create:controller-led"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WorkerService_CreateControllerLed_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_WorkerService_CreateControllerLed_0(annotatedContext, mux, outboundMarshaler, w, req, response_WorkerService_CreateControllerLed_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_WorkerService_UpdateWorker_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -822,6 +881,28 @@ func RegisterWorkerServiceHandlerClient(ctx context.Context, mux *runtime.ServeM
})
mux.Handle("POST", pattern_WorkerService_CreateControllerLed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/CreateControllerLed", runtime.WithHTTPPathPattern("/v1/workers:create:controller-led"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WorkerService_CreateControllerLed_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_WorkerService_CreateControllerLed_0(annotatedContext, mux, outboundMarshaler, w, req, response_WorkerService_CreateControllerLed_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_WorkerService_UpdateWorker_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -953,6 +1034,15 @@ func (m response_WorkerService_CreateWorkerLed_0) XXX_ResponseBody() interface{}
return response.Item
}
type response_WorkerService_CreateControllerLed_0 struct {
proto.Message
}
func (m response_WorkerService_CreateControllerLed_0) XXX_ResponseBody() interface{} {
response := m.Message.(*CreateControllerLedResponse)
return response.Item
}
type response_WorkerService_UpdateWorker_0 struct {
proto.Message
}
@@ -996,6 +1086,8 @@ var (
pattern_WorkerService_CreateWorkerLed_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "workers:create"}, "worker-led"))
pattern_WorkerService_CreateControllerLed_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "workers:create"}, "controller-led"))
pattern_WorkerService_UpdateWorker_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "workers", "id"}, ""))
pattern_WorkerService_DeleteWorker_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "workers", "id"}, ""))
@@ -1014,6 +1106,8 @@ var (
forward_WorkerService_CreateWorkerLed_0 = runtime.ForwardResponseMessage
forward_WorkerService_CreateControllerLed_0 = runtime.ForwardResponseMessage
forward_WorkerService_UpdateWorker_0 = runtime.ForwardResponseMessage
forward_WorkerService_DeleteWorker_0 = runtime.ForwardResponseMessage
@@ -28,12 +28,20 @@ type WorkerServiceClient interface {
// If the scope ID is missing, malformed, or reference a non existing scope,
// an error is returned.
ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error)
// CreateWorkerLed creates and stores a Worker in boundary. The provided
// request must include the Scope id in which the Worker will be created.
// If the Scope id is missing, malformed or references a non existing
// resource, an error is returned. If a name is provided that is in
// use in another Worker in the same scope, an error is returned.
// CreateWorkerLed creates and stores a Worker in Boundary. The provided
// request must include the Scope ID in which the Worker will be created. If
// the Scope ID is missing, malformed or references a non existing resource,
// an error is returned. If a name is provided that is in use in another
// Worker in the same scope, an error is returned.
CreateWorkerLed(ctx context.Context, in *CreateWorkerLedRequest, opts ...grpc.CallOption) (*CreateWorkerLedResponse, error)
// CreateControllerLed creates and stores a Worker in Boundary and returns an
// activation token that can be used by a worker binary to claim the created
// Worker's identity. The provided request must include the Scope ID in which
// the Worker will be created. If the Scope ID is missing, malformed or
// references a non existing resource, an error is returned. If a name is
// provided that is in use in another Worker in the same scope, an error is
// returned.
CreateControllerLed(ctx context.Context, in *CreateControllerLedRequest, opts ...grpc.CallOption) (*CreateControllerLedResponse, error)
// UpdateWorker updates an existing Worker in boundary. The provided
// Worker must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
@@ -93,6 +101,15 @@ func (c *workerServiceClient) CreateWorkerLed(ctx context.Context, in *CreateWor
return out, nil
}
func (c *workerServiceClient) CreateControllerLed(ctx context.Context, in *CreateControllerLedRequest, opts ...grpc.CallOption) (*CreateControllerLedResponse, error) {
out := new(CreateControllerLedResponse)
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/CreateControllerLed", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *workerServiceClient) UpdateWorker(ctx context.Context, in *UpdateWorkerRequest, opts ...grpc.CallOption) (*UpdateWorkerResponse, error) {
out := new(UpdateWorkerResponse)
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/UpdateWorker", in, out, opts...)
@@ -152,12 +169,20 @@ type WorkerServiceServer interface {
// If the scope ID is missing, malformed, or reference a non existing scope,
// an error is returned.
ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error)
// CreateWorkerLed creates and stores a Worker in boundary. The provided
// request must include the Scope id in which the Worker will be created.
// If the Scope id is missing, malformed or references a non existing
// resource, an error is returned. If a name is provided that is in
// use in another Worker in the same scope, an error is returned.
// CreateWorkerLed creates and stores a Worker in Boundary. The provided
// request must include the Scope ID in which the Worker will be created. If
// the Scope ID is missing, malformed or references a non existing resource,
// an error is returned. If a name is provided that is in use in another
// Worker in the same scope, an error is returned.
CreateWorkerLed(context.Context, *CreateWorkerLedRequest) (*CreateWorkerLedResponse, error)
// CreateControllerLed creates and stores a Worker in Boundary and returns an
// activation token that can be used by a worker binary to claim the created
// Worker's identity. The provided request must include the Scope ID in which
// the Worker will be created. If the Scope ID is missing, malformed or
// references a non existing resource, an error is returned. If a name is
// provided that is in use in another Worker in the same scope, an error is
// returned.
CreateControllerLed(context.Context, *CreateControllerLedRequest) (*CreateControllerLedResponse, error)
// UpdateWorker updates an existing Worker in boundary. The provided
// Worker must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
@@ -196,6 +221,9 @@ func (UnimplementedWorkerServiceServer) ListWorkers(context.Context, *ListWorker
func (UnimplementedWorkerServiceServer) CreateWorkerLed(context.Context, *CreateWorkerLedRequest) (*CreateWorkerLedResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateWorkerLed not implemented")
}
func (UnimplementedWorkerServiceServer) CreateControllerLed(context.Context, *CreateControllerLedRequest) (*CreateControllerLedResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateControllerLed not implemented")
}
func (UnimplementedWorkerServiceServer) UpdateWorker(context.Context, *UpdateWorkerRequest) (*UpdateWorkerResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorker not implemented")
}
@@ -278,6 +306,24 @@ func _WorkerService_CreateWorkerLed_Handler(srv interface{}, ctx context.Context
return interceptor(ctx, in, info, handler)
}
func _WorkerService_CreateControllerLed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateControllerLedRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WorkerServiceServer).CreateControllerLed(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/controller.api.services.v1.WorkerService/CreateControllerLed",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WorkerServiceServer).CreateControllerLed(ctx, req.(*CreateControllerLedRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WorkerService_UpdateWorker_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateWorkerRequest)
if err := dec(in); err != nil {
@@ -387,6 +433,10 @@ var WorkerService_ServiceDesc = grpc.ServiceDesc{
MethodName: "CreateWorkerLed",
Handler: _WorkerService_CreateWorkerLed_Handler,
},
{
MethodName: "CreateControllerLed",
Handler: _WorkerService_CreateControllerLed_Handler,
},
{
MethodName: "UpdateWorker",
Handler: _WorkerService_UpdateWorker_Handler,
+1 -1
View File
@@ -427,7 +427,7 @@ func Test_AnonRestrictions(t *testing.T) {
if i == resource.Controller || i == resource.Worker {
continue
}
for j := action.Type(1); j <= action.RemoveHostSources; j++ {
for j := action.Type(1); j <= action.CreateControllerLed; j++ {
res := Resource{
ScopeId: scope.Global.String(),
Id: "foobar",
@@ -72,6 +72,10 @@ message Worker {
// https://github.com/hashicorp/nodeenrollment
google.protobuf.StringValue worker_generated_auth_token = 150 [json_name = "worker_generated_auth_token"]; // @gotags: `class:"public"`
// Output only. An activation token that can be given to a worker to correlate
// it to the created resource.
google.protobuf.StringValue controller_generated_activation_token = 151 [json_name = "controller_generated_activation_token"]; // @gotags: `class:"secret"`
// Output only. The number of connections that this worker is currently handling.
google.protobuf.UInt32Value active_connection_count = 160 [json_name = "active_connection_count"]; // @gotags: `class:"public"`
@@ -38,11 +38,11 @@ service WorkerService {
};
}
// CreateWorkerLed creates and stores a Worker in boundary. The provided
// request must include the Scope id in which the Worker will be created.
// If the Scope id is missing, malformed or references a non existing
// resource, an error is returned. If a name is provided that is in
// use in another Worker in the same scope, an error is returned.
// CreateWorkerLed creates and stores a Worker in Boundary. The provided
// request must include the Scope ID in which the Worker will be created. If
// the Scope ID is missing, malformed or references a non existing resource,
// an error is returned. If a name is provided that is in use in another
// Worker in the same scope, an error is returned.
rpc CreateWorkerLed(CreateWorkerLedRequest) returns (CreateWorkerLedResponse) {
option (google.api.http) = {
post: "/v1/workers:create:worker-led"
@@ -54,6 +54,24 @@ service WorkerService {
};
}
// CreateControllerLed creates and stores a Worker in Boundary and returns an
// activation token that can be used by a worker binary to claim the created
// Worker's identity. The provided request must include the Scope ID in which
// the Worker will be created. If the Scope ID is missing, malformed or
// references a non existing resource, an error is returned. If a name is
// provided that is in use in another Worker in the same scope, an error is
// returned.
rpc CreateControllerLed(CreateControllerLedRequest) returns (CreateControllerLedResponse) {
option (google.api.http) = {
post: "/v1/workers:create:controller-led"
body: "item"
response_body: "item"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Creates a single Worker."
};
}
// UpdateWorker updates an existing Worker in boundary. The provided
// Worker must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
@@ -152,6 +170,15 @@ message CreateWorkerLedResponse {
resources.workers.v1.Worker item = 2;
}
message CreateControllerLedRequest {
resources.workers.v1.Worker item = 1;
}
message CreateControllerLedResponse {
string uri = 1; // @gotags: `class:"public"`
resources.workers.v1.Worker item = 2;
}
message UpdateWorkerRequest {
string id = 1; // @gotags: `class:"public"`
resources.workers.v1.Worker item = 2;
@@ -51,3 +51,29 @@ message WorkerCertBundle {
// @inject_tag: `gorm:"not_null"`
bytes cert_bundle = 30;
}
// WorkerAuthServerLedActivationToken contains all fields related to a
// WorkerAuthServerLedActivationToken resource
message WorkerAuthServerLedActivationToken {
// The worker_id of the worker that this activates
// @inject_tag: `gorm:"primary_key"`
string worker_id = 10;
// The token identifier, which is used for lookup
// @inject_tag: `gorm:"not_null"`
string token_id = 15;
// The creation time, encrypted to prevent tampering, as the time plus
// existence of the record allows authorization
// @inject_tag: `gorm:"not_null" wrapping:"ct,creation_time_data"`
bytes creation_time_encrypted = 20;
// The plaintext bytes of the creation time, which are never stored. This is a
// marshaled timestamppb.Timestamp.
// @inject_tag: `gorm:"-" wrapping:"pt,creation_time_data"`
bytes creation_time = 21;
// The key ID of the encrypting key
// @inject_tag: `gorm:"not_null"`
string key_id = 40;
}
+30 -22
View File
@@ -8,7 +8,7 @@ import (
)
// getOpts - iterate the inbound Options and return a struct
func getOpts(opt ...Option) options {
func GetOpts(opt ...Option) options {
opts := getDefaultOptions()
for _, o := range opt {
o(&opts)
@@ -21,26 +21,27 @@ type Option func(*options)
// options = how options are represented
type options struct {
withName string
withPublicId string
withDescription string
withAddress string
withLimit int
withLiveness time.Duration
withUpdateTags bool
withWorkerTags []*Tag
withWorkerKeyIdentifier string
withWorkerKeys WorkerKeys
withControllerEncryptionPrivateKey []byte
withKeyId string
withNonce []byte
withNewIdFunc func(context.Context) (string, error)
withFetchNodeCredentialsRequest *types.FetchNodeCredentialsRequest
withTestPkiWorkerAuthorized bool
withTestPkiWorkerKeyId *string
withWorkerType WorkerType
withRoot string
withStopAfter uint
withName string
withPublicId string
withDescription string
withAddress string
withLimit int
withLiveness time.Duration
withUpdateTags bool
withWorkerTags []*Tag
withWorkerKeyIdentifier string
withWorkerKeys WorkerKeys
withControllerEncryptionPrivateKey []byte
withKeyId string
withNonce []byte
withNewIdFunc func(context.Context) (string, error)
WithFetchNodeCredentialsRequest *types.FetchNodeCredentialsRequest
withTestPkiWorkerAuthorized bool
withTestPkiWorkerKeyId *string
withWorkerType WorkerType
withRoot string
withStopAfter uint
WithCreateControllerLedActivationToken bool
}
func getDefaultOptions() options {
@@ -153,7 +154,7 @@ func WithNewIdFunc(fn func(context.Context) (string, error)) Option {
// FetchNodeCredentialsRequest to be specified.
func WithFetchNodeCredentialsRequest(req *types.FetchNodeCredentialsRequest) Option {
return func(o *options) {
o.withFetchNodeCredentialsRequest = req
o.WithFetchNodeCredentialsRequest = req
}
}
@@ -188,3 +189,10 @@ func WithStopAfter(stopAfter uint) Option {
o.withStopAfter = stopAfter
}
}
// WithCreateControllerLedActivationToken provides an optional stop after count
func WithCreateControllerLedActivationToken(with bool) Option {
return func(o *options) {
o.WithCreateControllerLedActivationToken = with
}
}
+23 -17
View File
@@ -14,7 +14,7 @@ import (
func Test_GetOpts(t *testing.T) {
t.Parallel()
t.Run("WithName", func(t *testing.T) {
opts := getOpts(WithName("test"))
opts := GetOpts(WithName("test"))
testOpts := getDefaultOptions()
testOpts.withName = "test"
opts.withNewIdFunc = nil
@@ -22,7 +22,7 @@ func Test_GetOpts(t *testing.T) {
assert.Equal(t, opts, testOpts)
})
t.Run("WithPublicId", func(t *testing.T) {
opts := getOpts(WithPublicId("test"))
opts := GetOpts(WithPublicId("test"))
testOpts := getDefaultOptions()
testOpts.withPublicId = "test"
opts.withNewIdFunc = nil
@@ -30,7 +30,7 @@ func Test_GetOpts(t *testing.T) {
assert.Equal(t, opts, testOpts)
})
t.Run("WithDescription", func(t *testing.T) {
opts := getOpts(WithDescription("test desc"))
opts := GetOpts(WithDescription("test desc"))
testOpts := getDefaultOptions()
testOpts.withDescription = "test desc"
opts.withNewIdFunc = nil
@@ -38,7 +38,7 @@ func Test_GetOpts(t *testing.T) {
assert.Equal(t, opts, testOpts)
})
t.Run("WithLimit", func(t *testing.T) {
opts := getOpts(WithLimit(5))
opts := GetOpts(WithLimit(5))
testOpts := getDefaultOptions()
testOpts.withLimit = 5
opts.withNewIdFunc = nil
@@ -46,7 +46,7 @@ func Test_GetOpts(t *testing.T) {
assert.Equal(t, opts, testOpts)
})
t.Run("WithAddress", func(t *testing.T) {
opts := getOpts(WithAddress("test"))
opts := GetOpts(WithAddress("test"))
testOpts := getDefaultOptions()
testOpts.withAddress = "test"
opts.withNewIdFunc = nil
@@ -54,7 +54,7 @@ func Test_GetOpts(t *testing.T) {
assert.Equal(t, opts, testOpts)
})
t.Run("WithLiveness", func(t *testing.T) {
opts := getOpts(WithLiveness(time.Hour))
opts := GetOpts(WithLiveness(time.Hour))
testOpts := getDefaultOptions()
testOpts.withLiveness = time.Hour
opts.withNewIdFunc = nil
@@ -62,7 +62,7 @@ func Test_GetOpts(t *testing.T) {
assert.Equal(t, opts, testOpts)
})
t.Run("WithUpdateTags", func(t *testing.T) {
opts := getOpts(WithUpdateTags(true))
opts := GetOpts(WithUpdateTags(true))
testOpts := getDefaultOptions()
testOpts.withUpdateTags = true
opts.withNewIdFunc = nil
@@ -74,7 +74,7 @@ func Test_GetOpts(t *testing.T) {
{Key: "key1", Value: "val1"},
{Key: "key2", Value: "val2"},
}
opts := getOpts(WithWorkerTags(tags...))
opts := GetOpts(WithWorkerTags(tags...))
testOpts := getDefaultOptions()
testOpts.withWorkerTags = tags
opts.withNewIdFunc = nil
@@ -90,7 +90,7 @@ func Test_GetOpts(t *testing.T) {
workerSigningPubKey: populateBytes(20),
}
opts := getOpts(WithWorkerKeys(keys))
opts := GetOpts(WithWorkerKeys(keys))
testOpts = getDefaultOptions()
testOpts.withWorkerKeys = keys
opts.withNewIdFunc = nil
@@ -103,7 +103,7 @@ func Test_GetOpts(t *testing.T) {
key := populateBytes(20)
opts := getOpts(WithControllerEncryptionPrivateKey(key))
opts := GetOpts(WithControllerEncryptionPrivateKey(key))
testOpts = getDefaultOptions()
testOpts.withControllerEncryptionPrivateKey = key
opts.withNewIdFunc = nil
@@ -114,7 +114,7 @@ func Test_GetOpts(t *testing.T) {
assert := assert.New(t)
testOpts := getDefaultOptions()
opts := getOpts(WithKeyId("hi i'm another key id"))
opts := GetOpts(WithKeyId("hi i'm another key id"))
testOpts = getDefaultOptions()
testOpts.withKeyId = "hi i'm another key id"
opts.withNewIdFunc = nil
@@ -127,7 +127,7 @@ func Test_GetOpts(t *testing.T) {
nonce := populateBytes(20)
opts := getOpts(WithNonce(nonce))
opts := GetOpts(WithNonce(nonce))
testOpts = getDefaultOptions()
testOpts.withNonce = nonce
opts.withNewIdFunc = nil
@@ -137,7 +137,7 @@ func Test_GetOpts(t *testing.T) {
t.Run("WithNewIdFunc", func(t *testing.T) {
assert := assert.New(t)
testFn := func(context.Context) (string, error) { return "", nil }
opts := getOpts(WithNewIdFunc(testFn))
opts := GetOpts(WithNewIdFunc(testFn))
testOpts := getDefaultOptions()
testOpts.withNewIdFunc = testFn
assert.Equal(
@@ -150,7 +150,7 @@ func Test_GetOpts(t *testing.T) {
testOpts := getDefaultOptions()
var keyId string
opts := getOpts(WithTestPkiWorkerAuthorizedKeyId(&keyId))
opts := GetOpts(WithTestPkiWorkerAuthorizedKeyId(&keyId))
testOpts = getDefaultOptions()
testOpts.withTestPkiWorkerAuthorized = true
testOpts.withTestPkiWorkerKeyId = &keyId
@@ -161,19 +161,25 @@ func Test_GetOpts(t *testing.T) {
t.Run("WithWorkerType", func(t *testing.T) {
opts := getDefaultOptions()
assert.Empty(t, opts.withWorkerType)
opts = getOpts(WithWorkerType(KmsWorkerType))
opts = GetOpts(WithWorkerType(KmsWorkerType))
assert.Equal(t, KmsWorkerType, opts.withWorkerType)
})
t.Run("WithRoot", func(t *testing.T) {
opts := getDefaultOptions()
assert.Empty(t, opts.withRoot)
opts = getOpts(WithRoot("a"))
opts = GetOpts(WithRoot("a"))
assert.Equal(t, "a", opts.withRoot)
})
t.Run("WithStopAfter", func(t *testing.T) {
opts := getDefaultOptions()
assert.Empty(t, opts.withStopAfter)
opts = getOpts(WithStopAfter(10))
opts = GetOpts(WithStopAfter(10))
assert.Equal(t, uint(10), opts.withStopAfter)
})
t.Run("WithCreateControllerLedActivationToken", func(t *testing.T) {
opts := getDefaultOptions()
assert.False(t, opts.WithCreateControllerLedActivationToken)
opts = GetOpts(WithCreateControllerLedActivationToken(true))
assert.True(t, opts.WithCreateControllerLedActivationToken)
})
}
+1 -1
View File
@@ -44,7 +44,7 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...Option) (*Repo
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "nil kms")
}
opts := getOpts(opt...)
opts := GetOpts(opt...)
if opts.withLimit == 0 {
// zero signals the boundary defaults should be used.
opts.withLimit = db.DefaultLimit
+1 -1
View File
@@ -17,7 +17,7 @@ func (r *Repository) ListControllers(ctx context.Context, opt ...Option) ([]*sto
// WithLimit option or the repo defaultLimit. It accepts a reader, allowing it
// to be used within a transaction or without.
func (r *Repository) listControllersWithReader(ctx context.Context, reader db.Reader, opt ...Option) ([]*store.Controller, error) {
opts := getOpts(opt...)
opts := GetOpts(opt...)
liveness := opts.withLiveness
if liveness == 0 {
liveness = DefaultLiveness
+51 -19
View File
@@ -11,10 +11,12 @@ import (
"github.com/hashicorp/boundary/internal/server/store"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/go-dbw"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/registration"
"github.com/hashicorp/nodeenrollment/types"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
)
// DeleteWorker will delete a worker from the repository.
@@ -170,7 +172,7 @@ func (r *Repository) ListWorkers(ctx context.Context, scopeIds []string, opt ...
return nil, errors.New(ctx, errors.InvalidParameter, op, "no scope ids set")
}
opts := getOpts(opt...)
opts := GetOpts(opt...)
liveness := opts.withLiveness
if liveness == 0 {
liveness = DefaultLiveness
@@ -233,7 +235,7 @@ func (r *Repository) ListWorkers(ctx context.Context, scopeIds []string, opt ...
func (r *Repository) UpsertWorkerStatus(ctx context.Context, worker *Worker, opt ...Option) (*Worker, error) {
const op = "server.UpsertWorkerStatus"
opts := getOpts(opt...)
opts := GetOpts(opt...)
switch {
case worker == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "worker is nil")
@@ -492,10 +494,15 @@ func (r *Repository) UpdateWorker(ctx context.Context, worker *Worker, version u
// ReportedStatus and Tags are intentionally ignored when creating a worker (not
// included). Currently, a worker can only be created in the global scope
//
// Options supported: WithFetchNodeCredentialsRequest and WithNewIdFunc (this
// option is likely only useful for tests)
// Options supported: WithNewIdFunc (this option is likely only useful for
// tests), WithFetchNodeCredentialsRequest,
// WithCreateControllerLedActivationToken. The latter two are mutually
// exclusive.
func (r *Repository) CreateWorker(ctx context.Context, worker *Worker, opt ...Option) (*Worker, error) {
const op = "server.CreateWorker"
opts := GetOpts(opt...)
switch {
case worker == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing worker")
@@ -509,9 +516,10 @@ func (r *Repository) CreateWorker(ctx context.Context, worker *Worker, opt ...Op
return nil, errors.New(ctx, errors.InvalidParameter, op, "address is not empty")
case worker.LastStatusTime != nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "last status time is not nil")
case opts.WithFetchNodeCredentialsRequest != nil && opts.WithCreateControllerLedActivationToken:
return nil, errors.New(ctx, errors.InvalidParameter, op, "fetch node credentials request and controller led activation token option cannot both be set")
}
opts := getOpts(opt...)
var err error
if worker.PublicId, err = opts.withNewIdFunc(ctx); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to generate worker id"))
@@ -523,14 +531,11 @@ func (r *Repository) CreateWorker(ctx context.Context, worker *Worker, opt ...Op
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error generating state struct", err))
}
var databaseWrapper wrapping.Wrapper
var workerAuthRepo *WorkerAuthRepositoryStorage
if opts.withFetchNodeCredentialsRequest != nil {
// used to encrypt the privKey within the NodeInformation
databaseWrapper, err = r.kms.GetWrapper(ctx, scope.Global.String(), kms.KeyPurposeDatabase)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
databaseWrapper, err := r.kms.GetWrapper(context.Background(), worker.ScopeId, kms.KeyPurposeDatabase)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get database wrapper"))
}
var returnedWorker *Worker
@@ -547,12 +552,14 @@ func (r *Repository) CreateWorker(ctx context.Context, worker *Worker, opt ...Op
); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create worker"))
}
if opts.withFetchNodeCredentialsRequest != nil {
switch {
case opts.WithFetchNodeCredentialsRequest != nil:
workerAuthRepo, err = NewRepositoryStorage(ctx, read, w, r.kms)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create worker auth repository"))
}
nodeInfo, err := registration.AuthorizeNode(ctx, workerAuthRepo, opts.withFetchNodeCredentialsRequest, nodeenrollment.WithSkipStorage(true))
nodeInfo, err := registration.AuthorizeNode(ctx, workerAuthRepo, opts.WithFetchNodeCredentialsRequest, nodeenrollment.WithSkipStorage(true))
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to authorize node"))
}
@@ -560,7 +567,35 @@ func (r *Repository) CreateWorker(ctx context.Context, worker *Worker, opt ...Op
if err := StoreNodeInformationTx(ctx, w, databaseWrapper, nodeInfo); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to store node information"))
}
case opts.WithCreateControllerLedActivationToken:
tokenId, activationToken, err := registration.CreateServerLedActivationToken(ctx, nil, &types.ServerLedRegistrationRequest{},
nodeenrollment.WithSkipStorage(true),
nodeenrollment.WithState(state))
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create controller-led activation token"))
}
creationTime := timestamppb.Now()
creationTimeBytes, err := proto.Marshal(creationTime)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to marshal timestamp for activation token"))
}
activationTokenEntry, err := newWorkerAuthServerLedActivationToken(ctx, worker.PublicId, tokenId, creationTimeBytes)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in-memory activation token"))
}
if err := activationTokenEntry.encrypt(ctx, databaseWrapper); err != nil {
return errors.Wrap(ctx, err, op)
}
if err := w.Create(
ctx,
activationTokenEntry,
); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create worker activation token in storage"))
}
returnedWorker.ControllerGeneratedActivationToken = activationToken
}
return nil
},
); err != nil {
@@ -590,10 +625,7 @@ func (r *Repository) AddWorkerTags(ctx context.Context, workerId string, workerV
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("no worker found with public id %s", workerId))
}
newTags := worker.apiTags
for _, t := range tags {
newTags = append(newTags, t)
}
newTags := append(worker.apiTags, tags...)
_, err = r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(reader db.Reader, w db.Writer) error {
worker := worker.clone()
worker.PublicId = workerId
+57 -32
View File
@@ -2,6 +2,7 @@ package server_test
import (
"context"
"crypto/rand"
"fmt"
"strings"
"testing"
@@ -143,6 +144,7 @@ func TestLookupWorkerIdByKeyId(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
repo, err := server.NewRepository(rw, rw, kmsCache)
require.NoError(t, err)
ctx := context.Background()
@@ -252,6 +254,7 @@ func TestUpsertWorkerStatus(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
repo, err := server.NewRepository(rw, rw, kmsCache)
require.NoError(t, err)
@@ -496,9 +499,11 @@ func TestListWorkers(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
const testLimit = 10
repo, err := server.NewRepository(rw, rw, kms, server.WithLimit(testLimit))
repo, err := server.NewRepository(rw, rw, kmsCache, server.WithLimit(testLimit))
require.NoError(t, err)
ctx := context.Background()
@@ -696,7 +701,6 @@ func TestRepository_CreateWorker(t *testing.T) {
name string
setup func() *server.Worker
repo *server.Repository
fetchReq *types.FetchNodeCredentialsRequest
reader db.Reader
opt []server.Option
wantErr bool
@@ -812,19 +816,21 @@ func TestRepository_CreateWorker(t *testing.T) {
return w
},
reader: rw,
fetchReq: func() *types.FetchNodeCredentialsRequest {
// This happens on the worker
fileStorage, err := file.New(testCtx)
require.NoError(t, err)
defer fileStorage.Cleanup()
opt: []server.Option{server.WithFetchNodeCredentialsRequest(
func() *types.FetchNodeCredentialsRequest {
// This happens on the worker
fileStorage, err := file.New(testCtx)
require.NoError(t, err)
defer fileStorage.Cleanup()
nodeCreds, err := types.NewNodeCredentials(testCtx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(testCtx)
require.NoError(t, err)
return fetchReq
}(),
nodeCreds, err := types.NewNodeCredentials(testCtx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(testCtx)
require.NoError(t, err)
return fetchReq
}(),
)},
repo: func() *server.Repository {
mockConn, mock := db.TestSetupWithMock(t)
mock.ExpectQuery(`SELECT`).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
@@ -844,7 +850,7 @@ func TestRepository_CreateWorker(t *testing.T) {
return w
},
reader: rw,
fetchReq: &types.FetchNodeCredentialsRequest{},
opt: []server.Option{server.WithFetchNodeCredentialsRequest(&types.FetchNodeCredentialsRequest{})},
repo: testRepo,
wantErr: true,
wantErrContains: "unable to authorize node",
@@ -862,7 +868,7 @@ func TestRepository_CreateWorker(t *testing.T) {
wantErrIs: errors.NotUnique,
},
{
name: "success",
name: "success-no-options",
setup: func() *server.Worker {
w := server.NewWorker(scope.Global.String())
w.Name = "success"
@@ -892,29 +898,40 @@ func TestRepository_CreateWorker(t *testing.T) {
return w
},
reader: rw,
fetchReq: func() *types.FetchNodeCredentialsRequest {
// This happens on the worker
fileStorage, err := file.New(testCtx)
require.NoError(t, err)
defer fileStorage.Cleanup()
opt: []server.Option{server.WithFetchNodeCredentialsRequest(
func() *types.FetchNodeCredentialsRequest {
// This happens on the worker
fileStorage, err := file.New(testCtx)
require.NoError(t, err)
defer fileStorage.Cleanup()
nodeCreds, err := types.NewNodeCredentials(testCtx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(testCtx)
require.NoError(t, err)
return fetchReq
}(),
nodeCreds, err := types.NewNodeCredentials(testCtx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(testCtx)
require.NoError(t, err)
return fetchReq
}(),
)},
repo: testRepo,
},
{
name: "success-with-controller-activation-token",
setup: func() *server.Worker {
w := server.NewWorker(scope.Global.String())
w.Name = "success-with-controller-activation-token"
return w
},
reader: rw,
opt: []server.Option{server.WithCreateControllerLedActivationToken(true)},
repo: testRepo,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
testWorker := tc.setup()
tc.opt = append(tc.opt, server.WithFetchNodeCredentialsRequest(tc.fetchReq))
got, err := tc.repo.CreateWorker(testCtx, testWorker, tc.opt...)
if tc.wantErr {
require.Error(err)
@@ -942,12 +959,19 @@ func TestRepository_CreateWorker(t *testing.T) {
require.NoError(err)
assert.Empty(cmp.Diff(got, found, protocmp.Transform()))
if tc.fetchReq != nil {
opts := server.GetOpts(tc.opt...)
if opts.WithFetchNodeCredentialsRequest != nil {
worker := &server.WorkerAuth{
WorkerAuth: &store.WorkerAuth{},
}
require.NoError(tc.reader.LookupWhere(testCtx, worker, "worker_id = ?", []any{found.PublicId}))
}
if opts.WithCreateControllerLedActivationToken {
activationToken := &server.WorkerAuthServerLedActivationToken{
WorkerAuthServerLedActivationToken: &store.WorkerAuthServerLedActivationToken{},
}
require.NoError(tc.reader.LookupWhere(testCtx, activationToken, "worker_id = ?", []any{found.PublicId}))
}
})
}
}
@@ -959,6 +983,7 @@ func TestRepository_UpdateWorker(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
repo, err := server.NewRepository(rw, rw, kmsCache)
require.NoError(t, err)
+104 -6
View File
@@ -9,6 +9,7 @@ import (
"github.com/fatih/structs"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/timestamp"
@@ -85,6 +86,7 @@ func (r *WorkerAuthRepositoryStorage) Store(ctx context.Context, msg nodee.Messa
}); err != nil {
return errors.Wrap(ctx, err, op)
}
case *types.RootCertificates:
err := r.storeRootCertificates(ctx, t)
if err != nil {
@@ -343,6 +345,9 @@ func (r *WorkerAuthRepositoryStorage) Load(ctx context.Context, msg nodee.Messag
case *types.NodeInformation:
err = r.loadNodeInformation(ctx, t)
case *types.ServerLedActivationToken:
err = r.loadServerLedActivationToken(ctx, t)
case *types.RootCertificates:
err = r.loadRootCertificates(ctx, t)
@@ -416,6 +421,48 @@ func (r *WorkerAuthRepositoryStorage) loadNodeInformation(ctx context.Context, n
return nil
}
// Node information is loaded in two parts:
// * the workerAuth record
// * its certificate bundles
func (r *WorkerAuthRepositoryStorage) loadServerLedActivationToken(ctx context.Context, token *types.ServerLedActivationToken) error {
const op = "server.(WorkerAuthRepositoryStorage).loadServerLedActivationToken"
if token == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing ServerLedActivationToken")
}
activationTokenEntry := allocWorkerAuthServerLedActivationToken()
err := r.reader.LookupWhere(ctx, activationTokenEntry, "token_id = ?", []any{token.Id})
if err != nil {
if errors.Is(err, dbw.ErrRecordNotFound) {
return nodee.ErrNotFound
}
return errors.Wrap(ctx, err, op)
}
token.State, err = AttachWorkerIdToState(ctx, activationTokenEntry.WorkerId)
if err != nil {
return errors.Wrap(ctx, err, op)
}
// Decrypt marshaled creation time
databaseWrapper, err := r.kms.GetWrapper(ctx, scope.Global.String(), kms.KeyPurposeDatabase, kms.WithKeyId(activationTokenEntry.KeyId))
if err != nil {
return errors.Wrap(ctx, err, op)
}
if err := activationTokenEntry.decrypt(ctx, databaseWrapper); err != nil {
return errors.Wrap(ctx, err, op)
}
token.CreationTimeMarshaled = activationTokenEntry.CreationTime
token.CreationTime = new(timestamppb.Timestamp)
if err := proto.Unmarshal(token.CreationTimeMarshaled, token.CreationTime); err != nil {
return errors.Wrap(ctx, err, op)
}
return nil
}
func (r *WorkerAuthRepositoryStorage) findCertBundles(ctx context.Context, workerKeyId string) ([]*types.CertificateBundle, error) {
const op = "server.(WorkerAuthRepositoryStorage).findCertBundles"
if workerKeyId == "" {
@@ -537,9 +584,14 @@ func (r *WorkerAuthRepositoryStorage) Remove(ctx context.Context, msg nodee.Mess
}
// Determine type of message to remove
switch msg.(type) {
switch t := msg.(type) {
case *types.NodeInformation:
err := r.removeNodeInformation(ctx, msg.GetId())
err := r.removeNodeInformation(ctx, t)
if err != nil {
return errors.Wrap(ctx, err, op)
}
case *types.ServerLedActivationToken:
err := r.removeServerLedActivationToken(ctx, t)
if err != nil {
return errors.Wrap(ctx, err, op)
}
@@ -555,9 +607,12 @@ func (r *WorkerAuthRepositoryStorage) Remove(ctx context.Context, msg nodee.Mess
return nil
}
func (r *WorkerAuthRepositoryStorage) removeNodeInformation(ctx context.Context, id string) error {
func (r *WorkerAuthRepositoryStorage) removeNodeInformation(ctx context.Context, msg *types.NodeInformation) error {
const op = "server.(WorkerAuthRepositoryStorage).removeNodeInformation"
if id == "" {
switch {
case msg == nil:
return errors.New(ctx, errors.InvalidParameter, op, "nil node information")
case msg.Id == "":
return errors.New(ctx, errors.InvalidParameter, op, "empty id")
}
@@ -567,11 +622,11 @@ func (r *WorkerAuthRepositoryStorage) removeNodeInformation(ctx context.Context,
db.ExpBackoff{},
func(reader db.Reader, w db.Writer) error {
var err error
_, err = w.Exec(ctx, deleteWorkerAuthQuery, []interface{}{sql.Named("worker_key_identifier", id)})
_, err = w.Exec(ctx, deleteWorkerAuthQuery, []interface{}{sql.Named("worker_key_identifier", msg.Id)})
if err != nil {
return errors.Wrap(ctx, err, op)
}
_, err = w.Exec(ctx, deleteWorkerCertBundlesQuery, []interface{}{sql.Named("worker_key_identifier", id)})
_, err = w.Exec(ctx, deleteWorkerCertBundlesQuery, []interface{}{sql.Named("worker_key_identifier", msg.Id)})
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete workerAuth"))
}
@@ -585,6 +640,49 @@ func (r *WorkerAuthRepositoryStorage) removeNodeInformation(ctx context.Context,
return nil
}
func (r *WorkerAuthRepositoryStorage) removeServerLedActivationToken(ctx context.Context, msg *types.ServerLedActivationToken) error {
const op = "server.(WorkerAuthRepositoryStorage).removeServerLedActivationToken"
switch {
case msg == nil:
return errors.New(ctx, errors.InvalidParameter, op, "nil node information")
case msg.Id == "":
return errors.New(ctx, errors.InvalidParameter, op, "empty id")
case msg.State == nil:
return errors.New(ctx, errors.InvalidParameter, op, "missing state")
}
var workerInfo workerAuthWorkerId
if err := mapstructure.Decode(msg.State.AsMap(), &workerInfo); err != nil {
return errors.Wrap(ctx, err, op)
}
if workerInfo.WorkerId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "state missing worker id")
}
actToken := allocWorkerAuthServerLedActivationToken()
actToken.WorkerId = workerInfo.WorkerId
_, err := r.writer.DoTx(
ctx,
db.StdRetryCnt,
db.ExpBackoff{},
func(reader db.Reader, w db.Writer) error {
rowsDeleted, err := w.Delete(ctx, actToken)
if err != nil {
return errors.Wrap(ctx, err, op)
}
if rowsDeleted != 1 {
return errors.New(ctx, errors.UnexpectedRowsAffected, op, fmt.Sprintf("expected to delete one activation token, deleted %d", rowsDeleted))
}
return nil
},
)
if err != nil {
return errors.Wrap(ctx, err, op)
}
return nil
}
func (r *WorkerAuthRepositoryStorage) removeCertificateAuthority(ctx context.Context, cert *types.RootCertificates) error {
const op = "server.(WorkerAuthRepositoryStorage).removeCertificateAuthority"
+55 -10
View File
@@ -2,13 +2,18 @@ package server
import (
"context"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"strings"
"testing"
"time"
"github.com/fatih/structs"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/server/store"
"github.com/hashicorp/boundary/internal/types/scope"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/nodeenrollment"
@@ -17,9 +22,11 @@ import (
"github.com/hashicorp/nodeenrollment/storage/file"
"github.com/hashicorp/nodeenrollment/types"
"github.com/mitchellh/mapstructure"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/curve25519"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
@@ -135,18 +142,14 @@ func TestStoreCertAuthorityVersioning(t *testing.T) {
func TestStoreWorkerAuth(t *testing.T) {
require, assert := require.New(t), assert.New(t)
ctx := context.Background()
wrapper := db.TestWrapper(t)
rootWrapper := db.TestWrapper(t)
conn, _ := db.TestSetup(t, "postgres")
kmsCache := kms.TestKms(t, conn, wrapper)
kmsCache := kms.TestKms(t, conn, rootWrapper)
// Ensures the global scope contains a valid root key
err := kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
require.NoError(err)
wrapper, err = kmsCache.GetWrapper(context.Background(), scope.Global.String(), kms.KeyPurposeDatabase)
require.NoError(err)
require.NotNil(wrapper)
require.NoError(kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
worker := TestPkiWorker(t, conn, wrapper)
worker := TestPkiWorker(t, conn, rootWrapper)
rw := db.New(conn)
rootStorage, err := NewRepositoryStorage(ctx, rw, rw, kmsCache)
@@ -216,6 +219,49 @@ func TestStoreWorkerAuth(t *testing.T) {
require.Error(err)
}
func TestStoreServerLedActivationToken(t *testing.T) {
require, assert := require.New(t), assert.New(t)
ctx := context.Background()
rootWrapper := db.TestWrapper(t)
conn, _ := db.TestSetup(t, "postgres")
kmsCache := kms.TestKms(t, conn, rootWrapper)
// Ensure the global scope contains a valid root key
require.NoError(kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
rw := db.New(conn)
rootStorage, err := NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(err)
_, err = rotation.RotateRootCertificates(ctx, rootStorage)
require.NoError(err)
repo, err := NewRepository(rw, rw, kmsCache)
require.NoError(err)
worker, err := repo.CreateWorker(ctx, &Worker{Worker: &store.Worker{ScopeId: scope.Global.String()}}, WithCreateControllerLedActivationToken(true))
require.NoError(err)
require.NotEmpty(worker.ControllerGeneratedActivationToken)
// We should now look for an activation token value in storage using the
// lookup function and validate that it's populated
tokenNonce := new(types.ServerLedActivationTokenNonce)
marshaledNonce, err := base58.FastBase58Decoding(strings.TrimPrefix(worker.ControllerGeneratedActivationToken, nodeenrollment.ServerLedActivationTokenPrefix))
require.NoError(err)
require.NoError(proto.Unmarshal(marshaledNonce, tokenNonce))
hm := hmac.New(sha256.New, tokenNonce.HmacKeyBytes)
idBytes := hm.Sum(tokenNonce.Nonce)
actToken := &types.ServerLedActivationToken{
Id: base58.FastBase58Encoding(idBytes),
}
require.NoError(rootStorage.Load(ctx, actToken))
require.NotNil(actToken.CreationTime)
assert.False(actToken.CreationTime.AsTime().IsZero())
assert.Less(time.Until(actToken.CreationTime.AsTime()), time.Duration(0))
require.NoError(rootStorage.Remove(ctx, actToken))
require.Error(rootStorage.Load(ctx, actToken))
}
func TestUnsupportedMessages(t *testing.T) {
require := require.New(t)
ctx := context.Background()
@@ -253,8 +299,7 @@ func TestStoreNodeInformationTx(t *testing.T) {
kmsCache := kms.TestKms(t, conn, testWrapper)
// Ensures the global scope contains a valid root key
err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
require.NoError(t, err)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), scope.Global.String(), kms.KeyPurposeDatabase)
require.NoError(t, err)
+2 -2
View File
@@ -1,11 +1,11 @@
package store
// TableName overrides the table name used by Controller to `server_controller`
func (Controller) TableName() string {
func (*Controller) TableName() string {
return "server_controller"
}
// TableName overrides the table name used by WorkerTag to `worker_tag`
func (WorkerTag) TableName() string {
func (*WorkerTag) TableName() string {
return "server_worker_tag"
}
+128 -9
View File
@@ -203,6 +203,99 @@ func (x *WorkerCertBundle) GetCertBundle() []byte {
return nil
}
// WorkerAuthServerLedActivationToken contains all fields related to a
// WorkerAuthServerLedActivationToken resource
type WorkerAuthServerLedActivationToken struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The worker_id of the worker that this activates
// @inject_tag: `gorm:"primary_key"`
WorkerId string `protobuf:"bytes,10,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" gorm:"primary_key"`
// The token identifier, which is used for lookup
// @inject_tag: `gorm:"not_null"`
TokenId string `protobuf:"bytes,15,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty" gorm:"not_null"`
// The creation time, encrypted to prevent tampering, as the time plus
// existence of the record allows authorization
// @inject_tag: `gorm:"not_null" wrapping:"ct,creation_time_data"`
CreationTimeEncrypted []byte `protobuf:"bytes,20,opt,name=creation_time_encrypted,json=creationTimeEncrypted,proto3" json:"creation_time_encrypted,omitempty" gorm:"not_null" wrapping:"ct,creation_time_data"`
// The plaintext bytes of the creation time, which are never stored. This is a
// marshaled timestamppb.Timestamp.
// @inject_tag: `gorm:"-" wrapping:"pt,creation_time_data"`
CreationTime []byte `protobuf:"bytes,21,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty" gorm:"-" wrapping:"pt,creation_time_data"`
// The key ID of the encrypting key
// @inject_tag: `gorm:"not_null"`
KeyId string `protobuf:"bytes,40,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty" gorm:"not_null"`
}
func (x *WorkerAuthServerLedActivationToken) Reset() {
*x = WorkerAuthServerLedActivationToken{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_servers_store_v1_worker_auth_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *WorkerAuthServerLedActivationToken) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WorkerAuthServerLedActivationToken) ProtoMessage() {}
func (x *WorkerAuthServerLedActivationToken) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_servers_store_v1_worker_auth_proto_msgTypes[2]
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 WorkerAuthServerLedActivationToken.ProtoReflect.Descriptor instead.
func (*WorkerAuthServerLedActivationToken) Descriptor() ([]byte, []int) {
return file_controller_storage_servers_store_v1_worker_auth_proto_rawDescGZIP(), []int{2}
}
func (x *WorkerAuthServerLedActivationToken) GetWorkerId() string {
if x != nil {
return x.WorkerId
}
return ""
}
func (x *WorkerAuthServerLedActivationToken) GetTokenId() string {
if x != nil {
return x.TokenId
}
return ""
}
func (x *WorkerAuthServerLedActivationToken) GetCreationTimeEncrypted() []byte {
if x != nil {
return x.CreationTimeEncrypted
}
return nil
}
func (x *WorkerAuthServerLedActivationToken) GetCreationTime() []byte {
if x != nil {
return x.CreationTime
}
return nil
}
func (x *WorkerAuthServerLedActivationToken) GetKeyId() string {
if x != nil {
return x.KeyId
}
return ""
}
var File_controller_storage_servers_store_v1_worker_auth_proto protoreflect.FileDescriptor
var file_controller_storage_servers_store_v1_worker_auth_proto_rawDesc = []byte{
@@ -242,11 +335,24 @@ var file_controller_storage_servers_store_v1_worker_auth_proto_rawDesc = []byte{
0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x62,
0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x65, 0x72,
0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 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, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x22, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x65, 0x64, 0x41,
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b,
0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65,
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x23,
0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x15, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54,
0x69, 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x28, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 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, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72,
0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -261,10 +367,11 @@ func file_controller_storage_servers_store_v1_worker_auth_proto_rawDescGZIP() []
return file_controller_storage_servers_store_v1_worker_auth_proto_rawDescData
}
var file_controller_storage_servers_store_v1_worker_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_controller_storage_servers_store_v1_worker_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_controller_storage_servers_store_v1_worker_auth_proto_goTypes = []interface{}{
(*WorkerAuth)(nil), // 0: controller.storage.servers.store.v1.WorkerAuth
(*WorkerCertBundle)(nil), // 1: controller.storage.servers.store.v1.WorkerCertBundle
(*WorkerAuth)(nil), // 0: controller.storage.servers.store.v1.WorkerAuth
(*WorkerCertBundle)(nil), // 1: controller.storage.servers.store.v1.WorkerCertBundle
(*WorkerAuthServerLedActivationToken)(nil), // 2: controller.storage.servers.store.v1.WorkerAuthServerLedActivationToken
}
var file_controller_storage_servers_store_v1_worker_auth_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
@@ -304,6 +411,18 @@ func file_controller_storage_servers_store_v1_worker_auth_proto_init() {
return nil
}
}
file_controller_storage_servers_store_v1_worker_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WorkerAuthServerLedActivationToken); 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{
@@ -311,7 +430,7 @@ func file_controller_storage_servers_store_v1_worker_auth_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_storage_servers_store_v1_worker_auth_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
+2 -2
View File
@@ -99,7 +99,7 @@ func TestKmsWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...O
serversRepo, err := NewRepository(rw, rw, kms)
require.NoError(t, err)
ctx := context.Background()
opts := getOpts(opt...)
opts := GetOpts(opt...)
namePart, err := newWorkerId(ctx)
require.NoError(t, err)
@@ -150,7 +150,7 @@ func TestPkiWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...O
serversRepo, err := NewRepository(rw, rw, kmsCache)
require.NoError(t, err)
ctx := context.Background()
opts := getOpts(opt...)
opts := GetOpts(opt...)
require.NoError(t, err)
wrk := NewWorker(scope.Global.String(),
+4
View File
@@ -2,10 +2,12 @@ package server
import (
"context"
"crypto/rand"
"strings"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -38,6 +40,8 @@ func TestTestKmsWorker(t *testing.T) {
func TestTestPkiWorker(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
require.NoError(t, kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
const (
name = "test name"
description = "test description"
+4 -1
View File
@@ -67,13 +67,16 @@ type Worker struct {
// other based on the context in which the worker is passed. As such
// inputTags should only be read when performing mutations on the database.
inputTags []*Tag `gorm:"-"`
// This is used to pass the token back to the calling function
ControllerGeneratedActivationToken string `gorm:"-"`
}
// NewWorker returns a new Worker. Valid options are WithName, WithDescription
// WithAddress, and WithWorkerTags. All other options are ignored. This does
// not set any of the worker reported values.
func NewWorker(scopeId string, opt ...Option) *Worker {
opts := getOpts(opt...)
opts := GetOpts(opt...)
return &Worker{
Worker: &store.Worker{
ScopeId: scopeId,
+1 -1
View File
@@ -24,7 +24,7 @@ type WorkerKeys struct {
func newWorkerAuth(ctx context.Context, workerKeyIdentifier, workerId string, opt ...Option) (*WorkerAuth, error) {
const op = "server.newWorkerAuth"
opts := getOpts(opt...)
opts := GetOpts(opt...)
if workerKeyIdentifier == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no workerKeyIdentifier")
@@ -0,0 +1,113 @@
package server
import (
"context"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/server/store"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping"
"google.golang.org/protobuf/proto"
)
// WorkerAuthServerLedActivationToken contains an activation token for a worker
type WorkerAuthServerLedActivationToken struct {
*store.WorkerAuthServerLedActivationToken
tableName string `gorm:"-"`
}
// newWorkerAuthServerLedActivation creates a new token from the given values
func newWorkerAuthServerLedActivationToken(ctx context.Context, workerId, tokenId string, creationTime []byte, _ ...Option) (*WorkerAuthServerLedActivationToken, error) {
const op = "server.newWorkerAuthServerLedActivationToken"
switch {
case workerId == "":
return nil, errors.New(ctx, errors.InvalidParameter, op, "no worker id")
case tokenId == "":
return nil, errors.New(ctx, errors.InvalidParameter, op, "no token id")
case len(creationTime) == 0:
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty creation time")
}
l := &WorkerAuthServerLedActivationToken{
WorkerAuthServerLedActivationToken: &store.WorkerAuthServerLedActivationToken{
WorkerId: workerId,
TokenId: tokenId,
CreationTime: creationTime,
},
}
return l, nil
}
func allocWorkerAuthServerLedActivationToken() *WorkerAuthServerLedActivationToken {
return &WorkerAuthServerLedActivationToken{
WorkerAuthServerLedActivationToken: &store.WorkerAuthServerLedActivationToken{},
}
}
func (w *WorkerAuthServerLedActivationToken) clone() *WorkerAuthServerLedActivationToken {
cp := proto.Clone(w.WorkerAuthServerLedActivationToken)
return &WorkerAuthServerLedActivationToken{
WorkerAuthServerLedActivationToken: cp.(*store.WorkerAuthServerLedActivationToken),
}
}
// ValidateNewWorkerAuthServerLedActivationToken is called before storing a WorkerAuthActivationToken in the db
func (w *WorkerAuthServerLedActivationToken) ValidateNewWorkerAuthServerLedActivationToken(ctx context.Context) error {
const op = "server.(WorkerAuthServerLedActivationToken).ValidateNewWorkerAuthServerLedActivationToken"
if w.WorkerId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing worker id")
}
if w.TokenId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing token id")
}
if len(w.CreationTimeEncrypted) == 0 {
return errors.New(ctx, errors.InvalidParameter, op, "missing encrypted creation time")
}
return nil
}
// TableName returns the table name.
func (w *WorkerAuthServerLedActivationToken) TableName() string {
if w.tableName != "" {
return w.tableName
}
return "worker_auth_server_led_activation_token"
}
// SetTableName sets the table name.
func (w *WorkerAuthServerLedActivationToken) SetTableName(n string) {
w.tableName = n
}
// encrypt the activation token before storing
func (w *WorkerAuthServerLedActivationToken) encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
const op = "server.(WorkerAuthServerLedActivationToken).encrypt"
if cipher == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing cipher")
}
if err := structwrapping.WrapStruct(ctx, cipher, w.WorkerAuthServerLedActivationToken); err != nil {
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt))
}
keyId, err := cipher.KeyId(ctx)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt), errors.WithMsg("failed to read cipher key id"))
}
w.KeyId = keyId
return nil
}
// decrypt the auth method after reading it from the db
func (w *WorkerAuthServerLedActivationToken) decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
const op = "server.(WorkerAuthServerLedActivationToken).decrypt"
if cipher == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing cipher")
}
if err := structwrapping.UnwrapStruct(ctx, cipher, w.WorkerAuthServerLedActivationToken); err != nil {
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt))
}
return nil
}
@@ -0,0 +1,122 @@
package server
import (
"context"
"crypto/rand"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/go-dbw"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestWorkerAuthActivationTokenConstraints(t *testing.T) {
t.Parallel()
tlRequire, tlAssert := require.New(t), assert.New(t)
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrap := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrap)
tlRequire.NoError(kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)))
repo, err := NewRepository(rw, rw, kmsCache)
tlRequire.NoError(err)
// First create a worker without an activation token so we can verify it doesn't show up in the table
origWorker := NewWorker(scope.Global.String())
origWorker, err = repo.CreateWorker(ctx, origWorker)
tlRequire.NoError(err)
tlAssert.Empty(origWorker.ControllerGeneratedActivationToken)
activationToken := allocWorkerAuthServerLedActivationToken()
err = rw.LookupWhere(ctx, activationToken, "worker_id = ?", []any{origWorker.PublicId})
tlRequire.Error(err)
tlAssert.ErrorIs(err, dbw.ErrRecordNotFound)
// Now create a worker with an activation token and verify we can find it
worker := NewWorker(scope.Global.String())
worker, err = repo.CreateWorker(ctx, worker, WithCreateControllerLedActivationToken(true))
tlRequire.NoError(err)
tlAssert.NotEmpty(worker.ControllerGeneratedActivationToken)
activationToken = allocWorkerAuthServerLedActivationToken()
err = rw.LookupWhere(ctx, activationToken, "worker_id = ?", []any{worker.PublicId})
tlRequire.NoError(err)
tlAssert.Empty(activationToken.CreationTime)
tlAssert.NotEmpty(activationToken.KeyId)
tlAssert.NotEmpty(activationToken.TokenId)
tlAssert.NotEmpty(activationToken.CreationTimeEncrypted)
// Run some test cases. All are expected to result in error.
cases := []struct {
name string
createModifyFn func(*testing.T, *WorkerAuthServerLedActivationToken) *WorkerAuthServerLedActivationToken
updateModifyFn func(*testing.T, *WorkerAuthServerLedActivationToken) (string, []any) // If set, will update instead of create
wantErrContains string
}{
{
name: "fully-duplicate",
createModifyFn: func(t *testing.T, in *WorkerAuthServerLedActivationToken) *WorkerAuthServerLedActivationToken {
return in
},
wantErrContains: "worker_auth_server_led_activation_token_pkey",
},
{
name: "same-token-id",
createModifyFn: func(t *testing.T, in *WorkerAuthServerLedActivationToken) *WorkerAuthServerLedActivationToken {
in.WorkerId = origWorker.PublicId
return in
},
wantErrContains: "worker_auth_server_led_activation_token_token_id_uq",
},
{
name: "same-worker-id",
createModifyFn: func(t *testing.T, in *WorkerAuthServerLedActivationToken) *WorkerAuthServerLedActivationToken {
in.TokenId = in.TokenId[0:5]
return in
},
wantErrContains: "worker_auth_server_led_activation_token_pkey",
},
{
name: "modify-worker-id",
updateModifyFn: func(t *testing.T, in *WorkerAuthServerLedActivationToken) (string, []any) {
return "update worker_auth_server_led_activation_token set worker_id = ? where token_id = ?", []any{origWorker.PublicId, in.TokenId}
},
wantErrContains: "immutable column: worker_auth_server_led_activation_token.worker_id: integrity violation",
},
{
name: "modify-token-id",
updateModifyFn: func(t *testing.T, in *WorkerAuthServerLedActivationToken) (string, []any) {
return "update worker_auth_server_led_activation_token set token_id = ? where worker_id = ?", []any{in.TokenId[0:5], in.WorkerId}
},
wantErrContains: "immutable column: worker_auth_server_led_activation_token.token_id: integrity violation",
},
{
name: "modify-create-time",
updateModifyFn: func(t *testing.T, in *WorkerAuthServerLedActivationToken) (string, []any) {
return "update worker_auth_server_led_activation_token set creation_time_encrypted = ? where worker_id = ?", []any{in.CreationTimeEncrypted[0:5], in.WorkerId}
},
wantErrContains: "immutable column: worker_auth_server_led_activation_token.creation_time_encrypted: integrity violation",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
require, assert := require.New(t), assert.New(t)
testActivationToken := activationToken.clone()
var err error
if tc.updateModifyFn != nil {
queryStr, args := tc.updateModifyFn(t, testActivationToken)
var rowsUpdated int
rowsUpdated, err = rw.Exec(ctx, queryStr, args)
assert.Empty(rowsUpdated)
} else {
err = rw.Create(ctx, tc.createModifyFn(t, testActivationToken))
}
require.Error(err)
assert.Contains(err.Error(), tc.wantErrContains)
})
}
}
+3
View File
@@ -57,6 +57,7 @@ const (
AddWorkerTags Type = 46
SetWorkerTags Type = 47
RemoveWorkerTags Type = 48
CreateControllerLed Type = 49
// When adding new actions, be sure to update:
//
@@ -112,6 +113,7 @@ var Map = map[string]Type{
AddWorkerTags.String(): AddWorkerTags,
SetWorkerTags.String(): SetWorkerTags,
RemoveWorkerTags.String(): RemoveWorkerTags,
CreateControllerLed.String(): CreateControllerLed,
}
func (a Type) String() string {
@@ -165,6 +167,7 @@ func (a Type) String() string {
"add-worker-tags",
"set-worker-tags",
"remove-worker-tags",
"create:controller-led",
}[a]
}
+16
View File
@@ -99,6 +99,22 @@ func TestAction(t *testing.T) {
action: CreateWorkerLed,
want: "create:worker-led",
},
{
action: AddWorkerTags,
want: "add-worker-tags",
},
{
action: SetWorkerTags,
want: "set-worker-tags",
},
{
action: RemoveWorkerTags,
want: "remove-worker-tags",
},
{
action: CreateControllerLed,
want: "create:controller-led",
},
}
for _, tt := range tests {
t.Run(tt.want, func(t *testing.T) {
@@ -846,6 +846,14 @@ var worker = &Resource{
},
Actions: append(
lActions("a worker"),
&Action{
Name: "create:controller-led",
Description: "Create a worker using the controller-led workflow",
Examples: []string{
"type=<type>;actions=create",
"type=<type>;actions=create:controller-led",
},
},
&Action{
Name: "create:worker-led",
Description: "Create a worker using the worker-led workflow",
@@ -66,6 +66,9 @@ type Worker struct {
// token is a base58 encoded types.FetchNodeCredentialsRequest from
// https://github.com/hashicorp/nodeenrollment
WorkerGeneratedAuthToken *wrapperspb.StringValue `protobuf:"bytes,150,opt,name=worker_generated_auth_token,proto3" json:"worker_generated_auth_token,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. An activation token that can be given to a worker to correlate
// it to the created resource.
ControllerGeneratedActivationToken *wrapperspb.StringValue `protobuf:"bytes,151,opt,name=controller_generated_activation_token,proto3" json:"controller_generated_activation_token,omitempty" class:"secret"` // @gotags: `class:"secret"`
// Output only. The number of connections that this worker is currently handling.
ActiveConnectionCount *wrapperspb.UInt32Value `protobuf:"bytes,160,opt,name=active_connection_count,proto3" json:"active_connection_count,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. The type of the worker, denoted by how it authenticates: `pki`
@@ -200,6 +203,13 @@ func (x *Worker) GetWorkerGeneratedAuthToken() *wrapperspb.StringValue {
return nil
}
func (x *Worker) GetControllerGeneratedActivationToken() *wrapperspb.StringValue {
if x != nil {
return x.ControllerGeneratedActivationToken
}
return nil
}
func (x *Worker) GetActiveConnectionCount() *wrapperspb.UInt32Value {
if x != nil {
return x.ActiveConnectionCount
@@ -248,7 +258,7 @@ var file_controller_api_resources_workers_v1_worker_proto_rawDesc = []byte{
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0xd2, 0x0a, 0x0a, 0x06, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x0e, 0x0a,
0x74, 0x6f, 0x22, 0xc7, 0x0b, 0x0a, 0x06, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 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, 0x0a, 0x05, 0x73, 0x63, 0x6f,
@@ -301,45 +311,52 @@ var file_controller_api_resources_workers_v1_worker_proto_rawDesc = []byte{
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x52, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x67, 0x65, 0x6e, 0x65,
0x72, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x12, 0x57, 0x0a, 0x17, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0xa0, 0x01, 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,
0x52, 0x17, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x04, 0x74, 0x79, 0x70,
0x65, 0x18, 0xaa, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x55,
0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0xb4, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x38, 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, 0x77, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x41,
0x70, 0x69, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x70, 0x69,
0x5f, 0x74, 0x61, 0x67, 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, 0x1a, 0x5c, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69,
0x63, 0x61, 0x6c, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x12, 0x73, 0x0a, 0x25, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x67,
0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x97, 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, 0x52, 0x25,
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72,
0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x57, 0x0a, 0x17, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x18, 0xa0, 0x01, 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, 0x52, 0x17, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x13,
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0xaa, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
0x79, 0x70, 0x65, 0x12, 0x55, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18,
0xb4, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72,
0x6b, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x69, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x61, 0x67, 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, 0x1a, 0x5c, 0x0a, 0x12, 0x43,
0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, 0x0f, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 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, 0x30,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56,
0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,
0x56, 0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x50, 0x5a, 0x4e, 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, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73,
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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x3b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x3a, 0x02, 0x38, 0x01, 0x1a, 0x56, 0x0a, 0x0c, 0x41, 0x70, 0x69, 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, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x50, 0x5a, 0x4e,
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, 0x73, 0x64,
0x6b, 0x2f, 0x70, 0x62, 0x73, 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, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x3b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -376,16 +393,17 @@ var file_controller_api_resources_workers_v1_worker_proto_depIdxs = []int32{
2, // 6: controller.api.resources.workers.v1.Worker.config_tags:type_name -> controller.api.resources.workers.v1.Worker.ConfigTagsEntry
6, // 7: controller.api.resources.workers.v1.Worker.last_status_time:type_name -> google.protobuf.Timestamp
5, // 8: controller.api.resources.workers.v1.Worker.worker_generated_auth_token:type_name -> google.protobuf.StringValue
7, // 9: controller.api.resources.workers.v1.Worker.active_connection_count:type_name -> google.protobuf.UInt32Value
3, // 10: controller.api.resources.workers.v1.Worker.api_tags:type_name -> controller.api.resources.workers.v1.Worker.ApiTagsEntry
8, // 11: controller.api.resources.workers.v1.Worker.CanonicalTagsEntry.value:type_name -> google.protobuf.ListValue
8, // 12: controller.api.resources.workers.v1.Worker.ConfigTagsEntry.value:type_name -> google.protobuf.ListValue
8, // 13: controller.api.resources.workers.v1.Worker.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
14, // [14:14] is the sub-list for method output_type
14, // [14:14] is the sub-list for method input_type
14, // [14:14] is the sub-list for extension type_name
14, // [14:14] is the sub-list for extension extendee
0, // [0:14] is the sub-list for field type_name
5, // 9: controller.api.resources.workers.v1.Worker.controller_generated_activation_token:type_name -> google.protobuf.StringValue
7, // 10: controller.api.resources.workers.v1.Worker.active_connection_count:type_name -> google.protobuf.UInt32Value
3, // 11: controller.api.resources.workers.v1.Worker.api_tags:type_name -> controller.api.resources.workers.v1.Worker.ApiTagsEntry
8, // 12: controller.api.resources.workers.v1.Worker.CanonicalTagsEntry.value:type_name -> google.protobuf.ListValue
8, // 13: controller.api.resources.workers.v1.Worker.ConfigTagsEntry.value:type_name -> google.protobuf.ListValue
8, // 14: controller.api.resources.workers.v1.Worker.ApiTagsEntry.value:type_name -> google.protobuf.ListValue
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
}
func init() { file_controller_api_resources_workers_v1_worker_proto_init() }
@@ -1472,6 +1472,17 @@ documentation](https://www.boundaryproject.io/api-docs) for guidance.
<code>type=&lt;type&gt;;actions=list</code>
</li>
</ul>
<li>
<code>create:controller-led</code>: Create a worker using the controller-led workflow
</li>
<ul>
<li>
<code>type=&lt;type&gt;;actions=create</code>
</li>
<li>
<code>type=&lt;type&gt;;actions=create:controller-led</code>
</li>
</ul>
<li>
<code>create:worker-led</code>: Create a worker using the worker-led workflow
</li>
@@ -22,6 +22,46 @@ worker {
}
```
## Authorization Methods
There are two mechanisms that can be used to register a worker to the cluster.
### Controller-Led Authorization Flow
In this flow, the operator fetches an activation token from the controller's
`workers:create:controller-led` action (on the CLI, this is via `boundary
workers create controller-led`). That activation token is given to the worker
via the `controller_generated_activation_token` parameter. This can be done
either directly or via an env var or file by using `env://` or `file://` syntax:
```hcl
worker {
worker {
auth_storage_path="/boundary/demo-worker-1"
initial_upstreams = ["10.0.0.1"]
controller_generated_activation_token = "neslat_........."
# controller_generated_activation_token = "env://ACT_TOKEN"
# controller_generated_activation_token = "file:///tmp/worker_act_token"
}
```
Once the worker starts, it will read this token and use it to authorize to the
cluster. Note that this token is one-time-use; it is safe to keep it here even
after the worker has successfully authorized and authenticated, as it will be
unusable at that point.
Note: If this value is not present at worker startup time and the worker is not
authorized, it will print and write out suitable information for the worker-led
flow, described below. So long as the worker-led flow has not been used to
authorize the worker, if the controller-generated activation token is provided
and the worker restarted, it will make use of it.
### Worker-Led Authorization Flow
In this flow, the worker prints out an authorization request token to two
places: the startup information printed to stdout, and a file called
`auth_request_token` in the base of the configured `auth_storage_path`. This
token can be submitted to a controller at the `workers:create:worker-led` path;
on the CLI this would be via `boundary workers create worker-led
-worker-generated-auth-token`. No values are needed in the configuration file.
## KMS Configuration
PKI Workers credentials can be encrypted by including an optional KMS stanza with the purpose `worker-auth-storage`.