Merge remote-tracking branch 'origin/llb-byow'
This commit is contained in:
commit
be0f07cc65
195 files changed
+19423
-3433
No files matched your search
@@ -24,6 +24,8 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
|
||||
sessions after 1 hour.
|
||||
See Deprecations/Changes for some additional details.
|
||||
[PR](https://github.com/hashicorp/boundary/pull/2160).
|
||||
* event filtering: Change event filters to use lowercase and snake case for data
|
||||
elements like the rest of Boundary filters do.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
||||
@@ -148,6 +148,10 @@ protobuild:
|
||||
@protoc-go-inject-tag -input=./internal/kms/store/token_key.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/kms/store/session_key.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/kms/store/oidc_key.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/servers/store/controller.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/servers/store/worker.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/servers/store/root_certificate.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/servers/store/worker_auth.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/target/store/target.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/target/targettest/store/target.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/target/tcp/store/target.pb.go
|
||||
@@ -193,6 +197,10 @@ protobuild:
|
||||
@protoc-go-inject-tag -input=./internal/gen/controller/api/services/session_service.pb.go
|
||||
@protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/users/user.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/gen/controller/api/services/user_service.pb.go
|
||||
@protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/workers/worker.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/gen/controller/api/services/worker_service.pb.go
|
||||
@protoc-go-inject-tag -input=./internal/gen/controller/servers/services/server_coordination_service.pb.go
|
||||
|
||||
|
||||
# these protos, services and openapi artifacts are purely for testing purposes
|
||||
@protoc-go-inject-tag -input=./internal/gen/testing/event/event.pb.go
|
||||
|
||||
@@ -28,7 +28,6 @@ type Session struct {
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
States []*SessionState `json:"states,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
WorkerInfo []*WorkerInfo `json:"worker_info,omitempty"`
|
||||
Certificate []byte `json:"certificate,omitempty"`
|
||||
TerminationReason string `json:"termination_reason,omitempty"`
|
||||
AuthorizedActions []string `json:"authorized_actions,omitempty"`
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package sessions
|
||||
|
||||
type WorkerInfo struct {
|
||||
Address string `json:"address,omitempty"`
|
||||
}
|
||||
@@ -1,13 +1,5 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
func init() {
|
||||
structs.DefaultTagName = "json"
|
||||
}
|
||||
|
||||
type GenericResult interface {
|
||||
GetItem() interface{}
|
||||
GetResponse() *Response
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package workers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
)
|
||||
|
||||
// Option is a func that sets optional attributes for a call. This does not need
|
||||
// to be used directly, but instead option arguments are built from the
|
||||
// functions in this package. WithX options set a value to that given in the
|
||||
// argument; DefaultX options indicate that the value should be set to its
|
||||
// default. When an API call is made options are processed in ther order they
|
||||
// appear in the function call, so for a given argument X, a succession of WithX
|
||||
// or DefaultX calls will result in the last call taking effect.
|
||||
type Option func(*options)
|
||||
|
||||
type options struct {
|
||||
postMap map[string]interface{}
|
||||
queryMap map[string]string
|
||||
withAutomaticVersioning bool
|
||||
withSkipCurlOutput bool
|
||||
withFilter string
|
||||
withRecursive bool
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
return options{
|
||||
postMap: make(map[string]interface{}),
|
||||
queryMap: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func getOpts(opt ...Option) (options, []api.Option) {
|
||||
opts := getDefaultOptions()
|
||||
for _, o := range opt {
|
||||
if o != nil {
|
||||
o(&opts)
|
||||
}
|
||||
}
|
||||
var apiOpts []api.Option
|
||||
if opts.withSkipCurlOutput {
|
||||
apiOpts = append(apiOpts, api.WithSkipCurlOutput(true))
|
||||
}
|
||||
if opts.withFilter != "" {
|
||||
opts.queryMap["filter"] = opts.withFilter
|
||||
}
|
||||
if opts.withRecursive {
|
||||
opts.queryMap["recursive"] = strconv.FormatBool(opts.withRecursive)
|
||||
}
|
||||
return opts, apiOpts
|
||||
}
|
||||
|
||||
// If set, and if the version is zero during an update, the API will perform a
|
||||
// fetch to get the current version of the resource and populate it during the
|
||||
// update call. This is convenient but opens up the possibility for subtle
|
||||
// order-of-modification issues, so use carefully.
|
||||
func WithAutomaticVersioning(enable bool) Option {
|
||||
return func(o *options) {
|
||||
o.withAutomaticVersioning = enable
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipCurlOutput tells the API to not use the current call for cURL output.
|
||||
// Useful for when we need to look up versions.
|
||||
func WithSkipCurlOutput(skip bool) Option {
|
||||
return func(o *options) {
|
||||
o.withSkipCurlOutput = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithFilter tells the API to filter the items returned using the provided
|
||||
// filter term. The filter should be in a format supported by
|
||||
// hashicorp/go-bexpr.
|
||||
func WithFilter(filter string) Option {
|
||||
return func(o *options) {
|
||||
o.withFilter = strings.TrimSpace(filter)
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecursive tells the API to use recursion for listing operations on this
|
||||
// resource
|
||||
func WithRecursive(recurse bool) Option {
|
||||
return func(o *options) {
|
||||
o.withRecursive = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithDescription(inDescription string) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["description"] = inDescription
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultDescription() Option {
|
||||
return func(o *options) {
|
||||
o.postMap["description"] = nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithName(inName string) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["name"] = inName
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultName() Option {
|
||||
return func(o *options) {
|
||||
o.postMap["name"] = nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package workers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
)
|
||||
|
||||
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"`
|
||||
AuthorizedActions []string `json:"authorized_actions,omitempty"`
|
||||
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
type WorkerReadResult struct {
|
||||
Item *Worker
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
func (n WorkerReadResult) GetItem() interface{} {
|
||||
return n.Item
|
||||
}
|
||||
|
||||
func (n WorkerReadResult) GetResponse() *api.Response {
|
||||
return n.response
|
||||
}
|
||||
|
||||
type WorkerCreateResult = WorkerReadResult
|
||||
type WorkerUpdateResult = WorkerReadResult
|
||||
|
||||
type WorkerDeleteResult struct {
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
// GetItem will always be nil for WorkerDeleteResult
|
||||
func (n WorkerDeleteResult) GetItem() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n WorkerDeleteResult) GetResponse() *api.Response {
|
||||
return n.response
|
||||
}
|
||||
|
||||
type WorkerListResult struct {
|
||||
Items []*Worker
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
func (n WorkerListResult) GetItems() interface{} {
|
||||
return n.Items
|
||||
}
|
||||
|
||||
func (n WorkerListResult) GetResponse() *api.Response {
|
||||
return n.response
|
||||
}
|
||||
|
||||
// Client is a client for this collection
|
||||
type Client struct {
|
||||
client *api.Client
|
||||
}
|
||||
|
||||
// Creates a new client for this collection. The submitted API client is cloned;
|
||||
// modifications to it after generating this client will not have effect. If you
|
||||
// need to make changes to the underlying API client, use ApiClient() to access
|
||||
// it.
|
||||
func NewClient(c *api.Client) *Client {
|
||||
return &Client{client: c.Clone()}
|
||||
}
|
||||
|
||||
// ApiClient returns the underlying API client
|
||||
func (c *Client) ApiClient() *api.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func (c *Client) CreateWorkerLed(ctx context.Context, workerGeneratedAuthToken string, scopeId string, opt ...Option) (*WorkerCreateResult, error) {
|
||||
if scopeId == "" {
|
||||
return nil, fmt.Errorf("empty scopeId value passed into CreateWorkerLed request")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
if workerGeneratedAuthToken == "" {
|
||||
return nil, fmt.Errorf("empty workerGeneratedAuthToken value passed into CreateWorkerLed request")
|
||||
} else {
|
||||
opts.postMap["worker_generated_auth_token"] = workerGeneratedAuthToken
|
||||
}
|
||||
|
||||
opts.postMap["scope_id"] = scopeId
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "POST", "workers:create:worker-led", opts.postMap, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating CreateWorkerLed 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 CreateWorkerLed 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 CreateWorkerLed 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")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("workers/%s", url.PathEscape(id)), nil, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Read 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, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during Read call: %w", err)
|
||||
}
|
||||
|
||||
target := new(WorkerReadResult)
|
||||
target.Item = new(Worker)
|
||||
apiErr, err := resp.Decode(target.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Read response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) Update(ctx context.Context, id string, version uint32, opt ...Option) (*WorkerUpdateResult, error) {
|
||||
if id == "" {
|
||||
return nil, fmt.Errorf("empty id value passed into Update request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
if version == 0 {
|
||||
if !opts.withAutomaticVersioning {
|
||||
return nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
|
||||
}
|
||||
existingTarget, existingErr := c.Read(ctx, id, append([]Option{WithSkipCurlOutput(true)}, opt...)...)
|
||||
if existingErr != nil {
|
||||
if api.AsServerError(existingErr) != nil {
|
||||
return nil, fmt.Errorf("error from controller when performing initial check-and-set read: %w", existingErr)
|
||||
}
|
||||
return nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
|
||||
}
|
||||
if existingTarget == nil {
|
||||
return nil, errors.New("nil resource response found when performing initial check-and-set read")
|
||||
}
|
||||
if existingTarget.Item == nil {
|
||||
return nil, errors.New("nil resource found when performing initial check-and-set read")
|
||||
}
|
||||
version = existingTarget.Item.Version
|
||||
}
|
||||
|
||||
opts.postMap["version"] = version
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("workers/%s", url.PathEscape(id)), opts.postMap, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Update 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 Update call: %w", err)
|
||||
}
|
||||
|
||||
target := new(WorkerUpdateResult)
|
||||
target.Item = new(Worker)
|
||||
apiErr, err := resp.Decode(target.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Update response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) Delete(ctx context.Context, id string, opt ...Option) (*WorkerDeleteResult, error) {
|
||||
if id == "" {
|
||||
return nil, fmt.Errorf("empty id value passed into Delete request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("workers/%s", url.PathEscape(id)), nil, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Delete 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 Delete call: %w", err)
|
||||
}
|
||||
|
||||
apiErr, err := resp.Decode(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Delete response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
target := &WorkerDeleteResult{
|
||||
response: resp,
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*WorkerListResult, error) {
|
||||
if scopeId == "" {
|
||||
return nil, fmt.Errorf("empty scopeId value passed into List request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
opts.queryMap["scope_id"] = scopeId
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "GET", "workers", nil, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating List 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 List call: %w", err)
|
||||
}
|
||||
|
||||
target := new(WorkerListResult)
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding List response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
+82
-70
@@ -1,74 +1,86 @@
|
||||
package globals
|
||||
|
||||
const (
|
||||
IdField = "id"
|
||||
VersionField = "version"
|
||||
NameField = "name"
|
||||
DescriptionField = "description"
|
||||
CreatedTimeField = "created_time"
|
||||
UpdatedTimeField = "updated_time"
|
||||
TypeField = "type"
|
||||
AttributesField = "attributes"
|
||||
ScopeIdField = "scope_id"
|
||||
ScopeField = "scope"
|
||||
AuthMethodIdField = "auth_method_id"
|
||||
AccountIdField = "account_id"
|
||||
UserIdField = "user_id"
|
||||
IsPrimaryField = "is_primary"
|
||||
AuthorizedActionsField = "authorized_actions"
|
||||
AuthorizedCollectionActionsField = "authorized_collection_actions"
|
||||
ExpirationTimeField = "expiration_time"
|
||||
ApproximateLastUsedTimeField = "approximate_last_used_time"
|
||||
MembersField = "members"
|
||||
MemberIdsField = "member_ids"
|
||||
HostCatalogIdField = "host_catalog_id"
|
||||
HostSetIdsField = "host_set_ids"
|
||||
HostSourceIdsField = "host_source_ids"
|
||||
HostIdsField = "host_ids"
|
||||
PrincipalIdsField = "principal_ids"
|
||||
PrincipalsField = "principals"
|
||||
GrantScopeIdField = "grant_scope_id"
|
||||
GrantsField = "grants"
|
||||
GrantStringsField = "grant_strings"
|
||||
PrimaryAuthMethodIdField = "primary_auth_method_id"
|
||||
TargetIdField = "target_id"
|
||||
HostIdField = "host_id"
|
||||
HostSetIdField = "host_set_id"
|
||||
HostSetsField = "host_sets"
|
||||
HostSourcesField = "host_sources"
|
||||
AuthTokenIdField = "auth_token_id"
|
||||
EndpointField = "endpoint"
|
||||
CertificateField = "certificate"
|
||||
TerminationReasonField = "termination_reason"
|
||||
StatusField = "status"
|
||||
StatesField = "states"
|
||||
SessionConnectionLimitField = "session_connection_limit"
|
||||
SessionMaxSecondsField = "session_max_seconds"
|
||||
WorkerFilterField = "worker_filter"
|
||||
AccountIdsField = "account_ids"
|
||||
AccountsField = "accounts"
|
||||
LoginNameField = "login_name"
|
||||
FullNameField = "full_name"
|
||||
PrimaryAccountIdField = "primary_account_id"
|
||||
EmailField = "email"
|
||||
ManagedGroupIdsField = "managed_group_ids"
|
||||
FilterField = "filter"
|
||||
CredentialStoreIdField = "credential_store_id"
|
||||
ApplicationCredentialSourceIdsField = "application_credential_source_ids"
|
||||
ApplicationCredentialSourcesField = "application_credential_sources"
|
||||
PreferredEndpointsField = "preferred_endpoints"
|
||||
SyncIntervalSecondsField = "sync_interval_seconds"
|
||||
PluginIdField = "plugin_id"
|
||||
PluginField = "plugin"
|
||||
PluginNameField = "plugin_name"
|
||||
IpAddressesField = "ip_addresses"
|
||||
DnsNamesField = "dns_names"
|
||||
SecretsHmacField = "secrets_hmac"
|
||||
ExternalIdField = "external_id"
|
||||
EgressCredentialSourceIdsField = "egress_credential_source_ids"
|
||||
EgressCredentialSourcesField = "egress_credential_sources"
|
||||
ConnectionsField = "connections"
|
||||
CredentialTypeField = "credential_type"
|
||||
CredentialMappingOverridesField = "credential_mapping_overrides"
|
||||
MetricNamespace = "boundary"
|
||||
IdField = "id"
|
||||
VersionField = "version"
|
||||
NameField = "name"
|
||||
DescriptionField = "description"
|
||||
CreatedTimeField = "created_time"
|
||||
UpdatedTimeField = "updated_time"
|
||||
TypeField = "type"
|
||||
AttributesField = "attributes"
|
||||
ScopeIdField = "scope_id"
|
||||
ScopeField = "scope"
|
||||
AuthMethodIdField = "auth_method_id"
|
||||
AccountIdField = "account_id"
|
||||
UserIdField = "user_id"
|
||||
IsPrimaryField = "is_primary"
|
||||
AuthorizedActionsField = "authorized_actions"
|
||||
AuthorizedCollectionActionsField = "authorized_collection_actions"
|
||||
ExpirationTimeField = "expiration_time"
|
||||
ApproximateLastUsedTimeField = "approximate_last_used_time"
|
||||
MembersField = "members"
|
||||
MemberIdsField = "member_ids"
|
||||
HostCatalogIdField = "host_catalog_id"
|
||||
HostSetIdsField = "host_set_ids"
|
||||
HostSourceIdsField = "host_source_ids"
|
||||
HostIdsField = "host_ids"
|
||||
PrincipalIdsField = "principal_ids"
|
||||
PrincipalsField = "principals"
|
||||
GrantScopeIdField = "grant_scope_id"
|
||||
GrantsField = "grants"
|
||||
GrantStringsField = "grant_strings"
|
||||
PrimaryAuthMethodIdField = "primary_auth_method_id"
|
||||
TargetIdField = "target_id"
|
||||
HostIdField = "host_id"
|
||||
HostSetIdField = "host_set_id"
|
||||
HostSetsField = "host_sets"
|
||||
HostSourcesField = "host_sources"
|
||||
AuthTokenIdField = "auth_token_id"
|
||||
EndpointField = "endpoint"
|
||||
CertificateField = "certificate"
|
||||
TerminationReasonField = "termination_reason"
|
||||
StatusField = "status"
|
||||
StatesField = "states"
|
||||
SessionConnectionLimitField = "session_connection_limit"
|
||||
SessionMaxSecondsField = "session_max_seconds"
|
||||
WorkerFilterField = "worker_filter"
|
||||
AccountIdsField = "account_ids"
|
||||
AccountsField = "accounts"
|
||||
LoginNameField = "login_name"
|
||||
FullNameField = "full_name"
|
||||
PrimaryAccountIdField = "primary_account_id"
|
||||
EmailField = "email"
|
||||
ManagedGroupIdsField = "managed_group_ids"
|
||||
FilterField = "filter"
|
||||
CredentialStoreIdField = "credential_store_id"
|
||||
ApplicationCredentialLibraryIdsField = "application_credential_library_ids"
|
||||
ApplicationCredentialLibrariesField = "application_credential_libraries"
|
||||
ApplicationCredentialSourceIdsField = "application_credential_source_ids"
|
||||
ApplicationCredentialSourcesField = "application_credential_sources"
|
||||
PreferredEndpointsField = "preferred_endpoints"
|
||||
SyncIntervalSecondsField = "sync_interval_seconds"
|
||||
PluginIdField = "plugin_id"
|
||||
PluginField = "plugin"
|
||||
PluginNameField = "plugin_name"
|
||||
IpAddressesField = "ip_addresses"
|
||||
DnsNamesField = "dns_names"
|
||||
SecretsHmacField = "secrets_hmac"
|
||||
ExternalIdField = "external_id"
|
||||
EgressCredentialSourceIdsField = "egress_credential_source_ids"
|
||||
EgressCredentialSourcesField = "egress_credential_sources"
|
||||
ConnectionsField = "connections"
|
||||
CredentialTypeField = "credential_type"
|
||||
CredentialMappingOverridesField = "credential_mapping_overrides"
|
||||
MetricNamespace = "boundary"
|
||||
LastStatusTimeField = "last_status_time"
|
||||
AddressField = "address"
|
||||
CanonicalAddressField = "canonical_address"
|
||||
TagsField = "tags"
|
||||
CanonicalTagsField = "canonical_tags"
|
||||
ConfigTagsField = "config_tags"
|
||||
ConfigurationField = "configuration"
|
||||
WorkerGeneratedAuthTokenField = "worker_generated_auth_token"
|
||||
WorkerProvidedConfigurationField = "worker_provided_configuration"
|
||||
ActiveConnectionCountField = "active_connection_count"
|
||||
)
|
||||
+5
-4
@@ -1,8 +1,9 @@
|
||||
package globals
|
||||
|
||||
const (
|
||||
KmsPurposeRoot = "root"
|
||||
KmsPurposeWorkerAuth = "worker-auth"
|
||||
KmsPurposeRecovery = "recovery"
|
||||
KmsPurposeConfig = "config"
|
||||
KmsPurposeRoot = "root"
|
||||
KmsPurposeWorkerAuth = "worker-auth"
|
||||
KmsPurposeWorkerAuthStorage = "worker-auth-storage"
|
||||
KmsPurposeRecovery = "recovery"
|
||||
KmsPurposeConfig = "config"
|
||||
)
|
||||
@@ -6,6 +6,8 @@ replace github.com/hashicorp/boundary/api => ./api
|
||||
|
||||
replace github.com/hashicorp/boundary/sdk => ./sdk
|
||||
|
||||
//replace github.com/hashicorp/nodeenrollment => ../nodeenrollment
|
||||
|
||||
require (
|
||||
github.com/armon/go-metrics v0.3.9 // indirect
|
||||
github.com/fatih/color v1.13.0
|
||||
@@ -15,7 +17,7 @@ require (
|
||||
github.com/golang-migrate/migrate/v4 v4.15.1
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.7
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0
|
||||
github.com/hashicorp/boundary/api v0.0.24
|
||||
@@ -40,7 +42,7 @@ require (
|
||||
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2
|
||||
github.com/hashicorp/go-secure-stdlib/password v0.1.1
|
||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.0
|
||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.1
|
||||
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2
|
||||
github.com/hashicorp/go-sockaddr v1.0.2
|
||||
@@ -65,11 +67,13 @@ require (
|
||||
github.com/pires/go-proxyproto v0.6.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/posener/complete v1.2.3
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/ryanuber/go-glob v1.0.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.2
|
||||
github.com/zalando/go-keyring v0.2.1
|
||||
go.uber.org/atomic v1.9.0
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/tools v0.1.10
|
||||
@@ -86,16 +90,15 @@ require (
|
||||
require github.com/hashicorp/go-dbw v0.0.0-20220412153211-c470aec9369f // this is a branch and should be updated before merging
|
||||
|
||||
require (
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20220515130442-cac0b5ac133b
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
github.com/hashicorp/nodeenrollment v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
||||
github.com/AlecAivazis/survey/v2 v2.2.9 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
@@ -170,6 +173,7 @@ require (
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/sethvargo/go-diceware v0.3.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0 // indirect
|
||||
@@ -187,7 +191,7 @@ require (
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/driver/sqlite v1.2.4 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
@@ -582,8 +582,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github/v35 v35.2.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -715,8 +715,8 @@ github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2 h1:Tz6v3Jb2DRnDCfifRSjYKG
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
|
||||
github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60=
|
||||
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
|
||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.0 h1:TszfJJ1vJWdvPkPxYivP5TUTkOaXziE1jTKGmfOck94=
|
||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.0/go.mod h1:Io+g8iYs//ESo5x2Gy1rTTYaIHUyCZD7h16K7DiOUI4=
|
||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.1 h1:s47ax4xEIStj1YV7TRz6zS8LlNrTU86aEhL8pfSOG4U=
|
||||
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.1/go.mod h1:Mh8pP9IH9qnBQSSH3PYtSkGq3+KlIuw5kAS9W8++BLc=
|
||||
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 h1:SMGUnbpAcat8rIKHkBPjfv81yC46a8eCNZ2hsR2l1EI=
|
||||
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1/go.mod h1:Ch/bf00Qnx77MZd49JRgHYqHQjtEmTgGU2faufpVZb0=
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
|
||||
@@ -740,6 +740,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.0 h1:mhMVbrHM6NTDcpte/mOilP3Fd/HrcctshGs4/82EO6U=
|
||||
github.com/hashicorp/nodeenrollment v0.1.0/go.mod h1:LIPKi+g0g/vl3xhpbzugCalHSxX1PMeqnatkAsxRgyM=
|
||||
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=
|
||||
@@ -1178,6 +1180,8 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiB
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sethvargo/go-diceware v0.3.0 h1:UVVEfmN/uF50JfWAN7nbY6CiAlp5xeSx+5U0lWKkMCQ=
|
||||
github.com/sethvargo/go-diceware v0.3.0/go.mod h1:lH5Q/oSPMivseNdhMERAC7Ti5oOPqsaVddU1BcN1CY0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
@@ -1229,8 +1233,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
@@ -1908,8 +1913,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
|
||||
gorm.io/driver/postgres v1.2.2 h1:Ka9W6feOU+rPM9m007eYLMD4QoZuYGBnQ3Jp0faGSwg=
|
||||
gorm.io/driver/postgres v1.2.2/go.mod h1:Ik3tK+a3FMp8ORZl29v4b3M0RsgXsaeMXh9s9eVMXco=
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/sessions"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/users"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -35,6 +36,12 @@ type structureInfo struct {
|
||||
fields []fieldInfo
|
||||
}
|
||||
|
||||
type requiredParam struct {
|
||||
Name string
|
||||
Typ string
|
||||
PostType string
|
||||
}
|
||||
|
||||
type fieldInfo struct {
|
||||
Name string
|
||||
ProtoName string
|
||||
@@ -88,9 +95,8 @@ type structInfo struct {
|
||||
// useful to avoid collisions
|
||||
nameOverride string
|
||||
|
||||
// typeOnCreate indicates that create will be creating a concrete
|
||||
// implementation of an abstract type and thus a type field is necessary
|
||||
typeOnCreate bool
|
||||
// extraRequiredParams allows adding extra required parameters to templates
|
||||
extraRequiredParams []requiredParam
|
||||
|
||||
// recursiveListing indicates that the collection supports recursion when
|
||||
// listing
|
||||
@@ -150,7 +156,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "scopes/scope.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -186,7 +192,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "users/user.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -214,7 +220,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "groups/group.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -252,7 +258,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "roles/role.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -294,14 +300,20 @@ var inputStructs = []*structInfo{
|
||||
outFile: "authmethods/authmethods.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
pluralResourceName: "auth-methods",
|
||||
typeOnCreate: true,
|
||||
pluralResourceName: "auth-methods",
|
||||
extraRequiredParams: []requiredParam{
|
||||
{
|
||||
Name: "resourceType",
|
||||
Typ: "string",
|
||||
PostType: "type",
|
||||
},
|
||||
},
|
||||
versionEnabled: true,
|
||||
createResponseTypes: true,
|
||||
recursiveListing: true,
|
||||
@@ -322,7 +334,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "accounts/account.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -350,7 +362,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "managedgroups/managedgroups.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -386,15 +398,21 @@ var inputStructs = []*structInfo{
|
||||
outFile: "credentialstores/credential_store.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
pluralResourceName: "credential-stores",
|
||||
parentTypeName: "scope",
|
||||
typeOnCreate: true,
|
||||
pluralResourceName: "credential-stores",
|
||||
parentTypeName: "scope",
|
||||
extraRequiredParams: []requiredParam{
|
||||
{
|
||||
Name: "resourceType",
|
||||
Typ: "string",
|
||||
PostType: "type",
|
||||
},
|
||||
},
|
||||
versionEnabled: true,
|
||||
createResponseTypes: true,
|
||||
recursiveListing: true,
|
||||
@@ -425,7 +443,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "credentiallibraries/credential_library.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -456,17 +474,23 @@ var inputStructs = []*structInfo{
|
||||
outFile: "credentials/credential.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
extraRequiredParams: []requiredParam{
|
||||
{
|
||||
Name: "resourceType",
|
||||
Typ: "string",
|
||||
PostType: "type",
|
||||
},
|
||||
},
|
||||
pluralResourceName: "credentials",
|
||||
parentTypeName: "credential-store",
|
||||
versionEnabled: true,
|
||||
createResponseTypes: true,
|
||||
typeOnCreate: true,
|
||||
},
|
||||
|
||||
// Host related resources
|
||||
@@ -475,7 +499,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "hostcatalogs/host_catalog.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -496,8 +520,14 @@ var inputStructs = []*structInfo{
|
||||
SkipDefault: true,
|
||||
},
|
||||
},
|
||||
pluralResourceName: "host-catalogs",
|
||||
typeOnCreate: true,
|
||||
pluralResourceName: "host-catalogs",
|
||||
extraRequiredParams: []requiredParam{
|
||||
{
|
||||
Name: "resourceType",
|
||||
Typ: "string",
|
||||
PostType: "type",
|
||||
},
|
||||
},
|
||||
versionEnabled: true,
|
||||
createResponseTypes: true,
|
||||
recursiveListing: true,
|
||||
@@ -507,7 +537,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "hosts/host.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -528,7 +558,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "hostsets/host_set.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -591,7 +621,7 @@ var inputStructs = []*structInfo{
|
||||
outFile: "targets/target.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
commonCreateTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
@@ -639,8 +669,14 @@ var inputStructs = []*structInfo{
|
||||
FieldType: "[]string",
|
||||
},
|
||||
},
|
||||
versionEnabled: true,
|
||||
typeOnCreate: true,
|
||||
versionEnabled: true,
|
||||
extraRequiredParams: []requiredParam{
|
||||
{
|
||||
Name: "resourceType",
|
||||
Typ: "string",
|
||||
PostType: "type",
|
||||
},
|
||||
},
|
||||
createResponseTypes: true,
|
||||
recursiveListing: true,
|
||||
},
|
||||
@@ -648,10 +684,6 @@ var inputStructs = []*structInfo{
|
||||
inProto: &sessions.SessionState{},
|
||||
outFile: "sessions/state.gen.go",
|
||||
},
|
||||
{
|
||||
inProto: &sessions.WorkerInfo{},
|
||||
outFile: "sessions/workers.gen.go",
|
||||
},
|
||||
{
|
||||
inProto: &sessions.Connection{},
|
||||
outFile: "sessions/connection.gen.go",
|
||||
@@ -677,4 +709,37 @@ var inputStructs = []*structInfo{
|
||||
fieldFilter: []string{"private_key"},
|
||||
recursiveListing: true,
|
||||
},
|
||||
{
|
||||
inProto: &workers.Worker{},
|
||||
outFile: "workers/worker.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
template.Must(template.New("").Funcs(
|
||||
template.FuncMap{
|
||||
"snakeCase": snakeCase,
|
||||
"funcName": func() string {
|
||||
return "CreateWorkerLed"
|
||||
},
|
||||
"apiAction": func() string {
|
||||
return ":create:worker-led"
|
||||
},
|
||||
},
|
||||
).Parse(createTemplateStr)),
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
extraRequiredParams: []requiredParam{
|
||||
{
|
||||
Name: "workerGeneratedAuthToken",
|
||||
Typ: "string",
|
||||
PostType: "worker_generated_auth_token",
|
||||
},
|
||||
},
|
||||
pluralResourceName: "workers",
|
||||
createResponseTypes: true,
|
||||
recursiveListing: true,
|
||||
versionEnabled: true,
|
||||
},
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func parsePBs() {
|
||||
name = fmt.Sprintf("%s.%s", pkg, name)
|
||||
}
|
||||
switch name {
|
||||
case "v1.AuthorizedCollectionActionsEntry":
|
||||
case "v1.AuthorizedCollectionActionsEntry", "v1.CanonicalTagsEntry", "v1.TagsEntry", "v1.ConfigTagsEntry":
|
||||
fi.FieldType = "map[string][]string"
|
||||
default:
|
||||
fi.FieldType = sliceText + ptr + name
|
||||
|
||||
@@ -46,7 +46,7 @@ type templateInput struct {
|
||||
SliceSubtypes map[string]sliceSubtypeInfo
|
||||
ExtraFields []fieldInfo
|
||||
VersionEnabled bool
|
||||
TypeOnCreate bool
|
||||
ExtraRequiredParams []requiredParam
|
||||
CreateResponseTypes bool
|
||||
RecursiveListing bool
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func fillTemplates() {
|
||||
ParentTypeName: in.parentTypeName,
|
||||
ExtraFields: in.extraFields,
|
||||
VersionEnabled: in.versionEnabled,
|
||||
TypeOnCreate: in.typeOnCreate,
|
||||
ExtraRequiredParams: in.extraRequiredParams,
|
||||
CreateResponseTypes: in.createResponseTypes,
|
||||
RecursiveListing: in.recursiveListing,
|
||||
}
|
||||
@@ -346,14 +346,10 @@ func (c *Client) Delete(ctx context.Context, id string, opt... Option) (*{{ .Nam
|
||||
}
|
||||
`))
|
||||
|
||||
var createTemplate = template.Must(template.New("").Funcs(
|
||||
template.FuncMap{
|
||||
"snakeCase": snakeCase,
|
||||
},
|
||||
).Parse(`
|
||||
func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}CreateResult, error) {
|
||||
const createTemplateStr = `
|
||||
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 Create request")
|
||||
return nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into {{ funcName }} request")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
@@ -361,17 +357,17 @@ func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceTyp
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
{{ if .TypeOnCreate }} if resourceType == "" {
|
||||
return nil, fmt.Errorf("empty resourceType value passed into Create request")
|
||||
{{ range .ExtraRequiredParams }} if {{ .Name }} == "" {
|
||||
return nil, fmt.Errorf("empty {{ .Name }} value passed into {{ funcName }} request")
|
||||
} else {
|
||||
opts.postMap["type"] = resourceType
|
||||
opts.postMap["{{ .PostType }}"] = {{ .Name }}
|
||||
}{{ end }}
|
||||
|
||||
opts.postMap["{{ snakeCase .CollectionFunctionArg }}"] = {{ .CollectionFunctionArg }}
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "POST", "{{ .CollectionPath }}", opts.postMap, apiOpts...)
|
||||
req, err := c.client.NewRequest(ctx, "POST", "{{ .CollectionPath }}{{ apiAction }}", opts.postMap, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Create request: %w", err)
|
||||
return nil, fmt.Errorf("error creating {{ funcName }} request: %w", err)
|
||||
}
|
||||
{{ if ( eq .CollectionPath "\"scopes\"" ) }}
|
||||
opts.queryMap["scope_id"] = scopeId
|
||||
@@ -386,14 +382,14 @@ func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceTyp
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during Create call: %w", err)
|
||||
return nil, fmt.Errorf("error performing client request during {{ funcName }} call: %w", err)
|
||||
}
|
||||
|
||||
target := new({{ .Name }}CreateResult)
|
||||
target.Item = new({{ .Name }})
|
||||
apiErr, err := resp.Decode(target.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Create response: %w", err)
|
||||
return nil, fmt.Errorf("error decoding {{ funcName }} response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
@@ -401,7 +397,19 @@ func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceTyp
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
`))
|
||||
`
|
||||
|
||||
var commonCreateTemplate = template.Must(template.New("").Funcs(
|
||||
template.FuncMap{
|
||||
"snakeCase": snakeCase,
|
||||
"funcName": func() string {
|
||||
return "Create"
|
||||
},
|
||||
"apiAction": func() string {
|
||||
return ""
|
||||
},
|
||||
},
|
||||
).Parse(createTemplateStr))
|
||||
|
||||
var updateTemplate = template.Must(template.New("").Parse(`
|
||||
func (c *Client) Update(ctx context.Context, id string, version uint32, opt... Option) (*{{ .Name }}UpdateResult, error) {
|
||||
|
||||
@@ -36,6 +36,7 @@ type WorkerAuthInfo struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ConnectionNonce string `json:"connection_nonce"`
|
||||
ProxyAddress string `json:"proxy_address"`
|
||||
}
|
||||
|
||||
// Factory is the factory function to create a listener.
|
||||
|
||||
+27
-18
@@ -22,24 +22,25 @@ type Option func(*Options)
|
||||
|
||||
// Options - how Options are represented.
|
||||
type Options struct {
|
||||
withNoTokenScope bool
|
||||
withNoTokenValue bool
|
||||
withSkipDatabaseDestruction bool
|
||||
withSkipAuthMethodCreation bool
|
||||
withSkipOidcAuthMethodCreation bool
|
||||
withSkipScopesCreation bool
|
||||
withSkipHostResourcesCreation bool
|
||||
withSkipTargetCreation bool
|
||||
withContainerImage string
|
||||
withDialect string
|
||||
withDatabaseTemplate string
|
||||
withEventerConfig *event.EventerConfig
|
||||
withEventFlags *EventFlags
|
||||
withEventWrapper wrapping.Wrapper
|
||||
withAttributeFieldPrefix string
|
||||
withStatusCode int
|
||||
withHostPlugin func() (string, plugin.HostPluginServiceClient)
|
||||
withEventGating bool
|
||||
withNoTokenScope bool
|
||||
withNoTokenValue bool
|
||||
withSkipDatabaseDestruction bool
|
||||
withSkipAuthMethodCreation bool
|
||||
withSkipOidcAuthMethodCreation bool
|
||||
withSkipScopesCreation bool
|
||||
withSkipHostResourcesCreation bool
|
||||
withSkipTargetCreation bool
|
||||
withContainerImage string
|
||||
withDialect string
|
||||
withDatabaseTemplate string
|
||||
withEventerConfig *event.EventerConfig
|
||||
withEventFlags *EventFlags
|
||||
withEventWrapper wrapping.Wrapper
|
||||
withAttributeFieldPrefix string
|
||||
withStatusCode int
|
||||
withHostPlugin func() (string, plugin.HostPluginServiceClient)
|
||||
withEventGating bool
|
||||
withSkipWorkerAuthKmsInstantiation bool
|
||||
}
|
||||
|
||||
func getDefaultOptions() Options {
|
||||
@@ -188,3 +189,11 @@ func WithEventGating(with bool) Option {
|
||||
o.withEventGating = with
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipWorkerAuthKmsInstantiation causes KMS methods used for worker-auth to
|
||||
// not be processed, useful for dev mode
|
||||
func WithSkipWorkerAuthKmsInstantiation(with bool) Option {
|
||||
return func(o *Options) {
|
||||
o.withSkipWorkerAuthKmsInstantiation = with
|
||||
}
|
||||
}
|
||||
@@ -55,8 +55,11 @@ func TestServer_SetupKMSes(t *testing.T) {
|
||||
purposes: []string{globals.KmsPurposeRoot},
|
||||
},
|
||||
{
|
||||
name: "multi purpose",
|
||||
purposes: []string{globals.KmsPurposeRoot, globals.KmsPurposeRecovery, globals.KmsPurposeWorkerAuth, globals.KmsPurposeConfig},
|
||||
name: "multi purpose",
|
||||
purposes: []string{
|
||||
globals.KmsPurposeRoot, globals.KmsPurposeRecovery, globals.KmsPurposeWorkerAuth,
|
||||
globals.KmsPurposeWorkerAuthStorage, globals.KmsPurposeConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
logger := hclog.Default()
|
||||
@@ -89,6 +92,8 @@ func TestServer_SetupKMSes(t *testing.T) {
|
||||
assert.NotNil(s.RootKms)
|
||||
case globals.KmsPurposeWorkerAuth:
|
||||
assert.NotNil(s.WorkerAuthKms)
|
||||
case globals.KmsPurposeWorkerAuthStorage:
|
||||
assert.NotNil(s.WorkerAuthStorageKms)
|
||||
case globals.KmsPurposeRecovery:
|
||||
assert.NotNil(s.RecoveryKms)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -61,6 +62,9 @@ const (
|
||||
// TODO: This value is temporary, it will be removed once we have a better
|
||||
// story/direction on attributes and system defaults.
|
||||
statusGracePeriodEnvVar = "BOUNDARY_STATUS_GRACE_PERIOD"
|
||||
|
||||
// File name to use for storing workerAuth requests
|
||||
WorkerAuthReqFile = "auth_request_token"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -82,11 +86,12 @@ type Server struct {
|
||||
StderrLock *sync.Mutex
|
||||
Eventer *event.Eventer
|
||||
|
||||
RootKms wrapping.Wrapper
|
||||
WorkerAuthKms wrapping.Wrapper
|
||||
RecoveryKms wrapping.Wrapper
|
||||
Kms *kms.Kms
|
||||
SecureRandomReader io.Reader
|
||||
RootKms wrapping.Wrapper
|
||||
WorkerAuthKms wrapping.Wrapper
|
||||
WorkerAuthStorageKms wrapping.Wrapper
|
||||
RecoveryKms wrapping.Wrapper
|
||||
Kms *kms.Kms
|
||||
SecureRandomReader io.Reader
|
||||
|
||||
PrometheusRegisterer prometheus.Registerer
|
||||
|
||||
@@ -341,6 +346,29 @@ func (b *Server) RemovePidFile(pidPath string) error {
|
||||
return os.Remove(pidPath)
|
||||
}
|
||||
|
||||
func (b *Server) StoreWorkerAuthReq(authReq, workerAuthReqPath string) error {
|
||||
// Quit fast if no workerAuthReqFile
|
||||
if workerAuthReqPath == "" {
|
||||
return nil
|
||||
}
|
||||
workerAuthReqFilePath := filepath.Join(workerAuthReqPath, WorkerAuthReqFile)
|
||||
|
||||
// Open the workerAuthReq file
|
||||
workerAuthReqFile, err := os.OpenFile(workerAuthReqFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o640)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open file for worker auth request: %w", err)
|
||||
}
|
||||
defer workerAuthReqFile.Close()
|
||||
|
||||
// Write out the workerAuthRequest
|
||||
_, err = workerAuthReqFile.WriteString(authReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not write to file for worker auth request: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Server) PrintInfo(ui cli.Ui) {
|
||||
verInfo := version.Get()
|
||||
if verInfo.Version != "" {
|
||||
@@ -517,7 +545,9 @@ func (b *Server) SetupListeners(ui cli.Ui, config *configutil.SharedConfig, allo
|
||||
|
||||
// SetupKMSes takes in a parsed config, does some minor checking on purposes,
|
||||
// and sends each off to configutil to instantiate a wrapper.
|
||||
func (b *Server) SetupKMSes(ctx context.Context, ui cli.Ui, config *config.Config) error {
|
||||
func (b *Server) SetupKMSes(ctx context.Context, ui cli.Ui, config *config.Config, opt ...Option) error {
|
||||
opts := getOpts(opt...)
|
||||
|
||||
sharedConfig := config.SharedConfig
|
||||
var pluginLogger hclog.Logger
|
||||
var err error
|
||||
@@ -527,7 +557,11 @@ func (b *Server) SetupKMSes(ctx context.Context, ui cli.Ui, config *config.Confi
|
||||
switch purpose {
|
||||
case "":
|
||||
return errors.New("KMS block missing 'purpose'")
|
||||
case globals.KmsPurposeRoot, globals.KmsPurposeWorkerAuth, globals.KmsPurposeConfig:
|
||||
case globals.KmsPurposeWorkerAuth:
|
||||
if opts.withSkipWorkerAuthKmsInstantiation {
|
||||
continue
|
||||
}
|
||||
case globals.KmsPurposeRoot, globals.KmsPurposeConfig, globals.KmsPurposeWorkerAuthStorage:
|
||||
case globals.KmsPurposeRecovery:
|
||||
if config.Controller != nil && config.DevRecoveryKey != "" {
|
||||
kms.Config["key"] = config.DevRecoveryKey
|
||||
@@ -592,6 +626,8 @@ func (b *Server) SetupKMSes(ctx context.Context, ui cli.Ui, config *config.Confi
|
||||
b.RootKms = wrapper
|
||||
case globals.KmsPurposeWorkerAuth:
|
||||
b.WorkerAuthKms = wrapper
|
||||
case globals.KmsPurposeWorkerAuthStorage:
|
||||
b.WorkerAuthStorageKms = wrapper
|
||||
case globals.KmsPurposeRecovery:
|
||||
b.RecoveryKms = wrapper
|
||||
case globals.KmsPurposeConfig:
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/targetscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/userscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/version"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/workerscmd"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
@@ -1071,5 +1072,47 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
Func: "remove-accounts",
|
||||
}, nil
|
||||
},
|
||||
|
||||
"workers": func() (cli.Command, error) {
|
||||
return &workerscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
}, nil
|
||||
},
|
||||
"workers create": func() (cli.Command, error) {
|
||||
return &workerscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "create",
|
||||
}, nil
|
||||
},
|
||||
"workers create worker-led": func() (cli.Command, error) {
|
||||
return &workerscmd.WorkerLedCommand{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "create",
|
||||
}, nil
|
||||
},
|
||||
"workers read": func() (cli.Command, error) {
|
||||
return &workerscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "read",
|
||||
}, nil
|
||||
},
|
||||
"workers update": func() (cli.Command, error) {
|
||||
return &workerscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "update",
|
||||
}, nil
|
||||
},
|
||||
"workers delete": func() (cli.Command, error) {
|
||||
return &workerscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "delete",
|
||||
}, nil
|
||||
},
|
||||
"workers list": func() (cli.Command, error) {
|
||||
return &workerscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "list",
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -115,6 +115,12 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
c.plural = "auth token"
|
||||
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -25,12 +25,18 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/intglobals"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/servers/store"
|
||||
"github.com/hashicorp/boundary/internal/target/tcp"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/posener/complete"
|
||||
"go.uber.org/atomic"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -84,6 +90,10 @@ type Command struct {
|
||||
flagEveryEventDenyFilters []string
|
||||
flagCreateLoopbackHostPlugin bool
|
||||
flagPluginExecutionDir string
|
||||
flagUseKmsWorkerAuthMethod bool
|
||||
flagWorkerAuthStorageDir string
|
||||
flagWorkerAuthStorageSkipCleanup bool
|
||||
flagWorkerAuthRotationInterval time.Duration
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
@@ -327,6 +337,23 @@ 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-storage-dir",
|
||||
Target: &c.flagWorkerAuthStorageDir,
|
||||
Usage: "Specifies the directory to store worker authentication credentials in dev mode.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "worker-auth-storage-skip-cleanup",
|
||||
Target: &c.flagWorkerAuthStorageSkipCleanup,
|
||||
Usage: "Prevents deletion of temp worker credential storage directory if set",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "create-loopback-host-plugin",
|
||||
@@ -334,6 +361,12 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
Hidden: true,
|
||||
})
|
||||
|
||||
f.DurationVar(&base.DurationVar{
|
||||
Name: "worker-auth-rotation-interval",
|
||||
Target: &c.flagWorkerAuthRotationInterval,
|
||||
Hidden: true,
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
@@ -384,6 +417,7 @@ func (c *Command) Run(args []string) int {
|
||||
c.DevUnprivilegedPassword = c.flagUnprivilegedPassword
|
||||
c.DevTargetDefaultPort = c.flagTargetDefaultPort
|
||||
c.Config.Plugins.ExecutionDir = c.flagPluginExecutionDir
|
||||
c.Config.Worker.AuthStoragePath = c.flagWorkerAuthStorageDir
|
||||
if c.flagIdSuffix != "" {
|
||||
if len(c.flagIdSuffix) != 10 {
|
||||
c.UI.Error("Invalid ID suffix, must be exactly 10 characters")
|
||||
@@ -449,7 +483,7 @@ func (c *Command) Run(args []string) int {
|
||||
if c.flagControllerClusterListenAddr != "" {
|
||||
l.Address = c.flagControllerClusterListenAddr
|
||||
if !c.flagControllerOnly {
|
||||
c.Config.Worker.Controllers = []string{l.Address}
|
||||
c.Config.Worker.InitialUpstreams = []string{l.Address}
|
||||
}
|
||||
} else {
|
||||
l.Address = "127.0.0.1:9201"
|
||||
@@ -540,7 +574,7 @@ func (c *Command) Run(args []string) int {
|
||||
if c.flagRecoveryKey != "" {
|
||||
c.Config.DevRecoveryKey = c.flagRecoveryKey
|
||||
}
|
||||
if err := c.SetupKMSes(c.Context, c.UI, c.Config); err != nil {
|
||||
if err := c.SetupKMSes(c.Context, c.UI, c.Config, base.WithSkipWorkerAuthKmsInstantiation(!c.flagUseKmsWorkerAuthMethod)); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
@@ -548,14 +582,18 @@ func (c *Command) Run(args []string) int {
|
||||
c.UI.Error("Controller KMS not found after parsing KMS blocks")
|
||||
return base.CommandUserError
|
||||
}
|
||||
if c.WorkerAuthKms == nil {
|
||||
c.UI.Error("Worker Auth KMS not found after parsing KMS blocks")
|
||||
return base.CommandUserError
|
||||
if c.flagUseKmsWorkerAuthMethod {
|
||||
if c.WorkerAuthKms == nil {
|
||||
c.UI.Error("Worker Auth KMS not found after parsing KMS blocks")
|
||||
return base.CommandUserError
|
||||
}
|
||||
c.Config.Worker.Name = ""
|
||||
c.Config.Worker.Description = ""
|
||||
c.InfoKeys = append(c.InfoKeys, "[Worker-Auth] AEAD Key Bytes")
|
||||
c.Info["[Worker-Auth] AEAD Key Bytes"] = c.Config.DevWorkerAuthKey
|
||||
}
|
||||
c.InfoKeys = append(c.InfoKeys, "[Controller] AEAD Key Bytes")
|
||||
c.Info["[Controller] AEAD Key Bytes"] = c.Config.DevControllerKey
|
||||
c.InfoKeys = append(c.InfoKeys, "[Worker-Auth] AEAD Key Bytes")
|
||||
c.Info["[Worker-Auth] AEAD Key Bytes"] = c.Config.DevWorkerAuthKey
|
||||
c.InfoKeys = append(c.InfoKeys, "[Recovery] AEAD Key Bytes")
|
||||
c.Info["[Recovery] AEAD Key Bytes"] = c.Config.DevRecoveryKey
|
||||
|
||||
@@ -592,7 +630,7 @@ func (c *Command) Run(args []string) int {
|
||||
opts = append(opts, base.WithContainerImage(c.flagContainerImage))
|
||||
}
|
||||
if err := c.CreateDevDatabase(c.Context, opts...); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error creating dev database container %w", err).Error())
|
||||
c.UI.Error(fmt.Errorf("Error creating dev database container: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
@@ -613,12 +651,6 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
}
|
||||
|
||||
c.PrintInfo(c.UI)
|
||||
if err := c.ReleaseLogGate(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error releasing event gate: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
{
|
||||
c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginHostAws, base.EnabledPluginHostAzure)
|
||||
conf := &controller.Config{
|
||||
@@ -644,6 +676,8 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
}
|
||||
|
||||
errorEncountered := atomic.NewBool(false)
|
||||
|
||||
if !c.flagControllerOnly {
|
||||
conf := &worker.Config{
|
||||
RawConfig: c.Config,
|
||||
@@ -657,6 +691,10 @@ func (c *Command) Run(args []string) int {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
if c.flagWorkerAuthRotationInterval > 0 {
|
||||
c.worker.TestOverrideAuthRotationPeriod = c.flagWorkerAuthRotationInterval
|
||||
}
|
||||
|
||||
if err := c.worker.Start(); err != nil {
|
||||
retErr := fmt.Errorf("Error starting worker: %w", err)
|
||||
if err := c.worker.Shutdown(); err != nil {
|
||||
@@ -669,6 +707,54 @@ 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
|
||||
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 {
|
||||
c.UI.Error(retErr.Error())
|
||||
retErr = fmt.Errorf("Error shutting down worker: %w", err)
|
||||
}
|
||||
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)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
c.PrintInfo(c.UI)
|
||||
if err := c.ReleaseLogGate(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error releasing event gate: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
opsServer, err := ops.NewServer(c.Logger, c.controller, c.Listeners...)
|
||||
@@ -683,7 +769,7 @@ func (c *Command) Run(args []string) int {
|
||||
// Wait for shutdown
|
||||
shutdownTriggered := false
|
||||
|
||||
for !shutdownTriggered {
|
||||
for !shutdownTriggered && !errorEncountered.Load() {
|
||||
select {
|
||||
case <-c.ShutdownCh:
|
||||
c.UI.Output("==> Boundary dev environment shutdown triggered, interrupt again to force")
|
||||
@@ -704,11 +790,23 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
}()
|
||||
|
||||
shutdownTriggered = true
|
||||
|
||||
case <-c.SigUSR2Ch:
|
||||
buf := make([]byte, 32*1024*1024)
|
||||
n := runtime.Stack(buf[:], true)
|
||||
event.WriteSysEvent(context.TODO(), op, "goroutine trace", "stack", string(buf[:n]))
|
||||
}
|
||||
|
||||
if shutdownTriggered {
|
||||
if c.Config.Controller != nil {
|
||||
c.opsServer.WaitIfHealthExists(c.Config.Controller.GracefulShutdownWaitDuration, c.UI)
|
||||
}
|
||||
|
||||
if !c.flagControllerOnly {
|
||||
if !c.flagWorkerAuthStorageSkipCleanup {
|
||||
c.worker.WorkerAuthStorage.Cleanup()
|
||||
}
|
||||
if err := c.worker.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error shutting down worker: %w", err).Error())
|
||||
}
|
||||
@@ -722,15 +820,36 @@ func (c *Command) Run(args []string) int {
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Failed to shutdown ops listeners: %w", err).Error())
|
||||
}
|
||||
|
||||
shutdownTriggered = true
|
||||
|
||||
case <-c.SigUSR2Ch:
|
||||
buf := make([]byte, 32*1024*1024)
|
||||
n := runtime.Stack(buf[:], true)
|
||||
event.WriteSysEvent(context.TODO(), op, "goroutine trace", "stack", string(buf[:n]))
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
func authorizeWorker(ctx context.Context, c *controller.Controller, request string) error {
|
||||
reqBytes, err := base58.FastBase58Decoding(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error base58-decoding fetch node creds next proto value: %w", err)
|
||||
}
|
||||
// Decode the proto into the request
|
||||
req := new(types.FetchNodeCredentialsRequest)
|
||||
if err := proto.Unmarshal(reqBytes, req); err != nil {
|
||||
return fmt.Errorf("error unmarshaling common name value: %w", err)
|
||||
}
|
||||
|
||||
serversRepo, err := c.ServersRepoFn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching servers repo: %w", err)
|
||||
}
|
||||
|
||||
_, err = serversRepo.CreateWorker(ctx, &servers.Worker{
|
||||
Worker: &store.Worker{
|
||||
ScopeId: scope.Global.String(),
|
||||
},
|
||||
}, servers.WithFetchNodeCredentialsRequest(req))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating worker: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand_Flags(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := assert.New(t)
|
||||
|
||||
serverCmdUi := &base.BoundaryUI{
|
||||
Ui: &cli.ColoredUi{
|
||||
ErrorColor: cli.UiColorRed,
|
||||
WarnColor: cli.UiColorYellow,
|
||||
Ui: &cli.BasicUi{
|
||||
Reader: bufio.NewReader(os.Stdin),
|
||||
Writer: os.Stdout,
|
||||
},
|
||||
},
|
||||
Format: "table",
|
||||
}
|
||||
base.NewServer(base.NewCommand(serverCmdUi))
|
||||
|
||||
cmd := &Command{Server: base.NewServer(base.NewCommand(serverCmdUi))}
|
||||
got := cmd.Flags()
|
||||
completions := got.Completions()
|
||||
|
||||
assert.Contains(completions, "-log-level")
|
||||
assert.Contains(completions, "-log-format")
|
||||
assert.Contains(completions, "-id-suffix")
|
||||
assert.Contains(completions, "-password")
|
||||
assert.Contains(completions, "-login-name")
|
||||
assert.Contains(completions, "-unprivileged-password")
|
||||
assert.Contains(completions, "-unprivileged-login-name")
|
||||
assert.Contains(completions, "-api-listen-address")
|
||||
assert.Contains(completions, "-host-address")
|
||||
assert.Contains(completions, "-target-default-port")
|
||||
assert.Contains(completions, "-target-session-connection-limit")
|
||||
assert.Contains(completions, "-target-session-max-seconds")
|
||||
assert.Contains(completions, "-cluster-listen-address")
|
||||
assert.Contains(completions, "-controller-public-cluster-address")
|
||||
assert.Contains(completions, "-ops-listen-address")
|
||||
assert.Contains(completions, "-controller-only")
|
||||
assert.Contains(completions, "-proxy-listen-address")
|
||||
assert.Contains(completions, "-worker-public-address")
|
||||
assert.Contains(completions, "-worker-auth-key")
|
||||
assert.Contains(completions, "-disable-database-destruction")
|
||||
assert.Contains(completions, "-combine-logs")
|
||||
assert.Contains(completions, "-ui-passthrough-dir")
|
||||
assert.Contains(completions, "-recovery-key")
|
||||
assert.Contains(completions, "-database-url")
|
||||
assert.Contains(completions, "-container-image")
|
||||
assert.Contains(completions, "-event-format")
|
||||
assert.Contains(completions, "-observation-events")
|
||||
assert.Contains(completions, "-audit-events")
|
||||
assert.Contains(completions, "-system-events")
|
||||
assert.Contains(completions, "-audit-events")
|
||||
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-storage-dir")
|
||||
assert.Contains(completions, "-worker-auth-storage-skip-cleanup")
|
||||
|
||||
// keep adding assertions for other flags which should be set as a result of cmd.Flags()
|
||||
}
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -117,7 +117,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ kms "aead" {
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "api"
|
||||
address = "127.0.0.1:9500"
|
||||
tls_cert_file = "%s/bundle.pem"
|
||||
tls_key_file = "%s/bundle.pem"
|
||||
cors_enabled = true
|
||||
@@ -69,10 +70,12 @@ listener "tcp" {
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
address = "127.0.0.1:9501"
|
||||
purpose = "cluster"
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
address = "127.0.0.1:9502"
|
||||
purpose = "proxy"
|
||||
}
|
||||
`
|
||||
@@ -91,7 +94,9 @@ func TestServer_ReloadListener(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
controllerKey, workerAuthKey, recoveryKey := config.DevKeyGeneration()
|
||||
controllerKey := config.DevKeyGeneration()
|
||||
workerAuthKey := config.DevKeyGeneration()
|
||||
recoveryKey := config.DevKeyGeneration()
|
||||
|
||||
cmd := testServerCommand(t, testServerCommandOpts{
|
||||
CreateDevDatabase: true,
|
||||
@@ -131,7 +136,7 @@ func TestServer_ReloadListener(t *testing.T) {
|
||||
}()
|
||||
|
||||
testCertificateSerial := func(serial string) {
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:9200", &tls.Config{
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:9500", &tls.Config{
|
||||
RootCAs: certPool,
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/hashicorp/go-secure-stdlib/mlock"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
"go.uber.org/atomic"
|
||||
@@ -177,6 +178,8 @@ func (c *Command) Run(args []string) int {
|
||||
|
||||
base.StartMemProfiler(c.Context)
|
||||
|
||||
// Note: the checks directly after this must remain where they are because
|
||||
// they rely on the state of configured KMSes.
|
||||
if err := c.SetupKMSes(c.Context, c.UI, c.Config); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return base.CommandUserError
|
||||
@@ -187,9 +190,23 @@ func (c *Command) Run(args []string) int {
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
if c.WorkerAuthKms == nil {
|
||||
c.UI.Error("Worker Auth KMS not found after parsing KMS blocks")
|
||||
return base.CommandUserError
|
||||
if c.Config.Worker != nil {
|
||||
switch c.WorkerAuthKms {
|
||||
case nil:
|
||||
if c.Config.Worker.AuthStoragePath == "" {
|
||||
c.UI.Error("No worker auth KMS specified and no worker auth storage path specified.")
|
||||
return base.CommandUserError
|
||||
}
|
||||
if c.Config.Worker.Name != "" || c.Config.Worker.Description != "" {
|
||||
c.UI.Error("Worker config cannot contain name or description when using PKI-based worker authentication; it must be set via the API.")
|
||||
return base.CommandUserError
|
||||
}
|
||||
default:
|
||||
if c.Config.Worker.Name == "" {
|
||||
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.DefaultMaxRequestDuration != 0 {
|
||||
@@ -267,6 +284,9 @@ func (c *Command) Run(args []string) int {
|
||||
c.UI.Error(`Config activates worker but no listener with "proxy" purpose found`)
|
||||
return base.CommandUserError
|
||||
}
|
||||
if c.Config.Worker.ControllersRaw != nil {
|
||||
c.UI.Warn("The \"controllers\" field for worker config is deprecated. Please use \"initial_upstreams\" instead.")
|
||||
}
|
||||
|
||||
if err := c.SetupWorkerPublicAddress(c.Config, ""); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
@@ -276,25 +296,25 @@ func (c *Command) Run(args []string) int {
|
||||
c.Info["worker public proxy addr"] = c.Config.Worker.PublicAddr
|
||||
|
||||
if c.Config.Controller != nil {
|
||||
switch len(c.Config.Worker.Controllers) {
|
||||
switch len(c.Config.Worker.InitialUpstreams) {
|
||||
case 0:
|
||||
if c.Config.Controller.PublicClusterAddr != "" {
|
||||
clusterAddr = c.Config.Controller.PublicClusterAddr
|
||||
}
|
||||
c.Config.Worker.Controllers = []string{clusterAddr}
|
||||
c.Config.Worker.InitialUpstreams = []string{clusterAddr}
|
||||
case 1:
|
||||
if c.Config.Worker.Controllers[0] == clusterAddr {
|
||||
if c.Config.Worker.InitialUpstreams[0] == clusterAddr {
|
||||
break
|
||||
}
|
||||
if c.Config.Controller.PublicClusterAddr != "" &&
|
||||
c.Config.Worker.Controllers[0] == c.Config.Controller.PublicClusterAddr {
|
||||
c.Config.Worker.InitialUpstreams[0] == c.Config.Controller.PublicClusterAddr {
|
||||
break
|
||||
}
|
||||
// Best effort see if it's a domain name and if not assume it must match
|
||||
host, _, err := net.SplitHostPort(c.Config.Worker.Controllers[0])
|
||||
host, _, err := net.SplitHostPort(c.Config.Worker.InitialUpstreams[0])
|
||||
if err != nil && strings.Contains(err.Error(), "missing port in address") {
|
||||
err = nil
|
||||
host = c.Config.Worker.Controllers[0]
|
||||
host = c.Config.Worker.InitialUpstreams[0]
|
||||
}
|
||||
if err == nil {
|
||||
ip := net.ParseIP(host)
|
||||
@@ -305,17 +325,17 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
c.UI.Error(`When running a combined controller and worker, it's invalid to specify a "controllers" key in the worker block with any value other than the controller cluster address/port when using IPs rather than DNS names`)
|
||||
c.UI.Error(`When running a combined controller and worker, it's invalid to specify a "initial_upstreams" or "controllers" key in the worker block with any values other than the controller cluster or upstream worker address/port when using IPs rather than DNS names`)
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
for _, controller := range c.Config.Worker.Controllers {
|
||||
host, _, err := net.SplitHostPort(controller)
|
||||
for _, upstream := range c.Config.Worker.InitialUpstreams {
|
||||
host, _, err := net.SplitHostPort(upstream)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "missing port in address") {
|
||||
host = controller
|
||||
host = upstream
|
||||
} else {
|
||||
c.UI.Error(fmt.Errorf("Invalid controller address %q: %w", controller, err).Error())
|
||||
c.UI.Error(fmt.Errorf("Invalid worker upstream address %q: %w", upstream, err).Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
@@ -329,11 +349,19 @@ func (c *Command) Run(args []string) int {
|
||||
errMsg = "a multicast"
|
||||
}
|
||||
if errMsg != "" {
|
||||
c.UI.Error(fmt.Sprintf("Controller address %q is invalid: cannot be %s address", controller, errMsg))
|
||||
c.UI.Error(fmt.Sprintf("Worker upstream address %q is invalid: cannot be %s address", upstream, errMsg))
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.Config.HCPBClusterId != "" {
|
||||
_, err := uuid.ParseUUID(c.Config.HCPBClusterId)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Invalid HCPB cluster id %q: %w", c.Config.HCPBClusterId, err).Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := c.SetupListeners(c.UI, c.Config.SharedConfig, []string{"api", "cluster", "proxy", "ops"}); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
@@ -449,12 +477,6 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
}()
|
||||
|
||||
c.PrintInfo(c.UI)
|
||||
if err := c.ReleaseLogGate(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error releasing event gate: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
if c.Config.Controller != nil {
|
||||
c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginHostAws, base.EnabledPluginHostAzure)
|
||||
if err := c.StartController(c.Context); err != nil {
|
||||
@@ -473,6 +495,34 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
if c.WorkerAuthKms == nil && c.worker.WorkerAuthRegistrationRequest != "" {
|
||||
c.InfoKeys = append(c.InfoKeys, "worker auth registration request")
|
||||
c.Info["worker auth registration request"] = c.worker.WorkerAuthRegistrationRequest
|
||||
c.InfoKeys = append(c.InfoKeys, "worker auth current key id")
|
||||
c.Info["worker auth current key id"] = c.worker.WorkerAuthCurrentKeyId.Load()
|
||||
|
||||
// Write the WorkerAuth request to a file
|
||||
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())
|
||||
if err := c.controller.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
|
||||
}
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.PrintInfo(c.UI)
|
||||
if err := c.ReleaseLogGate(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error releasing event gate: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
opsServer, err := ops.NewServer(c.Logger, c.controller, c.Listeners...)
|
||||
@@ -520,10 +570,6 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
c.UI.Error("Controller has no name set. It must be the unique name of this instance.")
|
||||
return base.CommandUserError
|
||||
}
|
||||
if c.Config.Worker != nil && c.Config.Worker.Name == "" {
|
||||
c.UI.Error("Worker has no name set. It must be the unique name of this instance.")
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
@@ -633,6 +679,14 @@ func (c *Command) StartWorker() error {
|
||||
return fmt.Errorf("Error initializing worker: %w", err)
|
||||
}
|
||||
|
||||
if c.WorkerAuthKms == nil {
|
||||
if c.worker.WorkerAuthStorage == nil {
|
||||
return fmt.Errorf("No worker auth KMS specified and no worker auth storage found")
|
||||
}
|
||||
c.InfoKeys = append(c.InfoKeys, "worker auth storage path")
|
||||
c.Info["worker auth storage path"] = c.worker.WorkerAuthStorage.BaseDir()
|
||||
}
|
||||
|
||||
if err := c.worker.Start(); err != nil {
|
||||
retErr := fmt.Errorf("Error starting worker: %w", err)
|
||||
if err := c.worker.Shutdown(); err != nil {
|
||||
|
||||
@@ -14,9 +14,10 @@ import (
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/api/authtokens"
|
||||
"github.com/hashicorp/boundary/api/targets"
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/tests/helper"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/boundary/testing/controller"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/atomic"
|
||||
@@ -24,54 +25,13 @@ import (
|
||||
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets/tcp"
|
||||
)
|
||||
|
||||
const shutdownReloadApiAddr = "http://127.0.0.1:9203"
|
||||
|
||||
const shutdownReloadControllerConfig = `
|
||||
disable_mlock = true
|
||||
|
||||
controller {
|
||||
name = "dev-controller"
|
||||
description = "A default controller created in dev mode"
|
||||
database {
|
||||
url = "%s"
|
||||
}
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "root"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
key_id = "global_root"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "worker-auth"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
key_id = "global_worker-auth"
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "api"
|
||||
address = "127.0.0.1:9203"
|
||||
tls_disable = true
|
||||
cors_enabled = true
|
||||
cors_allowed_origins = ["*"]
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "cluster"
|
||||
address = "127.0.0.1:9204"
|
||||
}
|
||||
`
|
||||
|
||||
const shutdownReloadWorkerConfig = `
|
||||
const shutdownReloadWorkerProvidedConfiguration = `
|
||||
disable_mlock = true
|
||||
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1:9204"]
|
||||
initial_upstreams = ["%s"]
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
@@ -89,35 +49,16 @@ listener "tcp" {
|
||||
|
||||
func TestServer_ShutdownWorker(t *testing.T) {
|
||||
require := require.New(t)
|
||||
controllerKey, workerAuthKey, _ := config.DevKeyGeneration()
|
||||
|
||||
// Start the controller
|
||||
controllerCmd := testServerCommand(t, testServerCommandOpts{
|
||||
CreateDevDatabase: true,
|
||||
ControllerKey: controllerKey,
|
||||
UseDevAuthMethod: true,
|
||||
UseDevTarget: true,
|
||||
})
|
||||
t.Cleanup(func() {
|
||||
if controllerCmd.DevDatabaseCleanupFunc != nil {
|
||||
require.NoError(controllerCmd.DevDatabaseCleanupFunc())
|
||||
}
|
||||
})
|
||||
controllerCmd.presetConfig = atomic.NewString(fmt.Sprintf(shutdownReloadControllerConfig, controllerCmd.DatabaseUrl, controllerKey, workerAuthKey))
|
||||
|
||||
// Use code channel so that we can use test assertions on the returned integer.
|
||||
// It is illegal to call `t.FailNow()` from a goroutine.
|
||||
// https://pkg.go.dev/testing#T.FailNow
|
||||
controllerCodeChan := make(chan int)
|
||||
go func() {
|
||||
controllerCodeChan <- controllerCmd.Run(nil)
|
||||
}()
|
||||
|
||||
waitCh(t, controllerCmd.startedCh)
|
||||
rootWrapper, _ := wrapperWithKey(t)
|
||||
recoveryWrapper, _ := wrapperWithKey(t)
|
||||
workerAuthWrapper, key := wrapperWithKey(t)
|
||||
testController := controller.NewTestController(t, controller.WithWorkerAuthKms(workerAuthWrapper), controller.WithRootKms(rootWrapper), controller.WithRecoveryKms(recoveryWrapper))
|
||||
defer testController.Shutdown()
|
||||
|
||||
// Start the worker
|
||||
workerCmd := testServerCommand(t, testServerCommandOpts{})
|
||||
workerCmd.presetConfig = atomic.NewString(fmt.Sprintf(shutdownReloadWorkerConfig, workerAuthKey))
|
||||
workerCmd.presetConfig = atomic.NewString(fmt.Sprintf(shutdownReloadWorkerProvidedConfiguration, testController.ClusterAddrs()[0], key))
|
||||
|
||||
workerCodeChan := make(chan int)
|
||||
go func() {
|
||||
@@ -125,26 +66,32 @@ func TestServer_ShutdownWorker(t *testing.T) {
|
||||
}()
|
||||
waitCh(t, workerCmd.startedCh)
|
||||
|
||||
// Give the worker time for initial status or we can fail because no worker
|
||||
// is ready for the connection yet
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Set up the target
|
||||
ctx := context.Background()
|
||||
client := buildClient(t, shutdownReloadApiAddr)
|
||||
client := buildClient(t, testController.ApiAddrs()[0])
|
||||
setAuthToken(ctx, t, client)
|
||||
|
||||
tcl := targets.NewClient(client)
|
||||
tgt, err := tcl.Read(ctx, "ttcp_1234567890")
|
||||
tgtL, err := tcl.List(ctx, scope.Global.String(), targets.WithRecursive(true))
|
||||
require.NoError(err)
|
||||
require.Len(tgtL.Items, 1)
|
||||
tgt := tgtL.Items[0]
|
||||
require.NotNil(tgt)
|
||||
|
||||
// Create test server, update default port on target
|
||||
ts := helper.NewTestTcpServer(t)
|
||||
require.NotNil(ts)
|
||||
defer ts.Close()
|
||||
tgt, err = tcl.Update(ctx, tgt.Item.Id, tgt.Item.Version, targets.WithTcpTargetDefaultPort(ts.Port()))
|
||||
tgtR, err := tcl.Update(ctx, tgt.Id, tgt.Version, targets.WithTcpTargetDefaultPort(ts.Port()))
|
||||
require.NoError(err)
|
||||
require.NotNil(tgt)
|
||||
require.NotNil(tgtR)
|
||||
|
||||
// Authorize and connect
|
||||
sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890")
|
||||
sess := helper.NewTestSession(ctx, t, tcl, tgt.Id)
|
||||
sConn := sess.Connect(ctx, t)
|
||||
|
||||
// Run initial send/receive test, make sure things are working
|
||||
@@ -160,14 +107,7 @@ func TestServer_ShutdownWorker(t *testing.T) {
|
||||
|
||||
// Connection should fail, and the session should be closed on the DB.
|
||||
sConn.TestSendRecvFail(t)
|
||||
sess.ExpectConnectionStateOnController(ctx, t, controllerCmd.controller.ConnectionRepoFn, session.StatusClosed)
|
||||
|
||||
// We're done! Shutdown the controller, and that's it.
|
||||
close(controllerCmd.ShutdownCh)
|
||||
if <-controllerCodeChan != 0 {
|
||||
output := controllerCmd.UI.(*cli.MockUi).ErrorWriter.String() + controllerCmd.UI.(*cli.MockUi).OutputWriter.String()
|
||||
require.FailNow(output, "command exited with non-zero error code")
|
||||
}
|
||||
sess.ExpectConnectionStateOnController(ctx, t, testController.Controller().ConnectionRepoFn, session.StatusClosed)
|
||||
}
|
||||
|
||||
// largely copied from controller/testing.go
|
||||
|
||||
@@ -10,12 +10,19 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/testing/controller"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/hashicorp/go-kms-wrapping/v2/aead"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/atomic"
|
||||
@@ -24,26 +31,6 @@ import (
|
||||
const workerBaseConfig = `
|
||||
disable_mlock = true
|
||||
|
||||
telemetry {
|
||||
prometheus_retention_time = "24h"
|
||||
disable_hostname = true
|
||||
}
|
||||
|
||||
controller {
|
||||
name = "dev-controller"
|
||||
description = "A default controller created in dev mode"
|
||||
database {
|
||||
url = "%s"
|
||||
}
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "root"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
key_id = "global_root"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "worker-auth"
|
||||
aead_type = "aes-gcm"
|
||||
@@ -51,75 +38,54 @@ kms "aead" {
|
||||
key_id = "global_worker-auth"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "recovery"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
key_id = "global_recovery"
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "api"
|
||||
address = "127.0.0.1:9203"
|
||||
tls_disable = true
|
||||
cors_enabled = true
|
||||
cors_allowed_origins = ["*"]
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "cluster"
|
||||
address = "127.0.0.1:9204"
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
address = "127.0.0.1:9205"
|
||||
address = "127.0.0.1:9405"
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
const tag1Config = `
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "test"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1:9204"]
|
||||
initial_upstreams = ["%s"]
|
||||
tags {
|
||||
type = ["dev", "local"]
|
||||
}
|
||||
auth_storage_path = "%s"
|
||||
}
|
||||
`
|
||||
|
||||
const tag2Config = `
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "test"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1:9204"]
|
||||
initial_upstreams = ["%s"]
|
||||
tags {
|
||||
foo = ["bar", "baz"]
|
||||
}
|
||||
auth_storage_path = "%s"
|
||||
}
|
||||
`
|
||||
|
||||
func TestServer_ReloadWorkerTags(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
||||
rootWrapper, _ := wrapperWithKey(t)
|
||||
recoveryWrapper, _ := wrapperWithKey(t)
|
||||
workerAuthWrapper, key := wrapperWithKey(t)
|
||||
testController := controller.NewTestController(t, controller.WithWorkerAuthKms(workerAuthWrapper), controller.WithRootKms(rootWrapper), controller.WithRecoveryKms(recoveryWrapper))
|
||||
defer testController.Shutdown()
|
||||
|
||||
authStoragePath, err := os.MkdirTemp("", "")
|
||||
require.NoError(err)
|
||||
t.Cleanup(func() { os.RemoveAll(authStoragePath) })
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
controllerKey, workerAuthKey, recoveryKey := config.DevKeyGeneration()
|
||||
|
||||
cmd := testServerCommand(t, testServerCommandOpts{
|
||||
CreateDevDatabase: true,
|
||||
ControllerKey: controllerKey,
|
||||
UseDevAuthMethod: true,
|
||||
UseDevTarget: true,
|
||||
})
|
||||
defer func() {
|
||||
if cmd.DevDatabaseCleanupFunc != nil {
|
||||
require.NoError(cmd.DevDatabaseCleanupFunc())
|
||||
}
|
||||
}()
|
||||
|
||||
cmd.presetConfig = atomic.NewString(fmt.Sprintf(workerBaseConfig+tag1Config, cmd.DatabaseUrl, controllerKey, workerAuthKey, recoveryKey))
|
||||
cmd := testServerCommand(t, testServerCommandOpts{})
|
||||
cmd.presetConfig = atomic.NewString(fmt.Sprintf(workerBaseConfig+tag1Config, key, testController.ClusterAddrs()[0], filepath.Join(authStoragePath, "tag1")))
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
@@ -138,22 +104,21 @@ func TestServer_ReloadWorkerTags(t *testing.T) {
|
||||
|
||||
fetchWorkerTags := func(name string, key string, values []string) {
|
||||
t.Helper()
|
||||
serversRepo, err := cmd.controller.ServersRepoFn()
|
||||
serversRepo, err := testController.Controller().ServersRepoFn()
|
||||
require.NoError(err)
|
||||
tags, err := serversRepo.ListTagsForServers(cmd.Context, []string{name})
|
||||
w, err := serversRepo.LookupWorkerByName(testController.Context(), name)
|
||||
require.NoError(err)
|
||||
require.Len(tags, 2)
|
||||
require.Equal(key, tags[0].Key)
|
||||
require.Equal(values[0], tags[0].Value)
|
||||
require.Equal(key, tags[1].Key)
|
||||
require.Equal(values[1], tags[1].Value)
|
||||
require.NotNil(w)
|
||||
v, ok := w.CanonicalTags()[key]
|
||||
require.True(ok)
|
||||
require.ElementsMatch(values, v)
|
||||
}
|
||||
|
||||
// Give time to populate up to the controller
|
||||
time.Sleep(10 * time.Second)
|
||||
fetchWorkerTags("dev-worker", "type", []string{"dev", "local"})
|
||||
fetchWorkerTags("test", "type", []string{"dev", "local"})
|
||||
|
||||
cmd.presetConfig.Store(fmt.Sprintf(workerBaseConfig+tag2Config, cmd.DatabaseUrl, controllerKey, workerAuthKey, recoveryKey))
|
||||
cmd.presetConfig.Store(fmt.Sprintf(workerBaseConfig+tag2Config, key, testController.ClusterAddrs()[0], filepath.Join(authStoragePath, "tag2")))
|
||||
|
||||
cmd.SighupCh <- struct{}{}
|
||||
select {
|
||||
@@ -163,9 +128,31 @@ func TestServer_ReloadWorkerTags(t *testing.T) {
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
fetchWorkerTags("dev-worker", "foo", []string{"bar", "baz"})
|
||||
fetchWorkerTags("test", "foo", []string{"bar", "baz"})
|
||||
|
||||
close(cmd.ShutdownCh)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// TestWrapper initializes an AEAD wrapping.Wrapper for testing the oplog
|
||||
func wrapperWithKey(t testing.TB) (wrapping.Wrapper, string) {
|
||||
t.Helper()
|
||||
rootKey := make([]byte, 32)
|
||||
n, err := rand.Read(rootKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != 32 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
root := aead.NewWrapper()
|
||||
_, err = root.SetConfig(context.Background(), wrapping.WithKeyId(base64.StdEncoding.EncodeToString(rootKey)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := root.SetAesGcmKeyBytes(rootKey); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return root, base64.StdEncoding.EncodeToString(rootKey)
|
||||
}
|
||||
@@ -227,19 +227,6 @@ func printItemTable(result api.GenericResult) string {
|
||||
}
|
||||
}
|
||||
|
||||
var workerInfoMaps []map[string]interface{}
|
||||
if len(item.WorkerInfo) > 0 {
|
||||
for _, wi := range item.WorkerInfo {
|
||||
m := map[string]interface{}{
|
||||
"Address": wi.Address,
|
||||
}
|
||||
workerInfoMaps = append(workerInfoMaps, m)
|
||||
}
|
||||
if l := len("Address"); l > maxLength {
|
||||
maxLength = l
|
||||
}
|
||||
}
|
||||
|
||||
ret := []string{
|
||||
"",
|
||||
"Session information:",
|
||||
@@ -275,17 +262,5 @@ func printItemTable(result api.GenericResult) string {
|
||||
}
|
||||
}
|
||||
|
||||
if len(item.WorkerInfo) > 0 {
|
||||
ret = append(ret,
|
||||
fmt.Sprintf(" Worker Info: %s", ""),
|
||||
)
|
||||
for _, m := range workerInfoMaps {
|
||||
ret = append(ret,
|
||||
base.WrapMap(4, maxLength, m),
|
||||
"",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
@@ -112,6 +112,12 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
c.plural = "session"
|
||||
|
||||
@@ -123,7 +123,10 @@ func (c *Command) Run(args []string) int {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
package workerscmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/workers"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
)
|
||||
|
||||
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
|
||||
var helpStr string
|
||||
switch c.Func {
|
||||
case "":
|
||||
return base.WrapForHelpText([]string{
|
||||
"Usage: boundary workers [sub command] [options] [args]",
|
||||
"",
|
||||
" This command allows operations on Boundary worker resources. Example:",
|
||||
"",
|
||||
" Read a worker:",
|
||||
"",
|
||||
` $ boundary workers read -id w_1234567890`,
|
||||
"",
|
||||
" Please see the workers subcommand help for detailed usage information.",
|
||||
})
|
||||
default:
|
||||
helpStr = helpMap[c.Func]()
|
||||
}
|
||||
return helpStr + c.Flags().Help()
|
||||
}
|
||||
|
||||
func (c *Command) printListTable(items []*workers.Worker) string {
|
||||
if len(items) == 0 {
|
||||
return "No workers found"
|
||||
}
|
||||
|
||||
var output []string
|
||||
output = []string{
|
||||
"",
|
||||
"Worker information:",
|
||||
}
|
||||
for i, item := range items {
|
||||
if i > 0 {
|
||||
output = append(output, "")
|
||||
}
|
||||
if item.Id != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" ID: %s", item.Id),
|
||||
)
|
||||
} else {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" ID: %s", "(not available)"),
|
||||
)
|
||||
}
|
||||
if c.FlagRecursive && item.ScopeId != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Scope ID: %s", item.ScopeId),
|
||||
)
|
||||
}
|
||||
if item.Type != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Type: %s", item.Type),
|
||||
)
|
||||
}
|
||||
if item.Version > 0 {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Version: %d", item.Version),
|
||||
)
|
||||
}
|
||||
if item.Name != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Name: %s", item.Name),
|
||||
)
|
||||
}
|
||||
if item.Description != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Description: %s", item.Description),
|
||||
)
|
||||
}
|
||||
if item.Address != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Address: %s", item.Address),
|
||||
)
|
||||
}
|
||||
if !item.LastStatusTime.IsZero() {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Last Status Time: %s", item.LastStatusTime.Format(time.RFC1123)),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
output = append(output,
|
||||
" Authorized Actions:",
|
||||
base.WrapSlice(6, item.AuthorizedActions),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(output)
|
||||
}
|
||||
|
||||
func printItemTable(result api.GenericResult) string {
|
||||
item := result.GetItem().(*workers.Worker)
|
||||
nonAttributeMap := map[string]interface{}{}
|
||||
if item.Id != "" {
|
||||
nonAttributeMap["ID"] = item.Id
|
||||
}
|
||||
if item.Version != 0 {
|
||||
nonAttributeMap["Version"] = item.Version
|
||||
}
|
||||
if !item.CreatedTime.IsZero() {
|
||||
nonAttributeMap["Created Time"] = item.CreatedTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if !item.UpdatedTime.IsZero() {
|
||||
nonAttributeMap["Updated Time"] = item.UpdatedTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if item.Name != "" {
|
||||
nonAttributeMap["Name"] = item.Name
|
||||
}
|
||||
if item.Description != "" {
|
||||
nonAttributeMap["Description"] = item.Description
|
||||
}
|
||||
if item.Type != "" {
|
||||
nonAttributeMap["Type"] = item.Type
|
||||
}
|
||||
if item.Address != "" {
|
||||
nonAttributeMap["Address"] = item.Address
|
||||
}
|
||||
if !item.LastStatusTime.IsZero() {
|
||||
nonAttributeMap["Last Status Time"] = item.LastStatusTime
|
||||
}
|
||||
|
||||
resultMap := result.GetResponse().Map
|
||||
if count, ok := resultMap[globals.ActiveConnectionCountField]; ok {
|
||||
nonAttributeMap["Active Connection Count"] = count
|
||||
}
|
||||
|
||||
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
|
||||
|
||||
ret := []string{
|
||||
"",
|
||||
"Worker information:",
|
||||
base.WrapMap(2, maxLength+2, nonAttributeMap),
|
||||
}
|
||||
|
||||
if item.Scope != nil {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Scope:",
|
||||
base.ScopeInfoForOutput(item.Scope, maxLength),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.CanonicalTags) > 0 || len(item.ConfigTags) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Tags:",
|
||||
)
|
||||
if len(item.ConfigTags) > 0 {
|
||||
tagMap := make(map[string]any, len(item.ConfigTags))
|
||||
for k, v := range item.ConfigTags {
|
||||
tagMap[k] = v
|
||||
}
|
||||
ret = append(ret,
|
||||
" Worker Configuration:",
|
||||
base.WrapMap(6, 2, tagMap),
|
||||
)
|
||||
}
|
||||
if len(item.CanonicalTags) > 0 {
|
||||
tagMap := make(map[string]any, len(item.CanonicalTags))
|
||||
for k, v := range item.CanonicalTags {
|
||||
tagMap[k] = v
|
||||
}
|
||||
ret = append(ret,
|
||||
" Canonical:",
|
||||
base.WrapMap(6, 2, tagMap),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Authorized Actions:",
|
||||
base.WrapSlice(4, item.AuthorizedActions),
|
||||
)
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package workerscmd
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/workers"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
)
|
||||
|
||||
func init() {
|
||||
extraWorkerLedActionsFlagsMapFunc = extraWorkerLedActionsFlagsMapFuncImpl
|
||||
extraWorkerLedFlagsFunc = extraWorkerLedFlagsFuncImpl
|
||||
executeExtraWorkerLedActions = executeExtraWorkerLedActionsImpl
|
||||
}
|
||||
|
||||
type extraWorkerLedCmdVars struct {
|
||||
flagWorkerGeneratedAuthToken string
|
||||
}
|
||||
|
||||
func extraWorkerLedActionsFlagsMapFuncImpl() map[string][]string {
|
||||
return map[string][]string{
|
||||
"create": {"worker-generated-auth-token"},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) extraWorkerLedHelpFunc(helpMap map[string]func() string) string {
|
||||
var helpStr string
|
||||
switch c.Func {
|
||||
case "create":
|
||||
helpStr = base.WrapForHelpText([]string{
|
||||
"Usage: boundary workers create worker-led [options] [args]",
|
||||
"",
|
||||
" Create a worker using the worker-led approach by providing an auth token from the worker. Example:",
|
||||
"",
|
||||
` $ boundary workers create worker-led -name us-east-1-1 -worker-generated-auth-token <token>"`,
|
||||
"",
|
||||
"",
|
||||
})
|
||||
}
|
||||
return helpStr + c.Flags().Help()
|
||||
}
|
||||
|
||||
func extraWorkerLedFlagsFuncImpl(c *WorkerLedCommand, set *base.FlagSets, f *base.FlagSet) {
|
||||
f = set.NewFlagSet("Worker Creation Options")
|
||||
|
||||
for _, name := range flagsWorkerLedMap[c.Func] {
|
||||
switch name {
|
||||
case "worker-generated-auth-token":
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "worker-generated-auth-token",
|
||||
Target: &c.flagWorkerGeneratedAuthToken,
|
||||
Usage: "The auth token provided by the worker to use to register it to Boundary",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func executeExtraWorkerLedActionsImpl(c *WorkerLedCommand, origResult api.GenericResult, origError error, workerClient *workers.Client, version uint32, opts []workers.Option) (api.GenericResult, error) {
|
||||
switch c.Func {
|
||||
case "create":
|
||||
return workerClient.CreateWorkerLed(c.Context, c.flagWorkerGeneratedAuthToken, c.FlagScopeId, opts...)
|
||||
}
|
||||
return origResult, origError
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
// 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 initWorkerLedFlags() {
|
||||
flagsOnce.Do(func() {
|
||||
extraFlags := extraWorkerLedActionsFlagsMapFunc()
|
||||
for k, v := range extraFlags {
|
||||
flagsWorkerLedMap[k] = append(flagsWorkerLedMap[k], v...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
_ cli.Command = (*WorkerLedCommand)(nil)
|
||||
_ cli.CommandAutocomplete = (*WorkerLedCommand)(nil)
|
||||
)
|
||||
|
||||
type WorkerLedCommand struct {
|
||||
*base.Command
|
||||
|
||||
Func string
|
||||
|
||||
plural string
|
||||
|
||||
extraWorkerLedCmdVars
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) AutocompleteArgs() complete.Predictor {
|
||||
initWorkerLedFlags()
|
||||
return complete.PredictAnything
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) AutocompleteFlags() complete.Flags {
|
||||
initWorkerLedFlags()
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) Synopsis() string {
|
||||
if extra := extraWorkerLedSynopsisFunc(c); extra != "" {
|
||||
return extra
|
||||
}
|
||||
|
||||
synopsisStr := "worker"
|
||||
|
||||
synopsisStr = fmt.Sprintf("%s %s", "worker-led-type", synopsisStr)
|
||||
|
||||
return common.SynopsisFunc(c.Func, synopsisStr)
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) Help() string {
|
||||
initWorkerLedFlags()
|
||||
|
||||
var helpStr string
|
||||
helpMap := common.HelpMap("worker")
|
||||
|
||||
switch c.Func {
|
||||
|
||||
default:
|
||||
|
||||
helpStr = c.extraWorkerLedHelpFunc(helpMap)
|
||||
|
||||
}
|
||||
|
||||
// Keep linter from complaining if we don't actually generate code using it
|
||||
_ = helpMap
|
||||
return helpStr
|
||||
}
|
||||
|
||||
var flagsWorkerLedMap = map[string][]string{
|
||||
|
||||
"create": {"scope-id", "name", "description"},
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) Flags() *base.FlagSets {
|
||||
if len(flagsWorkerLedMap[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, "worker-led-type worker", flagsWorkerLedMap, c.Func)
|
||||
|
||||
extraWorkerLedFlagsFunc(c, set, f)
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *WorkerLedCommand) Run(args []string) int {
|
||||
initWorkerLedFlags()
|
||||
|
||||
switch c.Func {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
c.plural = "worker-led-type worker"
|
||||
switch c.Func {
|
||||
case "list":
|
||||
c.plural = "worker-led-type workers"
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
if strutil.StrListContains(flagsWorkerLedMap[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(flagsWorkerLedMap[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 := extraWorkerLedFlagsHandlingFunc(c, f, &opts); !ok {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var result api.GenericResult
|
||||
|
||||
switch c.Func {
|
||||
|
||||
}
|
||||
|
||||
result, err = executeExtraWorkerLedActions(c, result, err, workersClient, version, opts)
|
||||
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil {
|
||||
var opts []base.Option
|
||||
|
||||
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural), opts...)
|
||||
return base.CommandApiError
|
||||
}
|
||||
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
output, err := printCustomWorkerLedActionOutput(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(result))
|
||||
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(result); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
var (
|
||||
extraWorkerLedActionsFlagsMapFunc = func() map[string][]string { return nil }
|
||||
extraWorkerLedSynopsisFunc = func(*WorkerLedCommand) string { return "" }
|
||||
extraWorkerLedFlagsFunc = func(*WorkerLedCommand, *base.FlagSets, *base.FlagSet) {}
|
||||
extraWorkerLedFlagsHandlingFunc = func(*WorkerLedCommand, *base.FlagSets, *[]workers.Option) bool { return true }
|
||||
executeExtraWorkerLedActions = func(_ *WorkerLedCommand, inResult api.GenericResult, inErr error, _ *workers.Client, _ uint32, _ []workers.Option) (api.GenericResult, error) {
|
||||
return inResult, inErr
|
||||
}
|
||||
printCustomWorkerLedActionOutput = func(*WorkerLedCommand) (bool, error) { return false, nil }
|
||||
)
|
||||
@@ -0,0 +1,314 @@
|
||||
// Code generated by "make cli"; DO NOT EDIT.
|
||||
package workerscmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"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 initFlags() {
|
||||
flagsOnce.Do(func() {
|
||||
extraFlags := extraActionsFlagsMapFunc()
|
||||
for k, v := range extraFlags {
|
||||
flagsMap[k] = append(flagsMap[k], v...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
_ cli.Command = (*Command)(nil)
|
||||
_ cli.CommandAutocomplete = (*Command)(nil)
|
||||
)
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
|
||||
Func string
|
||||
|
||||
plural string
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteArgs() complete.Predictor {
|
||||
initFlags()
|
||||
return complete.PredictAnything
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteFlags() complete.Flags {
|
||||
initFlags()
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
if extra := extraSynopsisFunc(c); extra != "" {
|
||||
return extra
|
||||
}
|
||||
|
||||
synopsisStr := "worker"
|
||||
|
||||
return common.SynopsisFunc(c.Func, synopsisStr)
|
||||
}
|
||||
|
||||
func (c *Command) Help() string {
|
||||
initFlags()
|
||||
|
||||
var helpStr string
|
||||
helpMap := common.HelpMap("worker")
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "read":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
case "update":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
case "delete":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
case "list":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
default:
|
||||
|
||||
helpStr = c.extraHelpFunc(helpMap)
|
||||
|
||||
}
|
||||
|
||||
// Keep linter from complaining if we don't actually generate code using it
|
||||
_ = helpMap
|
||||
return helpStr
|
||||
}
|
||||
|
||||
var flagsMap = map[string][]string{
|
||||
|
||||
"read": {"id"},
|
||||
|
||||
"update": {"id", "name", "description", "version"},
|
||||
|
||||
"delete": {"id"},
|
||||
|
||||
"list": {"scope-id", "filter", "recursive"},
|
||||
}
|
||||
|
||||
func (c *Command) Flags() *base.FlagSets {
|
||||
if len(flagsMap[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, "worker", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
initFlags()
|
||||
|
||||
switch c.Func {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
c.plural = "worker"
|
||||
switch c.Func {
|
||||
case "list":
|
||||
c.plural = "workers"
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
if strutil.StrListContains(flagsMap[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(flagsMap[c.Func], "scope-id") {
|
||||
switch c.Func {
|
||||
|
||||
case "list":
|
||||
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
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "update":
|
||||
switch c.FlagVersion {
|
||||
case 0:
|
||||
opts = append(opts, workers.WithAutomaticVersioning(true))
|
||||
default:
|
||||
version = uint32(c.FlagVersion)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ok := extraFlagsHandlingFunc(c, f, &opts); !ok {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var result api.GenericResult
|
||||
|
||||
var listResult api.GenericListResult
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "read":
|
||||
result, err = workersClient.Read(c.Context, c.FlagId, opts...)
|
||||
|
||||
case "update":
|
||||
result, err = workersClient.Update(c.Context, c.FlagId, version, opts...)
|
||||
|
||||
case "delete":
|
||||
result, err = workersClient.Delete(c.Context, c.FlagId, opts...)
|
||||
|
||||
case "list":
|
||||
listResult, err = workersClient.List(c.Context, c.FlagScopeId, opts...)
|
||||
|
||||
}
|
||||
|
||||
result, err = executeExtraActions(c, result, err, workersClient, version, opts)
|
||||
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil {
|
||||
var opts []base.Option
|
||||
|
||||
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural), opts...)
|
||||
return base.CommandApiError
|
||||
}
|
||||
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
output, err := printCustomActionOutput(c)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
if output {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "delete":
|
||||
switch base.Format(c.UI) {
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(result); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
case "table":
|
||||
c.UI.Output("The delete operation completed successfully.")
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
case "list":
|
||||
switch base.Format(c.UI) {
|
||||
case "json":
|
||||
if ok := c.PrintJsonItems(listResult); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
case "table":
|
||||
listedItems := listResult.GetItems().([]*workers.Worker)
|
||||
c.UI.Output(c.printListTable(listedItems))
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
}
|
||||
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(printItemTable(result))
|
||||
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(result); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
var (
|
||||
flagsOnce = new(sync.Once)
|
||||
|
||||
extraActionsFlagsMapFunc = func() map[string][]string { return nil }
|
||||
extraSynopsisFunc = func(*Command) string { return "" }
|
||||
extraFlagsFunc = func(*Command, *base.FlagSets, *base.FlagSet) {}
|
||||
extraFlagsHandlingFunc = func(*Command, *base.FlagSets, *[]workers.Option) bool { return true }
|
||||
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *workers.Client, _ uint32, _ []workers.Option) (api.GenericResult, error) {
|
||||
return inResult, inErr
|
||||
}
|
||||
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
|
||||
)
|
||||
@@ -38,6 +38,7 @@ func HelpMap(resType string) map[string]func() string {
|
||||
resource.Host.String(): "h",
|
||||
resource.Session.String(): "s",
|
||||
resource.Target.String(): "t",
|
||||
resource.Worker.String(): "w",
|
||||
}
|
||||
return map[string]func() string{
|
||||
"base": func() string {
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/base62"
|
||||
configutil "github.com/hashicorp/go-secure-stdlib/configutil/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
@@ -57,6 +57,13 @@ kms "aead" {
|
||||
key_id = "global_worker-auth"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "worker-auth-storage"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
key_id = "global_worker-auth-storage"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "recovery"
|
||||
aead_type = "aes-gcm"
|
||||
@@ -87,9 +94,9 @@ listener "tcp" {
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags {
|
||||
type = ["dev", "local"]
|
||||
}
|
||||
@@ -105,17 +112,21 @@ type Config struct {
|
||||
Controller *Controller `hcl:"controller"`
|
||||
|
||||
// Dev-related options
|
||||
DevController bool `hcl:"-"`
|
||||
DevUiPassthroughDir string `hcl:"-"`
|
||||
DevControllerKey string `hcl:"-"`
|
||||
DevWorkerAuthKey string `hcl:"-"`
|
||||
DevRecoveryKey string `hcl:"-"`
|
||||
DevController bool `hcl:"-"`
|
||||
DevUiPassthroughDir string `hcl:"-"`
|
||||
DevControllerKey string `hcl:"-"`
|
||||
DevWorkerAuthKey string `hcl:"-"`
|
||||
DevWorkerAuthStorageKey string `hcl:"-"`
|
||||
DevRecoveryKey string `hcl:"-"`
|
||||
|
||||
// Eventing configuration for the controller
|
||||
Eventing *event.EventerConfig `hcl:"events"`
|
||||
|
||||
// Plugin-related options
|
||||
Plugins Plugins `hcl:"plugins"`
|
||||
|
||||
// Internal field for use with HCP deployments. Used if controllers/ initial_upstreams is not set
|
||||
HCPBClusterId string `hcl:"hcp_boundary_cluster_id"`
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
@@ -170,8 +181,12 @@ type Worker struct {
|
||||
|
||||
// We use a raw interface here so that we can take in a string
|
||||
// value pointing to an env var or file. We then resolve that
|
||||
// and get the actual controller addresses.
|
||||
Controllers []string `hcl:"-"`
|
||||
// and get the actual upstream controller or worker addresses.
|
||||
InitialUpstreams []string `hcl:"-"`
|
||||
InitialUpstreamsRaw any `hcl:"initial_upstreams"`
|
||||
|
||||
// The ControllersRaw field is deprecated and users should use InitialUpstreamsRaw instead.
|
||||
// TODO: remove this field when support is discontinued.
|
||||
ControllersRaw interface{} `hcl:"controllers"`
|
||||
|
||||
// We use a raw interface for parsing so that people can use JSON-like
|
||||
@@ -187,6 +202,9 @@ type Worker struct {
|
||||
//
|
||||
// TODO: This field is currently internal.
|
||||
StatusGracePeriodDuration time.Duration `hcl:"-"`
|
||||
|
||||
// AuthStoragePath represents the location a worker stores its node credentials, if set
|
||||
AuthStoragePath string `hcl:"auth_storage_path"`
|
||||
}
|
||||
|
||||
func (w *Worker) InitNameIfEmpty() (string, error) {
|
||||
@@ -202,9 +220,10 @@ func (w *Worker) InitNameIfEmpty() (string, error) {
|
||||
func initNameIfEmpty(name *string) error {
|
||||
if *name == "" {
|
||||
var err error
|
||||
if *name, err = base62.Random(10); err != nil {
|
||||
if *name, err = db.NewPublicId("w"); err != nil {
|
||||
return err
|
||||
}
|
||||
*name = strings.ToLower(*name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -230,8 +249,8 @@ func DevWorker() (*Config, error) {
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func DevKeyGeneration() (string, string, string) {
|
||||
var numBytes int64 = 96
|
||||
func DevKeyGeneration() string {
|
||||
var numBytes int64 = 32
|
||||
randBuf := new(bytes.Buffer)
|
||||
n, err := randBuf.ReadFrom(&io.LimitedReader{
|
||||
R: rand.Reader,
|
||||
@@ -241,21 +260,21 @@ func DevKeyGeneration() (string, string, string) {
|
||||
panic(err)
|
||||
}
|
||||
if n != numBytes {
|
||||
panic(fmt.Errorf("expected to read 64 bytes, read %d", n))
|
||||
panic(fmt.Errorf("expected to read 32 bytes, read %d", n))
|
||||
}
|
||||
controllerKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[0:32])
|
||||
workerAuthKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[32:64])
|
||||
recoveryKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[64:numBytes])
|
||||
|
||||
return controllerKey, workerAuthKey, recoveryKey
|
||||
devKey := base64.StdEncoding.EncodeToString(randBuf.Bytes())[:numBytes]
|
||||
return devKey
|
||||
}
|
||||
|
||||
// DevController is a Config that is used for dev mode of Boundary
|
||||
// controllers
|
||||
func DevController() (*Config, error) {
|
||||
controllerKey, workerAuthKey, recoveryKey := DevKeyGeneration()
|
||||
controllerKey := DevKeyGeneration()
|
||||
workerAuthKey := DevKeyGeneration()
|
||||
workerAuthStorageKey := DevKeyGeneration()
|
||||
recoveryKey := DevKeyGeneration()
|
||||
|
||||
hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, recoveryKey)
|
||||
hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, workerAuthStorageKey, recoveryKey)
|
||||
parsed, err := Parse(hclStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing dev config: %w", err)
|
||||
@@ -263,13 +282,17 @@ func DevController() (*Config, error) {
|
||||
parsed.DevController = true
|
||||
parsed.DevControllerKey = controllerKey
|
||||
parsed.DevWorkerAuthKey = workerAuthKey
|
||||
parsed.DevWorkerAuthStorageKey = workerAuthStorageKey
|
||||
parsed.DevRecoveryKey = recoveryKey
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func DevCombined() (*Config, error) {
|
||||
controllerKey, workerAuthKey, recoveryKey := DevKeyGeneration()
|
||||
hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, recoveryKey)
|
||||
controllerKey := DevKeyGeneration()
|
||||
workerAuthKey := DevKeyGeneration()
|
||||
workerAuthStorageKey := DevKeyGeneration()
|
||||
recoveryKey := DevKeyGeneration()
|
||||
hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, workerAuthStorageKey, recoveryKey)
|
||||
parsed, err := Parse(hclStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing dev config: %w", err)
|
||||
@@ -277,6 +300,7 @@ func DevCombined() (*Config, error) {
|
||||
parsed.DevController = true
|
||||
parsed.DevControllerKey = controllerKey
|
||||
parsed.DevWorkerAuthKey = workerAuthKey
|
||||
parsed.DevWorkerAuthStorageKey = workerAuthStorageKey
|
||||
parsed.DevRecoveryKey = recoveryKey
|
||||
return parsed, nil
|
||||
}
|
||||
@@ -505,9 +529,9 @@ func Parse(d string) (*Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
result.Worker.Controllers, err = parseWorkerControllers(result)
|
||||
result.Worker.InitialUpstreams, err = parseWorkerUpstreams(result)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse worker controllers: %w", err)
|
||||
return nil, fmt.Errorf("Failed to parse worker upstreams: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,35 +591,52 @@ func Parse(d string) (*Config, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseWorkerControllers(c *Config) ([]string, error) {
|
||||
// supportControllersRawConfig returns either initialUpstreamsRaw or controllersRaw depending on which is populated. Errors when both fields are populated.
|
||||
//
|
||||
func supportControllersRawConfig(initialUpstreamsRaw, controllersRaw any) (any, error) {
|
||||
switch {
|
||||
case initialUpstreamsRaw == nil && controllersRaw != nil:
|
||||
return controllersRaw, nil
|
||||
case initialUpstreamsRaw != nil && controllersRaw != nil:
|
||||
return nil, fmt.Errorf("both initial_upstreams and controllers fields are populated")
|
||||
}
|
||||
return initialUpstreamsRaw, nil
|
||||
}
|
||||
|
||||
func parseWorkerUpstreams(c *Config) ([]string, error) {
|
||||
if c == nil || c.Worker == nil {
|
||||
return nil, fmt.Errorf("config or worker field is nil")
|
||||
}
|
||||
if c.Worker.ControllersRaw == nil {
|
||||
if c.Worker.InitialUpstreamsRaw == nil && c.Worker.ControllersRaw == nil {
|
||||
// return nil here so that other address sources can be provided outside of config
|
||||
return nil, nil
|
||||
}
|
||||
rawUpstreams, err := supportControllersRawConfig(c.Worker.InitialUpstreamsRaw, c.Worker.ControllersRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch t := c.Worker.ControllersRaw.(type) {
|
||||
switch t := rawUpstreams.(type) {
|
||||
case []interface{}: // An array was configured directly in Boundary's HCL Config file.
|
||||
var controllers []string
|
||||
err := mapstructure.WeakDecode(c.Worker.ControllersRaw, &controllers)
|
||||
var upstreams []string
|
||||
err := mapstructure.WeakDecode(rawUpstreams, &upstreams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode worker controllers block into config field: %w", err)
|
||||
return nil, fmt.Errorf("failed to decode worker initial_upstreams block into config field: %w", err)
|
||||
}
|
||||
return controllers, nil
|
||||
return upstreams, nil
|
||||
|
||||
case string:
|
||||
controllersStr, err := parseutil.ParsePath(t)
|
||||
upstreamsStr, err := parseutil.ParsePath(t)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bad env var or file pointer: %w", err)
|
||||
}
|
||||
|
||||
var addrs []string
|
||||
err = json.Unmarshal([]byte(controllersStr), &addrs)
|
||||
var upstreams []string
|
||||
err = json.Unmarshal([]byte(upstreamsStr), &upstreams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal env/file contents: %w", err)
|
||||
}
|
||||
return addrs, nil
|
||||
return upstreams, nil
|
||||
|
||||
default:
|
||||
typ := reflect.TypeOf(t)
|
||||
|
||||
@@ -61,6 +61,14 @@ func TestDevController(t *testing.T) {
|
||||
"key_id": "global_worker-auth",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "aead",
|
||||
Purpose: []string{"worker-auth-storage"},
|
||||
Config: map[string]string{
|
||||
"aead_type": "aes-gcm",
|
||||
"key_id": "global_worker-auth-storage",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "aead",
|
||||
Purpose: []string{"recovery"},
|
||||
@@ -84,9 +92,11 @@ func TestDevController(t *testing.T) {
|
||||
exp.Seals[0].Config["key"] = actual.Seals[0].Config["key"]
|
||||
exp.Seals[1].Config["key"] = actual.Seals[1].Config["key"]
|
||||
exp.Seals[2].Config["key"] = actual.Seals[2].Config["key"]
|
||||
exp.Seals[3].Config["key"] = actual.Seals[3].Config["key"]
|
||||
exp.DevControllerKey = actual.Seals[0].Config["key"]
|
||||
exp.DevWorkerAuthKey = actual.Seals[1].Config["key"]
|
||||
exp.DevRecoveryKey = actual.Seals[2].Config["key"]
|
||||
exp.DevWorkerAuthStorageKey = actual.Seals[2].Config["key"]
|
||||
exp.DevRecoveryKey = actual.Seals[3].Config["key"]
|
||||
|
||||
assert.Equal(t, exp, actual)
|
||||
|
||||
@@ -180,10 +190,10 @@ func TestDevWorker(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Worker: &Worker{
|
||||
Name: "dev-worker",
|
||||
Description: "A default worker created in dev mode",
|
||||
Controllers: []string{"127.0.0.1"},
|
||||
ControllersRaw: []interface{}{"127.0.0.1"},
|
||||
Name: "w_1234567890",
|
||||
Description: "A default worker created in dev mode",
|
||||
InitialUpstreams: []string{"127.0.0.1"},
|
||||
InitialUpstreamsRaw: []interface{}{"127.0.0.1"},
|
||||
Tags: map[string][]string{
|
||||
"type": {"dev", "local"},
|
||||
},
|
||||
@@ -201,9 +211,9 @@ func TestDevWorker(t *testing.T) {
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags = ["type=dev", "type=local"]
|
||||
}
|
||||
`
|
||||
@@ -221,9 +231,9 @@ func TestDevWorker(t *testing.T) {
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags {
|
||||
type = "local"
|
||||
}
|
||||
@@ -246,9 +256,9 @@ func TestDevWorker(t *testing.T) {
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags = ["tyPe=dev", "type=local"]
|
||||
}
|
||||
`
|
||||
@@ -263,9 +273,9 @@ func TestDevWorker(t *testing.T) {
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "dev-worker"
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags = ["type=dev", "type=loCal"]
|
||||
}
|
||||
`
|
||||
@@ -282,7 +292,7 @@ func TestDevWorker(t *testing.T) {
|
||||
worker {
|
||||
name = "dev-work\u0000er"
|
||||
description = "A default worker created in dev mode"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags = ["type=dev", "type=local"]
|
||||
}
|
||||
`
|
||||
@@ -291,6 +301,170 @@ func TestDevWorker(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestDevCombined(t *testing.T) {
|
||||
actual, err := DevCombined()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
truePointer := new(bool)
|
||||
*truePointer = true
|
||||
exp := &Config{
|
||||
Eventing: event.DefaultEventerConfig(),
|
||||
SharedConfig: &configutil.SharedConfig{
|
||||
DisableMlock: true,
|
||||
Listeners: []*listenerutil.ListenerConfig{
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"api"},
|
||||
TLSDisable: true,
|
||||
CorsEnabled: truePointer,
|
||||
CorsAllowedOrigins: []string{"*"},
|
||||
},
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"cluster"},
|
||||
},
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"ops"},
|
||||
TLSDisable: true,
|
||||
},
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"proxy"},
|
||||
},
|
||||
},
|
||||
Seals: []*configutil.KMS{
|
||||
{
|
||||
Type: "aead",
|
||||
Purpose: []string{"root"},
|
||||
Config: map[string]string{
|
||||
"aead_type": "aes-gcm",
|
||||
"key_id": "global_root",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "aead",
|
||||
Purpose: []string{"worker-auth"},
|
||||
Config: map[string]string{
|
||||
"aead_type": "aes-gcm",
|
||||
"key_id": "global_worker-auth",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "aead",
|
||||
Purpose: []string{"worker-auth-storage"},
|
||||
Config: map[string]string{
|
||||
"aead_type": "aes-gcm",
|
||||
"key_id": "global_worker-auth-storage",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "aead",
|
||||
Purpose: []string{"recovery"},
|
||||
Config: map[string]string{
|
||||
"aead_type": "aes-gcm",
|
||||
"key_id": "global_recovery",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Controller: &Controller{
|
||||
Name: "dev-controller",
|
||||
Description: "A default controller created in dev mode",
|
||||
},
|
||||
DevController: true,
|
||||
Worker: &Worker{
|
||||
Name: "w_1234567890",
|
||||
Description: "A default worker created in dev mode",
|
||||
InitialUpstreams: []string{"127.0.0.1"},
|
||||
InitialUpstreamsRaw: []interface{}{"127.0.0.1"},
|
||||
Tags: map[string][]string{
|
||||
"type": {"dev", "local"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig
|
||||
exp.Listeners[1].RawConfig = actual.Listeners[1].RawConfig
|
||||
exp.Listeners[2].RawConfig = actual.Listeners[2].RawConfig
|
||||
exp.Listeners[3].RawConfig = actual.Listeners[3].RawConfig
|
||||
exp.Seals[0].Config["key"] = actual.Seals[0].Config["key"]
|
||||
exp.Seals[1].Config["key"] = actual.Seals[1].Config["key"]
|
||||
exp.Seals[2].Config["key"] = actual.Seals[2].Config["key"]
|
||||
exp.Seals[3].Config["key"] = actual.Seals[3].Config["key"]
|
||||
exp.DevControllerKey = actual.Seals[0].Config["key"]
|
||||
exp.DevWorkerAuthKey = actual.Seals[1].Config["key"]
|
||||
exp.DevWorkerAuthStorageKey = actual.Seals[2].Config["key"]
|
||||
exp.DevRecoveryKey = actual.Seals[3].Config["key"]
|
||||
exp.Worker.TagsRaw = actual.Worker.TagsRaw
|
||||
assert.Equal(t, exp, actual)
|
||||
}
|
||||
|
||||
func TestDevWorkerCredentialStorageDir(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
devWorkerProvidedConfiguration string
|
||||
storagePath string
|
||||
}{
|
||||
{
|
||||
name: "Relative Storage Directory",
|
||||
devWorkerProvidedConfiguration: `
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags {
|
||||
type = ["dev", "local"]
|
||||
}
|
||||
auth_storage_path = ".."
|
||||
}
|
||||
`,
|
||||
storagePath: "..",
|
||||
},
|
||||
{
|
||||
name: "Nonexistent Storage Directory",
|
||||
devWorkerProvidedConfiguration: `
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
}
|
||||
|
||||
worker {
|
||||
name = "w_1234567890"
|
||||
description = "A default worker created in dev mode"
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
tags {
|
||||
type = ["dev", "local"]
|
||||
}
|
||||
auth_storage_path = "nonexistent_dir/here"
|
||||
}
|
||||
`,
|
||||
storagePath: "nonexistent_dir/here",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parsed, err := Parse(devConfig + tt.devWorkerProvidedConfiguration)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.storagePath, parsed.Worker.AuthStoragePath)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevKeyGeneration(t *testing.T) {
|
||||
t.Parallel()
|
||||
dk := DevKeyGeneration()
|
||||
numBytes := 32
|
||||
require.Equal(t, numBytes, len(dk))
|
||||
require.NotEqual(t, dk, DevKeyGeneration())
|
||||
}
|
||||
|
||||
func TestParsingName(t *testing.T) {
|
||||
t.Parallel()
|
||||
config := `
|
||||
@@ -315,18 +489,18 @@ func TestParsingName(t *testing.T) {
|
||||
{
|
||||
name: "no env",
|
||||
templateController: "foobar",
|
||||
templateWorker: "barfoo",
|
||||
templateWorker: "test_worker_barfoo",
|
||||
expectedController: "foobar",
|
||||
expectedWorker: "barfoo",
|
||||
expectedWorker: "test_worker_barfoo",
|
||||
},
|
||||
{
|
||||
name: "env",
|
||||
templateController: fmt.Sprintf("env://%s", controllerEnv),
|
||||
templateWorker: fmt.Sprintf("env://%s", workerEnv),
|
||||
envController: "foobar2",
|
||||
envWorker: "barfoo2",
|
||||
envWorker: "env_name_barfoo2",
|
||||
expectedController: "foobar2",
|
||||
expectedWorker: "barfoo2",
|
||||
expectedWorker: "env_name_barfoo2",
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
@@ -390,7 +564,7 @@ func TestWorkerTags(t *testing.T) {
|
||||
name: "no tags",
|
||||
in: `
|
||||
worker {
|
||||
name = "testworker"
|
||||
name = "w_1234567890"
|
||||
}
|
||||
`,
|
||||
expWorkerTags: nil,
|
||||
@@ -400,7 +574,7 @@ func TestWorkerTags(t *testing.T) {
|
||||
name: "empty tags",
|
||||
in: `
|
||||
worker {
|
||||
name = "testworker"
|
||||
name = "w_1234567890"
|
||||
tags = {}
|
||||
}
|
||||
`,
|
||||
@@ -411,7 +585,7 @@ func TestWorkerTags(t *testing.T) {
|
||||
name: "empty tags 2",
|
||||
in: `
|
||||
worker {
|
||||
name = "testworker"
|
||||
name = "w_1234567890"
|
||||
tags = []
|
||||
}
|
||||
`,
|
||||
@@ -865,118 +1039,152 @@ func TestController_EventingConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkerControllers(t *testing.T) {
|
||||
func TestWorkerUpstreams(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
stateFn func(t *testing.T)
|
||||
expWorkerControllers []string
|
||||
expErr bool
|
||||
expErrIs error
|
||||
expErrStr string
|
||||
name string
|
||||
in string
|
||||
stateFn func(t *testing.T)
|
||||
expWorkerUpstreams []string
|
||||
expErr bool
|
||||
expErrIs error
|
||||
expErrStr string
|
||||
}{
|
||||
{
|
||||
name: "No Controllers",
|
||||
name: "No Upstreams",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
}
|
||||
`,
|
||||
expWorkerControllers: nil,
|
||||
expErr: false,
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "One Controller",
|
||||
name: "One Upstream",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
}
|
||||
`,
|
||||
expWorkerControllers: []string{"127.0.0.1"},
|
||||
expErr: false,
|
||||
expWorkerUpstreams: []string{"127.0.0.1"},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "Multiple controllers",
|
||||
name: "Multiple Upstreams",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = ["127.0.0.1", "127.0.0.2", "127.0.0.3"]
|
||||
initial_upstreams = ["127.0.0.1", "127.0.0.2", "127.0.0.3"]
|
||||
}
|
||||
`,
|
||||
expWorkerControllers: []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"},
|
||||
expErr: false,
|
||||
expWorkerUpstreams: []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "Using env var",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = "env://BOUNDARY_WORKER_CONTROLLERS"
|
||||
initial_upstreams = "env://BOUNDARY_WORKER_UPSTREAMS"
|
||||
}
|
||||
`,
|
||||
stateFn: func(t *testing.T) { t.Setenv("BOUNDARY_WORKER_CONTROLLERS", `["127.0.0.1", "127.0.0.2", "127.0.0.3"]`) },
|
||||
expWorkerControllers: []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"},
|
||||
expErr: false,
|
||||
stateFn: func(t *testing.T) { t.Setenv("BOUNDARY_WORKER_UPSTREAMS", `["127.0.0.1", "127.0.0.2", "127.0.0.3"]`) },
|
||||
expWorkerUpstreams: []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "Using env var - invalid input 1",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = "env://BOUNDARY_WORKER_CONTROLLERS"
|
||||
initial_upstreams = "env://BOUNDARY_WORKER_UPSTREAMS"
|
||||
}
|
||||
`,
|
||||
stateFn: func(t *testing.T) {
|
||||
controllers := `
|
||||
upstreams := `
|
||||
worker {
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
}
|
||||
`
|
||||
t.Setenv("BOUNDARY_WORKER_CONTROLLERS", controllers)
|
||||
t.Setenv("BOUNDARY_WORKER_UPSTREAMS", upstreams)
|
||||
},
|
||||
expWorkerControllers: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker controllers: failed to unmarshal env/file contents: invalid character 'w' looking for beginning of value",
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker upstreams: failed to unmarshal env/file contents: invalid character 'w' looking for beginning of value",
|
||||
},
|
||||
{
|
||||
name: "Using env var - invalid input 2",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = "env://BOUNDARY_WORKER_CONTROLLERS"
|
||||
initial_upstreams = "env://BOUNDARY_WORKER_UPSTREAMS"
|
||||
}
|
||||
`,
|
||||
stateFn: func(t *testing.T) { t.Setenv("BOUNDARY_WORKER_CONTROLLERS", `controllers = ["127.0.0.1"]`) },
|
||||
expWorkerControllers: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker controllers: failed to unmarshal env/file contents: invalid character 'c' looking for beginning of value",
|
||||
stateFn: func(t *testing.T) { t.Setenv("BOUNDARY_WORKER_UPSTREAMS", `initial_upstreams = ["127.0.0.1"]`) },
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker upstreams: failed to unmarshal env/file contents: invalid character 'i' looking for beginning of value",
|
||||
},
|
||||
{
|
||||
name: "Unsupported object",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = {
|
||||
initial_upstreams = {
|
||||
ip = "127.0.0.1"
|
||||
ip = "127.0.0.2"
|
||||
}
|
||||
}
|
||||
`,
|
||||
expWorkerControllers: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker controllers: unexpected type \"[]map[string]interface {}\"",
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker upstreams: unexpected type \"[]map[string]interface {}\"",
|
||||
},
|
||||
{
|
||||
name: "worker controllers set to invalid url",
|
||||
name: "Worker initial_upstreams set to invalid url",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = "env://\x00"
|
||||
initial_upstreams = "env://\x00"
|
||||
}`,
|
||||
expWorkerControllers: nil,
|
||||
expErr: true,
|
||||
expErrIs: parseutil.ErrNotAUrl,
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: true,
|
||||
expErrIs: parseutil.ErrNotAUrl,
|
||||
},
|
||||
{
|
||||
name: "Worker using deprecated controllers field",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = ["127.0.0.1", "127.0.0.2", "127.0.0.3"]
|
||||
}`,
|
||||
expWorkerUpstreams: []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "Different values in controllers and initial_upstreams field",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = ["127.0.0.1", "127.0.0.2", "127.0.0.3"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
}`,
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker upstreams: both initial_upstreams and controllers fields are populated",
|
||||
},
|
||||
{
|
||||
name: "Identical values in controllers and initial_upstreams field",
|
||||
in: `
|
||||
worker {
|
||||
name = "test"
|
||||
controllers = ["127.0.0.1"]
|
||||
initial_upstreams = ["127.0.0.1"]
|
||||
}`,
|
||||
expWorkerUpstreams: nil,
|
||||
expErr: true,
|
||||
expErrStr: "Failed to parse worker upstreams: both initial_upstreams and controllers fields are populated",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1000,7 +1208,7 @@ func TestWorkerControllers(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
require.NotNil(t, c.Worker)
|
||||
require.EqualValues(t, tt.expWorkerControllers, c.Worker.Controllers)
|
||||
require.EqualValues(t, tt.expWorkerUpstreams, c.Worker.InitialUpstreams)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,6 @@ type cmdInfo struct {
|
||||
// output env var and print
|
||||
HasExampleCliOutput bool
|
||||
|
||||
// IsAbstractType triggers some behavior specialized for abstract types,
|
||||
// e.g. those that have subcommands for create/update
|
||||
IsAbstractType bool
|
||||
|
||||
// HasId controls whether to add ID emptiness checking. Note that some
|
||||
// commands that allow name/scope id or name/scope name handling may skip
|
||||
// this in favor of custom logic.
|
||||
@@ -79,6 +75,10 @@ type cmdInfo struct {
|
||||
|
||||
// IsPluginType controls whether standard plugin flags are generated
|
||||
IsPluginType bool
|
||||
|
||||
// SkipClientCallActions allows skipping creation of an actual client
|
||||
// call for an action in favor of custom logic in extra actions
|
||||
SkipClientCallActions []string
|
||||
}
|
||||
|
||||
var inputStructs = map[string][]*cmdInfo{
|
||||
@@ -89,7 +89,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
HasExtraCommandVars: true,
|
||||
HasExtraHelpFunc: true,
|
||||
IsAbstractType: true,
|
||||
Container: "AuthMethod",
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
@@ -130,7 +129,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
ResourceType: resource.AuthMethod.String(),
|
||||
Pkg: "authmethods",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
HasExtraHelpFunc: true,
|
||||
Container: "Scope",
|
||||
HasId: true,
|
||||
@@ -179,7 +177,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
ResourceType: resource.CredentialStore.String(),
|
||||
Pkg: "credentialstores",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
HasExtraHelpFunc: true,
|
||||
Container: "Scope",
|
||||
HasId: true,
|
||||
@@ -221,7 +218,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
ResourceType: resource.CredentialLibrary.String(),
|
||||
Pkg: "credentiallibraries",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
HasExtraHelpFunc: true,
|
||||
Container: "CredentialStore",
|
||||
HasId: true,
|
||||
@@ -247,7 +243,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
ResourceType: resource.Credential.String(),
|
||||
Pkg: "credentials",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
HasExtraHelpFunc: true,
|
||||
Container: "CredentialStore",
|
||||
HasId: true,
|
||||
@@ -288,7 +283,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
ResourceType: resource.HostCatalog.String(),
|
||||
Pkg: "hostcatalogs",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
HasExtraHelpFunc: true,
|
||||
Container: "Scope",
|
||||
HasId: true,
|
||||
@@ -332,7 +326,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
HasExtraCommandVars: true,
|
||||
HasExtraHelpFunc: true,
|
||||
IsAbstractType: true,
|
||||
Container: "HostCatalog",
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
@@ -374,7 +367,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
Pkg: "hosts",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
HasExtraHelpFunc: true,
|
||||
IsAbstractType: true,
|
||||
Container: "HostCatalog",
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
@@ -400,7 +392,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
ResourceType: resource.ManagedGroup.String(),
|
||||
Pkg: "managedgroups",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
Container: "AuthMethod",
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
@@ -468,7 +459,6 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
HasExtraCommandVars: true,
|
||||
HasExtraHelpFunc: true,
|
||||
HasExampleCliOutput: true,
|
||||
IsAbstractType: true,
|
||||
HasName: true,
|
||||
HasDescription: true,
|
||||
Container: "Scope",
|
||||
@@ -504,4 +494,32 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
VersionedActions: []string{"update", "add-accounts", "remove-accounts", "set-accounts"},
|
||||
},
|
||||
},
|
||||
"workers": {
|
||||
{
|
||||
ResourceType: resource.Worker.String(),
|
||||
Pkg: "workers",
|
||||
StdActions: []string{"read", "update", "delete", "list"},
|
||||
HasExtraHelpFunc: true,
|
||||
HasId: true,
|
||||
Container: "Scope",
|
||||
HasName: true,
|
||||
HasDescription: true,
|
||||
VersionedActions: []string{"update"},
|
||||
},
|
||||
{
|
||||
ResourceType: resource.Worker.String(),
|
||||
Pkg: "workers",
|
||||
StdActions: []string{"create"},
|
||||
SubActionPrefix: "worker-led",
|
||||
HasExtraCommandVars: true,
|
||||
SkipNormalHelp: true,
|
||||
HasExtraHelpFunc: true,
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
Container: "Scope",
|
||||
HasDescription: true,
|
||||
NeedsSubtypeInCreate: true,
|
||||
SkipClientCallActions: []string{"create"},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -229,8 +229,12 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int {
|
||||
switch c.Func {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
{{ if .IsAbstractType }}
|
||||
case "create", "update":
|
||||
{{ if (not (hasAction .StdActions "create" ) )}}
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
{{ end }}
|
||||
{{ if (not (hasAction .StdActions "update" ) )}}
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
{{ end }}
|
||||
}
|
||||
@@ -403,9 +407,11 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int {
|
||||
switch c.Func {
|
||||
{{ range $i, $action := $input.StdActions }}
|
||||
{{ if eq $action "create" }}
|
||||
{{ if ( not ( hasAction $input.SkipClientCallActions "create") ) }}
|
||||
case "create":
|
||||
result, err = {{ $input.Pkg }}Client.Create(c.Context, {{ if (and $input.SubActionPrefix $input.NeedsSubtypeInCreate) }}"{{ $input.SubActionPrefix }}",{{ end }} c.Flag{{ $input.Container }}Id, opts...)
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if eq $action "read" }}
|
||||
case "read":
|
||||
result, err = {{ $input.Pkg }}Client.Read(c.Context, c.FlagId, opts...)
|
||||
|
||||
@@ -91,10 +91,10 @@ func TestSetupSleepyDevEnvironment(t *testing.T) {
|
||||
"foo": {"bar"},
|
||||
}
|
||||
w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{
|
||||
Config: conf,
|
||||
WorkerAuthKms: c1.Config().WorkerAuthKms,
|
||||
InitialControllers: c1.ClusterAddrs(),
|
||||
Logger: logger.Named("w1"),
|
||||
Config: conf,
|
||||
WorkerAuthKms: c1.Config().WorkerAuthKms,
|
||||
InitialUpstreams: c1.ClusterAddrs(),
|
||||
Logger: logger.Named("w1"),
|
||||
})
|
||||
defer w1.Shutdown()
|
||||
addr := c1.ApiAddrs()[0]
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/multihop"
|
||||
"github.com/hashicorp/nodeenrollment/registration"
|
||||
"github.com/hashicorp/nodeenrollment/rotation"
|
||||
"github.com/hashicorp/nodeenrollment/tls"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/hashicorp/nodeenrollment/util/temperror"
|
||||
)
|
||||
|
||||
type multihopServiceServer struct {
|
||||
multihop.UnimplementedMultihopServiceServer
|
||||
|
||||
storage nodeenrollment.Storage
|
||||
direct bool
|
||||
client *atomic.Value
|
||||
options []nodeenrollment.Option
|
||||
}
|
||||
|
||||
// NewMultihopServiceServer creates a new service implementing
|
||||
// MultihopServiceServer, storing values used for the implementing functions.
|
||||
func NewMultihopServiceServer(storage nodeenrollment.Storage, direct bool, client *atomic.Value, opt ...nodeenrollment.Option) (*multihopServiceServer, error) {
|
||||
const op = "cluster.handlers.NewMultihopServiceServer"
|
||||
|
||||
switch {
|
||||
case direct && nodeenrollment.IsNil(storage):
|
||||
return nil, fmt.Errorf("%s: running on controller and nil storage provided", op)
|
||||
case !direct && client == nil:
|
||||
return nil, fmt.Errorf("%s: running on worker and nil client provided", op)
|
||||
}
|
||||
|
||||
return &multihopServiceServer{
|
||||
storage: storage,
|
||||
direct: direct,
|
||||
client: client,
|
||||
options: opt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ multihop.MultihopServiceServer = (*multihopServiceServer)(nil)
|
||||
|
||||
// FetchNodeCredentials implements the MultihopServiceServer interface. If it's
|
||||
// direct (e.g. running on a controller) it handles the request directly,
|
||||
// otherwise sends it to its next hop.
|
||||
func (m *multihopServiceServer) FetchNodeCredentials(ctx context.Context, req *types.FetchNodeCredentialsRequest) (*types.FetchNodeCredentialsResponse, error) {
|
||||
const op = "cluster.handlers.(multihopServiceServer).FetchNodeCredentials"
|
||||
switch m.direct {
|
||||
case true:
|
||||
return registration.FetchNodeCredentials(ctx, m.storage, req, m.options...)
|
||||
|
||||
default:
|
||||
client := m.client.Load()
|
||||
if client == nil {
|
||||
return nil, fmt.Errorf("%s: error fetching multihop connection, client is nil", op)
|
||||
}
|
||||
multihopClient, ok := client.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return nil, temperror.New(errors.New("client could not be understood as a multihop service client"))
|
||||
}
|
||||
return multihopClient.FetchNodeCredentials(ctx, req)
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateServerCertificates implements the MultihopServiceServer interface. If
|
||||
// it's direct (e.g. running on a controller) it handles the request directly,
|
||||
// otherwise sends it to its next hop.
|
||||
func (m *multihopServiceServer) GenerateServerCertificates(ctx context.Context, req *types.GenerateServerCertificatesRequest) (*types.GenerateServerCertificatesResponse, error) {
|
||||
const op = "cluster.handlers.(multihopServiceServer).GenerateServerCertificates"
|
||||
switch m.direct {
|
||||
case true:
|
||||
return tls.GenerateServerCertificates(ctx, m.storage, req, m.options...)
|
||||
|
||||
default:
|
||||
client := m.client.Load()
|
||||
if client == nil {
|
||||
return nil, fmt.Errorf("%s: error fetching multihop connection, client is nil", op)
|
||||
}
|
||||
multihopClient, ok := client.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return nil, temperror.New(errors.New("client could not be understood as a multihop service client"))
|
||||
}
|
||||
return multihopClient.GenerateServerCertificates(ctx, req)
|
||||
}
|
||||
}
|
||||
|
||||
// RotateNodeCredentials implements the MultihopServiceServer interface. If it's
|
||||
// direct (e.g. running on a controller) it handles the request directly,
|
||||
// otherwise sends it to its next hop.
|
||||
func (m *multihopServiceServer) RotateNodeCredentials(ctx context.Context, req *types.RotateNodeCredentialsRequest) (*types.RotateNodeCredentialsResponse, error) {
|
||||
const op = "cluster.handlers.(multihopServiceServer).RotateNodeCredentials"
|
||||
switch m.direct {
|
||||
case true:
|
||||
return rotation.RotateNodeCredentials(ctx, m.storage, req, m.options...)
|
||||
|
||||
default:
|
||||
client := m.client.Load()
|
||||
if client == nil {
|
||||
return nil, fmt.Errorf("%s: error fetching multihop connection, client is nil", op)
|
||||
}
|
||||
multihopClient, ok := client.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return nil, temperror.New(errors.New("client could not be understood as a multihop service client"))
|
||||
}
|
||||
return multihopClient.RotateNodeCredentials(ctx, req)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
"github.com/hashicorp/go-bexpr"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type workerServiceServer struct {
|
||||
pbs.UnimplementedServerCoordinationServiceServer
|
||||
pbs.UnimplementedSessionServiceServer
|
||||
|
||||
serversRepoFn common.ServersRepoFactory
|
||||
sessionRepoFn common.SessionRepoFactory
|
||||
connectionRepoFn common.ConnectionRepoFactory
|
||||
updateTimes *sync.Map
|
||||
kms *kms.Kms
|
||||
}
|
||||
|
||||
func NewWorkerServiceServer(
|
||||
serversRepoFn common.ServersRepoFactory,
|
||||
sessionRepoFn common.SessionRepoFactory,
|
||||
connectionRepoFn common.ConnectionRepoFactory,
|
||||
updateTimes *sync.Map,
|
||||
kms *kms.Kms,
|
||||
) *workerServiceServer {
|
||||
return &workerServiceServer{
|
||||
serversRepoFn: serversRepoFn,
|
||||
sessionRepoFn: sessionRepoFn,
|
||||
connectionRepoFn: connectionRepoFn,
|
||||
updateTimes: updateTimes,
|
||||
kms: kms,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
_ pbs.SessionServiceServer = &workerServiceServer{}
|
||||
_ pbs.ServerCoordinationServiceServer = &workerServiceServer{}
|
||||
)
|
||||
|
||||
func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) {
|
||||
const op = "workers.(workerServiceServer).Status"
|
||||
// TODO: on the worker, if we get errors back from this repeatedly, do we
|
||||
// terminate all sessions since we can't know if they were canceled?
|
||||
|
||||
wStat := req.GetWorkerStatus()
|
||||
if wStat == nil {
|
||||
return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Worker sent nil status.")
|
||||
}
|
||||
switch {
|
||||
case wStat.GetName() == "" && wStat.GetKeyId() == "":
|
||||
return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Name and keyId are not set in the request; one is required.")
|
||||
case wStat.GetName() != "" && wStat.GetKeyId() != "":
|
||||
return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Name and keyId are both set in the request; only one is allowed.")
|
||||
case wStat.GetAddress() == "":
|
||||
return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Address is not set but is required.")
|
||||
}
|
||||
// This Store call is currently only for testing purposes
|
||||
ws.updateTimes.Store(wStat.GetName(), time.Now())
|
||||
|
||||
serverRepo, err := ws.serversRepoFn()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting servers repo"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to store worker status: %v", err)
|
||||
}
|
||||
|
||||
// Convert API tags to storage tags
|
||||
wTags := wStat.GetTags()
|
||||
workerTags := make([]*servers.Tag, 0, len(wTags))
|
||||
for _, v := range wTags {
|
||||
workerTags = append(workerTags, &servers.Tag{
|
||||
Key: v.GetKey(),
|
||||
Value: v.GetValue(),
|
||||
})
|
||||
}
|
||||
|
||||
wConf := servers.NewWorker(scope.Global.String(),
|
||||
servers.WithName(wStat.GetName()),
|
||||
servers.WithDescription(wStat.GetDescription()),
|
||||
servers.WithAddress(wStat.GetAddress()),
|
||||
servers.WithWorkerTags(workerTags...))
|
||||
opts := []servers.Option{servers.WithUpdateTags(req.GetUpdateTags())}
|
||||
if wStat.GetPublicId() != "" {
|
||||
opts = append(opts, servers.WithPublicId(wStat.GetPublicId()))
|
||||
}
|
||||
if wStat.GetKeyId() != "" {
|
||||
opts = append(opts, servers.WithKeyId(wStat.GetKeyId()))
|
||||
}
|
||||
wrk, err := serverRepo.UpsertWorkerStatus(ctx, wConf, opts...)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error storing worker status"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error storing worker status: %v", err)
|
||||
}
|
||||
controllers, err := serverRepo.ListControllers(ctx)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting current controllers"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error getting current controllers: %v", err)
|
||||
}
|
||||
|
||||
responseControllers := []*pbs.UpstreamServer{}
|
||||
for _, c := range controllers {
|
||||
thisController := &pbs.UpstreamServer{
|
||||
Address: c.Address,
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
}
|
||||
responseControllers = append(responseControllers, thisController)
|
||||
}
|
||||
ret := &pbs.StatusResponse{
|
||||
CalculatedUpstreams: responseControllers,
|
||||
WorkerId: wrk.GetPublicId(),
|
||||
}
|
||||
|
||||
stateReport := make([]session.StateReport, 0, len(req.GetJobs()))
|
||||
|
||||
for _, jobStatus := range req.GetJobs() {
|
||||
switch jobStatus.Job.GetType() {
|
||||
case pbs.JOBTYPE_JOBTYPE_SESSION:
|
||||
si := jobStatus.GetJob().GetSessionInfo()
|
||||
if si == nil {
|
||||
return nil, status.Error(codes.Internal, "Error getting session info at status time")
|
||||
}
|
||||
|
||||
switch si.Status {
|
||||
case pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING,
|
||||
pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED:
|
||||
// No need to see about canceling anything
|
||||
continue
|
||||
}
|
||||
|
||||
sr := session.StateReport{
|
||||
SessionId: si.GetSessionId(),
|
||||
ConnectionIds: make([]string, 0, len(si.GetConnections())),
|
||||
}
|
||||
for _, conn := range si.GetConnections() {
|
||||
switch conn.Status {
|
||||
case pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_AUTHORIZED,
|
||||
pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED:
|
||||
sr.ConnectionIds = append(sr.ConnectionIds, conn.GetConnectionId())
|
||||
}
|
||||
}
|
||||
stateReport = append(stateReport, sr)
|
||||
}
|
||||
}
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting sessions repo"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err)
|
||||
}
|
||||
connectionRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting connection repo"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err)
|
||||
}
|
||||
|
||||
notActive, err := session.WorkerStatusReport(ctx, sessRepo, connectionRepo, wrk.GetPublicId(), stateReport)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal,
|
||||
"Error comparing state of sessions for worker with public id %q: %v",
|
||||
wrk.GetPublicId(), err)
|
||||
}
|
||||
for _, na := range notActive {
|
||||
var connChanges []*pbs.Connection
|
||||
for _, connId := range na.ConnectionIds {
|
||||
connChanges = append(connChanges, &pbs.Connection{
|
||||
ConnectionId: connId,
|
||||
Status: session.StatusClosed.ProtoVal(),
|
||||
})
|
||||
}
|
||||
ret.JobsRequests = append(ret.JobsRequests, &pbs.JobChangeRequest{
|
||||
Job: &pbs.Job{
|
||||
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
||||
JobInfo: &pbs.Job_SessionInfo{
|
||||
SessionInfo: &pbs.SessionJobInfo{
|
||||
SessionId: na.SessionId,
|
||||
Status: na.Status.ProtoVal(),
|
||||
Connections: connChanges,
|
||||
},
|
||||
},
|
||||
},
|
||||
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) LookupSession(ctx context.Context, req *pbs.LookupSessionRequest) (*pbs.LookupSessionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).LookupSession"
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
sessionInfo, authzSummary, err := sessRepo.LookupSession(ctx, req.GetSessionId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error looking up session: %v", err)
|
||||
}
|
||||
if sessionInfo == nil {
|
||||
return nil, status.Error(codes.PermissionDenied, "Unknown session ID.")
|
||||
}
|
||||
if len(sessionInfo.States) == 0 {
|
||||
return nil, status.Error(codes.Internal, "Empty session states during lookup.")
|
||||
}
|
||||
|
||||
if sessionInfo.WorkerFilter != "" {
|
||||
if req.ServerId == "" {
|
||||
event.WriteError(ctx, op, errors.New("worker filter enabled for session but got no server ID from worker"))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Did not receive server ID when looking up session but filtering is enabled: %v", err)
|
||||
}
|
||||
serversRepo, err := ws.serversRepoFn()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting servers repo"))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error acquiring server repo when looking up session: %v", err)
|
||||
}
|
||||
var w *servers.Worker
|
||||
if req.WorkerKeyId != "" {
|
||||
workerId, err := serversRepo.LookupWorkerIdByKeyId(ctx, req.WorkerKeyId)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error looking up worker by keyId", "keyId", req.WorkerKeyId))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error looking up tags for server: %v", err)
|
||||
}
|
||||
w, err = serversRepo.LookupWorker(ctx, workerId)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error looking up worker by workerId", "workerId", workerId))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error looking up tags for server: %v", err)
|
||||
}
|
||||
} else {
|
||||
w, err = serversRepo.LookupWorkerByName(ctx, req.GetServerId())
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error looking up worker by name", "name", req.ServerId))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error looking up tags for server: %v", err)
|
||||
}
|
||||
}
|
||||
// Build the map for filtering.
|
||||
tagMap := w.CanonicalTags()
|
||||
|
||||
// Create the evaluator
|
||||
eval, err := bexpr.CreateEvaluator(sessionInfo.WorkerFilter)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error creating worker filter evaluator", "server_id", req.ServerId))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error creating worker filter evaluator: %v", err)
|
||||
}
|
||||
filterInput := map[string]interface{}{
|
||||
"name": w.GetName(),
|
||||
"tags": tagMap,
|
||||
}
|
||||
ok, err := eval.Evaluate(filterInput)
|
||||
if err != nil {
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal,
|
||||
fmt.Sprintf("Worker filter expression evaluation resulted in error: %s", err))
|
||||
}
|
||||
if !ok {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(
|
||||
codes.FailedPrecondition,
|
||||
"Worker filter expression precludes this worker from serving this session")
|
||||
}
|
||||
}
|
||||
|
||||
creds, err := sessRepo.ListSessionCredentials(ctx, sessionInfo.ScopeId, sessionInfo.PublicId)
|
||||
if err != nil {
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal,
|
||||
fmt.Sprintf("Error retrieving session credentials: %s", err))
|
||||
}
|
||||
var workerCreds []*pbs.Credential
|
||||
for _, c := range creds {
|
||||
m := &pbs.Credential{}
|
||||
err = proto.Unmarshal(c, m)
|
||||
if err != nil {
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal,
|
||||
fmt.Sprintf("Error unmarshaling credentials: %s", err))
|
||||
}
|
||||
workerCreds = append(workerCreds, m)
|
||||
}
|
||||
|
||||
resp := &pbs.LookupSessionResponse{
|
||||
Authorization: &targets.SessionAuthorizationData{
|
||||
SessionId: sessionInfo.GetPublicId(),
|
||||
Certificate: sessionInfo.Certificate,
|
||||
},
|
||||
Status: sessionInfo.States[0].Status.ProtoVal(),
|
||||
Version: sessionInfo.Version,
|
||||
TofuToken: string(sessionInfo.TofuToken),
|
||||
Endpoint: sessionInfo.Endpoint,
|
||||
Expiration: sessionInfo.ExpirationTime.Timestamp,
|
||||
ConnectionLimit: sessionInfo.ConnectionLimit,
|
||||
ConnectionsLeft: authzSummary.ConnectionLimit,
|
||||
HostId: sessionInfo.HostId,
|
||||
HostSetId: sessionInfo.HostSetId,
|
||||
TargetId: sessionInfo.TargetId,
|
||||
UserId: sessionInfo.UserId,
|
||||
Credentials: workerCreds,
|
||||
}
|
||||
if resp.ConnectionsLeft != -1 {
|
||||
resp.ConnectionsLeft -= int32(authzSummary.CurrentConnectionCount)
|
||||
}
|
||||
|
||||
wrapper, err := ws.kms.GetWrapper(ctx, sessionInfo.ScopeId, kms.KeyPurposeSessions, kms.WithKeyId(sessionInfo.KeyId))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error getting sessions wrapper: %v", err)
|
||||
}
|
||||
|
||||
// Derive the private key, which should match. Deriving on both ends allows
|
||||
// us to not store it in the DB.
|
||||
_, resp.Authorization.PrivateKey, err = session.DeriveED25519Key(ctx, wrapper, sessionInfo.UserId, sessionInfo.GetPublicId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error deriving session key: %v", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) CancelSession(ctx context.Context, req *pbs.CancelSessionRequest) (*pbs.CancelSessionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).CancelSession"
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
ses, _, err := sessRepo.LookupSession(ctx, req.GetSessionId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ses, err = sessRepo.CancelSession(ctx, req.GetSessionId(), ses.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbs.CancelSessionResponse{
|
||||
Status: ses.States[0].Status.ProtoVal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) ActivateSession(ctx context.Context, req *pbs.ActivateSessionRequest) (*pbs.ActivateSessionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).ActivateSession"
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
sessionInfo, sessionStates, err := sessRepo.ActivateSession(ctx, req.GetSessionId(), req.GetVersion(), []byte(req.GetTofuToken()))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error looking up session: %v", err)
|
||||
}
|
||||
if sessionInfo == nil {
|
||||
return nil, status.Error(codes.PermissionDenied, "Unknown session ID.")
|
||||
}
|
||||
if len(sessionStates) == 0 {
|
||||
return nil, status.Error(codes.Internal, "Invalid session state in activate response.")
|
||||
}
|
||||
|
||||
return &pbs.ActivateSessionResponse{
|
||||
Status: sessionStates[0].Status.ProtoVal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) AuthorizeConnection(ctx context.Context, req *pbs.AuthorizeConnectionRequest) (*pbs.AuthorizeConnectionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).AuthorizeConnection"
|
||||
connectionRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
sessionRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
serversRepo, err := ws.serversRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting servers repo: %v", err)
|
||||
}
|
||||
w, err := serversRepo.LookupWorkerByName(ctx, req.GetWorkerId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error looking up worker: %v", err)
|
||||
}
|
||||
if w == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "worker not found with name %q", req.GetWorkerId())
|
||||
}
|
||||
|
||||
connectionInfo, connStates, authzSummary, err := session.AuthorizeConnection(ctx, sessionRepo, connectionRepo, req.GetSessionId(), w.GetPublicId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connectionInfo == nil {
|
||||
return nil, status.Error(codes.Internal, "Invalid authorize connection response.")
|
||||
}
|
||||
if len(connStates) == 0 {
|
||||
return nil, status.Error(codes.Internal, "Invalid connection state in authorize response.")
|
||||
}
|
||||
|
||||
ret := &pbs.AuthorizeConnectionResponse{
|
||||
ConnectionId: connectionInfo.GetPublicId(),
|
||||
Status: connStates[0].Status.ProtoVal(),
|
||||
ConnectionsLeft: authzSummary.ConnectionLimit,
|
||||
}
|
||||
if ret.ConnectionsLeft != -1 {
|
||||
ret.ConnectionsLeft -= int32(authzSummary.CurrentConnectionCount)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) ConnectConnection(ctx context.Context, req *pbs.ConnectConnectionRequest) (*pbs.ConnectConnectionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).ConnectConnection"
|
||||
connRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
connectionInfo, connStates, err := connRepo.ConnectConnection(ctx, session.ConnectWith{
|
||||
ConnectionId: req.GetConnectionId(),
|
||||
ClientTcpAddress: req.GetClientTcpAddress(),
|
||||
ClientTcpPort: req.GetClientTcpPort(),
|
||||
EndpointTcpAddress: req.GetEndpointTcpAddress(),
|
||||
EndpointTcpPort: req.GetEndpointTcpPort(),
|
||||
UserClientIp: req.GetUserClientIp(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connectionInfo == nil {
|
||||
return nil, status.Error(codes.Internal, "Invalid connect connection response.")
|
||||
}
|
||||
|
||||
return &pbs.ConnectConnectionResponse{
|
||||
Status: connStates[0].Status.ProtoVal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) CloseConnection(ctx context.Context, req *pbs.CloseConnectionRequest) (*pbs.CloseConnectionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).CloseConnection"
|
||||
numCloses := len(req.GetCloseRequestData())
|
||||
if numCloses == 0 {
|
||||
return &pbs.CloseConnectionResponse{}, nil
|
||||
}
|
||||
|
||||
closeWiths := make([]session.CloseWith, 0, numCloses)
|
||||
closeIds := make([]string, 0, numCloses)
|
||||
|
||||
for _, v := range req.GetCloseRequestData() {
|
||||
closeIds = append(closeIds, v.GetConnectionId())
|
||||
closeWiths = append(closeWiths, session.CloseWith{
|
||||
ConnectionId: v.GetConnectionId(),
|
||||
BytesUp: v.GetBytesUp(),
|
||||
BytesDown: v.GetBytesDown(),
|
||||
ClosedReason: session.ClosedReason(v.GetReason()),
|
||||
})
|
||||
}
|
||||
connRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting connection repo: %v", err)
|
||||
}
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
closeInfos, err := session.CloseConnections(ctx, sessRepo, connRepo, closeWiths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if closeInfos == nil {
|
||||
return nil, status.Error(codes.Internal, "Invalid close connection response.")
|
||||
}
|
||||
|
||||
closeData := make([]*pbs.CloseConnectionResponseData, 0, numCloses)
|
||||
for _, v := range closeInfos {
|
||||
if v.Connection == nil {
|
||||
return nil, status.Errorf(codes.Internal, "No connection found while closing one of the connection IDs: %v", closeIds)
|
||||
}
|
||||
if len(v.ConnectionStates) == 0 {
|
||||
return nil, status.Errorf(codes.Internal, "No connection states found while closing one of the connection IDs: %v", closeIds)
|
||||
}
|
||||
closeData = append(closeData, &pbs.CloseConnectionResponseData{
|
||||
ConnectionId: v.Connection.GetPublicId(),
|
||||
Status: v.ConnectionStates[0].Status.ProtoVal(),
|
||||
})
|
||||
}
|
||||
|
||||
ret := &pbs.CloseConnectionResponse{
|
||||
CloseResponseData: closeData,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
+283
-68
@@ -1,4 +1,4 @@
|
||||
package workers_test
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -8,18 +8,26 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/cluster/handlers"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/servers/store"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/tcp"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/registration"
|
||||
"github.com/hashicorp/nodeenrollment/rotation"
|
||||
"github.com/hashicorp/nodeenrollment/storage/file"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
@@ -31,17 +39,10 @@ func TestStatus(t *testing.T) {
|
||||
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
|
||||
serverRepo, _ := servers.NewRepository(rw, rw, kms)
|
||||
serverRepo.UpsertServer(ctx, &servers.Server{
|
||||
serverRepo.UpsertController(ctx, &store.Controller{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
serverRepo.UpsertServer(ctx, &servers.Server{
|
||||
PrivateId: "test_worker1",
|
||||
Type: "worker",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
|
||||
serversRepoFn := func() (*servers.Repository, error) {
|
||||
return serverRepo, nil
|
||||
}
|
||||
@@ -70,7 +71,7 @@ func TestStatus(t *testing.T) {
|
||||
target.WithSessionConnectionLimit(-1),
|
||||
)
|
||||
|
||||
worker1 := session.TestWorker(t, conn, wrapper)
|
||||
worker1 := servers.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
@@ -83,14 +84,14 @@ func TestStatus(t *testing.T) {
|
||||
ConnectionLimit: 10,
|
||||
})
|
||||
tofu := session.TestTofu(t)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, worker1.PrivateId, worker1.Type, tofu)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
require.NotNil(t, s)
|
||||
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PrivateId)
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
@@ -104,23 +105,31 @@ func TestStatus(t *testing.T) {
|
||||
name: "No Sessions",
|
||||
wantErr: false,
|
||||
req: &pbs.StatusRequest{
|
||||
Worker: worker1,
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
PublicId: worker1.GetPublicId(),
|
||||
Name: worker1.GetName(),
|
||||
Address: worker1.GetAddress(),
|
||||
},
|
||||
},
|
||||
want: &pbs.StatusResponse{
|
||||
Controllers: []*servers.Server{
|
||||
CalculatedUpstreams: []*pbs.UpstreamServer{
|
||||
{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
WorkerId: worker1.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Still Active",
|
||||
wantErr: false,
|
||||
req: &pbs.StatusRequest{
|
||||
Worker: worker1,
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
PublicId: worker1.GetPublicId(),
|
||||
Name: worker1.GetName(),
|
||||
Address: worker1.GetAddress(),
|
||||
},
|
||||
Jobs: []*pbs.JobStatus{
|
||||
{
|
||||
Job: &pbs.Job{
|
||||
@@ -142,15 +151,37 @@ func TestStatus(t *testing.T) {
|
||||
},
|
||||
},
|
||||
want: &pbs.StatusResponse{
|
||||
Controllers: []*servers.Server{
|
||||
CalculatedUpstreams: []*pbs.UpstreamServer{
|
||||
{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
WorkerId: worker1.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "No Name or keyId",
|
||||
wantErr: true,
|
||||
req: &pbs.StatusRequest{
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
PublicId: worker1.GetPublicId(),
|
||||
Address: worker1.GetAddress(),
|
||||
},
|
||||
},
|
||||
wantErrMsg: status.Error(codes.InvalidArgument, "Name and keyId are not set in the request; one is required.").Error(),
|
||||
},
|
||||
{
|
||||
name: "No Address",
|
||||
wantErr: true,
|
||||
req: &pbs.StatusRequest{
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
PublicId: worker1.GetPublicId(),
|
||||
Name: worker1.GetName(),
|
||||
},
|
||||
},
|
||||
wantErrMsg: status.Error(codes.InvalidArgument, "Address is not set but is required.").Error(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -160,7 +191,7 @@ func TestStatus(t *testing.T) {
|
||||
got, err := s.Status(ctx, tc.req)
|
||||
if tc.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
assert.Equal(got, &pbs.StatusResponse{})
|
||||
assert.Equal(tc.wantErrMsg, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -170,14 +201,15 @@ func TestStatus(t *testing.T) {
|
||||
got,
|
||||
cmpopts.IgnoreUnexported(
|
||||
pbs.StatusResponse{},
|
||||
servers.Server{},
|
||||
servers.ServerWorkerStatus{},
|
||||
pbs.UpstreamServer{},
|
||||
pbs.JobChangeRequest{},
|
||||
pbs.Job{},
|
||||
pbs.Job_SessionInfo{},
|
||||
pbs.SessionJobInfo{},
|
||||
pbs.Connection{},
|
||||
),
|
||||
cmpopts.IgnoreFields(servers.Server{}, "CreateTime", "UpdateTime"),
|
||||
cmpopts.IgnoreFields(servers.ServerWorkerStatus{}, "Tags"),
|
||||
),
|
||||
)
|
||||
})
|
||||
@@ -193,17 +225,10 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
|
||||
serverRepo, _ := servers.NewRepository(rw, rw, kms)
|
||||
serverRepo.UpsertServer(ctx, &servers.Server{
|
||||
serverRepo.UpsertController(ctx, &store.Controller{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
serverRepo.UpsertServer(ctx, &servers.Server{
|
||||
PrivateId: "test_worker1",
|
||||
Type: "worker",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
|
||||
serversRepoFn := func() (*servers.Repository, error) {
|
||||
return serverRepo, nil
|
||||
}
|
||||
@@ -232,7 +257,7 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
target.WithSessionConnectionLimit(-1),
|
||||
)
|
||||
|
||||
worker1 := session.TestWorker(t, conn, wrapper)
|
||||
worker1 := servers.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
@@ -245,7 +270,7 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
ConnectionLimit: 10,
|
||||
})
|
||||
tofu := session.TestTofu(t)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, worker1.PrivateId, worker1.Type, tofu)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
||||
require.NoError(t, err)
|
||||
sess2 := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
@@ -258,13 +283,13 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
ConnectionLimit: 10,
|
||||
})
|
||||
tofu2 := session.TestTofu(t)
|
||||
sess2, _, err = repo.ActivateSession(ctx, sess2.PublicId, sess2.Version, worker1.PrivateId, worker1.Type, tofu2)
|
||||
sess2, _, err = repo.ActivateSession(ctx, sess2.PublicId, sess2.Version, tofu2)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
require.NotNil(t, s)
|
||||
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PrivateId)
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
@@ -283,7 +308,11 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
},
|
||||
req: &pbs.StatusRequest{
|
||||
Worker: worker1,
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
PublicId: worker1.GetPublicId(),
|
||||
Name: worker1.GetName(),
|
||||
Address: worker1.GetAddress(),
|
||||
},
|
||||
Jobs: []*pbs.JobStatus{
|
||||
{
|
||||
Job: &pbs.Job{
|
||||
@@ -305,11 +334,10 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
},
|
||||
},
|
||||
want: &pbs.StatusResponse{
|
||||
Controllers: []*servers.Server{
|
||||
CalculatedUpstreams: []*pbs.UpstreamServer{
|
||||
{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
JobsRequests: []*pbs.JobChangeRequest{
|
||||
@@ -326,6 +354,7 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
||||
},
|
||||
},
|
||||
WorkerId: worker1.PublicId,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -350,14 +379,15 @@ func TestStatusSessionClosed(t *testing.T) {
|
||||
got,
|
||||
cmpopts.IgnoreUnexported(
|
||||
pbs.StatusResponse{},
|
||||
servers.Server{},
|
||||
servers.ServerWorkerStatus{},
|
||||
pbs.UpstreamServer{},
|
||||
pbs.JobChangeRequest{},
|
||||
pbs.Job{},
|
||||
pbs.Job_SessionInfo{},
|
||||
pbs.SessionJobInfo{},
|
||||
pbs.Connection{},
|
||||
),
|
||||
cmpopts.IgnoreFields(servers.Server{}, "CreateTime", "UpdateTime"),
|
||||
cmpopts.IgnoreFields(servers.ServerWorkerStatus{}, "Tags"),
|
||||
),
|
||||
)
|
||||
})
|
||||
@@ -373,17 +403,13 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
|
||||
serverRepo, _ := servers.NewRepository(rw, rw, kms)
|
||||
serverRepo.UpsertServer(ctx, &servers.Server{
|
||||
serverRepo.UpsertController(ctx, &store.Controller{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
serverRepo.UpsertServer(ctx, &servers.Server{
|
||||
PrivateId: "test_worker1",
|
||||
Type: "worker",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
|
||||
worker1 := servers.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
serversRepoFn := func() (*servers.Repository, error) {
|
||||
return serverRepo, nil
|
||||
}
|
||||
@@ -412,8 +438,6 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
target.WithSessionConnectionLimit(-1),
|
||||
)
|
||||
|
||||
worker1 := session.TestWorker(t, conn, wrapper)
|
||||
|
||||
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
HostId: h.GetPublicId(),
|
||||
@@ -425,7 +449,7 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
ConnectionLimit: 10,
|
||||
})
|
||||
tofu := session.TestTofu(t)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, worker1.PrivateId, worker1.Type, tofu)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
||||
require.NoError(t, err)
|
||||
sess2 := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
@@ -438,20 +462,24 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
ConnectionLimit: 10,
|
||||
})
|
||||
tofu2 := session.TestTofu(t)
|
||||
sess2, _, err = repo.ActivateSession(ctx, sess2.PublicId, sess2.Version, worker1.PrivateId, worker1.Type, tofu2)
|
||||
sess2, _, err = repo.ActivateSession(ctx, sess2.PublicId, sess2.Version, tofu2)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
require.NotNil(t, s)
|
||||
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PrivateId)
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
||||
require.NoError(t, err)
|
||||
deadConn, _, err := connRepo.AuthorizeConnection(ctx, sess2.PublicId, worker1.PrivateId)
|
||||
deadConn, _, err := connRepo.AuthorizeConnection(ctx, sess2.PublicId, worker1.PublicId)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, deadConn.PublicId, connection.PublicId)
|
||||
|
||||
req := &pbs.StatusRequest{
|
||||
Worker: worker1,
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
PublicId: worker1.GetPublicId(),
|
||||
Name: worker1.GetName(),
|
||||
Address: worker1.GetAddress(),
|
||||
},
|
||||
Jobs: []*pbs.JobStatus{
|
||||
{
|
||||
Job: &pbs.Job{
|
||||
@@ -473,13 +501,13 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
},
|
||||
}
|
||||
want := &pbs.StatusResponse{
|
||||
Controllers: []*servers.Server{
|
||||
CalculatedUpstreams: []*pbs.UpstreamServer{
|
||||
{
|
||||
PrivateId: "test_controller1",
|
||||
Type: "controller",
|
||||
Address: "127.0.0.1",
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
WorkerId: worker1.PublicId,
|
||||
}
|
||||
|
||||
got, err := s.Status(ctx, req)
|
||||
@@ -489,14 +517,15 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
got,
|
||||
cmpopts.IgnoreUnexported(
|
||||
pbs.StatusResponse{},
|
||||
servers.Server{},
|
||||
servers.ServerWorkerStatus{},
|
||||
pbs.UpstreamServer{},
|
||||
pbs.JobChangeRequest{},
|
||||
pbs.Job{},
|
||||
pbs.Job_SessionInfo{},
|
||||
pbs.SessionJobInfo{},
|
||||
pbs.Connection{},
|
||||
),
|
||||
cmpopts.IgnoreFields(servers.Server{}, "CreateTime", "UpdateTime"),
|
||||
cmpopts.IgnoreFields(servers.ServerWorkerStatus{}, "Tags"),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -507,3 +536,189 @@ func TestStatusDeadConnection(t *testing.T) {
|
||||
assert.Nil(t, states[0].EndTime)
|
||||
assert.Equal(t, session.StatusClosed, states[0].Status)
|
||||
}
|
||||
|
||||
func TestStatusWorkerWithKeyId(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
|
||||
serverRepo, _ := servers.NewRepository(rw, rw, kms)
|
||||
serverRepo.UpsertController(ctx, &store.Controller{
|
||||
PrivateId: "test_controller1",
|
||||
Address: "127.0.0.1",
|
||||
})
|
||||
serversRepoFn := func() (*servers.Repository, error) {
|
||||
return serverRepo, nil
|
||||
}
|
||||
sessionRepoFn := func() (*session.Repository, error) {
|
||||
return session.NewRepository(rw, rw, kms)
|
||||
}
|
||||
connRepoFn := func() (*session.ConnectionRepository, error) {
|
||||
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
repo, err := sessionRepoFn()
|
||||
require.NoError(t, err)
|
||||
connRepo, err := connRepoFn()
|
||||
require.NoError(t, err)
|
||||
|
||||
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
||||
uId := at.GetIamUserId()
|
||||
hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0]
|
||||
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
|
||||
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
|
||||
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
|
||||
tar := tcp.TestTarget(
|
||||
ctx,
|
||||
t, conn, prj.GetPublicId(), "test",
|
||||
target.WithHostSources([]string{hs.GetPublicId()}),
|
||||
target.WithSessionConnectionLimit(-1),
|
||||
)
|
||||
|
||||
worker1 := servers.TestPkiWorker(t, conn, wrapper)
|
||||
|
||||
rootStorage, err := servers.NewRepositoryStorage(ctx, rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = rotation.RotateRootCertificates(ctx, rootStorage)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create struct to pass in with workerId that will be passed along to storage
|
||||
state, err := servers.AttachWorkerIdToState(ctx, worker1.PublicId)
|
||||
require.NoError(t, err)
|
||||
|
||||
// This happens on the worker
|
||||
fileStorage, err := file.New(ctx)
|
||||
require.NoError(t, err)
|
||||
nodeCreds, err := types.NewNodeCredentials(ctx, fileStorage)
|
||||
require.NoError(t, err)
|
||||
// Create request using worker id
|
||||
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// The AuthorizeNode request will result in a WorkerAuth record being stored under the workerId
|
||||
nodeInfo, err := registration.AuthorizeNode(ctx, rootStorage, fetchReq, nodeenrollment.WithState(state))
|
||||
require.NoError(t, err)
|
||||
|
||||
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
HostId: h.GetPublicId(),
|
||||
TargetId: tar.GetPublicId(),
|
||||
HostSetId: hs.GetPublicId(),
|
||||
AuthTokenId: at.GetPublicId(),
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Endpoint: "tcp://127.0.0.1:22",
|
||||
ConnectionLimit: 10,
|
||||
})
|
||||
tofu := session.TestTofu(t)
|
||||
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connRepoFn, new(sync.Map), kms)
|
||||
require.NotNil(t, s)
|
||||
|
||||
connection, _, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
wantErr bool
|
||||
wantErrMsg string
|
||||
req *pbs.StatusRequest
|
||||
want *pbs.StatusResponse
|
||||
}{
|
||||
{
|
||||
name: "Identify workerID based on keyId in status",
|
||||
wantErr: false,
|
||||
req: &pbs.StatusRequest{
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
Address: "someaddress",
|
||||
KeyId: nodeInfo.Id,
|
||||
},
|
||||
},
|
||||
want: &pbs.StatusResponse{
|
||||
CalculatedUpstreams: []*pbs.UpstreamServer{
|
||||
{
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
WorkerId: worker1.PublicId,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Active keyId Worker",
|
||||
wantErr: false,
|
||||
req: &pbs.StatusRequest{
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
KeyId: nodeInfo.Id,
|
||||
Address: "someaddress",
|
||||
},
|
||||
Jobs: []*pbs.JobStatus{
|
||||
{
|
||||
Job: &pbs.Job{
|
||||
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
||||
JobInfo: &pbs.Job_SessionInfo{
|
||||
SessionInfo: &pbs.SessionJobInfo{
|
||||
SessionId: sess.PublicId,
|
||||
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
||||
Connections: []*pbs.Connection{
|
||||
{
|
||||
ConnectionId: connection.PublicId,
|
||||
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &pbs.StatusResponse{
|
||||
CalculatedUpstreams: []*pbs.UpstreamServer{
|
||||
{
|
||||
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
WorkerId: worker1.PublicId,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
got, err := s.Status(ctx, tc.req)
|
||||
if tc.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(got, &pbs.StatusResponse{})
|
||||
assert.Equal(tc.wantErrMsg, err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Empty(
|
||||
cmp.Diff(
|
||||
tc.want,
|
||||
got,
|
||||
cmpopts.IgnoreUnexported(
|
||||
pbs.StatusResponse{},
|
||||
servers.ServerWorkerStatus{},
|
||||
pbs.UpstreamServer{},
|
||||
pbs.JobChangeRequest{},
|
||||
pbs.Job{},
|
||||
pbs.Job_SessionInfo{},
|
||||
pbs.SessionJobInfo{},
|
||||
pbs.Connection{},
|
||||
),
|
||||
cmpopts.IgnoreFields(servers.ServerWorkerStatus{}, "Tags"),
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/daemon/cluster/handlers"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/tcp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestLookupSession(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
|
||||
serversRepoFn := func() (*servers.Repository, error) {
|
||||
return servers.NewRepository(rw, rw, kms)
|
||||
}
|
||||
sessionRepoFn := func() (*session.Repository, error) {
|
||||
return session.NewRepository(rw, rw, kms)
|
||||
}
|
||||
connectionRepoFn := func() (*session.ConnectionRepository, error) {
|
||||
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
||||
uId := at.GetIamUserId()
|
||||
hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0]
|
||||
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
|
||||
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
|
||||
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
|
||||
tar := tcp.TestTarget(ctx, t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
|
||||
|
||||
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
HostId: h.GetPublicId(),
|
||||
TargetId: tar.GetPublicId(),
|
||||
HostSetId: hs.GetPublicId(),
|
||||
AuthTokenId: at.GetPublicId(),
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Endpoint: "tcp://127.0.0.1:22",
|
||||
})
|
||||
|
||||
egressSess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
||||
UserId: uId,
|
||||
HostId: h.GetPublicId(),
|
||||
TargetId: tar.GetPublicId(),
|
||||
HostSetId: hs.GetPublicId(),
|
||||
AuthTokenId: at.GetPublicId(),
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Endpoint: "tcp://127.0.0.1:22",
|
||||
})
|
||||
|
||||
repo, err := sessionRepoFn()
|
||||
require.NoError(t, err)
|
||||
|
||||
creds := []*pbs.Credential{
|
||||
{
|
||||
Credential: &pbs.Credential_UserPassword{
|
||||
UserPassword: &pbs.UserPassword{
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Credential: &pbs.Credential_UserPassword{
|
||||
UserPassword: &pbs.UserPassword{
|
||||
Username: "another-username",
|
||||
Password: "a different password",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
workerCreds := make([]session.Credential, 0, len(creds))
|
||||
for _, c := range creds {
|
||||
data, err := proto.Marshal(c)
|
||||
require.NoError(t, err)
|
||||
workerCreds = append(workerCreds, data)
|
||||
}
|
||||
err = repo.AddSessionCredentials(ctx, egressSess.ScopeId, egressSess.GetPublicId(), workerCreds)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := handlers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, new(sync.Map), kms)
|
||||
require.NotNil(t, s)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
wantErr bool
|
||||
wantErrMsg string
|
||||
want *pbs.LookupSessionResponse
|
||||
sessionId string
|
||||
}{
|
||||
{
|
||||
name: "Invalid session id",
|
||||
sessionId: "s_fakesession",
|
||||
wantErr: true,
|
||||
wantErrMsg: "rpc error: code = PermissionDenied desc = Unknown session ID.",
|
||||
},
|
||||
{
|
||||
name: "Valid",
|
||||
sessionId: sess.PublicId,
|
||||
want: &pbs.LookupSessionResponse{
|
||||
ConnectionLimit: 1,
|
||||
ConnectionsLeft: 1,
|
||||
Version: 1,
|
||||
Endpoint: sess.Endpoint,
|
||||
HostId: sess.HostId,
|
||||
HostSetId: sess.HostSetId,
|
||||
TargetId: sess.TargetId,
|
||||
UserId: sess.UserId,
|
||||
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_PENDING,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid-with-egress-creds",
|
||||
sessionId: egressSess.PublicId,
|
||||
want: &pbs.LookupSessionResponse{
|
||||
ConnectionLimit: 1,
|
||||
ConnectionsLeft: 1,
|
||||
Version: 1,
|
||||
Endpoint: egressSess.Endpoint,
|
||||
HostId: egressSess.HostId,
|
||||
HostSetId: egressSess.HostSetId,
|
||||
TargetId: egressSess.TargetId,
|
||||
UserId: egressSess.UserId,
|
||||
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_PENDING,
|
||||
Credentials: creds,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
req := &pbs.LookupSessionRequest{
|
||||
SessionId: tc.sessionId,
|
||||
}
|
||||
|
||||
got, err := s.LookupSession(ctx, req)
|
||||
if tc.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
assert.Equal(tc.wantErrMsg, err.Error())
|
||||
return
|
||||
}
|
||||
assert.Empty(
|
||||
cmp.Diff(
|
||||
tc.want,
|
||||
got,
|
||||
cmpopts.IgnoreUnexported(pbs.LookupSessionResponse{}, pbs.Credential{}, pbs.UserPassword{}),
|
||||
cmpopts.IgnoreFields(pbs.LookupSessionResponse{}, "Expiration", "Authorization"),
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -15,17 +15,18 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
AuthTokenRepoFactory = oidc.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFactory = func() (*vault.Repository, error)
|
||||
StaticCredentialRepoFactory = func() (*credstatic.Repository, error)
|
||||
IamRepoFactory func() (*iam.Repository, error)
|
||||
OidcAuthRepoFactory = oidc.OidcRepoFactory
|
||||
PasswordAuthRepoFactory func() (*password.Repository, error)
|
||||
ServersRepoFactory func() (*servers.Repository, error)
|
||||
StaticRepoFactory func() (*static.Repository, error)
|
||||
PluginHostRepoFactory func() (*pluginhost.Repository, error)
|
||||
HostPluginRepoFactory func() (*hostplugin.Repository, error)
|
||||
SessionRepoFactory func() (*session.Repository, error)
|
||||
ConnectionRepoFactory func() (*session.ConnectionRepository, error)
|
||||
TargetRepoFactory func() (*target.Repository, error)
|
||||
AuthTokenRepoFactory = oidc.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFactory = func() (*vault.Repository, error)
|
||||
StaticCredentialRepoFactory = func() (*credstatic.Repository, error)
|
||||
IamRepoFactory func() (*iam.Repository, error)
|
||||
OidcAuthRepoFactory = oidc.OidcRepoFactory
|
||||
PasswordAuthRepoFactory func() (*password.Repository, error)
|
||||
ServersRepoFactory func() (*servers.Repository, error)
|
||||
StaticRepoFactory func() (*static.Repository, error)
|
||||
PluginHostRepoFactory func() (*pluginhost.Repository, error)
|
||||
HostPluginRepoFactory func() (*hostplugin.Repository, error)
|
||||
SessionRepoFactory func() (*session.Repository, error)
|
||||
ConnectionRepoFactory func() (*session.ConnectionRepository, error)
|
||||
TargetRepoFactory func() (*target.Repository, error)
|
||||
WorkerAuthRepoStorageFactory func() (*servers.WorkerAuthRepositoryStorage, error)
|
||||
)
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/scheduler"
|
||||
"github.com/hashicorp/boundary/internal/scheduler/job"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
serversjob "github.com/hashicorp/boundary/internal/servers/job"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
@@ -65,19 +66,20 @@ type Controller struct {
|
||||
apiGrpcGatewayTicket string
|
||||
|
||||
// Repo factory methods
|
||||
AuthTokenRepoFn common.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFn common.VaultCredentialRepoFactory
|
||||
StaticCredentialRepoFn common.StaticCredentialRepoFactory
|
||||
IamRepoFn common.IamRepoFactory
|
||||
OidcRepoFn common.OidcAuthRepoFactory
|
||||
PasswordAuthRepoFn common.PasswordAuthRepoFactory
|
||||
ServersRepoFn common.ServersRepoFactory
|
||||
SessionRepoFn common.SessionRepoFactory
|
||||
ConnectionRepoFn common.ConnectionRepoFactory
|
||||
StaticHostRepoFn common.StaticRepoFactory
|
||||
PluginHostRepoFn common.PluginHostRepoFactory
|
||||
HostPluginRepoFn common.HostPluginRepoFactory
|
||||
TargetRepoFn common.TargetRepoFactory
|
||||
AuthTokenRepoFn common.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFn common.VaultCredentialRepoFactory
|
||||
StaticCredentialRepoFn common.StaticCredentialRepoFactory
|
||||
IamRepoFn common.IamRepoFactory
|
||||
OidcRepoFn common.OidcAuthRepoFactory
|
||||
PasswordAuthRepoFn common.PasswordAuthRepoFactory
|
||||
ServersRepoFn common.ServersRepoFactory
|
||||
SessionRepoFn common.SessionRepoFactory
|
||||
ConnectionRepoFn common.ConnectionRepoFactory
|
||||
StaticHostRepoFn common.StaticRepoFactory
|
||||
PluginHostRepoFn common.PluginHostRepoFactory
|
||||
HostPluginRepoFn common.HostPluginRepoFactory
|
||||
TargetRepoFn common.TargetRepoFactory
|
||||
WorkerAuthRepoStorageFn common.WorkerAuthRepoStorageFactory
|
||||
|
||||
scheduler *scheduler.Scheduler
|
||||
|
||||
@@ -299,6 +301,10 @@ func New(ctx context.Context, conf *Config) (*Controller, error) {
|
||||
c.ConnectionRepoFn = func() (*session.ConnectionRepository, error) {
|
||||
return session.NewConnectionRepository(ctx, dbase, dbase, c.kms)
|
||||
}
|
||||
c.WorkerAuthRepoStorageFn = func() (*servers.WorkerAuthRepositoryStorage, error) {
|
||||
return servers.NewRepositoryStorage(ctx, dbase, dbase, c.kms)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -308,7 +314,9 @@ func (c *Controller) Start() error {
|
||||
event.WriteSysEvent(context.TODO(), op, "already started, skipping")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.baseContext, c.baseCancel = context.WithCancel(context.Background())
|
||||
|
||||
if err := c.registerJobs(); err != nil {
|
||||
return fmt.Errorf("error registering jobs: %w", err)
|
||||
}
|
||||
@@ -316,9 +324,9 @@ func (c *Controller) Start() error {
|
||||
return fmt.Errorf("error starting controller listeners: %w", err)
|
||||
}
|
||||
|
||||
// Upsert server before starting tickers and scheduler to ensure the server exists
|
||||
if err := c.upsertServer(c.baseContext); err != nil {
|
||||
return fmt.Errorf("error upserting server: %w", err)
|
||||
// Upsert controller before starting tickers and scheduler to ensure the controller exists
|
||||
if err := c.upsertController(c.baseContext); err != nil {
|
||||
return fmt.Errorf("error upserting controller: %w", err)
|
||||
}
|
||||
if err := c.scheduler.Start(c.baseContext, c.schedulerWg); err != nil {
|
||||
return fmt.Errorf("error starting scheduler: %w", err)
|
||||
@@ -360,6 +368,9 @@ func (c *Controller) registerJobs() error {
|
||||
if err := session.RegisterJobs(c.baseContext, c.scheduler, rw, rw, c.kms, c.conf.StatusGracePeriodDuration); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := serversjob.RegisterJobs(c.baseContext, c.scheduler, rw, rw, c.kms); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/sessions"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/internal/metric"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
|
||||
@@ -224,6 +225,13 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error {
|
||||
}
|
||||
services.RegisterCredentialLibraryServiceServer(s, cl)
|
||||
}
|
||||
if _, ok := currentServices[services.WorkerService_ServiceDesc.ServiceName]; !ok {
|
||||
ws, err := workers.NewService(c.baseContext, c.ServersRepoFn, c.IamRepoFn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create worker handler service: %w", err)
|
||||
}
|
||||
services.RegisterWorkerServiceServer(s, ws)
|
||||
}
|
||||
if _, ok := currentServices[services.CredentialService_ServiceDesc.ServiceName]; !ok {
|
||||
c, err := credentials.NewService(c.StaticCredentialRepoFn, c.IamRepoFn)
|
||||
if err != nil {
|
||||
@@ -288,6 +296,9 @@ func registerGrpcGatewayEndpoints(ctx context.Context, gwMux *runtime.ServeMux,
|
||||
if err := services.RegisterCredentialLibraryServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
|
||||
return fmt.Errorf("failed to register credential library service handler: %w", err)
|
||||
}
|
||||
if err := services.RegisterWorkerServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
|
||||
return fmt.Errorf("failed to register worker service handler: %w", err)
|
||||
}
|
||||
if err := services.RegisterCredentialServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
|
||||
return fmt.Errorf("failed to register credential service handler: %w", err)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/sessions"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
@@ -63,6 +64,7 @@ var (
|
||||
resource.Role: roles.CollectionActions,
|
||||
resource.Scope: CollectionActions,
|
||||
resource.User: users.CollectionActions,
|
||||
resource.Worker: workers.CollectionActions,
|
||||
},
|
||||
|
||||
scope.Org.String(): {
|
||||
|
||||
@@ -95,6 +95,12 @@ var globalAuthorizedCollectionActions = map[string]*structpb.ListValue{
|
||||
structpb.NewStringValue("list"),
|
||||
},
|
||||
},
|
||||
"workers": {
|
||||
Values: []*structpb.Value{
|
||||
structpb.NewStringValue("create:worker-led"),
|
||||
structpb.NewStringValue("list"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var orgAuthorizedCollectionActions = map[string]*structpb.ListValue{
|
||||
|
||||
@@ -799,77 +799,27 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
// worker IDs below is used to contain their IDs in the same order. This is
|
||||
// used to fetch tags for filtering. But we avoid allocation unless we
|
||||
// actually need it.
|
||||
var workers []*pb.WorkerInfo
|
||||
var workerIds []string
|
||||
hasWorkerFilter := len(t.GetWorkerFilter()) > 0
|
||||
servers, err := serversRepo.ListServers(ctx, servers.ServerTypeWorker)
|
||||
selectedWorkers, err := serversRepo.ListWorkers(ctx, []string{scope.Global.String()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range servers {
|
||||
if hasWorkerFilter {
|
||||
workerIds = append(workerIds, v.GetPrivateId())
|
||||
}
|
||||
workers = append(workers, &pb.WorkerInfo{Address: v.Address})
|
||||
}
|
||||
|
||||
if hasWorkerFilter && len(workerIds) > 0 {
|
||||
finalWorkers := make([]*pb.WorkerInfo, 0, len(workers))
|
||||
// Fetch the tags for the given worker IDs
|
||||
tags, err := serversRepo.ListTagsForServers(ctx, workerIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Build the map for filtering. This is similar to the filter map we
|
||||
// built from the worker config, but with one extra level: a map of the
|
||||
// worker's ID to its filter map.
|
||||
tagMap := make(map[string]map[string][]string)
|
||||
for _, tag := range tags {
|
||||
currWorkerMap := tagMap[tag.ServerId]
|
||||
if currWorkerMap == nil {
|
||||
currWorkerMap = make(map[string][]string)
|
||||
tagMap[tag.ServerId] = currWorkerMap
|
||||
}
|
||||
currWorkerMap[tag.Key] = append(currWorkerMap[tag.Key], tag.Value)
|
||||
// We don't need to reinsert after the fact because maps are
|
||||
// reference types, so we don't need to re-insert into tagMap
|
||||
}
|
||||
|
||||
// Create the evaluator
|
||||
if len(t.GetWorkerFilter()) > 0 && len(selectedWorkers) > 0 {
|
||||
eval, err := bexpr.CreateEvaluator(t.GetWorkerFilter())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Iterate through the known worker IDs, and evaluate. If evaluation
|
||||
// returns true, add to the final worker slice, which is assigned back
|
||||
// to workers after this.
|
||||
for i, worker := range workerIds {
|
||||
filterInput := map[string]interface{}{
|
||||
"name": worker,
|
||||
"tags": tagMap[worker],
|
||||
}
|
||||
ok, err := eval.Evaluate(filterInput)
|
||||
if err != nil && !stderrors.Is(err, pointerstructure.ErrNotFound) {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(
|
||||
codes.FailedPrecondition,
|
||||
fmt.Sprintf("Worker filter expression evaluation resulted in error: %s", err))
|
||||
}
|
||||
if ok {
|
||||
finalWorkers = append(finalWorkers, workers[i])
|
||||
}
|
||||
selectedWorkers, err = workerList(selectedWorkers).filtered(eval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workers = finalWorkers
|
||||
}
|
||||
if len(workers) == 0 {
|
||||
|
||||
if len(selectedWorkers) == 0 {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(
|
||||
codes.FailedPrecondition,
|
||||
"No workers are available to handle this session, or all have been filtered.")
|
||||
}
|
||||
workerAddresses := make([]string, 0, len(workers))
|
||||
for _, worker := range workers {
|
||||
workerAddresses = append(workerAddresses, worker.GetAddress())
|
||||
}
|
||||
|
||||
requestedId := req.GetHostId()
|
||||
staticHostRepo, err := s.staticHostRepoFn()
|
||||
@@ -992,7 +942,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sess, privKey, err := sessionRepo.CreateSession(ctx, wrapper, sess, workerAddresses)
|
||||
sess, privKey, err := sessionRepo.CreateSession(ctx, wrapper, sess, workerList(selectedWorkers).addresses())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1091,7 +1041,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
PrivateKey: privKey,
|
||||
HostId: chosenEndpoint.HostId,
|
||||
Endpoint: endpointUrl.String(),
|
||||
WorkerInfo: workers,
|
||||
WorkerInfo: workerList(selectedWorkers).workerInfos(),
|
||||
ConnectionLimit: t.GetSessionConnectionLimit(),
|
||||
}
|
||||
marshaledSad, err := proto.Marshal(sad)
|
||||
@@ -1966,3 +1916,46 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// workerList is a helper type to make the selection of workers clearer and more declarative.
|
||||
type workerList []*servers.Worker
|
||||
|
||||
// addresses converts the slice of workers to a slice of their addresses
|
||||
func (w workerList) addresses() []string {
|
||||
ret := make([]string, 0, len(w))
|
||||
for _, worker := range w {
|
||||
ret = append(ret, worker.GetAddress())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// workerInfos converts the slice of workers to a slice of their workerInfo protos
|
||||
func (w workerList) workerInfos() []*pb.WorkerInfo {
|
||||
ret := make([]*pb.WorkerInfo, 0, len(w))
|
||||
for _, worker := range w {
|
||||
ret = append(ret, &pb.WorkerInfo{Address: worker.GetAddress()})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// filtered returns a new workerList where all elements contained in it are the
|
||||
// ones which from the original workerList that pass the evaluator's evaluation.
|
||||
func (w workerList) filtered(eval *bexpr.Evaluator) (workerList, error) {
|
||||
var ret []*servers.Worker
|
||||
for _, worker := range w {
|
||||
filterInput := map[string]interface{}{
|
||||
"name": worker.GetName(),
|
||||
"tags": worker.CanonicalTags(),
|
||||
}
|
||||
ok, err := eval.Evaluate(filterInput)
|
||||
if err != nil && !stderrors.Is(err, pointerstructure.ErrNotFound) {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(
|
||||
codes.FailedPrecondition,
|
||||
fmt.Sprintf("Worker filter expression evaluation resulted in error: %s", err))
|
||||
}
|
||||
if ok {
|
||||
ret = append(ret, worker)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package targets
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
"github.com/hashicorp/go-bexpr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWorkerList_Addresses(t *testing.T) {
|
||||
addresses := []string{
|
||||
"test1",
|
||||
"test2",
|
||||
"test3",
|
||||
"test4",
|
||||
}
|
||||
var workerInfos []*pb.WorkerInfo
|
||||
var tested workerList
|
||||
for _, a := range addresses {
|
||||
workerInfos = append(workerInfos, &pb.WorkerInfo{Address: a})
|
||||
tested = append(tested, servers.NewWorker(scope.Global.String(),
|
||||
servers.WithName(a),
|
||||
servers.WithAddress(a)))
|
||||
}
|
||||
assert.Equal(t, addresses, tested.addresses())
|
||||
assert.Equal(t, workerInfos, tested.workerInfos())
|
||||
}
|
||||
|
||||
func TestWorkerList_Filter(t *testing.T) {
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
var workers []*servers.Worker
|
||||
for i := 0; i < 5; i++ {
|
||||
switch {
|
||||
case i%2 == 0:
|
||||
workers = append(workers, servers.TestKmsWorker(t, conn, wrapper,
|
||||
servers.WithName(fmt.Sprintf("test_worker_%d", i)),
|
||||
servers.WithWorkerTags(&servers.Tag{
|
||||
Key: fmt.Sprintf("key%d", i),
|
||||
Value: fmt.Sprintf("value%d", i),
|
||||
})))
|
||||
default:
|
||||
workers = append(workers, servers.TestPkiWorker(t, conn, wrapper,
|
||||
servers.WithName(fmt.Sprintf("test_worker_%d", i)),
|
||||
servers.WithWorkerTags(&servers.Tag{
|
||||
Key: "key",
|
||||
Value: "configvalue",
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ev, err := bexpr.CreateEvaluator(`"/name" matches "test_worker_[13]" and "configvalue2" in "/tags/key"`)
|
||||
require.NoError(t, err)
|
||||
got, err := workerList(workers).filtered(ev)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, got, 0)
|
||||
}
|
||||
{
|
||||
ev, err := bexpr.CreateEvaluator(`"/name" matches "test_worker_[12]" and "configvalue" in "/tags/key"`)
|
||||
require.NoError(t, err)
|
||||
got, err := workerList(workers).filtered(ev)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, got, 1)
|
||||
}
|
||||
{
|
||||
ev, err := bexpr.CreateEvaluator(`"configvalue" in "/tags/key"`)
|
||||
require.NoError(t, err)
|
||||
got, err := workerList(workers).filtered(ev)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, got, 2)
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,12 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
credstatic "github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
cluster "github.com/hashicorp/boundary/internal/daemon/cluster/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentiallibraries"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentials"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
|
||||
@@ -2371,9 +2371,6 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
sessionRepoFn := func() (*session.Repository, error) {
|
||||
return session.NewRepository(rw, rw, kms)
|
||||
}
|
||||
connectionRepoFn := func() (*session.ConnectionRepository, error) {
|
||||
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
staticRepo, err := static.NewRepository(rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
staticHostRepoFn := func() (*static.Repository, error) {
|
||||
@@ -2532,14 +2529,7 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Tell our DB that there is a worker ready to serve the data
|
||||
workerService := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, &sync.Map{}, kms)
|
||||
_, err = workerService.Status(ctx, &spbs.StatusRequest{
|
||||
Worker: &spb.Server{
|
||||
PrivateId: "testworker",
|
||||
Address: "localhost:8457",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
servers.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
asRes1, err := s.AuthorizeSession(ctx, &pbs.AuthorizeSessionRequest{
|
||||
Id: tar.GetPublicId(),
|
||||
@@ -2641,9 +2631,6 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
|
||||
sessionRepoFn := func() (*session.Repository, error) {
|
||||
return session.NewRepository(rw, rw, kms)
|
||||
}
|
||||
connectionRepoFn := func() (*session.ConnectionRepository, error) {
|
||||
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
staticHostRepoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
@@ -2887,14 +2874,7 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Tell our DB that there is a worker ready to serve the data
|
||||
workerService := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, &sync.Map{}, kms)
|
||||
_, err = workerService.Status(ctx, &spbs.StatusRequest{
|
||||
Worker: &spb.Server{
|
||||
PrivateId: "testworker",
|
||||
Address: "localhost:8457",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
servers.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
asRes, err := s.AuthorizeSession(ctx, &pbs.AuthorizeSessionRequest{
|
||||
Id: tar.GetPublicId(),
|
||||
@@ -3002,11 +2982,12 @@ func TestAuthorizeSession_Errors(t *testing.T) {
|
||||
store := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
|
||||
|
||||
workerExists := func(tar target.Target) (version uint32) {
|
||||
workerService := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, &sync.Map{}, kms)
|
||||
workerService := cluster.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, connectionRepoFn, &sync.Map{}, kms)
|
||||
_, err := workerService.Status(context.Background(), &spbs.StatusRequest{
|
||||
Worker: &spb.Server{
|
||||
PrivateId: "testworker",
|
||||
Address: "localhost:123",
|
||||
WorkerStatus: &spb.ServerWorkerStatus{
|
||||
PublicId: "w_1234567890",
|
||||
Name: "w_1234567890",
|
||||
Address: "localhost:123",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -2,432 +2,616 @@ package workers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common/scopeids"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/perms"
|
||||
"github.com/hashicorp/boundary/internal/requests"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/servers/store"
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
"github.com/hashicorp/go-bexpr"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/mr-tron/base58"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
type workerServiceServer struct {
|
||||
pbs.UnimplementedServerCoordinationServiceServer
|
||||
pbs.UnimplementedSessionServiceServer
|
||||
|
||||
serversRepoFn common.ServersRepoFactory
|
||||
sessionRepoFn common.SessionRepoFactory
|
||||
connectionRepoFn common.ConnectionRepoFactory
|
||||
updateTimes *sync.Map
|
||||
kms *kms.Kms
|
||||
}
|
||||
|
||||
func NewWorkerServiceServer(
|
||||
serversRepoFn common.ServersRepoFactory,
|
||||
sessionRepoFn common.SessionRepoFactory,
|
||||
connectionRepoFn common.ConnectionRepoFactory,
|
||||
updateTimes *sync.Map,
|
||||
kms *kms.Kms,
|
||||
) *workerServiceServer {
|
||||
return &workerServiceServer{
|
||||
serversRepoFn: serversRepoFn,
|
||||
sessionRepoFn: sessionRepoFn,
|
||||
connectionRepoFn: connectionRepoFn,
|
||||
updateTimes: updateTimes,
|
||||
kms: kms,
|
||||
}
|
||||
}
|
||||
const (
|
||||
PkiWorkerType = "pki"
|
||||
KmsWorkerType = "kms"
|
||||
)
|
||||
|
||||
var (
|
||||
_ pbs.SessionServiceServer = &workerServiceServer{}
|
||||
_ pbs.ServerCoordinationServiceServer = &workerServiceServer{}
|
||||
maskManager handlers.MaskManager
|
||||
|
||||
// IdActions contains the set of actions that can be performed on
|
||||
// individual resources
|
||||
IdActions = action.ActionSet{
|
||||
action.NoOp,
|
||||
action.Read,
|
||||
action.Update,
|
||||
action.Delete,
|
||||
}
|
||||
|
||||
// CollectionActions contains the set of actions that can be performed on
|
||||
// this collection
|
||||
CollectionActions = action.ActionSet{
|
||||
action.CreateWorkerLed,
|
||||
action.List,
|
||||
}
|
||||
)
|
||||
|
||||
func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) {
|
||||
const op = "workers.(workerServiceServer).Status"
|
||||
// TODO: on the worker, if we get errors back from this repeatedly, do we
|
||||
// terminate all sessions since we can't know if they were canceled?
|
||||
ws.updateTimes.Store(req.Worker.PrivateId, time.Now())
|
||||
serverRepo, err := ws.serversRepoFn()
|
||||
func init() {
|
||||
var err error
|
||||
if maskManager, err = handlers.NewMaskManager(handlers.MaskDestination{&store.Worker{}}, handlers.MaskSource{&pb.Worker{}}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Service handles request as described by the pbs.WorkerServiceServer interface.
|
||||
type Service struct {
|
||||
pbs.UnimplementedWorkerServiceServer
|
||||
|
||||
repoFn common.ServersRepoFactory
|
||||
iamRepoFn common.IamRepoFactory
|
||||
}
|
||||
|
||||
// NewService returns a worker service which handles worker related requests to boundary.
|
||||
func NewService(ctx context.Context, repo common.ServersRepoFactory, iamRepoFn common.IamRepoFactory) (Service, error) {
|
||||
const op = "workers.NewService"
|
||||
if repo == nil {
|
||||
return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing servers repository")
|
||||
}
|
||||
if iamRepoFn == nil {
|
||||
return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing iam repository")
|
||||
}
|
||||
return Service{repoFn: repo, iamRepoFn: iamRepoFn}, nil
|
||||
}
|
||||
|
||||
var _ pbs.WorkerServiceServer = Service{}
|
||||
|
||||
// ListWorkers implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) ListWorkers(ctx context.Context, req *pbs.ListWorkersRequest) (*pbs.ListWorkersResponse, error) {
|
||||
if err := validateListRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetScopeId(), action.List)
|
||||
if authResults.Error != nil {
|
||||
// If it's forbidden, and it's a recursive request, and they're
|
||||
// successfully authenticated but just not authorized, keep going as we
|
||||
// may have authorization on downstream scopes. Or, if they've not
|
||||
// authenticated, still process in case u_anon has permissions.
|
||||
if (authResults.Error == handlers.ForbiddenError() || authResults.Error == handlers.UnauthenticatedError()) &&
|
||||
req.GetRecursive() &&
|
||||
authResults.AuthenticationFinished {
|
||||
} else {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
}
|
||||
|
||||
scopeIds, scopeInfoMap, err := scopeids.GetListingScopeIds(
|
||||
ctx, s.iamRepoFn, authResults, req.GetScopeId(), resource.Worker, req.GetRecursive())
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting servers repo"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to store worker status: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
connectionRepo, err := ws.connectionRepoFn()
|
||||
// If no scopes match, return an empty response
|
||||
if len(scopeIds) == 0 {
|
||||
return &pbs.ListWorkersResponse{}, nil
|
||||
}
|
||||
|
||||
ul, err := s.listFromRepo(ctx, scopeIds)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting sessions repo"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
req.Worker.Type = resource.Worker.String()
|
||||
controllers, _, err := serverRepo.UpsertServer(ctx, req.Worker, servers.WithUpdateTags(req.GetUpdateTags()))
|
||||
if len(ul) == 0 {
|
||||
return &pbs.ListWorkersResponse{}, nil
|
||||
}
|
||||
|
||||
filter, err := handlers.NewFilter(req.GetFilter())
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error storing worker status"))
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error storing worker status: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
ret := &pbs.StatusResponse{
|
||||
Controllers: controllers,
|
||||
finalItems := make([]*pb.Worker, 0, len(ul))
|
||||
res := perms.Resource{
|
||||
Type: resource.Worker,
|
||||
}
|
||||
for _, item := range ul {
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId)
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(scopeInfoMap[item.GetScopeId()]))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions))
|
||||
}
|
||||
|
||||
item, err := toProto(ctx, item, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if filter.Match(item) {
|
||||
finalItems = append(finalItems, item)
|
||||
}
|
||||
}
|
||||
return &pbs.ListWorkersResponse{Items: finalItems}, nil
|
||||
}
|
||||
|
||||
// GetWorker implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) GetWorker(ctx context.Context, req *pbs.GetWorkerRequest) (*pbs.GetWorkerResponse, error) {
|
||||
const op = "workers.(Service).GetWorker"
|
||||
|
||||
if err := validateGetRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetId(), action.Read)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
w, err := s.getFromRepo(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stateReport := make([]session.StateReport, 0, len(req.GetJobs()))
|
||||
outputFields, ok := requests.OutputFields(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
|
||||
for _, jobStatus := range req.GetJobs() {
|
||||
switch jobStatus.Job.GetType() {
|
||||
case pbs.JOBTYPE_JOBTYPE_SESSION:
|
||||
si := jobStatus.GetJob().GetSessionInfo()
|
||||
if si == nil {
|
||||
return nil, status.Error(codes.Internal, "Error getting session info at status time")
|
||||
}
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, w.GetPublicId(), IdActions).Strings()))
|
||||
}
|
||||
|
||||
switch si.Status {
|
||||
case pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING,
|
||||
pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED:
|
||||
// No need to see about canceling anything
|
||||
continue
|
||||
}
|
||||
item, err := toProto(ctx, w, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sr := session.StateReport{
|
||||
SessionId: si.GetSessionId(),
|
||||
ConnectionIds: make([]string, 0, len(si.GetConnections())),
|
||||
}
|
||||
for _, conn := range si.GetConnections() {
|
||||
switch conn.Status {
|
||||
case pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_AUTHORIZED,
|
||||
pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED:
|
||||
sr.ConnectionIds = append(sr.ConnectionIds, conn.GetConnectionId())
|
||||
return &pbs.GetWorkerResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
// CreateWorker implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) CreateWorkerLed(ctx context.Context, req *pbs.CreateWorkerLedRequest) (*pbs.CreateWorkerLedResponse, error) {
|
||||
const op = "workers.(Service).CreateWorkerLed"
|
||||
|
||||
if err := validateCreateRequest(req); 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())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: error decoding node_credentials_token: %w", op, err)
|
||||
}
|
||||
// Decode the proto into the request
|
||||
creds := new(types.FetchNodeCredentialsRequest)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: error creating worker: %w", op, err)
|
||||
}
|
||||
|
||||
outputFields, ok := requests.OutputFields(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, created.GetPublicId(), IdActions).Strings()))
|
||||
}
|
||||
|
||||
item, err := toProto(ctx, created, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbs.CreateWorkerLedResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
// DeleteWorker implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) DeleteWorker(ctx context.Context, req *pbs.DeleteWorkerRequest) (*pbs.DeleteWorkerResponse, error) {
|
||||
if err := validateDeleteRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetId(), action.Delete)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
_, err := s.deleteFromRepo(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// UpdateWorker implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) UpdateWorker(ctx context.Context, req *pbs.UpdateWorkerRequest) (*pbs.UpdateWorkerResponse, error) {
|
||||
const op = "workers.(Service).UpdateWorker"
|
||||
|
||||
if err := validateUpdateRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetId(), action.Update)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
w, err := s.updateInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputFields, ok := requests.OutputFields(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, w.GetPublicId(), IdActions).Strings()))
|
||||
}
|
||||
|
||||
item, err := toProto(ctx, w, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbs.UpdateWorkerResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
func (s Service) listFromRepo(ctx context.Context, scopeIds []string) ([]*servers.Worker, error) {
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wl, err := repo.ListWorkers(ctx, scopeIds, servers.WithLiveness(-1))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wl, nil
|
||||
}
|
||||
|
||||
func (s Service) getFromRepo(ctx context.Context, id string) (*servers.Worker, error) {
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w, err := repo.LookupWorker(ctx, id)
|
||||
if err != nil {
|
||||
if errors.IsNotFoundError(err) {
|
||||
return nil, handlers.NotFoundErrorf("Worker %q doesn't exist.", id)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if w == nil {
|
||||
return nil, handlers.NotFoundErrorf("Worker %q doesn't exist.", id)
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (s Service) createInRepo(ctx context.Context, worker *pb.Worker, creds *types.FetchNodeCredentialsRequest) (*servers.Worker, error) {
|
||||
const op = "workers.(Service).createInRepo"
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newWorker := servers.NewWorker(
|
||||
worker.GetScopeId(),
|
||||
servers.WithName(worker.GetName().GetValue()),
|
||||
servers.WithDescription(worker.GetDescription().GetValue()),
|
||||
)
|
||||
retWorker, err := repo.CreateWorker(ctx, newWorker, servers.WithFetchNodeCredentialsRequest(creds))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create worker"))
|
||||
}
|
||||
return retWorker, nil
|
||||
}
|
||||
|
||||
func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
|
||||
const op = "workers.(Service).deleteFromRepo"
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rows, err := repo.DeleteWorker(ctx, id)
|
||||
if err != nil {
|
||||
if errors.IsNotFoundError(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete worker"))
|
||||
}
|
||||
return rows > 0, nil
|
||||
}
|
||||
|
||||
func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Worker) (*servers.Worker, error) {
|
||||
const op = "workers.(Service).updateInRepo"
|
||||
var opts []servers.Option
|
||||
if desc := item.GetDescription(); desc != nil {
|
||||
opts = append(opts, servers.WithDescription(desc.GetValue()))
|
||||
}
|
||||
if name := item.GetName(); name != nil {
|
||||
opts = append(opts, servers.WithName(name.GetValue()))
|
||||
}
|
||||
w := servers.NewWorker(scopeId, opts...)
|
||||
w.PublicId = id
|
||||
dbMask := maskManager.Translate(mask)
|
||||
if len(dbMask) == 0 {
|
||||
return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid fields provided in the update mask."})
|
||||
}
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, rowsUpdated, err := repo.UpdateWorker(ctx, w, item.GetVersion(), dbMask)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update worker"))
|
||||
}
|
||||
if rowsUpdated == 0 {
|
||||
return nil, handlers.NotFoundErrorf("Worker %q doesn't exist or incorrect version provided.", id)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.VerifyResults {
|
||||
res := auth.VerifyResults{}
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
res.Error = err
|
||||
return res
|
||||
}
|
||||
|
||||
var parentId string
|
||||
opts := []auth.Option{auth.WithType(resource.Worker), auth.WithAction(a)}
|
||||
switch a {
|
||||
case action.List, action.CreateWorkerLed:
|
||||
parentId = id
|
||||
default:
|
||||
w, err := repo.LookupWorker(ctx, id)
|
||||
if err != nil {
|
||||
res.Error = err
|
||||
return res
|
||||
}
|
||||
if w == nil {
|
||||
res.Error = handlers.NotFoundError()
|
||||
return res
|
||||
}
|
||||
parentId = w.GetScopeId()
|
||||
opts = append(opts, auth.WithId(id))
|
||||
}
|
||||
opts = append(opts, auth.WithScopeId(parentId))
|
||||
return auth.Verify(ctx, opts...)
|
||||
}
|
||||
|
||||
func toProto(ctx context.Context, in *servers.Worker, opt ...handlers.Option) (*pb.Worker, error) {
|
||||
const op = "workers.toProto"
|
||||
opts := handlers.GetOpts(opt...)
|
||||
if opts.WithOutputFields == nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "output fields not found when building worker proto")
|
||||
}
|
||||
outputFields := *opts.WithOutputFields
|
||||
|
||||
out := pb.Worker{}
|
||||
if outputFields.Has(globals.IdField) {
|
||||
out.Id = in.GetPublicId()
|
||||
}
|
||||
if outputFields.Has(globals.ScopeIdField) {
|
||||
out.ScopeId = in.GetScopeId()
|
||||
}
|
||||
if outputFields.Has(globals.DescriptionField) && in.GetDescription() != "" {
|
||||
out.Description = wrapperspb.String(in.GetDescription())
|
||||
}
|
||||
if outputFields.Has(globals.NameField) && in.GetName() != "" {
|
||||
out.Name = wrapperspb.String(in.GetName())
|
||||
}
|
||||
if outputFields.Has(globals.CreatedTimeField) {
|
||||
out.CreatedTime = in.GetCreateTime().GetTimestamp()
|
||||
}
|
||||
if outputFields.Has(globals.UpdatedTimeField) {
|
||||
out.UpdatedTime = in.GetUpdateTime().GetTimestamp()
|
||||
}
|
||||
if outputFields.Has(globals.VersionField) {
|
||||
out.Version = in.GetVersion()
|
||||
}
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
out.Scope = opts.WithScope
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
out.AuthorizedActions = opts.WithAuthorizedActions
|
||||
if in.Type == KmsWorkerType && out.AuthorizedActions != nil {
|
||||
// KMS workers cannot be updated through the API
|
||||
allActions := out.AuthorizedActions
|
||||
out.AuthorizedActions = make([]string, 0, len(allActions))
|
||||
for _, act := range allActions {
|
||||
if act != action.Update.String() {
|
||||
out.AuthorizedActions = append(out.AuthorizedActions, act)
|
||||
}
|
||||
}
|
||||
stateReport = append(stateReport, sr)
|
||||
}
|
||||
}
|
||||
if outputFields.Has(globals.AddressField) && in.GetAddress() != "" {
|
||||
out.Address = in.GetAddress()
|
||||
}
|
||||
if outputFields.Has(globals.TypeField) && in.GetType() != "" {
|
||||
out.Type = in.GetType()
|
||||
}
|
||||
if outputFields.Has(globals.LastStatusTimeField) {
|
||||
out.LastStatusTime = in.GetLastStatusTime().GetTimestamp()
|
||||
}
|
||||
if outputFields.Has(globals.ActiveConnectionCountField) {
|
||||
out.ActiveConnectionCount = &wrapperspb.UInt32Value{Value: in.ActiveConnectionCount()}
|
||||
}
|
||||
if outputFields.Has(globals.ConfigTagsField) && len(in.GetConfigTags()) > 0 {
|
||||
var err error
|
||||
out.ConfigTags, err = tagsToMapProto(in.GetConfigTags())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error preparing config tags proto"))
|
||||
}
|
||||
}
|
||||
if outputFields.Has(globals.CanonicalTagsField) && len(in.CanonicalTags()) > 0 {
|
||||
var err error
|
||||
out.CanonicalTags, err = tagsToMapProto(in.CanonicalTags())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error preparing canonical tags proto"))
|
||||
}
|
||||
}
|
||||
|
||||
notActive, err := session.WorkerStatusReport(ctx, sessRepo, connectionRepo, req.Worker.PrivateId, stateReport)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error comparing state of sessions for worker: %s: %v", req.Worker.PrivateId, err)
|
||||
}
|
||||
for _, na := range notActive {
|
||||
var connChanges []*pbs.Connection
|
||||
for _, connId := range na.ConnectionIds {
|
||||
connChanges = append(connChanges, &pbs.Connection{
|
||||
ConnectionId: connId,
|
||||
Status: session.StatusClosed.ProtoVal(),
|
||||
})
|
||||
}
|
||||
ret.JobsRequests = append(ret.JobsRequests, &pbs.JobChangeRequest{
|
||||
Job: &pbs.Job{
|
||||
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
||||
JobInfo: &pbs.Job_SessionInfo{
|
||||
SessionInfo: &pbs.SessionJobInfo{
|
||||
SessionId: na.SessionId,
|
||||
Status: na.Status.ProtoVal(),
|
||||
Connections: connChanges,
|
||||
},
|
||||
},
|
||||
},
|
||||
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
||||
})
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func tagsToMapProto(in map[string][]string) (map[string]*structpb.ListValue, error) {
|
||||
b := make(map[string][]interface{})
|
||||
for k, v := range in {
|
||||
result := make([]interface{}, 0, len(v))
|
||||
for _, t := range v {
|
||||
result = append(result, t)
|
||||
}
|
||||
b[k] = result
|
||||
}
|
||||
ret := make(map[string]*structpb.ListValue)
|
||||
var err error
|
||||
for k, v := range b {
|
||||
ret[k], err = structpb.NewList(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) LookupSession(ctx context.Context, req *pbs.LookupSessionRequest) (*pbs.LookupSessionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).LookupSession"
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
sessionInfo, authzSummary, err := sessRepo.LookupSession(ctx, req.GetSessionId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error looking up session: %v", err)
|
||||
}
|
||||
if sessionInfo == nil {
|
||||
return nil, status.Error(codes.PermissionDenied, "Unknown session ID.")
|
||||
}
|
||||
if len(sessionInfo.States) == 0 {
|
||||
return nil, status.Error(codes.Internal, "Empty session states during lookup.")
|
||||
}
|
||||
|
||||
if sessionInfo.WorkerFilter != "" {
|
||||
if req.ServerId == "" {
|
||||
event.WriteError(ctx, op, errors.New("worker filter enabled for session but got no server ID from worker"))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Did not receive server ID when looking up session but filtering is enabled: %v", err)
|
||||
}
|
||||
serversRepo, err := ws.serversRepoFn()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error getting servers repo"))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error acquiring server repo when looking up session: %v", err)
|
||||
}
|
||||
tags, err := serversRepo.ListTagsForServers(ctx, []string{req.ServerId})
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error looking up tags for server", "server_id", req.ServerId))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error looking up tags for server: %v", err)
|
||||
}
|
||||
// Build the map for filtering.
|
||||
tagMap := make(map[string][]string)
|
||||
for _, tag := range tags {
|
||||
tagMap[tag.Key] = append(tagMap[tag.Key], tag.Value)
|
||||
// We don't need to reinsert after the fact because maps are
|
||||
// reference types, so we don't need to re-insert into tagMap
|
||||
}
|
||||
|
||||
// Create the evaluator
|
||||
eval, err := bexpr.CreateEvaluator(sessionInfo.WorkerFilter)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error creating worker filter evaluator", "server_id", req.ServerId))
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal, "Error creating worker filter evaluator: %v", err)
|
||||
}
|
||||
filterInput := map[string]interface{}{
|
||||
"name": req.ServerId,
|
||||
"tags": tagMap,
|
||||
}
|
||||
ok, err := eval.Evaluate(filterInput)
|
||||
if err != nil {
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal,
|
||||
fmt.Sprintf("Worker filter expression evaluation resulted in error: %s", err))
|
||||
}
|
||||
if !ok {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(
|
||||
codes.FailedPrecondition,
|
||||
"Worker filter expression precludes this worker from serving this session")
|
||||
}
|
||||
}
|
||||
|
||||
creds, err := sessRepo.ListSessionCredentials(ctx, sessionInfo.ScopeId, sessionInfo.PublicId)
|
||||
if err != nil {
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal,
|
||||
fmt.Sprintf("Error retrieving session credentials: %s", err))
|
||||
}
|
||||
var workerCreds []*pbs.Credential
|
||||
for _, c := range creds {
|
||||
m := &pbs.Credential{}
|
||||
err = proto.Unmarshal(c, m)
|
||||
if err != nil {
|
||||
return &pbs.LookupSessionResponse{}, status.Errorf(codes.Internal,
|
||||
fmt.Sprintf("Error unmarshaling credentials: %s", err))
|
||||
}
|
||||
workerCreds = append(workerCreds, m)
|
||||
}
|
||||
|
||||
resp := &pbs.LookupSessionResponse{
|
||||
Authorization: &targets.SessionAuthorizationData{
|
||||
SessionId: sessionInfo.GetPublicId(),
|
||||
Certificate: sessionInfo.Certificate,
|
||||
},
|
||||
Status: sessionInfo.States[0].Status.ProtoVal(),
|
||||
Version: sessionInfo.Version,
|
||||
TofuToken: string(sessionInfo.TofuToken),
|
||||
Endpoint: sessionInfo.Endpoint,
|
||||
Expiration: sessionInfo.ExpirationTime.Timestamp,
|
||||
ConnectionLimit: sessionInfo.ConnectionLimit,
|
||||
ConnectionsLeft: authzSummary.ConnectionLimit,
|
||||
HostId: sessionInfo.HostId,
|
||||
HostSetId: sessionInfo.HostSetId,
|
||||
TargetId: sessionInfo.TargetId,
|
||||
UserId: sessionInfo.UserId,
|
||||
Credentials: workerCreds,
|
||||
}
|
||||
if resp.ConnectionsLeft != -1 {
|
||||
resp.ConnectionsLeft -= int32(authzSummary.CurrentConnectionCount)
|
||||
}
|
||||
|
||||
wrapper, err := ws.kms.GetWrapper(ctx, sessionInfo.ScopeId, kms.KeyPurposeSessions, kms.WithKeyId(sessionInfo.KeyId))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error getting sessions wrapper: %v", err)
|
||||
}
|
||||
|
||||
// Derive the private key, which should match. Deriving on both ends allows
|
||||
// us to not store it in the DB.
|
||||
_, resp.Authorization.PrivateKey, err = session.DeriveED25519Key(ctx, wrapper, sessionInfo.UserId, sessionInfo.GetPublicId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Error deriving session key: %v", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce
|
||||
// requirements on the structure of the request. They verify that:
|
||||
// * The path passed in is correctly formatted
|
||||
// * All required parameters are set
|
||||
// * There are no conflicting parameters provided
|
||||
func validateGetRequest(req *pbs.GetWorkerRequest) error {
|
||||
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, servers.WorkerPrefix)
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) CancelSession(ctx context.Context, req *pbs.CancelSessionRequest) (*pbs.CancelSessionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).CancelSession"
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
func validateListRequest(req *pbs.ListWorkersRequest) error {
|
||||
badFields := map[string]string{}
|
||||
if req.GetScopeId() != scope.Global.String() {
|
||||
badFields["scope_id"] = "Must be 'global' when listing."
|
||||
}
|
||||
|
||||
ses, _, err := sessRepo.LookupSession(ctx, req.GetSessionId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if _, err := handlers.NewFilter(req.GetFilter()); err != nil {
|
||||
badFields["filter"] = fmt.Sprintf("This field could not be parsed. %v", err)
|
||||
}
|
||||
|
||||
ses, err = sessRepo.CancelSession(ctx, req.GetSessionId(), ses.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(badFields) > 0 {
|
||||
return handlers.InvalidArgumentErrorf("Error in provided request.", badFields)
|
||||
}
|
||||
|
||||
return &pbs.CancelSessionResponse{
|
||||
Status: ses.States[0].Status.ProtoVal(),
|
||||
}, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) ActivateSession(ctx context.Context, req *pbs.ActivateSessionRequest) (*pbs.ActivateSessionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).ActivateSession"
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
sessionInfo, sessionStates, err := sessRepo.ActivateSession(
|
||||
ctx,
|
||||
req.GetSessionId(),
|
||||
req.GetVersion(),
|
||||
req.GetWorkerId(),
|
||||
resource.Worker.String(),
|
||||
[]byte(req.GetTofuToken()))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error looking up session: %v", err)
|
||||
}
|
||||
if sessionInfo == nil {
|
||||
return nil, status.Error(codes.PermissionDenied, "Unknown session ID.")
|
||||
}
|
||||
if len(sessionStates) == 0 {
|
||||
return nil, status.Error(codes.Internal, "Invalid session state in activate response.")
|
||||
}
|
||||
|
||||
return &pbs.ActivateSessionResponse{
|
||||
Status: sessionStates[0].Status.ProtoVal(),
|
||||
}, nil
|
||||
func validateDeleteRequest(req *pbs.DeleteWorkerRequest) error {
|
||||
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, servers.WorkerPrefix)
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) AuthorizeConnection(ctx context.Context, req *pbs.AuthorizeConnectionRequest) (*pbs.AuthorizeConnectionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).AuthorizeConnection"
|
||||
connectionRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
sessionRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
connectionInfo, connStates, authzSummary, err := session.AuthorizeConnection(ctx, sessionRepo, connectionRepo, req.GetSessionId(), req.GetWorkerId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connectionInfo == nil {
|
||||
return nil, status.Error(codes.Internal, "Invalid authorize connection response.")
|
||||
}
|
||||
if len(connStates) == 0 {
|
||||
return nil, status.Error(codes.Internal, "Invalid connection state in authorize response.")
|
||||
}
|
||||
|
||||
ret := &pbs.AuthorizeConnectionResponse{
|
||||
ConnectionId: connectionInfo.GetPublicId(),
|
||||
Status: connStates[0].Status.ProtoVal(),
|
||||
ConnectionsLeft: authzSummary.ConnectionLimit,
|
||||
}
|
||||
if ret.ConnectionsLeft != -1 {
|
||||
ret.ConnectionsLeft -= int32(authzSummary.CurrentConnectionCount)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
func validateUpdateRequest(req *pbs.UpdateWorkerRequest) error {
|
||||
return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string {
|
||||
badFields := map[string]string{}
|
||||
if req.GetItem().GetAddress() != "" {
|
||||
badFields[globals.AddressField] = "This is a read only field."
|
||||
}
|
||||
if req.GetItem().GetCanonicalTags() != nil {
|
||||
badFields[globals.CanonicalAddressField] = "This is a read only field."
|
||||
}
|
||||
if req.GetItem().GetConfigTags() != nil {
|
||||
badFields[globals.TagsField] = "This is a read only field."
|
||||
}
|
||||
nameString := req.GetItem().GetName().String()
|
||||
if !strutil.Printable(nameString) {
|
||||
badFields[globals.NameField] = "Contains non-printable characters"
|
||||
}
|
||||
if strings.ToLower(nameString) != nameString {
|
||||
badFields[globals.NameField] = "Must be all lowercase."
|
||||
}
|
||||
descriptionString := req.GetItem().GetDescription().String()
|
||||
if !strutil.Printable(descriptionString) {
|
||||
badFields[globals.DescriptionField] = "Contains non-printable characters."
|
||||
}
|
||||
return badFields
|
||||
}, servers.WorkerPrefix)
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) ConnectConnection(ctx context.Context, req *pbs.ConnectConnectionRequest) (*pbs.ConnectConnectionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).ConnectConnection"
|
||||
connRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
connectionInfo, connStates, err := connRepo.ConnectConnection(ctx, session.ConnectWith{
|
||||
ConnectionId: req.GetConnectionId(),
|
||||
ClientTcpAddress: req.GetClientTcpAddress(),
|
||||
ClientTcpPort: req.GetClientTcpPort(),
|
||||
EndpointTcpAddress: req.GetEndpointTcpAddress(),
|
||||
EndpointTcpPort: req.GetEndpointTcpPort(),
|
||||
UserClientIp: req.GetUserClientIp(),
|
||||
func validateCreateRequest(req *pbs.CreateWorkerLedRequest) error {
|
||||
return handlers.ValidateCreateRequest(req.GetItem(), 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() {
|
||||
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 {
|
||||
badFields[globals.WorkerGeneratedAuthTokenField] = cannotBeEmptyMsg
|
||||
}
|
||||
if req.GetItem().Address != "" {
|
||||
badFields[globals.CanonicalAddressField] = readOnlyFieldMsg
|
||||
}
|
||||
if req.GetItem().CanonicalTags != nil {
|
||||
badFields[globals.CanonicalTagsField] = readOnlyFieldMsg
|
||||
}
|
||||
if req.GetItem().ConfigTags != nil {
|
||||
badFields[globals.ConfigTagsField] = readOnlyFieldMsg
|
||||
}
|
||||
if req.GetItem().LastStatusTime != nil {
|
||||
badFields[globals.LastStatusTimeField] = readOnlyFieldMsg
|
||||
}
|
||||
if req.GetItem().AuthorizedActions != nil {
|
||||
badFields[globals.AuthorizedActionsField] = readOnlyFieldMsg
|
||||
}
|
||||
nameString := req.GetItem().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()
|
||||
if !strutil.Printable(descriptionString) {
|
||||
badFields[globals.DescriptionField] = "Description contains non-printable characters."
|
||||
}
|
||||
return badFields
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connectionInfo == nil {
|
||||
return nil, status.Error(codes.Internal, "Invalid connect connection response.")
|
||||
}
|
||||
|
||||
return &pbs.ConnectConnectionResponse{
|
||||
Status: connStates[0].Status.ProtoVal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) CloseConnection(ctx context.Context, req *pbs.CloseConnectionRequest) (*pbs.CloseConnectionResponse, error) {
|
||||
const op = "workers.(workerServiceServer).CloseConnection"
|
||||
numCloses := len(req.GetCloseRequestData())
|
||||
if numCloses == 0 {
|
||||
return &pbs.CloseConnectionResponse{}, nil
|
||||
}
|
||||
|
||||
closeWiths := make([]session.CloseWith, 0, numCloses)
|
||||
closeIds := make([]string, 0, numCloses)
|
||||
|
||||
for _, v := range req.GetCloseRequestData() {
|
||||
closeIds = append(closeIds, v.GetConnectionId())
|
||||
closeWiths = append(closeWiths, session.CloseWith{
|
||||
ConnectionId: v.GetConnectionId(),
|
||||
BytesUp: v.GetBytesUp(),
|
||||
BytesDown: v.GetBytesDown(),
|
||||
ClosedReason: session.ClosedReason(v.GetReason()),
|
||||
})
|
||||
}
|
||||
connRepo, err := ws.connectionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting connection repo: %v", err)
|
||||
}
|
||||
|
||||
sessRepo, err := ws.sessionRepoFn()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "error getting session repo: %v", err)
|
||||
}
|
||||
|
||||
closeInfos, err := session.CloseConnections(ctx, sessRepo, connRepo, closeWiths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if closeInfos == nil {
|
||||
return nil, status.Error(codes.Internal, "Invalid close connection response.")
|
||||
}
|
||||
|
||||
closeData := make([]*pbs.CloseConnectionResponseData, 0, numCloses)
|
||||
for _, v := range closeInfos {
|
||||
if v.Connection == nil {
|
||||
return nil, status.Errorf(codes.Internal, "No connection found while closing one of the connection IDs: %v", closeIds)
|
||||
}
|
||||
if len(v.ConnectionStates) == 0 {
|
||||
return nil, status.Errorf(codes.Internal, "No connection states found while closing one of the connection IDs: %v", closeIds)
|
||||
}
|
||||
closeData = append(closeData, &pbs.CloseConnectionResponseData{
|
||||
ConnectionId: v.Connection.GetPublicId(),
|
||||
Status: v.ConnectionStates[0].Status.ProtoVal(),
|
||||
})
|
||||
}
|
||||
|
||||
ret := &pbs.CloseConnectionResponse{
|
||||
CloseResponseData: closeData,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,12 +1,14 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
nodee "github.com/hashicorp/nodeenrollment"
|
||||
)
|
||||
|
||||
// tempError is an error that satisfies the temporary error interface that is
|
||||
@@ -62,42 +64,61 @@ func newInterceptingListener(c *Controller, baseLn net.Listener) *interceptingLi
|
||||
|
||||
func (m *interceptingListener) Accept() (net.Conn, error) {
|
||||
const op = "controller.(interceptingListener).Accept"
|
||||
ctx := context.TODO()
|
||||
ctx := m.c.baseContext
|
||||
conn, err := m.baseLn.Accept()
|
||||
if err != nil {
|
||||
// We may already be closed but can't be sure, so just try anyways
|
||||
if conn != nil {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(context.TODO(), op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
}
|
||||
}
|
||||
return nil, newTempError(err)
|
||||
}
|
||||
|
||||
nonce := make([]byte, 20)
|
||||
read, err := conn.Read(nonce)
|
||||
if err != nil {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
tlsConn := conn.(*tls.Conn)
|
||||
switch {
|
||||
case nodee.ContainsKnownAlpnProto(tlsConn.ConnectionState().NegotiatedProtocol):
|
||||
keyId, err := nodee.KeyIdFromPkix(tlsConn.ConnectionState().PeerCertificates[0].SubjectKeyId)
|
||||
if err != nil {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
}
|
||||
return nil, newTempError(fmt.Errorf("error deriving key id from newly-authenticated node: %w", err))
|
||||
}
|
||||
return nil, newTempError(fmt.Errorf("error reading nonce from connection: %w", err))
|
||||
}
|
||||
if read != len(nonce) {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
event.WriteSysEvent(ctx, op, "worker successfully authenticated", "key_id", keyId)
|
||||
return conn, nil
|
||||
|
||||
case strings.HasPrefix(tlsConn.ConnectionState().NegotiatedProtocol, "v1workerauth"):
|
||||
nonce := make([]byte, 20)
|
||||
read, err := conn.Read(nonce)
|
||||
if err != nil {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
}
|
||||
return nil, newTempError(fmt.Errorf("error reading nonce from connection: %w", err))
|
||||
}
|
||||
return nil, newTempError(fmt.Errorf("error reading nonce from worker, expected %d bytes, got %d", 20, read))
|
||||
}
|
||||
workerInfoRaw, found := m.c.workerAuthCache.Load(string(nonce))
|
||||
if !found {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
if read != len(nonce) {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
}
|
||||
return nil, newTempError(fmt.Errorf("error reading nonce from worker, expected %d bytes, got %d", 20, read))
|
||||
}
|
||||
return nil, newTempError(errors.New("did not find valid nonce for incoming worker"))
|
||||
workerInfoRaw, found := m.c.workerAuthCache.Load(string(nonce))
|
||||
if !found {
|
||||
if err := conn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing worker connection"))
|
||||
}
|
||||
return nil, newTempError(errors.New("did not find valid nonce for incoming worker"))
|
||||
}
|
||||
workerInfo := workerInfoRaw.(*workerAuthEntry)
|
||||
workerInfo.conn = tlsConn
|
||||
event.WriteSysEvent(ctx, op, "worker successfully authed", "name", workerInfo.Name, "description", workerInfo.Description, "proxy_address", workerInfo.ProxyAddress)
|
||||
return tlsConn, nil
|
||||
|
||||
default:
|
||||
return nil, newTempError(errors.New("unable to authenticate incoming connection"))
|
||||
}
|
||||
workerInfo := workerInfoRaw.(*workerAuthEntry)
|
||||
workerInfo.conn = conn
|
||||
event.WriteSysEvent(ctx, op, "worker successfully authed", "name", workerInfo.Name)
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (m *interceptingListener) Close() error {
|
||||
|
||||
@@ -13,10 +13,12 @@ import (
|
||||
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/cluster/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/internal/metric"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/nodeenrollment/multihop"
|
||||
"github.com/hashicorp/nodeenrollment/protocol"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@@ -103,9 +105,25 @@ func (c *Controller) configureForApi(ln *base.ServerListener) ([]func(), error)
|
||||
}
|
||||
|
||||
func (c *Controller) configureForCluster(ln *base.ServerListener) (func(), error) {
|
||||
l := tls.NewListener(ln.ClusterListener, &tls.Config{
|
||||
GetConfigForClient: c.validateWorkerTls,
|
||||
})
|
||||
const op = "controller.configureForCluster"
|
||||
|
||||
workerAuthStorage, err := c.WorkerAuthRepoStorageFn()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching worker auth storage: %w", err)
|
||||
}
|
||||
|
||||
l, err := protocol.NewInterceptingListener(
|
||||
&protocol.InterceptingListenerConfiguration{
|
||||
Context: c.baseContext,
|
||||
Storage: workerAuthStorage,
|
||||
BaseListener: ln.ClusterListener,
|
||||
BaseTlsConfiguration: &tls.Config{
|
||||
GetConfigForClient: c.validateWorkerTls,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error instantiating node auth listener: %w", err)
|
||||
}
|
||||
|
||||
workerReqInterceptor, err := workerRequestInfoInterceptor(c.baseContext, c.conf.Eventer)
|
||||
if err != nil {
|
||||
@@ -125,10 +143,21 @@ func (c *Controller) configureForCluster(ln *base.ServerListener) (func(), error
|
||||
),
|
||||
)
|
||||
|
||||
workerService := workers.NewWorkerServiceServer(c.ServersRepoFn, c.SessionRepoFn, c.ConnectionRepoFn,
|
||||
workerService := handlers.NewWorkerServiceServer(c.ServersRepoFn, c.SessionRepoFn, c.ConnectionRepoFn,
|
||||
c.workerStatusUpdateTimes, c.kms)
|
||||
pbs.RegisterServerCoordinationServiceServer(workerServer, workerService)
|
||||
pbs.RegisterSessionServiceServer(workerServer, workerService)
|
||||
|
||||
multihopService, err := handlers.NewMultihopServiceServer(
|
||||
workerAuthStorage,
|
||||
true,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: error creating multihop service handler: %w", op, err)
|
||||
}
|
||||
multihop.RegisterMultihopServiceServer(workerServer, multihopService)
|
||||
|
||||
metric.InitializeClusterCollectors(c.conf.PrometheusRegisterer, workerServer)
|
||||
|
||||
ln.GrpcServer = workerServer
|
||||
|
||||
@@ -735,10 +735,10 @@ func (tc *TestController) AddClusterControllerMember(t testing.TB, opts *TestCon
|
||||
// WaitForNextWorkerStatusUpdate waits for the next status check from a worker to
|
||||
// come in. If it does not come in within the default status grace
|
||||
// period, this function returns an error.
|
||||
func (tc *TestController) WaitForNextWorkerStatusUpdate(workerId string) error {
|
||||
func (tc *TestController) WaitForNextWorkerStatusUpdate(workerStatusName string) error {
|
||||
const op = "controller.(TestController).WaitForNextWorkerStatusUpdate"
|
||||
ctx := context.TODO()
|
||||
event.WriteSysEvent(ctx, op, "waiting for next status report from worker", "worker", workerId)
|
||||
event.WriteSysEvent(ctx, op, "waiting for next status report from worker", "worker", workerStatusName)
|
||||
waitStatusStart := time.Now()
|
||||
ctx, cancel := context.WithTimeout(tc.ctx, tc.b.StatusGracePeriodDuration)
|
||||
defer cancel()
|
||||
@@ -777,7 +777,7 @@ func (tc *TestController) WaitForNextWorkerStatusUpdate(workerId string) error {
|
||||
return false
|
||||
}
|
||||
|
||||
if workerStatusUpdateId == workerId {
|
||||
if workerStatusUpdateId == workerStatusName {
|
||||
waitStatusCurrent = workerStatusUpdateTime
|
||||
return false
|
||||
}
|
||||
@@ -795,10 +795,10 @@ func (tc *TestController) WaitForNextWorkerStatusUpdate(workerId string) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error waiting for next status report from worker", "worker", workerId))
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error waiting for next status report from worker", "worker", workerStatusName))
|
||||
return err
|
||||
}
|
||||
event.WriteSysEvent(ctx, op, "waiting for next status report from worker received successfully", "worker", workerId)
|
||||
event.WriteSysEvent(ctx, op, "waiting for next status report from worker received successfully", "worker", workerStatusName)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/servers/store"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
)
|
||||
|
||||
// In the future we could make this configurable
|
||||
@@ -30,7 +30,7 @@ func (c *Controller) startStatusTicking(cancelCtx context.Context) {
|
||||
return
|
||||
|
||||
case <-timer.C:
|
||||
if err := c.upsertServer(cancelCtx); err != nil {
|
||||
if err := c.upsertController(cancelCtx); err != nil {
|
||||
event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error fetching repository for status update"))
|
||||
}
|
||||
timer.Reset(statusInterval)
|
||||
@@ -38,21 +38,18 @@ func (c *Controller) startStatusTicking(cancelCtx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) upsertServer(ctx context.Context) error {
|
||||
const op = "controller.(Controller).upsertServer"
|
||||
server := &servers.Server{
|
||||
PrivateId: c.conf.RawConfig.Controller.Name,
|
||||
Name: c.conf.RawConfig.Controller.Name,
|
||||
Type: resource.Controller.String(),
|
||||
Description: c.conf.RawConfig.Controller.Description,
|
||||
Address: c.conf.RawConfig.Controller.PublicClusterAddr,
|
||||
func (c *Controller) upsertController(ctx context.Context) error {
|
||||
const op = "controller.(Controller).upsertController"
|
||||
controller := &store.Controller{
|
||||
PrivateId: c.conf.RawConfig.Controller.Name,
|
||||
Address: c.conf.RawConfig.Controller.PublicClusterAddr,
|
||||
}
|
||||
repo, err := c.ServersRepoFn()
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("error fetching repository for status update"))
|
||||
}
|
||||
|
||||
_, _, err = repo.UpsertServer(ctx, server)
|
||||
_, err = repo.UpsertController(ctx, controller)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("error performing status update"))
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ type workerAuthEntry struct {
|
||||
// been replayed, then stores connection information into the auth cache, which
|
||||
// is used by the intercepting listener to log information.
|
||||
func (c Controller) validateWorkerTls(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
const op = "controller.(Controller).validateWorkerTls"
|
||||
for _, p := range hello.SupportedProtos {
|
||||
switch {
|
||||
case strings.HasPrefix(p, "v1workerauth-"):
|
||||
@@ -50,7 +51,7 @@ func (c Controller) validateWorkerTls(hello *tls.ClientHelloInfo) (*tls.Config,
|
||||
return tlsConf, err
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil, errors.New("no supported protos found in hello")
|
||||
}
|
||||
|
||||
// v1WorkerAuthConfig:
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
berrors "github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/multihop"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
)
|
||||
|
||||
func (w *Worker) startAuthRotationTicking(cancelCtx context.Context) {
|
||||
const op = "worker.(Worker).startAuthRotationTicking"
|
||||
if w.conf.WorkerAuthKms != nil {
|
||||
// Nothing to do here, just immediately exit
|
||||
// FIXME: Write a system event
|
||||
return
|
||||
}
|
||||
|
||||
// The default time to use when we encounter an error or some other reason
|
||||
// we can't get a better reset time
|
||||
const defaultResetDuration = time.Hour
|
||||
timer := time.NewTimer(defaultResetDuration)
|
||||
// You're not supposed to call reset on timers that haven't been stopped or
|
||||
// expired, so we stop it here so it resets in the loop below. That way if
|
||||
// we want to adjust time, e.g. for tests, we can set the resetDuration
|
||||
// value from within the loop
|
||||
timer.Stop()
|
||||
var resetDuration time.Duration // will start at 0, so we run immediately
|
||||
for {
|
||||
if w.TestOverrideAuthRotationPeriod != 0 {
|
||||
resetDuration = w.TestOverrideAuthRotationPeriod
|
||||
}
|
||||
timer.Reset(resetDuration)
|
||||
|
||||
select {
|
||||
case <-cancelCtx.Done():
|
||||
event.WriteSysEvent(cancelCtx, op, "auth rotation ticking shutting down")
|
||||
return
|
||||
|
||||
case <-timer.C:
|
||||
resetDuration = defaultResetDuration
|
||||
|
||||
// Check if it's time to rotate and if not don't do anything
|
||||
currentNodeCreds, err := types.LoadNodeCredentials(cancelCtx, w.WorkerAuthStorage, nodeenrollment.CurrentId, nodeenrollment.WithWrapper(w.conf.WorkerAuthStorageKms))
|
||||
if err != nil {
|
||||
if errors.Is(err, nodeenrollment.ErrNotFound) {
|
||||
// Be silent
|
||||
continue
|
||||
}
|
||||
event.WriteError(cancelCtx, op, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if currentNodeCreds == nil {
|
||||
event.WriteSysEvent(cancelCtx, op, "no error loading worker auth creds but nil creds, skipping rotation")
|
||||
continue
|
||||
}
|
||||
|
||||
// Check the certificates to see if it's time
|
||||
if len(currentNodeCreds.CertificateBundles) != 2 {
|
||||
// Likely this means we haven't been authorized yet, and
|
||||
// unclear what to do in any other situation
|
||||
continue
|
||||
}
|
||||
|
||||
var earliestValid, latestValid time.Time
|
||||
// Go through the bundles and find the full range of time that we
|
||||
// have valid certificates
|
||||
for _, bundle := range currentNodeCreds.CertificateBundles {
|
||||
if curr := bundle.CertificateNotBefore.AsTime(); earliestValid.IsZero() || curr.Before(earliestValid) {
|
||||
earliestValid = curr
|
||||
}
|
||||
if curr := bundle.CertificateNotAfter.AsTime(); latestValid.IsZero() || curr.After(latestValid) {
|
||||
latestValid = curr
|
||||
}
|
||||
}
|
||||
// Ensure that our time periods aren't somehow quite messed up
|
||||
now := time.Now()
|
||||
if earliestValid.After(now) || latestValid.Before(now) || earliestValid.After(latestValid) {
|
||||
// We basically have no valid creds so we can't rotate.
|
||||
// TODO (maybe): Have this trigger a new set of creds and request?
|
||||
event.WriteSysEvent(cancelCtx, op, "not within node creds validity period, unsure what to do, not rotating")
|
||||
continue
|
||||
}
|
||||
|
||||
// Figure out the midpoint; if we're after it, try to rotate
|
||||
var shouldRotate bool
|
||||
switch {
|
||||
case w.TestOverrideAuthRotationPeriod != 0:
|
||||
shouldRotate = true
|
||||
default:
|
||||
delta := latestValid.Sub(earliestValid)
|
||||
shouldRotate = now.Before(earliestValid.Add(delta / 2))
|
||||
}
|
||||
|
||||
if !shouldRotate {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := rotateWorkerAuth(cancelCtx, w, currentNodeCreds); err != nil {
|
||||
event.WriteError(cancelCtx, op, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO (maybe): Calculate new delta and set a custom retry time on the timer?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rotateWorkerAuth is a one-stop shop to perform a rotation, given a valid set
|
||||
// of current node credentials. Note that it doesn't really sanity check inputs;
|
||||
// it is meant to be called from other functions that have validated these
|
||||
// inputs and is separated out purely for (a) cleanliness/readability of the
|
||||
// ticking function and (b) possible future re-use.
|
||||
func rotateWorkerAuth(ctx context.Context, w *Worker, currentNodeCreds *types.NodeCredentials) error {
|
||||
const op = "worker.rotateWorkerAuth"
|
||||
|
||||
randReaderOpt := nodeenrollment.WithRandomReader(w.conf.SecureRandomReader)
|
||||
|
||||
// Ensure we can get some needed values prior to actually doing generation
|
||||
currentKeyId, err := nodeenrollment.KeyIdFromPkix(currentNodeCreds.CertificatePublicKeyPkix)
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
client := w.controllerMultihopConn.Load()
|
||||
if client == nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
multihopClient, ok := client.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
// Generate a new set of credentials but don't persist them yet
|
||||
newNodeCreds, err := types.NewNodeCredentials(
|
||||
ctx,
|
||||
w.WorkerAuthStorage,
|
||||
randReaderOpt,
|
||||
nodeenrollment.WithWrapper(w.conf.WorkerAuthKms),
|
||||
nodeenrollment.WithSkipStorage(true),
|
||||
)
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
// Get a signed request from the new credentials
|
||||
fetchReq, err := newNodeCreds.CreateFetchNodeCredentialsRequest(ctx, randReaderOpt)
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
// Encrypt the values to the server
|
||||
encFetchReq, err := nodeenrollment.EncryptMessage(ctx, currentKeyId, fetchReq, currentNodeCreds, randReaderOpt)
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
resp, err := multihopClient.RotateNodeCredentials(ctx, &types.RotateNodeCredentialsRequest{
|
||||
CertificatePublicKeyPkix: currentNodeCreds.CertificatePublicKeyPkix,
|
||||
EncryptedFetchNodeCredentialsRequest: encFetchReq,
|
||||
})
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
// Decrypt the response using current credentials
|
||||
fetchResp := new(types.FetchNodeCredentialsResponse)
|
||||
if err := nodeenrollment.DecryptMessage(
|
||||
ctx,
|
||||
currentKeyId,
|
||||
resp.EncryptedFetchNodeCredentialsResponse,
|
||||
currentNodeCreds,
|
||||
fetchResp,
|
||||
); err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
// Call handle on the inner response, which will be encrypted to the
|
||||
// new node credentials. This will also store the result,
|
||||
// overwriting the current credentials.
|
||||
newNodeCreds, err = newNodeCreds.HandleFetchNodeCredentialsResponse(
|
||||
ctx,
|
||||
w.WorkerAuthStorage,
|
||||
fetchResp,
|
||||
nodeenrollment.WithWrapper(w.conf.WorkerAuthKms),
|
||||
)
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
newKeyId, err := nodeenrollment.KeyIdFromPkix(newNodeCreds.CertificatePublicKeyPkix)
|
||||
if err != nil {
|
||||
return berrors.Wrap(ctx, err, op)
|
||||
}
|
||||
w.WorkerAuthCurrentKeyId.Store(newKeyId)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package worker_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller"
|
||||
"github.com/hashicorp/boundary/internal/daemon/worker"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/servers/store"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// TestRotationTicking ensures that we see new credential information for a
|
||||
// worker on both the controller side and worker side in a periodic fashion
|
||||
func TestRotationTicking(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require, assert := require.New(t), assert.New(t)
|
||||
logger := hclog.New(&hclog.LoggerOptions{
|
||||
Level: hclog.Trace,
|
||||
})
|
||||
|
||||
conf, err := config.DevController()
|
||||
require.NoError(err)
|
||||
|
||||
c := controller.NewTestController(t, &controller.TestControllerOpts{
|
||||
Config: conf,
|
||||
Logger: logger.Named("controller"),
|
||||
})
|
||||
t.Cleanup(c.Shutdown)
|
||||
|
||||
const rotationPeriod = 20 * time.Second
|
||||
|
||||
w := worker.NewTestWorker(t, &worker.TestWorkerOpts{
|
||||
InitialUpstreams: c.ClusterAddrs(),
|
||||
Logger: logger.Named("worker"),
|
||||
AuthRotationPeriod: rotationPeriod,
|
||||
})
|
||||
t.Cleanup(w.Shutdown)
|
||||
|
||||
// Get a servers repo and worker auth repo
|
||||
serversRepo, err := c.Controller().ServersRepoFn()
|
||||
require.NoError(err)
|
||||
workerAuthRepo, err := c.Controller().WorkerAuthRepoStorageFn()
|
||||
require.NoError(err)
|
||||
|
||||
// Give time for the job to ensure that roots are created and offset us from
|
||||
// the rotation period
|
||||
time.Sleep(rotationPeriod / 2)
|
||||
|
||||
// Verify that there are no nodes authorized yet
|
||||
auths, err := workerAuthRepo.List(c.Context(), (*types.NodeInformation)(nil))
|
||||
require.NoError(err)
|
||||
assert.Len(auths, 0)
|
||||
|
||||
// Perform initial authentication of worker to controller
|
||||
reqBytes, err := base58.FastBase58Decoding(w.Worker().WorkerAuthRegistrationRequest)
|
||||
require.NoError(err)
|
||||
|
||||
// Decode the proto into the request and create the worker
|
||||
req := new(types.FetchNodeCredentialsRequest)
|
||||
require.NoError(proto.Unmarshal(reqBytes, req))
|
||||
_, err = serversRepo.CreateWorker(c.Context(), &servers.Worker{
|
||||
Worker: &store.Worker{
|
||||
ScopeId: scope.Global.String(),
|
||||
},
|
||||
}, servers.WithFetchNodeCredentialsRequest(req))
|
||||
require.NoError(err)
|
||||
|
||||
// Verify we see one authorized set of credentials now
|
||||
auths, err = workerAuthRepo.List(c.Context(), (*types.NodeInformation)(nil))
|
||||
require.NoError(err)
|
||||
assert.Len(auths, 1)
|
||||
// Fetch creds and store current key
|
||||
currNodeCreds, err := types.LoadNodeCredentials(w.Context(), w.Worker().WorkerAuthStorage, nodeenrollment.CurrentId)
|
||||
require.NoError(err)
|
||||
currKey := currNodeCreds.CertificatePublicKeyPkix
|
||||
|
||||
// Now we wait and check that we see new values in the DB and different
|
||||
// creds on the worker after each rotation period
|
||||
for i := 2; i < 5; i++ {
|
||||
time.Sleep(rotationPeriod)
|
||||
|
||||
// Verify we see the expected number, since we aren't expiring any it
|
||||
// should be equal to the number of times we did rotations
|
||||
auths, err = workerAuthRepo.List(c.Context(), (*types.NodeInformation)(nil))
|
||||
require.NoError(err)
|
||||
assert.Len(auths, i)
|
||||
|
||||
// Fetch creds and compare current key
|
||||
currNodeCreds, err := types.LoadNodeCredentials(w.Context(), w.Worker().WorkerAuthStorage, nodeenrollment.CurrentId)
|
||||
require.NoError(err)
|
||||
assert.NotEqual(currKey, currNodeCreds.CertificatePublicKeyPkix)
|
||||
currKey = currNodeCreds.CertificatePublicKeyPkix
|
||||
currKeyId, err := nodeenrollment.KeyIdFromPkix(currNodeCreds.CertificatePublicKeyPkix)
|
||||
require.NoError(err)
|
||||
assert.Equal(currKeyId, w.Worker().WorkerAuthCurrentKeyId.Load())
|
||||
|
||||
// Stop and start the client connections to ensure the new credentials
|
||||
// are valid; if not, we won't establish a new connection and rotation
|
||||
// will fail
|
||||
w.Worker().Resolver().UpdateState(resolver.State{Addresses: []resolver.Address{}})
|
||||
cc, err := w.Worker().GrpcClientConn()
|
||||
require.NoError(err)
|
||||
require.NoError(cc.Close())
|
||||
require.NoError(w.Worker().StartControllerConnections())
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -23,15 +25,24 @@ import (
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/go-secure-stdlib/base62"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/multihop"
|
||||
"github.com/hashicorp/nodeenrollment/protocol"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/backoff"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func (w *Worker) startControllerConnections() error {
|
||||
const op = "worker.(Worker).startControllerConnections"
|
||||
initialAddrs := make([]resolver.Address, 0, len(w.conf.RawConfig.Worker.Controllers))
|
||||
for _, addr := range w.conf.RawConfig.Worker.Controllers {
|
||||
const hcpbUrlSuffix = ".proxy.boundary.hashicorp.cloud:9202"
|
||||
|
||||
// StartControllerConnections starts up the resolver and initiates controller
|
||||
// connection client creation
|
||||
func (w *Worker) StartControllerConnections() error {
|
||||
const op = "worker.(Worker).StartControllerConnections"
|
||||
initialAddrs := make([]resolver.Address, 0, len(w.conf.RawConfig.Worker.InitialUpstreams))
|
||||
for _, addr := range w.conf.RawConfig.Worker.InitialUpstreams {
|
||||
switch {
|
||||
case strings.HasPrefix(addr, "/"):
|
||||
initialAddrs = append(initialAddrs, resolver.Address{Addr: addr})
|
||||
@@ -41,21 +52,27 @@ func (w *Worker) startControllerConnections() error {
|
||||
host, port, err = net.SplitHostPort(net.JoinHostPort(addr, "9201"))
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing controller address: %w", err)
|
||||
return fmt.Errorf("error parsing upstream address: %w", err)
|
||||
}
|
||||
initialAddrs = append(initialAddrs, resolver.Address{Addr: net.JoinHostPort(host, port)})
|
||||
}
|
||||
}
|
||||
|
||||
if len(initialAddrs) == 0 {
|
||||
return errors.New("no initial controller addresses found")
|
||||
if w.conf.RawConfig.HCPBClusterId != "" {
|
||||
clusterAddress := fmt.Sprintf("%s%s", w.conf.RawConfig.HCPBClusterId, hcpbUrlSuffix)
|
||||
initialAddrs = append(initialAddrs, resolver.Address{Addr: clusterAddress})
|
||||
event.WriteSysEvent(w.baseContext, op, fmt.Sprintf("Setting HCPB Cluster address %s as upstream address", clusterAddress))
|
||||
} else {
|
||||
return errors.New("no initial upstream addresses found")
|
||||
}
|
||||
}
|
||||
|
||||
w.Resolver().InitialState(resolver.State{
|
||||
Addresses: initialAddrs,
|
||||
})
|
||||
if err := w.createClientConn(initialAddrs[0].Addr); err != nil {
|
||||
return fmt.Errorf("error making client connection to controller: %w", err)
|
||||
return fmt.Errorf("error making client connection to upstream address: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -64,39 +81,79 @@ func (w *Worker) startControllerConnections() error {
|
||||
func (w *Worker) controllerDialerFunc() func(context.Context, string) (net.Conn, error) {
|
||||
const op = "worker.(Worker).controllerDialerFunc"
|
||||
return func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
tlsConf, authInfo, err := w.workerAuthTLSConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating tls config for worker auth: %w", err)
|
||||
}
|
||||
dialer := &net.Dialer{}
|
||||
var nonTlsConn net.Conn
|
||||
var conn net.Conn
|
||||
var err error
|
||||
switch {
|
||||
case strings.HasPrefix(addr, "/"):
|
||||
nonTlsConn, err = dialer.DialContext(ctx, "unix", addr)
|
||||
case w.conf.WorkerAuthKms != nil:
|
||||
conn, err = w.v1KmsAuthDialFn(ctx, addr)
|
||||
default:
|
||||
nonTlsConn, err = dialer.DialContext(ctx, "tcp", addr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to dial to controller: %w", err)
|
||||
}
|
||||
tlsConn := tls.Client(nonTlsConn, tlsConf)
|
||||
written, err := tlsConn.Write([]byte(authInfo.ConnectionNonce))
|
||||
if err != nil {
|
||||
if err := nonTlsConn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing connection after writing failure"))
|
||||
conn, err = protocol.Dial(ctx, w.WorkerAuthStorage, addr, nodeenrollment.WithWrapper(w.conf.WorkerAuthStorageKms))
|
||||
// No error and a valid connection means the WorkerAuthRegistrationRequest was populated
|
||||
// We can remove the stored workerAuthRequest file
|
||||
if err == nil && conn != nil {
|
||||
if w.WorkerAuthStorage.BaseDir() != "" {
|
||||
workerAuthReqFilePath := filepath.Join(w.WorkerAuthStorage.BaseDir(), base.WorkerAuthReqFile)
|
||||
// Intentionally ignoring any error removing this file
|
||||
_ = os.Remove(workerAuthReqFilePath)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to write connection nonce: %w", err)
|
||||
}
|
||||
if written != len(authInfo.ConnectionNonce) {
|
||||
if err := nonTlsConn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing connection after writing failure"))
|
||||
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.
|
||||
default:
|
||||
event.WriteError(ctx, op, err)
|
||||
}
|
||||
|
||||
if err == nil && conn != nil {
|
||||
if !w.everAuthenticated.Load() {
|
||||
w.everAuthenticated.Store(true)
|
||||
}
|
||||
return nil, fmt.Errorf("expected to write %d bytes of connection nonce, wrote %d", len(authInfo.ConnectionNonce), written)
|
||||
event.WriteSysEvent(ctx, op, "worker has successfully authenticated")
|
||||
}
|
||||
return tlsConn, nil
|
||||
|
||||
return conn, err
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Worker) v1KmsAuthDialFn(ctx context.Context, addr string) (net.Conn, error) {
|
||||
const op = "worker.(Worker).v1KmsAuthDialFn"
|
||||
tlsConf, authInfo, err := w.workerAuthTLSConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating tls config for worker auth: %w", err)
|
||||
}
|
||||
dialer := &net.Dialer{}
|
||||
var nonTlsConn net.Conn
|
||||
switch {
|
||||
case strings.HasPrefix(addr, "/"):
|
||||
nonTlsConn, err = dialer.DialContext(ctx, "unix", addr)
|
||||
default:
|
||||
nonTlsConn, err = dialer.DialContext(ctx, "tcp", addr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to dial to upstream: %w", err)
|
||||
}
|
||||
tlsConn := tls.Client(nonTlsConn, tlsConf)
|
||||
written, err := tlsConn.Write([]byte(authInfo.ConnectionNonce))
|
||||
if err != nil {
|
||||
if err := nonTlsConn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing connection after writing failure"))
|
||||
}
|
||||
return nil, fmt.Errorf("unable to write connection nonce: %w", err)
|
||||
}
|
||||
if written != len(authInfo.ConnectionNonce) {
|
||||
if err := nonTlsConn.Close(); err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error closing connection after writing failure"))
|
||||
}
|
||||
return nil, fmt.Errorf("expected to write %d bytes of connection nonce, wrote %d", len(authInfo.ConnectionNonce), written)
|
||||
}
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
func (w *Worker) createClientConn(addr string) error {
|
||||
const op = "worker.(Worker).createClientConn"
|
||||
defaultTimeout := (time.Second + time.Nanosecond).String()
|
||||
@@ -113,35 +170,47 @@ func (w *Worker) createClientConn(addr string) error {
|
||||
}
|
||||
`, defaultTimeout)
|
||||
res := w.Resolver()
|
||||
cc, err := grpc.DialContext(w.baseContext,
|
||||
fmt.Sprintf("%s:///%s", res.Scheme(), addr),
|
||||
dialOpts := []grpc.DialOption{
|
||||
grpc.WithResolvers(res),
|
||||
grpc.WithUnaryInterceptor(metric.InstrumentClusterClient()),
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt32)),
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(math.MaxInt32)),
|
||||
grpc.WithContextDialer(w.controllerDialerFunc()),
|
||||
grpc.WithInsecure(),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithDefaultServiceConfig(defServiceConfig),
|
||||
// Don't have the resolver reach out for a service config from the
|
||||
// resolver, use the one specified as default
|
||||
grpc.WithDisableServiceConfig(),
|
||||
grpc.WithConnectParams(grpc.ConnectParams{
|
||||
Backoff: backoff.Config{
|
||||
BaseDelay: time.Second,
|
||||
Multiplier: 1.2,
|
||||
Jitter: 0.2,
|
||||
MaxDelay: 3 * time.Second,
|
||||
},
|
||||
}),
|
||||
}
|
||||
cc, err := grpc.DialContext(w.baseContext,
|
||||
fmt.Sprintf("%s:///%s", res.Scheme(), addr),
|
||||
dialOpts...,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error dialing controller for worker auth: %w", err)
|
||||
}
|
||||
w.grpcClientConn.Store(cc)
|
||||
|
||||
w.controllerStatusConn.Store(pbs.NewServerCoordinationServiceClient(cc))
|
||||
w.controllerSessionConn.Store(pbs.NewSessionServiceClient(cc))
|
||||
|
||||
event.WriteSysEvent(w.baseContext, op, "connected to controller", "address", addr)
|
||||
w.controllerMultihopConn.Store(multihop.NewMultihopServiceClient(cc))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Worker) workerAuthTLSConfig() (*tls.Config, *base.WorkerAuthInfo, error) {
|
||||
var err error
|
||||
info := &base.WorkerAuthInfo{
|
||||
Name: w.conf.RawConfig.Worker.Name,
|
||||
Description: w.conf.RawConfig.Worker.Description,
|
||||
Name: w.conf.RawConfig.Worker.Name,
|
||||
Description: w.conf.RawConfig.Worker.Description,
|
||||
ProxyAddress: w.conf.RawConfig.Worker.PublicAddr,
|
||||
}
|
||||
|
||||
info.ConnectionNonce, err = w.nonceFn(20)
|
||||
|
||||
@@ -6,14 +6,24 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/daemon/cluster/handlers"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
nodee "github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/multihop"
|
||||
nodeenet "github.com/hashicorp/nodeenrollment/net"
|
||||
"github.com/hashicorp/nodeenrollment/protocol"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/hashicorp/nodeenrollment/util/temperror"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func (w *Worker) startListeners() error {
|
||||
@@ -27,32 +37,30 @@ func (w *Worker) startListeners() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: unable to initialize std logger: %w", op, err)
|
||||
}
|
||||
|
||||
servers := make([]func(), 0, len(w.listeners))
|
||||
for i := range w.listeners {
|
||||
ln := w.listeners[i]
|
||||
workerServer, err := w.configureForWorker(ln, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: failed to configure for worker: %w", op, err)
|
||||
}
|
||||
servers = append(servers, workerServer)
|
||||
if w.proxyListener == nil {
|
||||
return fmt.Errorf("%s: nil proxy listener", op)
|
||||
}
|
||||
|
||||
for _, s := range servers {
|
||||
s()
|
||||
workerServer, err := w.configureForWorker(w.proxyListener, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: failed to configure for worker: %w", op, err)
|
||||
}
|
||||
|
||||
workerServer()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Worker) configureForWorker(ln *base.ServerListener, logger *log.Logger) (func(), error) {
|
||||
const op = "worker.configureForWorker"
|
||||
|
||||
handler, err := w.handler(HandlerProperties{ListenerConfig: ln.Config})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cancelCtx := w.baseContext
|
||||
server := &http.Server{
|
||||
httpServer := &http.Server{
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
@@ -61,80 +69,187 @@ func (w *Worker) configureForWorker(ln *base.ServerListener, logger *log.Logger)
|
||||
return cancelCtx
|
||||
},
|
||||
}
|
||||
ln.HTTPServer = server
|
||||
ln.HTTPServer = httpServer
|
||||
|
||||
if ln.Config.HTTPReadHeaderTimeout > 0 {
|
||||
server.ReadHeaderTimeout = ln.Config.HTTPReadHeaderTimeout
|
||||
httpServer.ReadHeaderTimeout = ln.Config.HTTPReadHeaderTimeout
|
||||
}
|
||||
if ln.Config.HTTPReadTimeout > 0 {
|
||||
server.ReadTimeout = ln.Config.HTTPReadTimeout
|
||||
httpServer.ReadTimeout = ln.Config.HTTPReadTimeout
|
||||
}
|
||||
if ln.Config.HTTPWriteTimeout > 0 {
|
||||
server.WriteTimeout = ln.Config.HTTPWriteTimeout
|
||||
httpServer.WriteTimeout = ln.Config.HTTPWriteTimeout
|
||||
}
|
||||
if ln.Config.HTTPIdleTimeout > 0 {
|
||||
server.IdleTimeout = ln.Config.HTTPIdleTimeout
|
||||
httpServer.IdleTimeout = ln.Config.HTTPIdleTimeout
|
||||
}
|
||||
|
||||
l := tls.NewListener(ln.ProxyListener, &tls.Config{
|
||||
GetConfigForClient: w.getSessionTls,
|
||||
})
|
||||
fetchCredsFn := func(
|
||||
ctx context.Context,
|
||||
_ nodee.Storage,
|
||||
req *types.FetchNodeCredentialsRequest,
|
||||
_ ...nodee.Option,
|
||||
) (*types.FetchNodeCredentialsResponse, error) {
|
||||
client := w.controllerMultihopConn.Load()
|
||||
if client == nil {
|
||||
return nil, temperror.New(errors.New("error fetching controller connection, client is nil"))
|
||||
}
|
||||
multihopClient, ok := client.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return nil, temperror.New(errors.New("client could not be understood as a multihop service client"))
|
||||
}
|
||||
// log.Println("proxying fetch node credentials request")
|
||||
return multihopClient.FetchNodeCredentials(ctx, req)
|
||||
}
|
||||
|
||||
return func() { go server.Serve(l) }, nil
|
||||
generateServerCertificatesFn := func(
|
||||
ctx context.Context,
|
||||
_ nodee.Storage,
|
||||
req *types.GenerateServerCertificatesRequest,
|
||||
_ ...nodee.Option,
|
||||
) (*types.GenerateServerCertificatesResponse, error) {
|
||||
client := w.controllerMultihopConn.Load()
|
||||
if client == nil {
|
||||
return nil, temperror.New(errors.New("error fetching controller connection, client is nil"))
|
||||
}
|
||||
multihopClient, ok := client.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return nil, temperror.New(errors.New("client could not be understood as a multihop service client"))
|
||||
}
|
||||
// log.Println("proxying generate server cert request")
|
||||
return multihopClient.GenerateServerCertificates(ctx, req)
|
||||
}
|
||||
|
||||
interceptingListener, err := protocol.NewInterceptingListener(
|
||||
&protocol.InterceptingListenerConfiguration{
|
||||
Context: w.baseContext,
|
||||
Storage: w.WorkerAuthStorage,
|
||||
BaseListener: ln.ProxyListener,
|
||||
BaseTlsConfiguration: &tls.Config{
|
||||
GetConfigForClient: w.getSessionTls,
|
||||
},
|
||||
FetchCredsFunc: fetchCredsFn,
|
||||
GenerateServerCertificatesFunc: generateServerCertificatesFn,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error instantiating node auth listener: %w", err)
|
||||
}
|
||||
|
||||
w.workerAuthSplitListener = nodeenet.NewSplitListener(interceptingListener)
|
||||
|
||||
downstreamServer := grpc.NewServer(
|
||||
grpc.MaxRecvMsgSize(math.MaxInt32),
|
||||
grpc.MaxSendMsgSize(math.MaxInt32),
|
||||
)
|
||||
multihopService, err := handlers.NewMultihopServiceServer(
|
||||
w.WorkerAuthStorage,
|
||||
false,
|
||||
w.controllerMultihopConn,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: error creating multihop service handler: %w", op, err)
|
||||
}
|
||||
multihop.RegisterMultihopServiceServer(downstreamServer, multihopService)
|
||||
statusSessionService := NewWorkerProxyServiceServer(w.controllerStatusConn, w.controllerSessionConn)
|
||||
pbs.RegisterServerCoordinationServiceServer(downstreamServer, statusSessionService)
|
||||
pbs.RegisterSessionServiceServer(downstreamServer, statusSessionService)
|
||||
|
||||
ln.GrpcServer = downstreamServer
|
||||
|
||||
return func() {
|
||||
go w.workerAuthSplitListener.Start()
|
||||
go httpServer.Serve(w.workerAuthSplitListener.OtherListener())
|
||||
go ln.GrpcServer.Serve(
|
||||
&eventingListener{
|
||||
ctx: cancelCtx,
|
||||
baseLn: w.workerAuthSplitListener.NodeEnrollmentListener(),
|
||||
},
|
||||
)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *Worker) stopServersAndListeners() error {
|
||||
var closeErrors *multierror.Error
|
||||
err := w.stopHttpServersAndListeners()
|
||||
if err != nil {
|
||||
closeErrors = multierror.Append(closeErrors, err)
|
||||
var mg multierror.Group
|
||||
mg.Go(w.stopHttpServer)
|
||||
mg.Go(w.stopClusterGrpcServer)
|
||||
|
||||
// FIXME (jeff): For some reason, unlike the controller, the grpc server
|
||||
// really likes to hang on closing. Maybe because it's never served a
|
||||
// connection? This is a workaround to force it until I can dig in.
|
||||
var cancel context.CancelFunc
|
||||
if w.workerAuthSplitListener != nil {
|
||||
var ctx context.Context
|
||||
ctx, cancel = context.WithTimeout(w.baseContext, 2*time.Second)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
w.workerAuthSplitListener.Stop()
|
||||
cancel()
|
||||
}()
|
||||
}
|
||||
|
||||
err = w.stopAnyListeners()
|
||||
if err != nil {
|
||||
closeErrors = multierror.Append(closeErrors, err)
|
||||
stopErrors := mg.Wait()
|
||||
|
||||
if w.workerAuthSplitListener != nil {
|
||||
cancel()
|
||||
err := w.workerAuthSplitListener.Stop()
|
||||
if err != nil {
|
||||
stopErrors = multierror.Append(stopErrors, err)
|
||||
}
|
||||
}
|
||||
|
||||
return closeErrors.ErrorOrNil()
|
||||
err := w.stopAnyListeners()
|
||||
if err != nil {
|
||||
stopErrors = multierror.Append(stopErrors, err)
|
||||
}
|
||||
|
||||
return stopErrors.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (w *Worker) stopHttpServersAndListeners() error {
|
||||
var closeErrors *multierror.Error
|
||||
for i := range w.listeners {
|
||||
ln := w.listeners[i]
|
||||
if ln.HTTPServer == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(w.baseContext, ln.Config.MaxRequestDuration)
|
||||
ln.HTTPServer.Shutdown(ctx)
|
||||
cancel()
|
||||
|
||||
err := ln.ProxyListener.Close()
|
||||
err = listenerCloseErrorCheck(ln.Config.Type, err)
|
||||
if err != nil {
|
||||
closeErrors = multierror.Append(closeErrors, err)
|
||||
}
|
||||
func (w *Worker) stopHttpServer() error {
|
||||
if w.proxyListener == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return closeErrors.ErrorOrNil()
|
||||
if w.proxyListener.HTTPServer == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(w.baseContext, w.proxyListener.Config.MaxRequestDuration)
|
||||
w.proxyListener.HTTPServer.Shutdown(ctx)
|
||||
cancel()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Worker) stopClusterGrpcServer() error {
|
||||
if w.proxyListener == nil {
|
||||
return nil
|
||||
}
|
||||
if w.proxyListener.GrpcServer == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
w.proxyListener.GrpcServer.GracefulStop()
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopAnyListeners does a final once over the known
|
||||
// listeners to make sure we didn't miss any;
|
||||
// expected to run at the end of stopServersAndListeners.
|
||||
func (w *Worker) stopAnyListeners() error {
|
||||
if w.proxyListener == nil {
|
||||
return nil
|
||||
}
|
||||
var closeErrors *multierror.Error
|
||||
for _, ln := range w.listeners {
|
||||
if ln == nil || ln.ProxyListener == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err := ln.ProxyListener.Close()
|
||||
err = listenerCloseErrorCheck(ln.Config.Type, err)
|
||||
if err != nil {
|
||||
closeErrors = multierror.Append(closeErrors, err)
|
||||
}
|
||||
var err error
|
||||
if w.workerAuthSplitListener != nil {
|
||||
err = w.workerAuthSplitListener.Stop()
|
||||
} else if w.proxyListener.ProxyListener != nil {
|
||||
err = w.proxyListener.ProxyListener.Close()
|
||||
}
|
||||
err = listenerCloseErrorCheck("proxy", err)
|
||||
if err != nil {
|
||||
closeErrors = multierror.Append(closeErrors, err)
|
||||
}
|
||||
|
||||
return closeErrors.ErrorOrNil()
|
||||
@@ -160,3 +275,36 @@ func listenerCloseErrorCheck(lnType string, err error) error {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type eventingListener struct {
|
||||
ctx context.Context
|
||||
baseLn net.Listener
|
||||
}
|
||||
|
||||
func (e *eventingListener) Accept() (net.Conn, error) {
|
||||
const op = "worker.(eventingListener).Accept"
|
||||
conn, err := e.baseLn.Accept()
|
||||
if err != nil || conn == nil {
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// This is all best-effort; anything going wrong here shouldn't disrupt the
|
||||
// connection, so on error simply stop trying to get to an event
|
||||
tlsConn, ok := conn.(*tls.Conn)
|
||||
if ok && len(tlsConn.ConnectionState().PeerCertificates) > 0 {
|
||||
keyId, err := nodee.KeyIdFromPkix(tlsConn.ConnectionState().PeerCertificates[0].SubjectKeyId)
|
||||
if err == nil {
|
||||
event.WriteSysEvent(e.ctx, op, "worker successfully authenticated", "key_id", keyId)
|
||||
}
|
||||
}
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (e *eventingListener) Close() error {
|
||||
return e.baseLn.Close()
|
||||
}
|
||||
|
||||
func (e *eventingListener) Addr() net.Addr {
|
||||
return e.baseLn.Addr()
|
||||
}
|
||||
@@ -3,13 +3,10 @@ package worker
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/go-secure-stdlib/listenerutil"
|
||||
@@ -18,30 +15,19 @@ import (
|
||||
|
||||
func TestStartListeners(t *testing.T) {
|
||||
testNonTlsRejected := func(t *testing.T, resp *http.Response, err error) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Client sent an HTTP request to an HTTPS server.\n", string(body))
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
listeners []*listenerutil.ListenerConfig
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
assertions func(t *testing.T, w *Worker, addrs []string)
|
||||
name string
|
||||
proxyListeners []*listenerutil.ListenerConfig
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
assertions func(t *testing.T, w *Worker, addr string)
|
||||
}{
|
||||
{
|
||||
name: "one tcp listener, one unix listener",
|
||||
listeners: []*listenerutil.ListenerConfig{
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"proxy"},
|
||||
Address: "127.0.0.1:0",
|
||||
TLSDisable: true,
|
||||
},
|
||||
name: "unix listener",
|
||||
proxyListeners: []*listenerutil.ListenerConfig{
|
||||
{
|
||||
Type: "unix",
|
||||
Purpose: []string{"proxy"},
|
||||
@@ -50,68 +36,30 @@ func TestStartListeners(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expErr: false,
|
||||
assertions: func(t *testing.T, w *Worker, addrs []string) {
|
||||
require.Len(t, addrs, 2)
|
||||
|
||||
resp, err := http.Get("http://" + addrs[0] + "/v1/proxy/")
|
||||
testNonTlsRejected(t, resp, err)
|
||||
|
||||
assertions: func(t *testing.T, w *Worker, addr string) {
|
||||
cl := http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: func(network, addr string) (net.Conn, error) { return net.Dial("unix", addrs[1]) },
|
||||
Dial: func(network, addr string) (net.Conn, error) { return net.Dial("unix", addr) },
|
||||
},
|
||||
}
|
||||
resp, err = cl.Get("http://anything.domain/v1/proxy/")
|
||||
resp, err := cl.Get("http://anything.domain/v1/proxy/")
|
||||
testNonTlsRejected(t, resp, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple tcp listeners, multiple unix listeners",
|
||||
listeners: []*listenerutil.ListenerConfig{
|
||||
name: "tcp listener",
|
||||
proxyListeners: []*listenerutil.ListenerConfig{
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"proxy"},
|
||||
Address: "127.0.0.1:0",
|
||||
TLSDisable: true,
|
||||
},
|
||||
{
|
||||
Type: "tcp",
|
||||
Purpose: []string{"proxy"},
|
||||
Address: "127.0.0.1:0",
|
||||
TLSDisable: true,
|
||||
},
|
||||
{
|
||||
Type: "unix",
|
||||
Purpose: []string{"proxy"},
|
||||
Address: "/tmp/boundary-worker-test-start-listeners0.sock",
|
||||
TLSDisable: true,
|
||||
},
|
||||
{
|
||||
Type: "unix",
|
||||
Purpose: []string{"proxy"},
|
||||
Address: "/tmp/boundary-worker-test-start-listeners1.sock",
|
||||
TLSDisable: true,
|
||||
},
|
||||
},
|
||||
expErr: false,
|
||||
assertions: func(t *testing.T, w *Worker, addrs []string) {
|
||||
require.Len(t, addrs, 4)
|
||||
|
||||
resp, err := http.Get("http://" + addrs[0] + "/v1/proxy/")
|
||||
assertions: func(t *testing.T, w *Worker, addr string) {
|
||||
resp, err := http.Get("http://" + addr + "/v1/proxy/")
|
||||
testNonTlsRejected(t, resp, err)
|
||||
|
||||
resp, err = http.Get("http://" + addrs[1] + "/v1/proxy/")
|
||||
testNonTlsRejected(t, resp, err)
|
||||
|
||||
for _, proxyAddr := range []string{addrs[2], addrs[3]} {
|
||||
cl := http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: func(network, addr string) (net.Conn, error) { return net.Dial("unix", proxyAddr) },
|
||||
},
|
||||
}
|
||||
resp, err = cl.Get("http://anything.domain/v1/proxy")
|
||||
testNonTlsRejected(t, resp, err)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -119,7 +67,7 @@ func TestStartListeners(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
conf := NewTestWorker(t, &TestWorkerOpts{DisableAutoStart: true}).w.conf
|
||||
conf.RawConfig.SharedConfig.Listeners = tt.listeners
|
||||
conf.RawConfig.SharedConfig.Listeners = tt.proxyListeners
|
||||
|
||||
err := conf.SetupListeners(nil, conf.RawConfig.SharedConfig, []string{"proxy"})
|
||||
require.NoError(t, err)
|
||||
@@ -136,12 +84,8 @@ func TestStartListeners(t *testing.T) {
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
addrs := make([]string, 0)
|
||||
for _, l := range w.listeners {
|
||||
addrs = append(addrs, l.ProxyListener.Addr().String())
|
||||
}
|
||||
if tt.assertions != nil {
|
||||
tt.assertions(t, w, addrs)
|
||||
tt.assertions(t, w, w.proxyListener.ProxyListener.Addr().String())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -158,14 +102,14 @@ func TestStopHttpServersAndListeners(t *testing.T) {
|
||||
{
|
||||
name: "no listeners",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{listeners: []*base.ServerListener{}}
|
||||
return &Worker{proxyListener: &base.ServerListener{}}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "nil listeners slice",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{listeners: nil}
|
||||
return &Worker{proxyListener: nil}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
@@ -173,65 +117,42 @@ func TestStopHttpServersAndListeners(t *testing.T) {
|
||||
name: "listeners with nil http server",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{
|
||||
listeners: []*base.ServerListener{
|
||||
{HTTPServer: nil},
|
||||
{HTTPServer: nil},
|
||||
{HTTPServer: nil},
|
||||
proxyListener: &base.ServerListener{
|
||||
HTTPServer: nil,
|
||||
},
|
||||
}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple listeners",
|
||||
name: "valid listener with http server",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
l1, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
l2, err := net.Listen("unix", "/tmp/boundary-worker-TestStopHttpServersAndListeners-"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
||||
require.NoError(t, err)
|
||||
|
||||
s1 := &http.Server{}
|
||||
s2 := &http.Server{}
|
||||
|
||||
go s1.Serve(l1)
|
||||
go s2.Serve(l2)
|
||||
|
||||
// Make sure they're up
|
||||
_, err = http.Get("http://" + l1.Addr().String())
|
||||
require.NoError(t, err)
|
||||
|
||||
c := http.Client{Transport: &http.Transport{
|
||||
Dial: func(network, addr string) (net.Conn, error) {
|
||||
return net.Dial("unix", l2.Addr().String())
|
||||
},
|
||||
}}
|
||||
_, err = c.Get("http://random.domain")
|
||||
require.NoError(t, err)
|
||||
|
||||
return &Worker{
|
||||
baseContext: context.Background(),
|
||||
listeners: []*base.ServerListener{
|
||||
{
|
||||
ProxyListener: l1,
|
||||
HTTPServer: s1,
|
||||
Config: &listenerutil.ListenerConfig{Type: "tcp"},
|
||||
},
|
||||
{
|
||||
ProxyListener: l2,
|
||||
HTTPServer: s2,
|
||||
Config: &listenerutil.ListenerConfig{Type: "tcp"},
|
||||
},
|
||||
proxyListener: &base.ServerListener{
|
||||
ProxyListener: l1,
|
||||
HTTPServer: s1,
|
||||
Config: &listenerutil.ListenerConfig{Type: "tcp"},
|
||||
},
|
||||
}
|
||||
},
|
||||
assertions: func(t *testing.T, w *Worker) {
|
||||
// Asserts the HTTP Servers are closed.
|
||||
require.ErrorIs(t, w.listeners[0].HTTPServer.Serve(w.listeners[0].ProxyListener), http.ErrServerClosed)
|
||||
require.ErrorIs(t, w.listeners[1].HTTPServer.Serve(w.listeners[1].ProxyListener), http.ErrServerClosed)
|
||||
require.ErrorIs(t, w.proxyListener.HTTPServer.Serve(w.proxyListener.ProxyListener), http.ErrServerClosed)
|
||||
|
||||
// Asserts the underlying listeners are closed.
|
||||
require.ErrorIs(t, w.listeners[0].ProxyListener.Close(), net.ErrClosed)
|
||||
require.ErrorIs(t, w.listeners[1].ProxyListener.Close(), net.ErrClosed)
|
||||
require.ErrorIs(t, w.proxyListener.ProxyListener.Close(), net.ErrClosed)
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
@@ -240,7 +161,7 @@ func TestStopHttpServersAndListeners(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := tt.workerFn(t)
|
||||
err := w.stopHttpServersAndListeners()
|
||||
err := w.stopServersAndListeners()
|
||||
if tt.expErr {
|
||||
require.EqualError(t, err, tt.expErrStr)
|
||||
return
|
||||
@@ -265,66 +186,14 @@ func TestStopAnyListeners(t *testing.T) {
|
||||
{
|
||||
name: "nil listeners",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{listeners: nil}
|
||||
return &Worker{proxyListener: nil}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "no listeners",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{listeners: []*base.ServerListener{}}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "listeners slice with nil server listeners",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{listeners: []*base.ServerListener{nil, nil, nil}}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "non-empty but nil listeners",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
return &Worker{listeners: []*base.ServerListener{
|
||||
{ProxyListener: nil}, {ProxyListener: nil}, {ProxyListener: nil},
|
||||
}}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple listeners, including a closed one",
|
||||
workerFn: func(t *testing.T) *Worker {
|
||||
l1, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
|
||||
l2, err := net.Listen("unix", "/tmp/boundary-worker-TestStopAnyListeners-"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
||||
require.NoError(t, err)
|
||||
|
||||
l3, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, l3.Close())
|
||||
|
||||
return &Worker{listeners: []*base.ServerListener{
|
||||
{
|
||||
Config: &listenerutil.ListenerConfig{Type: "tcp"},
|
||||
ProxyListener: l1,
|
||||
},
|
||||
{
|
||||
Config: &listenerutil.ListenerConfig{Type: "tcp"},
|
||||
ProxyListener: l2,
|
||||
},
|
||||
{
|
||||
Config: &listenerutil.ListenerConfig{Type: "tcp"},
|
||||
ProxyListener: l3,
|
||||
},
|
||||
}}
|
||||
},
|
||||
assertions: func(t *testing.T, w *Worker) {
|
||||
for i := range w.listeners {
|
||||
ln := w.listeners[i]
|
||||
require.ErrorIs(t, ln.ProxyListener.Close(), net.ErrClosed)
|
||||
}
|
||||
return &Worker{proxyListener: &base.ServerListener{}}
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ package worker
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
@@ -11,13 +12,14 @@ import (
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
type LastStatusInformation struct {
|
||||
*pbs.StatusResponse
|
||||
StatusTime time.Time
|
||||
StatusTime time.Time
|
||||
LastCalculatedUpstreams []string
|
||||
}
|
||||
|
||||
func (w *Worker) startStatusTicking(cancelCtx context.Context) {
|
||||
@@ -90,6 +92,15 @@ func (w *Worker) WaitForNextSuccessfulStatusUpdate() error {
|
||||
|
||||
func (w *Worker) sendWorkerStatus(cancelCtx context.Context) {
|
||||
const op = "worker.(Worker).sendWorkerStatus"
|
||||
|
||||
// If we've never managed to successfully authenticate then we won't have
|
||||
// any session information anyways and this will produce a ton of noise in
|
||||
// observability, so suppress it
|
||||
if !w.everAuthenticated.Load() {
|
||||
event.WriteSysEvent(cancelCtx, op, "worker is not authenticated to an upstream, not sending status")
|
||||
return
|
||||
}
|
||||
|
||||
// First send info as-is. We'll perform cleanup duties after we
|
||||
// get cancel/job change info back.
|
||||
var activeJobs []*pbs.JobStatus
|
||||
@@ -127,22 +138,30 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context) {
|
||||
|
||||
// Send status information
|
||||
client := w.controllerStatusConn.Load().(pbs.ServerCoordinationServiceClient)
|
||||
var tags map[string]*servers.TagValues
|
||||
var tags []*servers.TagPair
|
||||
// If we're not going to request a tag update, no reason to have these
|
||||
// marshaled on every status call.
|
||||
if w.updateTags.Load() {
|
||||
tags = w.tags.Load().(map[string]*servers.TagValues)
|
||||
tags = w.tags.Load().([]*servers.TagPair)
|
||||
}
|
||||
statusCtx, statusCancel := context.WithTimeout(cancelCtx, common.StatusTimeout)
|
||||
defer statusCancel()
|
||||
|
||||
keyId := w.WorkerAuthCurrentKeyId.Load()
|
||||
|
||||
if w.conf.RawConfig.Worker.Name == "" && keyId == "" {
|
||||
event.WriteError(statusCtx, op, errors.New("worker name and keyId are both empty; one is needed to identify a worker"),
|
||||
event.WithInfoMsg("error making status request to controller"))
|
||||
}
|
||||
|
||||
result, err := client.Status(statusCtx, &pbs.StatusRequest{
|
||||
Jobs: activeJobs,
|
||||
Worker: &servers.Server{
|
||||
PrivateId: w.conf.RawConfig.Worker.Name,
|
||||
Type: resource.Worker.String(),
|
||||
WorkerStatus: &servers.ServerWorkerStatus{
|
||||
Name: w.conf.RawConfig.Worker.Name,
|
||||
Description: w.conf.RawConfig.Worker.Description,
|
||||
Address: w.conf.RawConfig.Worker.PublicAddr,
|
||||
Tags: tags,
|
||||
KeyId: keyId,
|
||||
},
|
||||
UpdateTags: w.updateTags.Load(),
|
||||
})
|
||||
@@ -182,19 +201,27 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context) {
|
||||
}
|
||||
} else {
|
||||
w.updateTags.Store(false)
|
||||
addrs := make([]resolver.Address, 0, len(result.Controllers))
|
||||
strAddrs := make([]string, 0, len(result.Controllers))
|
||||
for _, v := range result.Controllers {
|
||||
addrs = append(addrs, resolver.Address{Addr: v.Address})
|
||||
strAddrs = append(strAddrs, v.Address)
|
||||
// This may be nil if we are in a multiple hop scenario
|
||||
var addrs []resolver.Address
|
||||
var newUpstreams []string
|
||||
if len(result.CalculatedUpstreams) > 0 {
|
||||
addrs = make([]resolver.Address, 0, len(result.CalculatedUpstreams))
|
||||
for _, v := range result.CalculatedUpstreams {
|
||||
addrs = append(addrs, resolver.Address{Addr: v.Address})
|
||||
newUpstreams = append(newUpstreams, v.Address)
|
||||
}
|
||||
lastStatus := w.lastStatusSuccess.Load().(*LastStatusInformation)
|
||||
// Compare upstreams; update resolver if there is a difference, and emit an event with old and new addresses
|
||||
if lastStatus != nil && !strutil.EquivalentSlices(lastStatus.LastCalculatedUpstreams, newUpstreams) {
|
||||
upstreamsMessage := fmt.Sprintf("Upstreams has changed; old upstreams were: %s, new upstreams are: %s", lastStatus.LastCalculatedUpstreams, newUpstreams)
|
||||
event.WriteSysEvent(cancelCtx, op, upstreamsMessage)
|
||||
w.Resolver().UpdateState(resolver.State{Addresses: addrs})
|
||||
} else if lastStatus == nil {
|
||||
w.Resolver().UpdateState(resolver.State{Addresses: addrs})
|
||||
event.WriteSysEvent(cancelCtx, op, fmt.Sprintf("Upstreams after first status set to: %s", newUpstreams))
|
||||
}
|
||||
}
|
||||
switch len(strAddrs) {
|
||||
case 0:
|
||||
event.WriteError(statusCtx, op, errors.New("got no controller addresses from controller; possibly prior to first status save, not persisting"))
|
||||
default:
|
||||
w.Resolver().UpdateState(resolver.State{Addresses: addrs})
|
||||
}
|
||||
w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now()})
|
||||
w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now(), LastCalculatedUpstreams: newUpstreams})
|
||||
|
||||
for _, request := range result.GetJobsRequests() {
|
||||
switch request.GetRequestType() {
|
||||
|
||||
@@ -4,17 +4,18 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/internal/daemon/worker/session"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/base62"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -31,7 +32,7 @@ type TestWorker struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// Worker returns the underlying controller
|
||||
// Worker returns the underlying worker
|
||||
func (tw *TestWorker) Worker() *Worker {
|
||||
return tw.w
|
||||
}
|
||||
@@ -52,10 +53,10 @@ func (tw *TestWorker) Name() string {
|
||||
return tw.name
|
||||
}
|
||||
|
||||
func (tw *TestWorker) ControllerAddrs() []string {
|
||||
func (tw *TestWorker) UpstreamAddrs() []string {
|
||||
var addrs []string
|
||||
lastStatus := tw.w.LastStatusSuccess()
|
||||
for _, v := range lastStatus.GetControllers() {
|
||||
for _, v := range lastStatus.GetCalculatedUpstreams() {
|
||||
addrs = append(addrs, v.Address)
|
||||
}
|
||||
|
||||
@@ -164,8 +165,8 @@ type TestWorkerOpts struct {
|
||||
// Config; if not provided a dev one will be created
|
||||
Config *config.Config
|
||||
|
||||
// Sets initial controller addresses
|
||||
InitialControllers []string
|
||||
// Sets initial upstream addresses
|
||||
InitialUpstreams []string
|
||||
|
||||
// If true, the worker will not be started
|
||||
DisableAutoStart bool
|
||||
@@ -173,6 +174,12 @@ type TestWorkerOpts struct {
|
||||
// The worker auth KMS to use, or one will be created
|
||||
WorkerAuthKms wrapping.Wrapper
|
||||
|
||||
// The worker credential storage KMS to use, or one will be created
|
||||
WorkerAuthStorageKms wrapping.Wrapper
|
||||
|
||||
// The location of the worker's auth storage
|
||||
WorkerAuthStoragePath string
|
||||
|
||||
// The name to use for the worker, otherwise one will be randomly
|
||||
// generated, unless provided in a non-nil Config
|
||||
Name string
|
||||
@@ -191,6 +198,9 @@ type TestWorkerOpts struct {
|
||||
// Overrides worker's nonceFn, for cases where we want to have control
|
||||
// over the nonce we send to the Controller
|
||||
NonceFn randFn
|
||||
|
||||
// If set, override the normal auth rotation period
|
||||
AuthRotationPeriod time.Duration
|
||||
}
|
||||
|
||||
func NewTestWorker(t testing.TB, opts *TestWorkerOpts) *TestWorker {
|
||||
@@ -223,8 +233,8 @@ func NewTestWorker(t testing.TB, opts *TestWorkerOpts) *TestWorker {
|
||||
opts.Config.Worker.Name = opts.Name
|
||||
}
|
||||
|
||||
if len(opts.InitialControllers) > 0 {
|
||||
opts.Config.Worker.Controllers = opts.InitialControllers
|
||||
if len(opts.InitialUpstreams) > 0 {
|
||||
opts.Config.Worker.InitialUpstreams = opts.InitialUpstreams
|
||||
}
|
||||
|
||||
// Start a logger
|
||||
@@ -260,6 +270,8 @@ func NewTestWorker(t testing.TB, opts *TestWorkerOpts) *TestWorker {
|
||||
switch {
|
||||
case opts.WorkerAuthKms != nil:
|
||||
tw.b.WorkerAuthKms = opts.WorkerAuthKms
|
||||
case opts.WorkerAuthStorageKms != nil:
|
||||
tw.b.WorkerAuthStorageKms = opts.WorkerAuthStorageKms
|
||||
default:
|
||||
if err := tw.b.SetupKMSes(tw.b.Context, nil, opts.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -288,6 +300,8 @@ func NewTestWorker(t testing.TB, opts *TestWorkerOpts) *TestWorker {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tw.w.TestOverrideAuthRotationPeriod = opts.AuthRotationPeriod
|
||||
|
||||
if opts.NonceFn != nil {
|
||||
tw.w.nonceFn = opts.NonceFn
|
||||
}
|
||||
@@ -309,17 +323,19 @@ func (tw *TestWorker) AddClusterWorkerMember(t testing.TB, opts *TestWorkerOpts)
|
||||
}
|
||||
nextOpts := &TestWorkerOpts{
|
||||
WorkerAuthKms: tw.w.conf.WorkerAuthKms,
|
||||
WorkerAuthStorageKms: tw.w.conf.WorkerAuthStorageKms,
|
||||
Name: opts.Name,
|
||||
InitialControllers: tw.ControllerAddrs(),
|
||||
InitialUpstreams: tw.UpstreamAddrs(),
|
||||
Logger: tw.w.conf.Logger,
|
||||
StatusGracePeriodDuration: opts.StatusGracePeriodDuration,
|
||||
}
|
||||
if nextOpts.Name == "" {
|
||||
var err error
|
||||
nextOpts.Name, err = base62.Random(5)
|
||||
nextOpts.Name, err = db.NewPublicId("w")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
nextOpts.Name = strings.ToLower(nextOpts.Name)
|
||||
event.WriteSysEvent(context.TODO(), op, "worker name generated", "name", nextOpts.Name)
|
||||
}
|
||||
return NewTestWorker(t, nextOpts)
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/daemon/worker/session"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -60,3 +62,28 @@ func TestTestWorkerLookupSessionMissing(t *testing.T) {
|
||||
require.False(ok)
|
||||
require.Equal(TestSessionInfo{}, actual)
|
||||
}
|
||||
|
||||
func TestTestWorker_WorkerAuthStorageKms(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
wrapper wrapping.Wrapper
|
||||
}{
|
||||
{
|
||||
name: "Nil Wrapper",
|
||||
wrapper: nil,
|
||||
},
|
||||
{
|
||||
name: "Valid Wrapper",
|
||||
wrapper: db.TestWrapper(t),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
tw := NewTestWorker(t, &TestWorkerOpts{
|
||||
WorkerAuthStorageKms: tt.wrapper,
|
||||
})
|
||||
require.Equal(tt.wrapper, tw.Config().WorkerAuthStorageKms)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,10 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/mr-tron/base58"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
@@ -21,13 +25,18 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/daemon/worker/session"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-secure-stdlib/base62"
|
||||
"github.com/hashicorp/go-secure-stdlib/mlock"
|
||||
"github.com/hashicorp/nodeenrollment/multihop"
|
||||
nodeenet "github.com/hashicorp/nodeenrollment/net"
|
||||
nodeefile "github.com/hashicorp/nodeenrollment/storage/file"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
ua "go.uber.org/atomic"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/resolver/manual"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type randFn func(length int) (string, error)
|
||||
@@ -42,7 +51,10 @@ type Worker struct {
|
||||
|
||||
tickerWg sync.WaitGroup
|
||||
|
||||
grpcClientConn *atomic.Value
|
||||
|
||||
controllerStatusConn *atomic.Value
|
||||
everAuthenticated *ua.Bool
|
||||
lastStatusSuccess *atomic.Value
|
||||
workerStartTime time.Time
|
||||
|
||||
@@ -51,7 +63,9 @@ type Worker struct {
|
||||
controllerSessionConn *atomic.Value
|
||||
sessionInfoMap *sync.Map
|
||||
|
||||
listeners []*base.ServerListener
|
||||
controllerMultihopConn *atomic.Value
|
||||
|
||||
proxyListener *base.ServerListener
|
||||
|
||||
// Used to generate a random nonce for Controller connections
|
||||
nonceFn randFn
|
||||
@@ -62,11 +76,18 @@ type Worker struct {
|
||||
// This stores whether or not to send updated tags on the next status
|
||||
// request. It can be set via startup in New below, or (eventually) via
|
||||
// SIGHUP.
|
||||
updateTags ua.Bool
|
||||
updateTags *ua.Bool
|
||||
|
||||
// Test-specific options
|
||||
// The storage for node enrollment
|
||||
WorkerAuthStorage *nodeefile.Storage
|
||||
WorkerAuthCurrentKeyId *ua.String
|
||||
WorkerAuthRegistrationRequest string
|
||||
workerAuthSplitListener *nodeenet.SplitListener
|
||||
|
||||
// Test-specific options (and possibly hidden dev-mode flags)
|
||||
TestOverrideX509VerifyDnsName string
|
||||
TestOverrideX509VerifyCertPool *x509.CertPool
|
||||
TestOverrideAuthRotationPeriod time.Duration
|
||||
}
|
||||
|
||||
func New(conf *Config) (*Worker, error) {
|
||||
@@ -75,16 +96,21 @@ func New(conf *Config) (*Worker, error) {
|
||||
metric.InitializeClusterClientCollectors(conf.PrometheusRegisterer)
|
||||
|
||||
w := &Worker{
|
||||
conf: conf,
|
||||
logger: conf.Logger.Named("worker"),
|
||||
started: ua.NewBool(false),
|
||||
controllerStatusConn: new(atomic.Value),
|
||||
lastStatusSuccess: new(atomic.Value),
|
||||
controllerResolver: new(atomic.Value),
|
||||
controllerSessionConn: new(atomic.Value),
|
||||
sessionInfoMap: new(sync.Map),
|
||||
tags: new(atomic.Value),
|
||||
nonceFn: base62.Random,
|
||||
conf: conf,
|
||||
logger: conf.Logger.Named("worker"),
|
||||
started: ua.NewBool(false),
|
||||
grpcClientConn: new(atomic.Value),
|
||||
controllerStatusConn: new(atomic.Value),
|
||||
everAuthenticated: ua.NewBool(false),
|
||||
lastStatusSuccess: new(atomic.Value),
|
||||
controllerResolver: new(atomic.Value),
|
||||
controllerSessionConn: new(atomic.Value),
|
||||
sessionInfoMap: new(sync.Map),
|
||||
controllerMultihopConn: new(atomic.Value),
|
||||
tags: new(atomic.Value),
|
||||
updateTags: ua.NewBool(false),
|
||||
nonceFn: base62.Random,
|
||||
WorkerAuthCurrentKeyId: new(ua.String),
|
||||
}
|
||||
|
||||
w.lastStatusSuccess.Store((*LastStatusInformation)(nil))
|
||||
@@ -121,6 +147,7 @@ func New(conf *Config) (*Worker, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var listenerCount int
|
||||
for i := range conf.Listeners {
|
||||
l := conf.Listeners[i]
|
||||
if l == nil || l.Config == nil || l.Config.Purpose == nil {
|
||||
@@ -131,11 +158,20 @@ func New(conf *Config) (*Worker, error) {
|
||||
}
|
||||
switch l.Config.Purpose[0] {
|
||||
case "proxy":
|
||||
w.listeners = append(w.listeners, l)
|
||||
if w.proxyListener == nil {
|
||||
w.proxyListener = l
|
||||
}
|
||||
listenerCount++
|
||||
}
|
||||
}
|
||||
if len(w.listeners) == 0 {
|
||||
return nil, fmt.Errorf("no proxy listeners found")
|
||||
if listenerCount != 1 {
|
||||
return nil, fmt.Errorf("exactly one proxy listener is required")
|
||||
}
|
||||
|
||||
w.WorkerAuthStorage, err = nodeefile.New(w.baseContext,
|
||||
nodeefile.WithBaseDirectory(w.conf.RawConfig.Worker.AuthStoragePath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w, nil
|
||||
@@ -143,29 +179,144 @@ func New(conf *Config) (*Worker, error) {
|
||||
|
||||
func (w *Worker) Start() error {
|
||||
const op = "worker.(Worker).Start"
|
||||
|
||||
w.baseContext, w.baseCancel = context.WithCancel(context.Background())
|
||||
|
||||
if w.started.Load() {
|
||||
event.WriteSysEvent(w.baseContext, op, "already started, skipping")
|
||||
return nil
|
||||
}
|
||||
|
||||
w.baseContext, w.baseCancel = context.WithCancel(context.Background())
|
||||
|
||||
scheme := strconv.FormatInt(time.Now().UnixNano(), 36)
|
||||
controllerResolver := manual.NewBuilderWithScheme(scheme)
|
||||
w.controllerResolver.Store(controllerResolver)
|
||||
|
||||
if w.conf.WorkerAuthKms == nil {
|
||||
// In this section, we look for existing worker credentials. The two
|
||||
// variables below store whether to create new credentials and whether
|
||||
// to create a fetch request so it can be displayed in the worker
|
||||
// startup info. These may be different because if initial creds have
|
||||
// been generated on the worker side but not yet authorized/fetched from
|
||||
// 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.
|
||||
var createNodeAuthCreds bool
|
||||
var createFetchRequest bool
|
||||
nodeCreds, err := types.LoadNodeCredentials(w.baseContext, w.WorkerAuthStorage, nodeenrollment.CurrentId, nodeenrollment.WithWrapper(w.conf.WorkerAuthStorageKms))
|
||||
switch {
|
||||
case err == nil:
|
||||
// It's unclear why this would ever happen -- it shouldn't -- so
|
||||
// this is simply safety against panics if something goes
|
||||
// catastrophically wrong
|
||||
if nodeCreds == nil {
|
||||
event.WriteSysEvent(w.baseContext, op, "no error loading worker auth creds but nil creds, creating new creds for registration")
|
||||
createNodeAuthCreds = true
|
||||
createFetchRequest = true
|
||||
break
|
||||
}
|
||||
|
||||
// Check that we have valid creds, or that we have generated creds but
|
||||
// simply are still waiting on authentication (in which case we don't
|
||||
// want to invalidate what we've already sent)
|
||||
var validCreds bool
|
||||
switch len(nodeCreds.CertificateBundles) {
|
||||
case 0:
|
||||
// Still waiting on initial creds, so don't invalidate the request
|
||||
// by creating new credentials. However, we will generate and
|
||||
// display a new valid request in case the first was lost.
|
||||
createFetchRequest = true
|
||||
|
||||
default:
|
||||
now := time.Now()
|
||||
for _, bundle := range nodeCreds.CertificateBundles {
|
||||
if bundle.CertificateNotBefore.AsTime().Before(now) && bundle.CertificateNotAfter.AsTime().After(now) {
|
||||
// If we have a certificate in its validity period,
|
||||
// everything is fine
|
||||
validCreds = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Certificates are both expired, so create new credentials and
|
||||
// output a request based on those
|
||||
createNodeAuthCreds = !validCreds
|
||||
createFetchRequest = !validCreds
|
||||
}
|
||||
|
||||
case errors.Is(err, nodeenrollment.ErrNotFound):
|
||||
// Nothing was found on disk, so create
|
||||
createNodeAuthCreds = true
|
||||
createFetchRequest = true
|
||||
|
||||
default:
|
||||
// Some other type of error happened, bail out
|
||||
return fmt.Errorf("error loading worker auth creds: %w", err)
|
||||
}
|
||||
|
||||
// NOTE: this block _must_ be before the `if createFetchRequest` block
|
||||
// or the fetch request may have no credentials to work with
|
||||
if createNodeAuthCreds {
|
||||
nodeCreds, err = types.NewNodeCredentials(
|
||||
w.baseContext,
|
||||
w.WorkerAuthStorage,
|
||||
nodeenrollment.WithRandomReader(w.conf.SecureRandomReader),
|
||||
nodeenrollment.WithWrapper(w.conf.WorkerAuthStorageKms),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating new worker auth creds: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if createFetchRequest {
|
||||
if nodeCreds == nil {
|
||||
return fmt.Errorf("need to create fetch request but worker auth creds are nil: %w", err)
|
||||
}
|
||||
req, err := nodeCreds.CreateFetchNodeCredentialsRequest(w.baseContext, nodeenrollment.WithRandomReader(w.conf.SecureRandomReader))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating worker auth fetch credentials request: %w", err)
|
||||
}
|
||||
reqBytes, err := proto.Marshal(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling worker auth fetch credentials request: %w", err)
|
||||
}
|
||||
w.WorkerAuthRegistrationRequest = base58.FastBase58Encoding(reqBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error encoding worker auth registration request: %w", err)
|
||||
}
|
||||
currentKeyId, err := nodeenrollment.KeyIdFromPkix(nodeCreds.CertificatePublicKeyPkix)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deriving worker auth key id: %w", err)
|
||||
}
|
||||
w.WorkerAuthCurrentKeyId.Store(currentKeyId)
|
||||
}
|
||||
// Regardless, we want to load the currentKeyId
|
||||
currentKeyId, err := nodeenrollment.KeyIdFromPkix(nodeCreds.CertificatePublicKeyPkix)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deriving worker auth key id: %w", err)
|
||||
}
|
||||
w.WorkerAuthCurrentKeyId.Store(currentKeyId)
|
||||
}
|
||||
|
||||
if err := w.startListeners(); err != nil {
|
||||
return fmt.Errorf("error starting worker listeners: %w", err)
|
||||
}
|
||||
if err := w.startControllerConnections(); err != nil {
|
||||
if err := w.StartControllerConnections(); err != nil {
|
||||
return fmt.Errorf("error making controller connections: %w", err)
|
||||
}
|
||||
|
||||
w.tickerWg.Add(1)
|
||||
// Rather than deal with some of the potential error conditions for Add on
|
||||
// the waitgroup vs. Done (in case a function exits immediately), we will
|
||||
// always start rotation and simply exit early if we're using KMS, and
|
||||
// always add 2 here.
|
||||
w.tickerWg.Add(2)
|
||||
go func() {
|
||||
defer w.tickerWg.Done()
|
||||
w.startStatusTicking(w.baseContext)
|
||||
}()
|
||||
go func() {
|
||||
defer w.tickerWg.Done()
|
||||
w.startAuthRotationTicking(w.baseContext)
|
||||
}()
|
||||
|
||||
w.workerStartTime = time.Now()
|
||||
w.started.Store(true)
|
||||
@@ -241,19 +392,40 @@ func (w *Worker) Resolver() *manual.Resolver {
|
||||
|
||||
func (w *Worker) ParseAndStoreTags(incoming map[string][]string) {
|
||||
if len(incoming) == 0 {
|
||||
w.tags.Store(map[string]*servers.TagValues{})
|
||||
w.tags.Store([]*servers.TagPair{})
|
||||
return
|
||||
}
|
||||
tags := make(map[string]*servers.TagValues, len(incoming))
|
||||
for k, v := range incoming {
|
||||
tags[k] = &servers.TagValues{
|
||||
Values: append(make([]string, 0, len(v)), v...),
|
||||
tags := []*servers.TagPair{}
|
||||
for k, vals := range incoming {
|
||||
for _, v := range vals {
|
||||
tags = append(tags, &servers.TagPair{
|
||||
Key: k,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
w.tags.Store(tags)
|
||||
w.updateTags.Store(true)
|
||||
}
|
||||
|
||||
// GrpcClientConn returns the underlying client connection
|
||||
func (w *Worker) GrpcClientConn() (*grpc.ClientConn, error) {
|
||||
rawConn := w.grpcClientConn.Load()
|
||||
if rawConn == nil {
|
||||
return nil, errors.New("unable to load grpc client conn")
|
||||
}
|
||||
cc, ok := rawConn.(*grpc.ClientConn)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid grpc client connection %T", rawConn)
|
||||
}
|
||||
if cc == nil {
|
||||
return nil, fmt.Errorf("client connection is nil")
|
||||
}
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
// ControllerSessionConn returns the underlying session service client
|
||||
func (w *Worker) ControllerSessionConn() (pbs.SessionServiceClient, error) {
|
||||
rawConn := w.controllerSessionConn.Load()
|
||||
if rawConn == nil {
|
||||
@@ -270,6 +442,40 @@ func (w *Worker) ControllerSessionConn() (pbs.SessionServiceClient, error) {
|
||||
return sessClient, nil
|
||||
}
|
||||
|
||||
// ControllerServerCoordinationServiceConn returns the underlying server coordination service client
|
||||
func (w *Worker) ControllerServerCoordinationServiceConn() (pbs.ServerCoordinationServiceClient, error) {
|
||||
rawConn := w.controllerStatusConn.Load()
|
||||
if rawConn == nil {
|
||||
return nil, errors.New("unable to load controller service coordination service connection")
|
||||
}
|
||||
statusClient, ok := rawConn.(pbs.ServerCoordinationServiceClient)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid service coordination service client %T", rawConn)
|
||||
}
|
||||
if statusClient == nil {
|
||||
return nil, fmt.Errorf("service coordination service client is nil")
|
||||
}
|
||||
|
||||
return statusClient, nil
|
||||
}
|
||||
|
||||
// ControllerMultihopConn returns the underlying multihop service client
|
||||
func (w *Worker) ControllerMultihopConn() (multihop.MultihopServiceClient, error) {
|
||||
rawConn := w.controllerMultihopConn.Load()
|
||||
if rawConn == nil {
|
||||
return nil, errors.New("unable to load controller multihop service connection")
|
||||
}
|
||||
multihopClient, ok := rawConn.(multihop.MultihopServiceClient)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid multihop client %T", rawConn)
|
||||
}
|
||||
if multihopClient == nil {
|
||||
return nil, fmt.Errorf("session multihop is nil")
|
||||
}
|
||||
|
||||
return multihopClient, nil
|
||||
}
|
||||
|
||||
func (w *Worker) getSessionTls(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
const op = "worker.(Worker).getSessionTls"
|
||||
ctx := w.baseContext
|
||||
@@ -300,8 +506,9 @@ func (w *Worker) getSessionTls(hello *tls.ClientHelloInfo) (*tls.Config, error)
|
||||
defer cancel()
|
||||
|
||||
resp, err := conn.LookupSession(timeoutContext, &pbs.LookupSessionRequest{
|
||||
ServerId: w.conf.RawConfig.Worker.Name,
|
||||
SessionId: sessionId,
|
||||
ServerId: w.conf.RawConfig.Worker.Name,
|
||||
SessionId: sessionId,
|
||||
WorkerKeyId: w.WorkerAuthCurrentKeyId.Load(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error validating session: %w", err)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
)
|
||||
|
||||
type workerProxyServiceServer struct {
|
||||
pbs.UnimplementedServerCoordinationServiceServer
|
||||
pbs.UnimplementedSessionServiceServer
|
||||
|
||||
scsClient *atomic.Value
|
||||
ssClient *atomic.Value
|
||||
}
|
||||
|
||||
func NewWorkerProxyServiceServer(
|
||||
scsClient *atomic.Value,
|
||||
ssClient *atomic.Value,
|
||||
) *workerProxyServiceServer {
|
||||
return &workerProxyServiceServer{
|
||||
scsClient: scsClient,
|
||||
ssClient: ssClient,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
_ pbs.ServerCoordinationServiceServer = &workerProxyServiceServer{}
|
||||
_ pbs.SessionServiceServer = &workerProxyServiceServer{}
|
||||
)
|
||||
|
||||
func (ws *workerProxyServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) {
|
||||
resp, err := ws.scsClient.Load().(pbs.ServerCoordinationServiceClient).Status(ctx, req)
|
||||
|
||||
if resp != nil {
|
||||
// We don't currently support distributing new addreses to workers
|
||||
// multiple hops away so ensure they're stripped out
|
||||
resp.CalculatedUpstreams = nil
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (ws *workerProxyServiceServer) LookupSession(ctx context.Context, req *pbs.LookupSessionRequest) (*pbs.LookupSessionResponse, error) {
|
||||
return ws.ssClient.Load().(pbs.SessionServiceClient).LookupSession(ctx, req)
|
||||
}
|
||||
|
||||
func (ws *workerProxyServiceServer) CancelSession(ctx context.Context, req *pbs.CancelSessionRequest) (*pbs.CancelSessionResponse, error) {
|
||||
return ws.ssClient.Load().(pbs.SessionServiceClient).CancelSession(ctx, req)
|
||||
}
|
||||
|
||||
func (ws *workerProxyServiceServer) ActivateSession(ctx context.Context, req *pbs.ActivateSessionRequest) (*pbs.ActivateSessionResponse, error) {
|
||||
return ws.ssClient.Load().(pbs.SessionServiceClient).ActivateSession(ctx, req)
|
||||
}
|
||||
|
||||
func (ws *workerProxyServiceServer) AuthorizeConnection(ctx context.Context, req *pbs.AuthorizeConnectionRequest) (*pbs.AuthorizeConnectionResponse, error) {
|
||||
return ws.ssClient.Load().(pbs.SessionServiceClient).AuthorizeConnection(ctx, req)
|
||||
}
|
||||
|
||||
func (ws *workerProxyServiceServer) ConnectConnection(ctx context.Context, req *pbs.ConnectConnectionRequest) (*pbs.ConnectConnectionResponse, error) {
|
||||
return ws.ssClient.Load().(pbs.SessionServiceClient).ConnectConnection(ctx, req)
|
||||
}
|
||||
|
||||
func (ws *workerProxyServiceServer) CloseConnection(ctx context.Context, req *pbs.CloseConnectionRequest) (*pbs.CloseConnectionResponse, error) {
|
||||
return ws.ssClient.Load().(pbs.SessionServiceClient).CloseConnection(ctx, req)
|
||||
}
|
||||
@@ -1,14 +1,27 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/listenerutil"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/registration"
|
||||
"github.com/hashicorp/nodeenrollment/rotation"
|
||||
nodeefile "github.com/hashicorp/nodeenrollment/storage/file"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func TestWorkerNew(t *testing.T) {
|
||||
@@ -23,13 +36,13 @@ func TestWorkerNew(t *testing.T) {
|
||||
name: "nil listeners",
|
||||
in: &Config{Server: &base.Server{Listeners: nil}},
|
||||
expErr: true,
|
||||
expErrMsg: "no proxy listeners found",
|
||||
expErrMsg: "exactly one proxy listener is required",
|
||||
},
|
||||
{
|
||||
name: "zero listeners",
|
||||
in: &Config{Server: &base.Server{Listeners: []*base.ServerListener{}}},
|
||||
expErr: true,
|
||||
expErrMsg: "no proxy listeners found",
|
||||
expErrMsg: "exactly one proxy listener is required",
|
||||
},
|
||||
{
|
||||
name: "populated with nil values",
|
||||
@@ -43,7 +56,7 @@ func TestWorkerNew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expErr: true,
|
||||
expErrMsg: "no proxy listeners found",
|
||||
expErrMsg: "exactly one proxy listener is required",
|
||||
},
|
||||
{
|
||||
name: "multiple purposes",
|
||||
@@ -60,7 +73,7 @@ func TestWorkerNew(t *testing.T) {
|
||||
expErrMsg: `found listener with multiple purposes "api,proxy"`,
|
||||
},
|
||||
{
|
||||
name: "valid listeners",
|
||||
name: "too many proxy listeners",
|
||||
in: &Config{
|
||||
Server: &base.Server{
|
||||
Listeners: []*base.ServerListener{
|
||||
@@ -71,10 +84,21 @@ func TestWorkerNew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expErr: false,
|
||||
assertions: func(t *testing.T, w *Worker) {
|
||||
require.Len(t, w.listeners, 2)
|
||||
expErr: true,
|
||||
expErrMsg: "exactly one proxy listener is required",
|
||||
},
|
||||
{
|
||||
name: "valid listeners",
|
||||
in: &Config{
|
||||
Server: &base.Server{
|
||||
Listeners: []*base.ServerListener{
|
||||
{Config: &listenerutil.ListenerConfig{Purpose: []string{"api"}}},
|
||||
{Config: &listenerutil.ListenerConfig{Purpose: []string{"proxy"}}},
|
||||
{Config: &listenerutil.ListenerConfig{Purpose: []string{"cluster"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
expErr: false,
|
||||
},
|
||||
{
|
||||
name: "worker nonce func is set",
|
||||
@@ -112,3 +136,139 @@ func TestWorkerNew(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupWorkerAuthStorage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
ts := db.TestWrapper(t)
|
||||
keyId, err := ts.KeyId(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// First, just test the key ID is populated
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { require.NoError(t, os.RemoveAll(tmpDir)) })
|
||||
tw := NewTestWorker(t, &TestWorkerOpts{
|
||||
WorkerAuthStorageKms: ts,
|
||||
WorkerAuthStoragePath: tmpDir,
|
||||
DisableAutoStart: true,
|
||||
})
|
||||
t.Cleanup(tw.Shutdown)
|
||||
err = tw.Worker().Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
wKeyId, err := tw.Config().WorkerAuthStorageKms.KeyId(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, keyId, wKeyId)
|
||||
|
||||
// Create a fresh persistent dir for the following tests
|
||||
tmpDir, err = os.MkdirTemp("", "")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { require.NoError(t, os.RemoveAll(tmpDir)) })
|
||||
|
||||
// Get an initial set of authorized node credentials
|
||||
initStorage, err := nodeefile.New(ctx)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(initStorage.Cleanup)
|
||||
_, err = rotation.RotateRootCertificates(ctx, initStorage)
|
||||
require.NoError(t, err)
|
||||
initNodeCreds, err := types.NewNodeCredentials(ctx, initStorage)
|
||||
require.NoError(t, err)
|
||||
req, err := initNodeCreds.CreateFetchNodeCredentialsRequest(ctx)
|
||||
require.NoError(t, err)
|
||||
_, err = registration.AuthorizeNode(ctx, initStorage, req)
|
||||
require.NoError(t, err)
|
||||
fetchResp, err := registration.FetchNodeCredentials(ctx, initStorage, req)
|
||||
require.NoError(t, err)
|
||||
initNodeCreds, err = initNodeCreds.HandleFetchNodeCredentialsResponse(ctx, initStorage, fetchResp)
|
||||
require.NoError(t, err)
|
||||
initKeyId, err := nodeenrollment.KeyIdFromPkix(initNodeCreds.CertificatePublicKeyPkix)
|
||||
require.NoError(t, err)
|
||||
|
||||
nonce := make([]byte, nodeenrollment.NonceSize)
|
||||
_, err = rand.Reader.Read(nonce)
|
||||
require.NoError(t, err)
|
||||
|
||||
// What's going on here: in each test we are simulating a startup of a
|
||||
// worker that has storage in various states. The input is a function to
|
||||
// modify the current state of node credentials by using the worker's
|
||||
// storage, but this happens before Start so we haven't done checking yet;
|
||||
// the assertions check what the final result is.
|
||||
tests := []struct {
|
||||
name string
|
||||
in func(t *testing.T, w *Worker)
|
||||
expKeyId string // If set, the existing key ID to expect
|
||||
expRegistrationRequest bool // Whether we should have seen a registration request generated
|
||||
expError string // Some other error
|
||||
}{
|
||||
{
|
||||
name: "no creds",
|
||||
in: func(t *testing.T, w *Worker) {
|
||||
// Do nothing; in this case it will have already been cleared
|
||||
},
|
||||
expRegistrationRequest: true,
|
||||
},
|
||||
{
|
||||
name: "valid creds",
|
||||
in: func(t *testing.T, w *Worker) {
|
||||
// Store the authorized creds
|
||||
require.NoError(t, initNodeCreds.Store(ctx, w.WorkerAuthStorage))
|
||||
},
|
||||
expKeyId: initKeyId,
|
||||
},
|
||||
{
|
||||
name: "existing but not validated",
|
||||
in: func(t *testing.T, w *Worker) {
|
||||
creds := proto.Clone(initNodeCreds).(*types.NodeCredentials)
|
||||
creds.CertificateBundles = nil
|
||||
creds.RegistrationNonce = nonce
|
||||
require.NoError(t, creds.Store(ctx, w.WorkerAuthStorage))
|
||||
},
|
||||
expKeyId: initKeyId,
|
||||
expRegistrationRequest: true,
|
||||
},
|
||||
{
|
||||
name: "existing and outside cert times", // Note that cert from next CA will already not be valid
|
||||
in: func(t *testing.T, w *Worker) {
|
||||
creds := proto.Clone(initNodeCreds).(*types.NodeCredentials)
|
||||
creds.CertificateBundles[0].CertificateNotBefore = timestamppb.New(time.Time{})
|
||||
creds.CertificateBundles[0].CertificateNotAfter = timestamppb.New(time.Time{})
|
||||
require.NoError(t, creds.Store(ctx, w.WorkerAuthStorage))
|
||||
},
|
||||
expRegistrationRequest: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tw := NewTestWorker(t, &TestWorkerOpts{
|
||||
WorkerAuthStoragePath: tmpDir,
|
||||
DisableAutoStart: true,
|
||||
})
|
||||
t.Cleanup(tw.Shutdown)
|
||||
|
||||
// Always clear out storage that was there before, ignore errors
|
||||
_ = tw.Worker().WorkerAuthStorage.Remove(ctx, &types.NodeCredentials{Id: string(nodeenrollment.CurrentId)})
|
||||
|
||||
// Run node credentials modification
|
||||
tt.in(t, tw.Worker())
|
||||
|
||||
// Start up to run logic
|
||||
require.NoError(t, tw.Worker().Start())
|
||||
|
||||
// Validate existing key was loaded or new key was created and loaded
|
||||
if tt.expKeyId != "" {
|
||||
assert.Equal(t, tt.expKeyId, tw.Worker().WorkerAuthCurrentKeyId.Load())
|
||||
} else {
|
||||
assert.NotEmpty(t, tw.Worker().WorkerAuthCurrentKeyId.Load())
|
||||
}
|
||||
if tt.expRegistrationRequest {
|
||||
assert.NotEmpty(t, tw.Worker().WorkerAuthRegistrationRequest)
|
||||
} else {
|
||||
assert.Empty(t, tw.Worker().WorkerAuthRegistrationRequest)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
begin;
|
||||
|
||||
-- wt_network_address defines a type for a network address.
|
||||
-- While wt_dns_names does exist, a wt_network_address can be either a dns name
|
||||
-- or an ip address.
|
||||
create domain wt_network_address as text
|
||||
constraint wt_network_address_too_short
|
||||
check (length(trim(value)) > 0)
|
||||
constraint wt_network_address_too_long
|
||||
check (length(trim(value)) < 256);
|
||||
comment on domain wt_network_address is
|
||||
'standard column for a network address.';
|
||||
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,278 @@
|
||||
begin;
|
||||
|
||||
-- Split the server table into two new tables: controller and worker
|
||||
|
||||
create table server_controller (
|
||||
private_id text primary key,
|
||||
description wt_description,
|
||||
address wt_network_address not null,
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp
|
||||
);
|
||||
comment on table server_controller is
|
||||
'server_controller is a table where each row represents a Boundary controller.';
|
||||
|
||||
create trigger immutable_columns before update on server_controller
|
||||
for each row execute procedure immutable_columns('private_id','create_time');
|
||||
|
||||
create trigger default_create_time_column before insert on server_controller
|
||||
for each row execute procedure default_create_time();
|
||||
|
||||
create trigger controller_insert_time_column before insert on server_controller
|
||||
for each row execute procedure update_time_column();
|
||||
|
||||
create trigger controller_update_time_column before update on server_controller
|
||||
for each row execute procedure update_time_column();
|
||||
|
||||
-- Worker table takes the place of the server table.
|
||||
-- instead of the private_id we use a wt_public_id field named public_id since
|
||||
-- workers will now be exposed as resources in boundary.
|
||||
|
||||
create table server_worker_type_enm (
|
||||
name text primary key
|
||||
constraint only_predefined_types_allowed
|
||||
check (
|
||||
name in (
|
||||
'pki',
|
||||
'kms'
|
||||
)
|
||||
)
|
||||
);
|
||||
comment on table server_worker_type_enm is
|
||||
'server_worker_type_enm is an enumeration table for worker types. '
|
||||
'It contains rows for representing the pki and kms types.';
|
||||
|
||||
insert into server_worker_type_enm (name)
|
||||
values
|
||||
('pki'),
|
||||
('kms');
|
||||
|
||||
create table server_worker (
|
||||
public_id wt_public_id primary key,
|
||||
scope_id wt_scope_id not null
|
||||
references iam_scope_global(scope_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
description wt_description
|
||||
constraint description_only_has_printable_characters
|
||||
check (description is null or description !~ '[^[:print:]]'),
|
||||
name wt_name -- server_worker_scope_id_name_uq defines an appropriate uniqueness constraint for name
|
||||
constraint worker_name_must_be_set_by_status
|
||||
check (
|
||||
type != 'kms' or name is not null
|
||||
)
|
||||
constraint name_must_be_lowercase
|
||||
check (name is null or lower(trim(name)) = name)
|
||||
constraint name_only_has_printable_characters
|
||||
check (name is null or name !~ '[^[:print:]]'),
|
||||
address wt_network_address
|
||||
constraint address_must_be_set_by_status
|
||||
check (
|
||||
-- address can be null only no status update has been received yet.
|
||||
(last_status_time is not null and address is not null)
|
||||
or
|
||||
(last_status_time is null and address is null)
|
||||
),
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp,
|
||||
version wt_version,
|
||||
type text not null
|
||||
constraint server_worker_type_enm_fkey
|
||||
references server_worker_type_enm (name)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
last_status_time timestamp with time zone
|
||||
constraint last_status_time_not_before_create_time
|
||||
check (last_status_time >= create_time)
|
||||
constraint last_status_time_always_set_for_kms
|
||||
check (type != 'kms' or last_status_time is not null),
|
||||
constraint server_worker_scope_id_name_uq
|
||||
unique(scope_id, name)
|
||||
);
|
||||
comment on table server_worker is
|
||||
'server_worker is a table where each row represents a Boundary worker.';
|
||||
|
||||
create trigger immutable_columns before update on server_worker
|
||||
for each row execute procedure immutable_columns('public_id', 'scope_id', 'type', 'create_time');
|
||||
|
||||
create trigger default_create_time_column before insert on server_worker
|
||||
for each row execute procedure default_create_time();
|
||||
|
||||
create trigger worker_insert_time_column before insert on server_worker
|
||||
for each row execute procedure update_time_column();
|
||||
|
||||
create trigger worker_update_time_column before update on server_worker
|
||||
for each row execute procedure update_time_column();
|
||||
|
||||
-- fixme: we should only update the version column when type = 'pki', but that
|
||||
-- can be deferred
|
||||
create trigger update_version_column after update of version, description, name on server_worker
|
||||
for each row execute procedure update_version_column();
|
||||
|
||||
create function immutable_kms_name()
|
||||
returns trigger
|
||||
as $$
|
||||
begin
|
||||
if old.type = 'kms' and new.name is distinct from old.name then
|
||||
raise exception 'immutable column for kms worker: server_worker.name' using
|
||||
errcode = '23601',
|
||||
schema = tg_table_schema,
|
||||
table = tg_table_name,
|
||||
column = 'name';
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function immutable_kms_name is
|
||||
'function used in before update triggers to make name column immutable for kms workers';
|
||||
|
||||
create trigger immutable_kms_name before update on server_worker
|
||||
for each row execute procedure immutable_kms_name();
|
||||
|
||||
create function update_kms_server_worker_update_last_status_time_column()
|
||||
returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.type = 'kms' then
|
||||
new.last_status_time = now();
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function update_kms_server_worker_update_last_status_time_column is
|
||||
'function used to update the last_status_time column in server_worker with type kms to now';
|
||||
|
||||
create trigger update_kms_server_worker_last_status_time_column before update of address, name, description on server_worker
|
||||
for each row execute procedure update_kms_server_worker_update_last_status_time_column();
|
||||
|
||||
create function update_pki_server_worker_update_last_status_time_column()
|
||||
returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.type = 'pki' then
|
||||
new.last_status_time = now();
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function update_pki_server_worker_update_last_status_time_column is
|
||||
'function used to update the last_status_time column in server_worker with type pki to now';
|
||||
|
||||
create trigger update_pki_server_worker_last_status_time_column before update of address on server_worker
|
||||
for each row execute procedure update_pki_server_worker_update_last_status_time_column();
|
||||
|
||||
create function insert_kms_server_worker_update_last_status_time_column()
|
||||
returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.type = 'kms' then
|
||||
new.last_status_time = now();
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function insert_kms_server_worker_update_last_status_time_column is
|
||||
'function used to update the last_status_time column in server_worker with type kms to now';
|
||||
|
||||
create trigger insert_server_worker_last_update_time_column before insert on server_worker
|
||||
for each row execute procedure insert_kms_server_worker_update_last_status_time_column();
|
||||
|
||||
-- Create table worker tag
|
||||
create table server_worker_tag_enm (
|
||||
source text primary key
|
||||
constraint only_predefined_server_worker_tag_sources_allowed
|
||||
check (
|
||||
source in ('configuration', 'api')
|
||||
)
|
||||
);
|
||||
|
||||
insert into server_worker_tag_enm (source)
|
||||
values
|
||||
('configuration'),
|
||||
('api');
|
||||
|
||||
create table server_worker_tag (
|
||||
worker_id wt_public_id
|
||||
constraint server_worker_fkey
|
||||
references server_worker(public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
key wt_tagpair,
|
||||
value wt_tagpair,
|
||||
source text not null
|
||||
constraint server_worker_tag_enm_fkey
|
||||
references server_worker_tag_enm(source)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
primary key(worker_id, key, value, source)
|
||||
);
|
||||
|
||||
|
||||
-- Aaand drop server_tag
|
||||
drop table server_tag;
|
||||
|
||||
-- Update session table to use worker_id instead of server_id, drop view first because of dependency on server type
|
||||
drop view session_list;
|
||||
|
||||
-- Update session table to use worker_id instead of server_id
|
||||
-- Updating the session table modified in 01/01_server_tags_migrations.up.sql
|
||||
drop trigger update_version_column
|
||||
on session;
|
||||
alter table session
|
||||
drop constraint session_server_id_fkey,
|
||||
drop column server_type,
|
||||
drop column server_id;
|
||||
create trigger
|
||||
update_version_column
|
||||
after update of version, termination_reason, key_id, tofu_token on session
|
||||
for each row execute procedure update_version_column();
|
||||
|
||||
-- Update session_connection table to use worker_id instead of server_id
|
||||
-- Table last updated in 21/02_session.up.sql
|
||||
alter table session_connection
|
||||
drop column server_id,
|
||||
add column worker_id wt_public_id,
|
||||
add constraint server_worker_fkey
|
||||
foreign key (worker_id)
|
||||
references server_worker (public_id)
|
||||
on delete set null
|
||||
on update cascade;
|
||||
|
||||
-- Update job run table so that server id references controller id
|
||||
-- We are not migrating the values from server_id to controller_id. The fkey
|
||||
-- constraint says that server_id can be set to null when the server is deleted
|
||||
-- which is what this migration does (removing all records from the server table).
|
||||
-- Not migrating values make it easier to change types in the server_worker and
|
||||
-- server_controller tables (like from text to wt_public_id or text to wt_address)
|
||||
-- without having to worry about old values being valid in the new types.
|
||||
-- Finally, neither jobs nor servers are exposed out of boundary so the risk of
|
||||
-- losing data that would be useful later on is diminished.
|
||||
alter table job_run
|
||||
add column controller_id text,
|
||||
drop column server_id;
|
||||
alter table job_run
|
||||
add constraint controller_id_must_be_at_least_10_characters
|
||||
check(
|
||||
length(trim(controller_id)) > 10
|
||||
),
|
||||
add constraint server_controller_fkey
|
||||
foreign key (controller_id)
|
||||
references server_controller (private_id)
|
||||
on delete set null
|
||||
on update cascade;
|
||||
|
||||
-- Since the above alter tables sets all controller_ids to null running jobs
|
||||
-- can no longer be reclaimed by any controller and should be considered
|
||||
-- interrupted.
|
||||
update job_run
|
||||
set
|
||||
status = 'interrupted',
|
||||
end_time = current_timestamp
|
||||
where
|
||||
status = 'running';
|
||||
|
||||
-- Drop the server and server_type_enm tables
|
||||
drop table server;
|
||||
drop table server_type_enm;
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,168 @@
|
||||
begin;
|
||||
|
||||
create table worker_auth_operational_indicator_enm(
|
||||
state text primary key
|
||||
constraint only_predefined_worker_auth_states_allowed
|
||||
check (
|
||||
state in ('next','current')
|
||||
)
|
||||
);
|
||||
|
||||
comment on table worker_auth_operational_indicator_enm is
|
||||
'worker_auth_operational_indicator_enm is an enumeration table representing the state of certificates used for worker authentication.';
|
||||
|
||||
insert into worker_auth_operational_indicator_enm (state)
|
||||
values
|
||||
('next'),
|
||||
('current');
|
||||
|
||||
create table worker_auth_ca(
|
||||
private_id text primary key
|
||||
constraint only_roots_id_allowed
|
||||
check (private_id in ('roots')),
|
||||
version wt_version,
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp
|
||||
);
|
||||
|
||||
create trigger
|
||||
immutable_columns
|
||||
before
|
||||
update on worker_auth_ca
|
||||
for each row execute procedure immutable_columns('private_id','create_time');
|
||||
|
||||
create trigger worker_auth_ca_default_create_time_column
|
||||
before
|
||||
insert on worker_auth_ca
|
||||
for each row execute procedure default_create_time();
|
||||
|
||||
create trigger worker_auth_ca_update_time_column
|
||||
before
|
||||
update on worker_auth_ca
|
||||
for each row execute procedure update_time_column();
|
||||
|
||||
insert into worker_auth_ca(private_id) values('roots');
|
||||
|
||||
create trigger update_version_column after update on worker_auth_ca
|
||||
for each row execute procedure update_version_column(private_id);
|
||||
|
||||
comment on table worker_auth_ca is
|
||||
'worker_auth_ca is a one-row versioned table used for locking for certificate rotation on the worker_auth_ca_certificate table.';
|
||||
|
||||
create table worker_auth_ca_certificate(
|
||||
serial_number numeric,
|
||||
certificate bytea not null
|
||||
constraint certificate_must_not_be_empty
|
||||
check(length(certificate) > 0),
|
||||
not_valid_before wt_timestamp not null,
|
||||
not_valid_after wt_timestamp not null
|
||||
constraint not_valid_before_must_be_before_not_valid_after
|
||||
check(not_valid_before < not_valid_after),
|
||||
public_key bytea primary key
|
||||
constraint public_key_must_not_be_empty
|
||||
check(length(public_key) > 0),
|
||||
private_key bytea not null -- encrypted PEM encoded private key
|
||||
constraint private_key_must_not_be_empty
|
||||
check(length(private_key) > 0),
|
||||
key_id kms_private_id not null -- key used to encrypt entries via wrapping wrapper.
|
||||
constraint kms_data_key_version_fkey
|
||||
references kms_data_key_version (private_id)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
state text unique not null
|
||||
constraint worker_auth_operational_indicator_enm_fkey
|
||||
references worker_auth_operational_indicator_enm(state)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
issuing_ca text not null
|
||||
constraint worker_auth_ca_fkey
|
||||
references worker_auth_ca(private_id)
|
||||
);
|
||||
|
||||
create trigger
|
||||
immutable_columns
|
||||
before
|
||||
update on worker_auth_ca_certificate
|
||||
for each row execute procedure immutable_columns('serial_number', 'certificate', 'not_valid_before', 'not_valid_after',
|
||||
'public_key', 'private_key', 'key_id', 'state', 'issuing_ca');
|
||||
|
||||
comment on table worker_auth_ca_certificate is
|
||||
'worker_auth_ca_certificate is a table where each row represents a root certificate for used for worker authentication.';
|
||||
|
||||
create table worker_auth_authorized(
|
||||
worker_key_identifier text primary key, -- The public key id for this WorkerAuth entry, generated from the signing pub key
|
||||
worker_id wt_public_id not null
|
||||
constraint server_worker_fkey
|
||||
references server_worker (public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
worker_signing_pub_key bytea not null
|
||||
constraint worker_signing_pub_key_must_not_be_empty
|
||||
check(length(worker_signing_pub_key) > 0),
|
||||
worker_encryption_pub_key bytea not null
|
||||
constraint worker_encryption_pub_key_must_not_be_empty
|
||||
check(length(worker_encryption_pub_key) > 0),
|
||||
controller_encryption_priv_key bytea not null -- encrypted PEM encoded private key
|
||||
constraint controller_encryption_priv_key_must_not_be_empty
|
||||
check(length(controller_encryption_priv_key) > 0),
|
||||
key_id kms_private_id not null -- key used to encrypt entries via wrapping wrapper.
|
||||
constraint kms_data_key_version_fkey
|
||||
references kms_data_key_version (private_id)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
nonce bytea -- encrypted value
|
||||
);
|
||||
comment on table worker_auth_authorized is
|
||||
'worker_auth_authorized is a table where each row represents key and cert data associated with an authorized worker.';
|
||||
|
||||
create trigger
|
||||
immutable_columns
|
||||
before
|
||||
update on worker_auth_authorized
|
||||
for each row execute procedure immutable_columns('worker_key_identifier', 'worker_id', 'worker_signing_pub_key',
|
||||
'worker_encryption_pub_key', 'controller_encryption_priv_key', 'key_id', 'nonce');
|
||||
|
||||
create function insert_worker_auth_authorized_type_check()
|
||||
returns trigger
|
||||
as $$
|
||||
begin
|
||||
perform from server_worker where type = 'pki' and public_id = new.worker_id;
|
||||
if not found then
|
||||
raise exception 'invalid type: non pki worker cannot be authorized in worker_auth_authorized table';
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function insert_worker_auth_authorized_type_check is
|
||||
'function used to only allow workers of type pki to be authorized';
|
||||
|
||||
create trigger insert_worker_auth_authorized_type_check before insert on worker_auth_authorized
|
||||
for each row execute procedure insert_worker_auth_authorized_type_check();
|
||||
|
||||
create table worker_auth_certificate_bundle(
|
||||
root_certificate_public_key bytea not null
|
||||
constraint worker_auth_ca_certificate_fkey
|
||||
references worker_auth_ca_certificate(public_key)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
worker_key_identifier text not null
|
||||
constraint worker_auth_authorized_fkey
|
||||
references worker_auth_authorized(worker_key_identifier)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
cert_bundle bytea
|
||||
constraint current_cert_bundle_must_not_be_empty
|
||||
check(length(cert_bundle) > 0),
|
||||
primary key(root_certificate_public_key, worker_key_identifier)
|
||||
);
|
||||
|
||||
comment on table worker_auth_certificate_bundle is
|
||||
'worker_auth_certificate_bundle is a table where each row represents a cert bundle issued by a ca certificate for a worker.';
|
||||
|
||||
create trigger
|
||||
immutable_columns
|
||||
before
|
||||
update on worker_auth_certificate_bundle
|
||||
for each row execute procedure immutable_columns('root_certificate_public_key', 'worker_key_identifier', 'cert_bundle');
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,67 @@
|
||||
begin;
|
||||
|
||||
-- worker_aggregate view allows the worker and configuration to be read at the
|
||||
-- same time.
|
||||
create view server_worker_aggregate as
|
||||
with worker_config_tags(worker_id, source, tags) as (
|
||||
select
|
||||
ct.worker_id,
|
||||
ct.source,
|
||||
-- keys and tags can be any lowercase printable character so use uppercase characters as delimitors.
|
||||
string_agg(distinct concat_ws('Y', ct.key, ct.value), 'Z') as tags
|
||||
from server_worker_tag ct
|
||||
group by ct.worker_id, ct.source
|
||||
),
|
||||
connection_count (worker_id, count) as (
|
||||
select
|
||||
worker_id,
|
||||
count(1) as count
|
||||
from session_connection
|
||||
where closed_reason is null
|
||||
group by worker_id
|
||||
)
|
||||
select
|
||||
w.public_id,
|
||||
w.scope_id,
|
||||
w.description,
|
||||
w.name,
|
||||
w.address,
|
||||
w.create_time,
|
||||
w.update_time,
|
||||
w.version,
|
||||
w.last_status_time,
|
||||
w.type,
|
||||
cc.count as active_connection_count,
|
||||
-- keys and tags can be any lowercase printable character so use uppercase characters as delimitors.
|
||||
wt.tags as api_tags,
|
||||
ct.tags as worker_config_tags
|
||||
from server_worker w
|
||||
left join worker_config_tags wt on
|
||||
w.public_id = wt.worker_id and wt.source = 'api'
|
||||
left join worker_config_tags ct on
|
||||
w.public_id = ct.worker_id and ct.source = 'configuration'
|
||||
left join connection_count as cc on
|
||||
w.public_id = cc.worker_id;
|
||||
comment on view server_worker_aggregate is
|
||||
'server_worker_aggregate contains the worker resource with its worker provided config values and its configuration and api provided tags.';
|
||||
|
||||
-- Replaces the view created in 9/01.
|
||||
-- Remove the worker id from this view. In actuality this is almost a no-op
|
||||
-- because no server information was ever getting populated here due to a bug
|
||||
-- in the update mask when updating a session at the time we activate a session.
|
||||
create view session_list as
|
||||
select
|
||||
s.public_id, s.user_id, s.host_id, s.target_id,
|
||||
s.host_set_id, s.auth_token_id, s.scope_id, s.certificate,s.expiration_time,
|
||||
s.connection_limit, s.tofu_token, s.key_id, s.termination_reason, s.version,
|
||||
s.create_time, s.update_time, s.endpoint, s.worker_filter,
|
||||
ss.state, ss.previous_end_time, ss.start_time, ss.end_time, sc.public_id as connection_id,
|
||||
sc.client_tcp_address, sc.client_tcp_port, sc.endpoint_tcp_address, sc.endpoint_tcp_port,
|
||||
sc.bytes_up, sc.bytes_down, sc.closed_reason
|
||||
from session s
|
||||
join session_state ss on
|
||||
s.public_id = ss.session_id
|
||||
left join session_connection sc on
|
||||
s.public_id = sc.session_id;
|
||||
|
||||
commit;
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
_ "github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
"github.com/hashicorp/boundary/internal/db/schema"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
aead "github.com/hashicorp/go-kms-wrapping/v2/aead"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
pgDriver "gorm.io/driver/postgres"
|
||||
)
|
||||
|
||||
// setup the tests (initialize the database one-time and intialized
|
||||
@@ -73,6 +75,23 @@ func TestSetup(t testing.TB, dialect string, opt ...TestOption) (*DB, string) {
|
||||
return db, url
|
||||
}
|
||||
|
||||
// TestSetupWithMock will return a test DB and an associated Sqlmock which can
|
||||
// be used to mock out the db responses.
|
||||
func TestSetupWithMock(t *testing.T) (*DB, sqlmock.Sqlmock) {
|
||||
t.Helper()
|
||||
require := require.New(t)
|
||||
db, mock, err := sqlmock.New()
|
||||
require.NoError(err)
|
||||
require.NoError(err)
|
||||
dbw, err := dbw.OpenWith(pgDriver.New(pgDriver.Config{
|
||||
Conn: db,
|
||||
}))
|
||||
require.NoError(err)
|
||||
return &DB{
|
||||
wrapped: dbw,
|
||||
}, mock
|
||||
}
|
||||
|
||||
// TestWrapper initializes an AEAD wrapping.Wrapper for testing the oplog
|
||||
func TestWrapper(t testing.TB) wrapping.Wrapper {
|
||||
t.Helper()
|
||||
|
||||
@@ -22,5 +22,5 @@ func Now() *Timestamp {
|
||||
|
||||
// AsTime converts x to a time.Time.
|
||||
func (x *Timestamp) AsTime() time.Time {
|
||||
return x.Timestamp.AsTime()
|
||||
return x.GetTimestamp().AsTime()
|
||||
}
|
||||
@@ -52,6 +52,9 @@
|
||||
},
|
||||
{
|
||||
"name": "controller.api.services.v1.UserService"
|
||||
},
|
||||
{
|
||||
"name": "controller.api.services.v1.WorkerService"
|
||||
}
|
||||
],
|
||||
"schemes": [
|
||||
@@ -3661,6 +3664,155 @@
|
||||
"controller.api.services.v1.UserService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/workers": {
|
||||
"get": {
|
||||
"summary": "Lists all Workers.",
|
||||
"operationId": "WorkerService_ListWorkers",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controller.api.services.v1.ListWorkersResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "scope_id",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "recursive",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "filter",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"controller.api.services.v1.WorkerService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/workers/{id}": {
|
||||
"get": {
|
||||
"summary": "Gets a single Worker.",
|
||||
"operationId": "WorkerService_GetWorker",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"controller.api.services.v1.WorkerService"
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"summary": "Deletes a Worker.",
|
||||
"operationId": "WorkerService_DeleteWorker",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controller.api.services.v1.DeleteWorkerResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"controller.api.services.v1.WorkerService"
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"summary": "Updates a Worker.",
|
||||
"operationId": "WorkerService_UpdateWorker",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "item",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "update_mask",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"controller.api.services.v1.WorkerService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/workers:create:worker-led": {
|
||||
"post": {
|
||||
"summary": "Creates a single Worker.",
|
||||
"operationId": "WorkerService_CreateWorkerLed",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -4909,14 +5061,6 @@
|
||||
"description": "Output only. The current status of this Session.",
|
||||
"readOnly": true
|
||||
},
|
||||
"worker_info": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/controller.api.resources.sessions.v1.WorkerInfo"
|
||||
},
|
||||
"description": "Output only. Worker information given to the client.",
|
||||
"readOnly": true
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
@@ -4968,15 +5112,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.resources.sessions.v1.WorkerInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "The address of the worker."
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.resources.targets.v1.CredentialSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5386,6 +5521,107 @@
|
||||
},
|
||||
"title": "User contains all fields related to a User resource"
|
||||
},
|
||||
"controller.api.resources.workers.v1.Worker": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Output only. The ID of the User.",
|
||||
"readOnly": true
|
||||
},
|
||||
"scope_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the Scope this resource is in."
|
||||
},
|
||||
"scope": {
|
||||
"$ref": "#/definitions/controller.api.resources.scopes.v1.ScopeInfo",
|
||||
"description": "Output only. Scope information for this resource.",
|
||||
"readOnly": true
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Optional name for identification purposes. Can only be set through the API\nfor `pki`-type workers; read-only for `kms`-type workers."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Optional user-set description for identification purposes. Can only be set\nthrough the API for `pki`-type workers; read-only for `kms`-type workers."
|
||||
},
|
||||
"created_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Output only. The time this resource was created.",
|
||||
"readOnly": true
|
||||
},
|
||||
"updated_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Output only. The time this resource was last updated.",
|
||||
"readOnly": true
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version."
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Output only. The address that this worker is reachable at, as sourced from\nthe worker's configuration file.",
|
||||
"readOnly": true
|
||||
},
|
||||
"canonical_tags": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"description": "Output only. The deduplicated union of the tags reported by the worker from\nits configuration and any tags added through other means. This is used\nwhen applying worker filters.",
|
||||
"readOnly": true
|
||||
},
|
||||
"config_tags": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"description": "Output only. The tags set in the worker's configuration file.",
|
||||
"readOnly": true
|
||||
},
|
||||
"last_status_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Output only. The time this worker daemon last reported its status.",
|
||||
"readOnly": true
|
||||
},
|
||||
"worker_generated_auth_token": {
|
||||
"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"
|
||||
},
|
||||
"active_connection_count": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Output only. The number of connections that this worker is currently handling.",
|
||||
"readOnly": true
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Output only. The type of the worker, denoted by how it authenticates: `pki`\nor `kms`.",
|
||||
"readOnly": true
|
||||
},
|
||||
"authorized_actions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Output only. The available actions on this resource for the requester.",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"title": "Worker contains all fields related to a Worker resource"
|
||||
},
|
||||
"controller.api.services.v1.AddGroupMembersResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5653,6 +5889,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.CreateWorkerLedResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"item": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.DeleteAccountResponse": {
|
||||
"type": "object"
|
||||
},
|
||||
@@ -5698,6 +5945,9 @@
|
||||
"controller.api.services.v1.DeleteUserResponse": {
|
||||
"type": "object"
|
||||
},
|
||||
"controller.api.services.v1.DeleteWorkerResponse": {
|
||||
"type": "object"
|
||||
},
|
||||
"controller.api.services.v1.GetAccountResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5826,6 +6076,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.GetWorkerResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.ListAccountsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6002,6 +6260,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.ListWorkersResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.RemoveGroupMembersResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6250,6 +6519,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.UpdateWorkerResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/controller.api.resources.workers.v1.Worker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"google.protobuf.NullValue": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
||||
@@ -0,0 +1,858 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc (unknown)
|
||||
// source: controller/api/services/v1/worker_service.proto
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
|
||||
workers "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/workers"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GetWorkerRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *GetWorkerRequest) Reset() {
|
||||
*x = GetWorkerRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetWorkerRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetWorkerRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[0]
|
||||
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 GetWorkerRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetWorkerRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *GetWorkerRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type GetWorkerResponse 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 *GetWorkerResponse) Reset() {
|
||||
*x = GetWorkerResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetWorkerResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetWorkerResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetWorkerResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetWorkerResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetWorkerResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *GetWorkerResponse) GetItem() *workers.Worker {
|
||||
if x != nil {
|
||||
return x.Item
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListWorkersRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ScopeId string `protobuf:"bytes,1,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
Recursive bool `protobuf:"varint,20,opt,name=recursive,proto3" json:"recursive,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
|
||||
}
|
||||
|
||||
func (x *ListWorkersRequest) Reset() {
|
||||
*x = ListWorkersRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ListWorkersRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListWorkersRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_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 ListWorkersRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListWorkersRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ListWorkersRequest) GetScopeId() string {
|
||||
if x != nil {
|
||||
return x.ScopeId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListWorkersRequest) GetRecursive() bool {
|
||||
if x != nil {
|
||||
return x.Recursive
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ListWorkersRequest) GetFilter() string {
|
||||
if x != nil {
|
||||
return x.Filter
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListWorkersResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Items []*workers.Worker `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListWorkersResponse) Reset() {
|
||||
*x = ListWorkersResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ListWorkersResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListWorkersResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[3]
|
||||
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 ListWorkersResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListWorkersResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ListWorkersResponse) GetItems() []*workers.Worker {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CreateWorkerLedRequest 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 *CreateWorkerLedRequest) Reset() {
|
||||
*x = CreateWorkerLedRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CreateWorkerLedRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CreateWorkerLedRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CreateWorkerLedRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CreateWorkerLedRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CreateWorkerLedRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *CreateWorkerLedRequest) GetItem() *workers.Worker {
|
||||
if x != nil {
|
||||
return x.Item
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CreateWorkerLedResponse 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 *CreateWorkerLedResponse) Reset() {
|
||||
*x = CreateWorkerLedResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CreateWorkerLedResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CreateWorkerLedResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CreateWorkerLedResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CreateWorkerLedResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CreateWorkerLedResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *CreateWorkerLedResponse) GetUri() string {
|
||||
if x != nil {
|
||||
return x.Uri
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreateWorkerLedResponse) GetItem() *workers.Worker {
|
||||
if x != nil {
|
||||
return x.Item
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateWorkerRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
Item *workers.Worker `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"`
|
||||
UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,3,opt,name=update_mask,proto3" json:"update_mask,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateWorkerRequest) Reset() {
|
||||
*x = UpdateWorkerRequest{}
|
||||
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 *UpdateWorkerRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateWorkerRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateWorkerRequest) 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 UpdateWorkerRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *UpdateWorkerRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateWorkerRequest) GetItem() *workers.Worker {
|
||||
if x != nil {
|
||||
return x.Item
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UpdateWorkerRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
|
||||
if x != nil {
|
||||
return x.UpdateMask
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateWorkerResponse 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 *UpdateWorkerResponse) Reset() {
|
||||
*x = UpdateWorkerResponse{}
|
||||
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 *UpdateWorkerResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateWorkerResponse) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateWorkerResponse) 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 UpdateWorkerResponse.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateWorkerResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *UpdateWorkerResponse) GetItem() *workers.Worker {
|
||||
if x != nil {
|
||||
return x.Item
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteWorkerRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *DeleteWorkerRequest) Reset() {
|
||||
*x = DeleteWorkerRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DeleteWorkerRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteWorkerRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message {
|
||||
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 {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *DeleteWorkerRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DeleteWorkerResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *DeleteWorkerResponse) Reset() {
|
||||
*x = DeleteWorkerResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DeleteWorkerResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteWorkerResponse) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteWorkerResponse) ProtoReflect() protoreflect.Message {
|
||||
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 {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeleteWorkerResponse.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteWorkerResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
var File_controller_api_services_v1_worker_service_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_controller_api_services_v1_worker_service_proto_rawDesc = []byte{
|
||||
0x0a, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69,
|
||||
0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x1a, 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, 0x1a, 0x30, 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, 0x2f,
|
||||
0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
|
||||
0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f,
|
||||
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66,
|
||||
0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e,
|
||||
0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e,
|
||||
0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0x22, 0x0a, 0x10, 0x47, 0x65, 0x74, 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, 0x54, 0x0a, 0x11, 0x47, 0x65, 0x74, 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, 0x65, 0x0a, 0x12, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65,
|
||||
0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72,
|
||||
0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74,
|
||||
0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
|
||||
0x22, 0x58, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 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, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x59, 0x0a, 0x16, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 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, 0x6c, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57,
|
||||
0x6f, 0x72, 0x6b, 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, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x32, 0xf2, 0x06, 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, 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, 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 (
|
||||
file_controller_api_services_v1_worker_service_proto_rawDescOnce sync.Once
|
||||
file_controller_api_services_v1_worker_service_proto_rawDescData = file_controller_api_services_v1_worker_service_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_controller_api_services_v1_worker_service_proto_rawDescGZIP() []byte {
|
||||
file_controller_api_services_v1_worker_service_proto_rawDescOnce.Do(func() {
|
||||
file_controller_api_services_v1_worker_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_services_v1_worker_service_proto_rawDescData)
|
||||
})
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_controller_api_services_v1_worker_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
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
|
||||
(*workers.Worker)(nil), // 10: controller.api.resources.workers.v1.Worker
|
||||
(*fieldmaskpb.FieldMask)(nil), // 11: google.protobuf.FieldMask
|
||||
}
|
||||
var file_controller_api_services_v1_worker_service_proto_depIdxs = []int32{
|
||||
10, // 0: controller.api.services.v1.GetWorkerResponse.item:type_name -> controller.api.resources.workers.v1.Worker
|
||||
10, // 1: controller.api.services.v1.ListWorkersResponse.items:type_name -> controller.api.resources.workers.v1.Worker
|
||||
10, // 2: controller.api.services.v1.CreateWorkerLedRequest.item:type_name -> controller.api.resources.workers.v1.Worker
|
||||
10, // 3: controller.api.services.v1.CreateWorkerLedResponse.item:type_name -> controller.api.resources.workers.v1.Worker
|
||||
10, // 4: controller.api.services.v1.UpdateWorkerRequest.item:type_name -> controller.api.resources.workers.v1.Worker
|
||||
11, // 5: controller.api.services.v1.UpdateWorkerRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
10, // 6: controller.api.services.v1.UpdateWorkerResponse.item:type_name -> controller.api.resources.workers.v1.Worker
|
||||
0, // 7: controller.api.services.v1.WorkerService.GetWorker:input_type -> controller.api.services.v1.GetWorkerRequest
|
||||
2, // 8: controller.api.services.v1.WorkerService.ListWorkers:input_type -> controller.api.services.v1.ListWorkersRequest
|
||||
4, // 9: controller.api.services.v1.WorkerService.CreateWorkerLed:input_type -> controller.api.services.v1.CreateWorkerLedRequest
|
||||
6, // 10: controller.api.services.v1.WorkerService.UpdateWorker:input_type -> controller.api.services.v1.UpdateWorkerRequest
|
||||
8, // 11: controller.api.services.v1.WorkerService.DeleteWorker:input_type -> controller.api.services.v1.DeleteWorkerRequest
|
||||
1, // 12: controller.api.services.v1.WorkerService.GetWorker:output_type -> controller.api.services.v1.GetWorkerResponse
|
||||
3, // 13: controller.api.services.v1.WorkerService.ListWorkers:output_type -> controller.api.services.v1.ListWorkersResponse
|
||||
5, // 14: controller.api.services.v1.WorkerService.CreateWorkerLed:output_type -> controller.api.services.v1.CreateWorkerLedResponse
|
||||
7, // 15: controller.api.services.v1.WorkerService.UpdateWorker:output_type -> controller.api.services.v1.UpdateWorkerResponse
|
||||
9, // 16: controller.api.services.v1.WorkerService.DeleteWorker:output_type -> controller.api.services.v1.DeleteWorkerResponse
|
||||
12, // [12:17] is the sub-list for method output_type
|
||||
7, // [7:12] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_controller_api_services_v1_worker_service_proto_init() }
|
||||
func file_controller_api_services_v1_worker_service_proto_init() {
|
||||
if File_controller_api_services_v1_worker_service_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_controller_api_services_v1_worker_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetWorkerRequest); 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[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetWorkerResponse); 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[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ListWorkersRequest); 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[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ListWorkersResponse); 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[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CreateWorkerLedRequest); 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[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CreateWorkerLedResponse); 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[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*UpdateWorkerRequest); 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[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*UpdateWorkerResponse); 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[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DeleteWorkerRequest); 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[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DeleteWorkerResponse); 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{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_controller_api_services_v1_worker_service_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_controller_api_services_v1_worker_service_proto_goTypes,
|
||||
DependencyIndexes: file_controller_api_services_v1_worker_service_proto_depIdxs,
|
||||
MessageInfos: file_controller_api_services_v1_worker_service_proto_msgTypes,
|
||||
}.Build()
|
||||
File_controller_api_services_v1_worker_service_proto = out.File
|
||||
file_controller_api_services_v1_worker_service_proto_rawDesc = nil
|
||||
file_controller_api_services_v1_worker_service_proto_goTypes = nil
|
||||
file_controller_api_services_v1_worker_service_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: controller/api/services/v1/worker_service.proto
|
||||
|
||||
/*
|
||||
Package services is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = metadata.Join
|
||||
|
||||
func request_WorkerService_GetWorker_0(ctx context.Context, marshaler runtime.Marshaler, client WorkerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetWorkerRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetWorker(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_WorkerService_GetWorker_0(ctx context.Context, marshaler runtime.Marshaler, server WorkerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetWorkerRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetWorker(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_WorkerService_ListWorkers_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_WorkerService_ListWorkers_0(ctx context.Context, marshaler runtime.Marshaler, client WorkerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ListWorkersRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WorkerService_ListWorkers_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ListWorkers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_WorkerService_ListWorkers_0(ctx context.Context, marshaler runtime.Marshaler, server WorkerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ListWorkersRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WorkerService_ListWorkers_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.ListWorkers(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_WorkerService_CreateWorkerLed_0(ctx context.Context, marshaler runtime.Marshaler, client WorkerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CreateWorkerLedRequest
|
||||
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.CreateWorkerLed(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_WorkerService_CreateWorkerLed_0(ctx context.Context, marshaler runtime.Marshaler, server WorkerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CreateWorkerLedRequest
|
||||
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.CreateWorkerLed(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}}
|
||||
)
|
||||
|
||||
func request_WorkerService_UpdateWorker_0(ctx context.Context, marshaler runtime.Marshaler, client WorkerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateWorkerRequest
|
||||
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)
|
||||
}
|
||||
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
|
||||
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Item); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
} else {
|
||||
protoReq.UpdateMask = fieldMask
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WorkerService_UpdateWorker_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateWorker(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_WorkerService_UpdateWorker_0(ctx context.Context, marshaler runtime.Marshaler, server WorkerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateWorkerRequest
|
||||
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)
|
||||
}
|
||||
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
|
||||
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Item); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
} else {
|
||||
protoReq.UpdateMask = fieldMask
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WorkerService_UpdateWorker_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.UpdateWorker(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_WorkerService_DeleteWorker_0(ctx context.Context, marshaler runtime.Marshaler, client WorkerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq DeleteWorkerRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
msg, err := client.DeleteWorker(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_WorkerService_DeleteWorker_0(ctx context.Context, marshaler runtime.Marshaler, server WorkerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq DeleteWorkerRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
msg, err := server.DeleteWorker(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterWorkerServiceHandlerServer registers the http handlers for service WorkerService to "mux".
|
||||
// UnaryRPC :call WorkerServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterWorkerServiceHandlerFromEndpoint instead.
|
||||
func RegisterWorkerServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server WorkerServiceServer) error {
|
||||
|
||||
mux.Handle("GET", pattern_WorkerService_GetWorker_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
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/GetWorker", runtime.WithHTTPPathPattern("/v1/workers/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_WorkerService_GetWorker_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_GetWorker_0(ctx, mux, outboundMarshaler, w, req, response_WorkerService_GetWorker_0{resp}, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_WorkerService_ListWorkers_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
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/ListWorkers", runtime.WithHTTPPathPattern("/v1/workers"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_WorkerService_ListWorkers_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_ListWorkers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_WorkerService_CreateWorkerLed_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
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/CreateWorkerLed", runtime.WithHTTPPathPattern("/v1/workers:create:worker-led"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_WorkerService_CreateWorkerLed_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_CreateWorkerLed_0(ctx, mux, outboundMarshaler, w, req, response_WorkerService_CreateWorkerLed_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()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/UpdateWorker", runtime.WithHTTPPathPattern("/v1/workers/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_WorkerService_UpdateWorker_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_UpdateWorker_0(ctx, mux, outboundMarshaler, w, req, response_WorkerService_UpdateWorker_0{resp}, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_WorkerService_DeleteWorker_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
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/DeleteWorker", runtime.WithHTTPPathPattern("/v1/workers/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_WorkerService_DeleteWorker_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_DeleteWorker_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterWorkerServiceHandlerFromEndpoint is same as RegisterWorkerServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterWorkerServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterWorkerServiceHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterWorkerServiceHandler registers the http handlers for service WorkerService to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterWorkerServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterWorkerServiceHandlerClient(ctx, mux, NewWorkerServiceClient(conn))
|
||||
}
|
||||
|
||||
// RegisterWorkerServiceHandlerClient registers the http handlers for service WorkerService
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "WorkerServiceClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WorkerServiceClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "WorkerServiceClient" to call the correct interceptors.
|
||||
func RegisterWorkerServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WorkerServiceClient) error {
|
||||
|
||||
mux.Handle("GET", pattern_WorkerService_GetWorker_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
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/GetWorker", runtime.WithHTTPPathPattern("/v1/workers/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_WorkerService_GetWorker_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_GetWorker_0(ctx, mux, outboundMarshaler, w, req, response_WorkerService_GetWorker_0{resp}, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_WorkerService_ListWorkers_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
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/ListWorkers", runtime.WithHTTPPathPattern("/v1/workers"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_WorkerService_ListWorkers_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_ListWorkers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_WorkerService_CreateWorkerLed_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
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/CreateWorkerLed", runtime.WithHTTPPathPattern("/v1/workers:create:worker-led"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_WorkerService_CreateWorkerLed_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_CreateWorkerLed_0(ctx, mux, outboundMarshaler, w, req, response_WorkerService_CreateWorkerLed_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()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/UpdateWorker", runtime.WithHTTPPathPattern("/v1/workers/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_WorkerService_UpdateWorker_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_UpdateWorker_0(ctx, mux, outboundMarshaler, w, req, response_WorkerService_UpdateWorker_0{resp}, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_WorkerService_DeleteWorker_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
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.WorkerService/DeleteWorker", runtime.WithHTTPPathPattern("/v1/workers/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_WorkerService_DeleteWorker_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_WorkerService_DeleteWorker_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type response_WorkerService_GetWorker_0 struct {
|
||||
proto.Message
|
||||
}
|
||||
|
||||
func (m response_WorkerService_GetWorker_0) XXX_ResponseBody() interface{} {
|
||||
response := m.Message.(*GetWorkerResponse)
|
||||
return response.Item
|
||||
}
|
||||
|
||||
type response_WorkerService_CreateWorkerLed_0 struct {
|
||||
proto.Message
|
||||
}
|
||||
|
||||
func (m response_WorkerService_CreateWorkerLed_0) XXX_ResponseBody() interface{} {
|
||||
response := m.Message.(*CreateWorkerLedResponse)
|
||||
return response.Item
|
||||
}
|
||||
|
||||
type response_WorkerService_UpdateWorker_0 struct {
|
||||
proto.Message
|
||||
}
|
||||
|
||||
func (m response_WorkerService_UpdateWorker_0) XXX_ResponseBody() interface{} {
|
||||
response := m.Message.(*UpdateWorkerResponse)
|
||||
return response.Item
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_WorkerService_GetWorker_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "workers", "id"}, ""))
|
||||
|
||||
pattern_WorkerService_ListWorkers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "workers"}, ""))
|
||||
|
||||
pattern_WorkerService_CreateWorkerLed_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "workers:create"}, "worker-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"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_WorkerService_GetWorker_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkerService_ListWorkers_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkerService_CreateWorkerLed_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkerService_UpdateWorker_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_WorkerService_DeleteWorker_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
@@ -0,0 +1,291 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// WorkerServiceClient is the client API for WorkerService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type WorkerServiceClient interface {
|
||||
// GetWorker returns a stored Worker if present. The provided request
|
||||
// must include the Worker ID for the Worker being retrieved. If
|
||||
// that ID is missing, malformed or reference a non existing
|
||||
// resource an error is returned.
|
||||
GetWorker(ctx context.Context, in *GetWorkerRequest, opts ...grpc.CallOption) (*GetWorkerResponse, error)
|
||||
// ListWorkers returns a list of stored Workers which exist inside the provided
|
||||
// scope. The request must include the scope ID for the Workers being listed.
|
||||
// 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(ctx context.Context, in *CreateWorkerLedRequest, opts ...grpc.CallOption) (*CreateWorkerLedResponse, 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
|
||||
// a field's value, include the field in the update mask and don't set it
|
||||
// in the provided Worker. An error is returned if either the Worker id is
|
||||
// missing or reference a non existing resource. An error is also returned
|
||||
// if the request attempts to update the name to one that is already in use
|
||||
// in this Scope.
|
||||
UpdateWorker(ctx context.Context, in *UpdateWorkerRequest, opts ...grpc.CallOption) (*UpdateWorkerResponse, error)
|
||||
// DeleteWorker removes a Worker from Boundary. If the provided Worker ID
|
||||
// is malformed or not provided an error is returned.
|
||||
DeleteWorker(ctx context.Context, in *DeleteWorkerRequest, opts ...grpc.CallOption) (*DeleteWorkerResponse, error)
|
||||
}
|
||||
|
||||
type workerServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewWorkerServiceClient(cc grpc.ClientConnInterface) WorkerServiceClient {
|
||||
return &workerServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *workerServiceClient) GetWorker(ctx context.Context, in *GetWorkerRequest, opts ...grpc.CallOption) (*GetWorkerResponse, error) {
|
||||
out := new(GetWorkerResponse)
|
||||
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/GetWorker", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *workerServiceClient) ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error) {
|
||||
out := new(ListWorkersResponse)
|
||||
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/ListWorkers", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *workerServiceClient) CreateWorkerLed(ctx context.Context, in *CreateWorkerLedRequest, opts ...grpc.CallOption) (*CreateWorkerLedResponse, error) {
|
||||
out := new(CreateWorkerLedResponse)
|
||||
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/CreateWorkerLed", 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...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *workerServiceClient) DeleteWorker(ctx context.Context, in *DeleteWorkerRequest, opts ...grpc.CallOption) (*DeleteWorkerResponse, error) {
|
||||
out := new(DeleteWorkerResponse)
|
||||
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/DeleteWorker", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// WorkerServiceServer is the server API for WorkerService service.
|
||||
// All implementations must embed UnimplementedWorkerServiceServer
|
||||
// for forward compatibility
|
||||
type WorkerServiceServer interface {
|
||||
// GetWorker returns a stored Worker if present. The provided request
|
||||
// must include the Worker ID for the Worker being retrieved. If
|
||||
// that ID is missing, malformed or reference a non existing
|
||||
// resource an error is returned.
|
||||
GetWorker(context.Context, *GetWorkerRequest) (*GetWorkerResponse, error)
|
||||
// ListWorkers returns a list of stored Workers which exist inside the provided
|
||||
// scope. The request must include the scope ID for the Workers being listed.
|
||||
// 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(context.Context, *CreateWorkerLedRequest) (*CreateWorkerLedResponse, 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
|
||||
// a field's value, include the field in the update mask and don't set it
|
||||
// in the provided Worker. An error is returned if either the Worker id is
|
||||
// missing or reference a non existing resource. An error is also returned
|
||||
// if the request attempts to update the name to one that is already in use
|
||||
// in this Scope.
|
||||
UpdateWorker(context.Context, *UpdateWorkerRequest) (*UpdateWorkerResponse, error)
|
||||
// DeleteWorker removes a Worker from Boundary. If the provided Worker ID
|
||||
// is malformed or not provided an error is returned.
|
||||
DeleteWorker(context.Context, *DeleteWorkerRequest) (*DeleteWorkerResponse, error)
|
||||
mustEmbedUnimplementedWorkerServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedWorkerServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedWorkerServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedWorkerServiceServer) GetWorker(context.Context, *GetWorkerRequest) (*GetWorkerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetWorker not implemented")
|
||||
}
|
||||
func (UnimplementedWorkerServiceServer) ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWorkers not implemented")
|
||||
}
|
||||
func (UnimplementedWorkerServiceServer) CreateWorkerLed(context.Context, *CreateWorkerLedRequest) (*CreateWorkerLedResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateWorkerLed not implemented")
|
||||
}
|
||||
func (UnimplementedWorkerServiceServer) UpdateWorker(context.Context, *UpdateWorkerRequest) (*UpdateWorkerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorker not implemented")
|
||||
}
|
||||
func (UnimplementedWorkerServiceServer) DeleteWorker(context.Context, *DeleteWorkerRequest) (*DeleteWorkerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteWorker not implemented")
|
||||
}
|
||||
func (UnimplementedWorkerServiceServer) mustEmbedUnimplementedWorkerServiceServer() {}
|
||||
|
||||
// UnsafeWorkerServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to WorkerServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeWorkerServiceServer interface {
|
||||
mustEmbedUnimplementedWorkerServiceServer()
|
||||
}
|
||||
|
||||
func RegisterWorkerServiceServer(s grpc.ServiceRegistrar, srv WorkerServiceServer) {
|
||||
s.RegisterService(&WorkerService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _WorkerService_GetWorker_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetWorkerRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkerServiceServer).GetWorker(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/controller.api.services.v1.WorkerService/GetWorker",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkerServiceServer).GetWorker(ctx, req.(*GetWorkerRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WorkerService_ListWorkers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListWorkersRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkerServiceServer).ListWorkers(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/controller.api.services.v1.WorkerService/ListWorkers",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkerServiceServer).ListWorkers(ctx, req.(*ListWorkersRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WorkerService_CreateWorkerLed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateWorkerLedRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkerServiceServer).CreateWorkerLed(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/controller.api.services.v1.WorkerService/CreateWorkerLed",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkerServiceServer).CreateWorkerLed(ctx, req.(*CreateWorkerLedRequest))
|
||||
}
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkerServiceServer).UpdateWorker(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/controller.api.services.v1.WorkerService/UpdateWorker",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkerServiceServer).UpdateWorker(ctx, req.(*UpdateWorkerRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WorkerService_DeleteWorker_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteWorkerRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkerServiceServer).DeleteWorker(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/controller.api.services.v1.WorkerService/DeleteWorker",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkerServiceServer).DeleteWorker(ctx, req.(*DeleteWorkerRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// WorkerService_ServiceDesc is the grpc.ServiceDesc for WorkerService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var WorkerService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "controller.api.services.v1.WorkerService",
|
||||
HandlerType: (*WorkerServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetWorker",
|
||||
Handler: _WorkerService_GetWorker_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListWorkers",
|
||||
Handler: _WorkerService_ListWorkers_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateWorkerLed",
|
||||
Handler: _WorkerService_CreateWorkerLed_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateWorker",
|
||||
Handler: _WorkerService_UpdateWorker_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteWorker",
|
||||
Handler: _WorkerService_DeleteWorker_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "controller/api/services/v1/worker_service.proto",
|
||||
}
|
||||
@@ -222,12 +222,61 @@ func (CHANGETYPE) EnumDescriptor() ([]byte, []int) {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
type UpstreamServer_TYPE int32
|
||||
|
||||
const (
|
||||
UpstreamServer_TYPE_UNSPECIFIED UpstreamServer_TYPE = 0
|
||||
UpstreamServer_TYPE_CONTROLLER UpstreamServer_TYPE = 1
|
||||
UpstreamServer_TYPE_WORKER UpstreamServer_TYPE = 2
|
||||
)
|
||||
|
||||
// Enum value maps for UpstreamServer_TYPE.
|
||||
var (
|
||||
UpstreamServer_TYPE_name = map[int32]string{
|
||||
0: "TYPE_UNSPECIFIED",
|
||||
1: "TYPE_CONTROLLER",
|
||||
2: "TYPE_WORKER",
|
||||
}
|
||||
UpstreamServer_TYPE_value = map[string]int32{
|
||||
"TYPE_UNSPECIFIED": 0,
|
||||
"TYPE_CONTROLLER": 1,
|
||||
"TYPE_WORKER": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x UpstreamServer_TYPE) Enum() *UpstreamServer_TYPE {
|
||||
p := new(UpstreamServer_TYPE)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x UpstreamServer_TYPE) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (UpstreamServer_TYPE) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_enumTypes[4].Descriptor()
|
||||
}
|
||||
|
||||
func (UpstreamServer_TYPE) Type() protoreflect.EnumType {
|
||||
return &file_controller_servers_services_v1_server_coordination_service_proto_enumTypes[4]
|
||||
}
|
||||
|
||||
func (x UpstreamServer_TYPE) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpstreamServer_TYPE.Descriptor instead.
|
||||
func (UpstreamServer_TYPE) EnumDescriptor() ([]byte, []int) {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{4, 0}
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"`
|
||||
ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
Status CONNECTIONSTATUS `protobuf:"varint,2,opt,name=status,proto3,enum=controller.servers.services.v1.CONNECTIONSTATUS" json:"status,omitempty"`
|
||||
}
|
||||
|
||||
@@ -282,7 +331,7 @@ type SessionJobInfo struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
|
||||
SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
Status SESSIONSTATUS `protobuf:"varint,2,opt,name=status,proto3,enum=controller.servers.services.v1.SESSIONSTATUS" json:"status,omitempty"`
|
||||
Connections []*Connection `protobuf:"bytes,3,rep,name=connections,proto3" json:"connections,omitempty"`
|
||||
}
|
||||
@@ -462,15 +511,70 @@ func (x *JobStatus) GetJob() *Job {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpstreamServer returns the controller address in the StatusResponse but may be used in the future to return
|
||||
// worker address.
|
||||
type UpstreamServer struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// type specifies between controller or worker.
|
||||
Type UpstreamServer_TYPE `protobuf:"varint,10,opt,name=type,proto3,enum=controller.servers.services.v1.UpstreamServer_TYPE" json:"type,omitempty"`
|
||||
// Address of the daemon
|
||||
Address string `protobuf:"bytes,20,opt,name=address,proto3" json:"address,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *UpstreamServer) Reset() {
|
||||
*x = UpstreamServer{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *UpstreamServer) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpstreamServer) ProtoMessage() {}
|
||||
|
||||
func (x *UpstreamServer) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpstreamServer.ProtoReflect.Descriptor instead.
|
||||
func (*UpstreamServer) Descriptor() ([]byte, []int) {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *UpstreamServer) GetType() UpstreamServer_TYPE {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return UpstreamServer_TYPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (x *UpstreamServer) GetAddress() string {
|
||||
if x != nil {
|
||||
return x.Address
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StatusRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The worker info. We could use information from the TLS connection but this
|
||||
// is easier and going the other route doesn't provijde much benefit -- if you
|
||||
// get access to the key and spoof the connection, you're already compromised.
|
||||
Worker *servers.Server `protobuf:"bytes,10,opt,name=worker,proto3" json:"worker,omitempty"`
|
||||
// Jobs which this worker wants to report the status.
|
||||
Jobs []*JobStatus `protobuf:"bytes,20,rep,name=jobs,proto3" json:"jobs,omitempty"`
|
||||
// Whether to update tags from the Server block on this RPC. We only need to
|
||||
@@ -478,12 +582,17 @@ type StatusRequest struct {
|
||||
// changed allows us to avoid constant database operations for something that
|
||||
// won't change very often, if ever.
|
||||
UpdateTags bool `protobuf:"varint,30,opt,name=update_tags,json=updateTags,proto3" json:"update_tags,omitempty"`
|
||||
// Replaces the old worker field:
|
||||
// The worker info. We could use information from the TLS connection but this
|
||||
// is easier and going the other route doesn't provide much benefit -- if you
|
||||
// get access to the key and spoof the connection, you're already compromised.
|
||||
WorkerStatus *servers.ServerWorkerStatus `protobuf:"bytes,40,opt,name=worker_status,json=workerStatus,proto3" json:"worker_status,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StatusRequest) Reset() {
|
||||
*x = StatusRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[4]
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -496,7 +605,7 @@ func (x *StatusRequest) String() string {
|
||||
func (*StatusRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StatusRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[4]
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -509,14 +618,7 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead.
|
||||
func (*StatusRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *StatusRequest) GetWorker() *servers.Server {
|
||||
if x != nil {
|
||||
return x.Worker
|
||||
}
|
||||
return nil
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *StatusRequest) GetJobs() []*JobStatus {
|
||||
@@ -533,6 +635,13 @@ func (x *StatusRequest) GetUpdateTags() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *StatusRequest) GetWorkerStatus() *servers.ServerWorkerStatus {
|
||||
if x != nil {
|
||||
return x.WorkerStatus
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type JobChangeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -545,7 +654,7 @@ type JobChangeRequest struct {
|
||||
func (x *JobChangeRequest) Reset() {
|
||||
*x = JobChangeRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[5]
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -558,7 +667,7 @@ func (x *JobChangeRequest) String() string {
|
||||
func (*JobChangeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *JobChangeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[5]
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -571,7 +680,7 @@ func (x *JobChangeRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use JobChangeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*JobChangeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{5}
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *JobChangeRequest) GetJob() *Job {
|
||||
@@ -593,21 +702,23 @@ type StatusResponse struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Active controllers. This can be used (eventually) for connection
|
||||
// management.
|
||||
Controllers []*servers.Server `protobuf:"bytes,10,rep,name=controllers,proto3" json:"controllers,omitempty"`
|
||||
// List of jobs and the expected state changes. For example, this will
|
||||
// include jobs witch change type of canceled for jobs which are active on a
|
||||
// worker but should be canceled. This could also contain a request to start a
|
||||
// job such as a worker -> worker proxy for establishing a session through an
|
||||
// enclave.
|
||||
JobsRequests []*JobChangeRequest `protobuf:"bytes,20,rep,name=jobs_requests,json=jobsRequests,proto3" json:"jobs_requests,omitempty"`
|
||||
// UpstreamServer currently returns the controller address in the StatusResponse.
|
||||
CalculatedUpstreams []*UpstreamServer `protobuf:"bytes,30,rep,name=calculated_upstreams,json=calculatedUpstreams,proto3" json:"calculated_upstreams,omitempty"`
|
||||
// The ID of the worker which made the request. The worker can send this value in subsequent requests so the
|
||||
// controller does not need to do a database lookup for the id using the name field.
|
||||
WorkerId string `protobuf:"bytes,40,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *StatusResponse) Reset() {
|
||||
*x = StatusResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6]
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -620,7 +731,7 @@ func (x *StatusResponse) String() string {
|
||||
func (*StatusResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StatusResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6]
|
||||
mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -633,14 +744,7 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead.
|
||||
func (*StatusResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *StatusResponse) GetControllers() []*servers.Server {
|
||||
if x != nil {
|
||||
return x.Controllers
|
||||
}
|
||||
return nil
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *StatusResponse) GetJobsRequests() []*JobChangeRequest {
|
||||
@@ -650,6 +754,20 @@ func (x *StatusResponse) GetJobsRequests() []*JobChangeRequest {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *StatusResponse) GetCalculatedUpstreams() []*UpstreamServer {
|
||||
if x != nil {
|
||||
return x.CalculatedUpstreams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *StatusResponse) GetWorkerId() string {
|
||||
if x != nil {
|
||||
return x.WorkerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_controller_servers_services_v1_server_coordination_service_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_rawDesc = []byte{
|
||||
@@ -696,79 +814,99 @@ var file_controller_servers_services_v1_server_coordination_service_proto_rawDes
|
||||
0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62,
|
||||
0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0xa6, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65,
|
||||
0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x3d,
|
||||
0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f,
|
||||
0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x1f, 0x0a,
|
||||
0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x1e, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x67, 0x73, 0x22, 0x98,
|
||||
0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x4d, 0x0a, 0x0c, 0x72, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x52, 0x0b, 0x72, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0xa8, 0x01, 0x0a, 0x0e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x12, 0x55, 0x0a,
|
||||
0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0xb7, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65,
|
||||
0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x59, 0x50, 0x45, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x42, 0x0a, 0x04, 0x54,
|
||||
0x59, 0x50, 0x45, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50,
|
||||
0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x59, 0x50,
|
||||
0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x4f, 0x4c, 0x4c, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0f,
|
||||
0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x45, 0x52, 0x10, 0x02, 0x22,
|
||||
0xcd, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x3d, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73,
|
||||
0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18,
|
||||
0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x67,
|
||||
0x73, 0x12, 0x4e, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x52, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x22,
|
||||
0x98, 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x4d, 0x0a, 0x0c, 0x72,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0e, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x52, 0x0b, 0x72,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0xfa, 0x01, 0x0a, 0x0e, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a,
|
||||
0x0d, 0x6a, 0x6f, 0x62, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x14,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0c, 0x6a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x73, 0x2a, 0x92, 0x01, 0x0a, 0x10, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54,
|
||||
0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e,
|
||||
0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e,
|
||||
0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1f, 0x0a, 0x1b, 0x43,
|
||||
0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f,
|
||||
0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a,
|
||||
0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17,
|
||||
0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x9e, 0x01, 0x0a, 0x0d, 0x53, 0x45,
|
||||
0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x1d, 0x0a, 0x19, 0x53,
|
||||
0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53,
|
||||
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45,
|
||||
0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44,
|
||||
0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e,
|
||||
0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12,
|
||||
0x1b, 0x0a, 0x17, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18,
|
||||
0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, 0x45,
|
||||
0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x37, 0x0a, 0x07, 0x4a, 0x4f,
|
||||
0x42, 0x54, 0x59, 0x50, 0x45, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45,
|
||||
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13,
|
||||
0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f,
|
||||
0x4e, 0x10, 0x01, 0x2a, 0x45, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50,
|
||||
0x45, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f,
|
||||
0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a,
|
||||
0x17, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41,
|
||||
0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x01, 0x32, 0x86, 0x01, 0x0a, 0x19, 0x53,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x65, 0x73, 0x74, 0x73, 0x12, 0x61, 0x0a, 0x14, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74,
|
||||
0x65, 0x64, 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x1e, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65,
|
||||
0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x52, 0x13, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x70,
|
||||
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65,
|
||||
0x72, 0x5f, 0x69, 0x64, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x49, 0x64, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x2a, 0x92, 0x01, 0x0a, 0x10, 0x43, 0x4f, 0x4e, 0x4e,
|
||||
0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x20, 0x0a, 0x1c,
|
||||
0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1f,
|
||||
0x0a, 0x1b, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54,
|
||||
0x55, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12,
|
||||
0x1e, 0x0a, 0x1a, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41,
|
||||
0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12,
|
||||
0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41,
|
||||
0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x9e, 0x01, 0x0a,
|
||||
0x0d, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x1d,
|
||||
0x0a, 0x19, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f,
|
||||
0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a,
|
||||
0x15, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50,
|
||||
0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x53, 0x53,
|
||||
0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45,
|
||||
0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41,
|
||||
0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12,
|
||||
0x1c, 0x0a, 0x18, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x37, 0x0a,
|
||||
0x07, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x54,
|
||||
0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
|
||||
0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x53,
|
||||
0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x2a, 0x45, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45,
|
||||
0x54, 0x59, 0x50, 0x45, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59,
|
||||
0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
|
||||
0x12, 0x1b, 0x0a, 0x17, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55,
|
||||
0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x01, 0x32, 0x86, 0x01,
|
||||
0x0a, 0x19, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x06, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -783,42 +921,45 @@ func file_controller_servers_services_v1_server_coordination_service_proto_rawDe
|
||||
return file_controller_servers_services_v1_server_coordination_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_goTypes = []interface{}{
|
||||
(CONNECTIONSTATUS)(0), // 0: controller.servers.services.v1.CONNECTIONSTATUS
|
||||
(SESSIONSTATUS)(0), // 1: controller.servers.services.v1.SESSIONSTATUS
|
||||
(JOBTYPE)(0), // 2: controller.servers.services.v1.JOBTYPE
|
||||
(CHANGETYPE)(0), // 3: controller.servers.services.v1.CHANGETYPE
|
||||
(*Connection)(nil), // 4: controller.servers.services.v1.Connection
|
||||
(*SessionJobInfo)(nil), // 5: controller.servers.services.v1.SessionJobInfo
|
||||
(*Job)(nil), // 6: controller.servers.services.v1.Job
|
||||
(*JobStatus)(nil), // 7: controller.servers.services.v1.JobStatus
|
||||
(*StatusRequest)(nil), // 8: controller.servers.services.v1.StatusRequest
|
||||
(*JobChangeRequest)(nil), // 9: controller.servers.services.v1.JobChangeRequest
|
||||
(*StatusResponse)(nil), // 10: controller.servers.services.v1.StatusResponse
|
||||
(*servers.Server)(nil), // 11: controller.servers.v1.Server
|
||||
(CONNECTIONSTATUS)(0), // 0: controller.servers.services.v1.CONNECTIONSTATUS
|
||||
(SESSIONSTATUS)(0), // 1: controller.servers.services.v1.SESSIONSTATUS
|
||||
(JOBTYPE)(0), // 2: controller.servers.services.v1.JOBTYPE
|
||||
(CHANGETYPE)(0), // 3: controller.servers.services.v1.CHANGETYPE
|
||||
(UpstreamServer_TYPE)(0), // 4: controller.servers.services.v1.UpstreamServer.TYPE
|
||||
(*Connection)(nil), // 5: controller.servers.services.v1.Connection
|
||||
(*SessionJobInfo)(nil), // 6: controller.servers.services.v1.SessionJobInfo
|
||||
(*Job)(nil), // 7: controller.servers.services.v1.Job
|
||||
(*JobStatus)(nil), // 8: controller.servers.services.v1.JobStatus
|
||||
(*UpstreamServer)(nil), // 9: controller.servers.services.v1.UpstreamServer
|
||||
(*StatusRequest)(nil), // 10: controller.servers.services.v1.StatusRequest
|
||||
(*JobChangeRequest)(nil), // 11: controller.servers.services.v1.JobChangeRequest
|
||||
(*StatusResponse)(nil), // 12: controller.servers.services.v1.StatusResponse
|
||||
(*servers.ServerWorkerStatus)(nil), // 13: controller.servers.v1.ServerWorkerStatus
|
||||
}
|
||||
var file_controller_servers_services_v1_server_coordination_service_proto_depIdxs = []int32{
|
||||
0, // 0: controller.servers.services.v1.Connection.status:type_name -> controller.servers.services.v1.CONNECTIONSTATUS
|
||||
1, // 1: controller.servers.services.v1.SessionJobInfo.status:type_name -> controller.servers.services.v1.SESSIONSTATUS
|
||||
4, // 2: controller.servers.services.v1.SessionJobInfo.connections:type_name -> controller.servers.services.v1.Connection
|
||||
5, // 2: controller.servers.services.v1.SessionJobInfo.connections:type_name -> controller.servers.services.v1.Connection
|
||||
2, // 3: controller.servers.services.v1.Job.type:type_name -> controller.servers.services.v1.JOBTYPE
|
||||
5, // 4: controller.servers.services.v1.Job.session_info:type_name -> controller.servers.services.v1.SessionJobInfo
|
||||
6, // 5: controller.servers.services.v1.JobStatus.job:type_name -> controller.servers.services.v1.Job
|
||||
11, // 6: controller.servers.services.v1.StatusRequest.worker:type_name -> controller.servers.v1.Server
|
||||
7, // 7: controller.servers.services.v1.StatusRequest.jobs:type_name -> controller.servers.services.v1.JobStatus
|
||||
6, // 8: controller.servers.services.v1.JobChangeRequest.job:type_name -> controller.servers.services.v1.Job
|
||||
3, // 9: controller.servers.services.v1.JobChangeRequest.request_type:type_name -> controller.servers.services.v1.CHANGETYPE
|
||||
11, // 10: controller.servers.services.v1.StatusResponse.controllers:type_name -> controller.servers.v1.Server
|
||||
9, // 11: controller.servers.services.v1.StatusResponse.jobs_requests:type_name -> controller.servers.services.v1.JobChangeRequest
|
||||
8, // 12: controller.servers.services.v1.ServerCoordinationService.Status:input_type -> controller.servers.services.v1.StatusRequest
|
||||
10, // 13: controller.servers.services.v1.ServerCoordinationService.Status:output_type -> controller.servers.services.v1.StatusResponse
|
||||
13, // [13:14] is the sub-list for method output_type
|
||||
12, // [12:13] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
6, // 4: controller.servers.services.v1.Job.session_info:type_name -> controller.servers.services.v1.SessionJobInfo
|
||||
7, // 5: controller.servers.services.v1.JobStatus.job:type_name -> controller.servers.services.v1.Job
|
||||
4, // 6: controller.servers.services.v1.UpstreamServer.type:type_name -> controller.servers.services.v1.UpstreamServer.TYPE
|
||||
8, // 7: controller.servers.services.v1.StatusRequest.jobs:type_name -> controller.servers.services.v1.JobStatus
|
||||
13, // 8: controller.servers.services.v1.StatusRequest.worker_status:type_name -> controller.servers.v1.ServerWorkerStatus
|
||||
7, // 9: controller.servers.services.v1.JobChangeRequest.job:type_name -> controller.servers.services.v1.Job
|
||||
3, // 10: controller.servers.services.v1.JobChangeRequest.request_type:type_name -> controller.servers.services.v1.CHANGETYPE
|
||||
11, // 11: controller.servers.services.v1.StatusResponse.jobs_requests:type_name -> controller.servers.services.v1.JobChangeRequest
|
||||
9, // 12: controller.servers.services.v1.StatusResponse.calculated_upstreams:type_name -> controller.servers.services.v1.UpstreamServer
|
||||
10, // 13: controller.servers.services.v1.ServerCoordinationService.Status:input_type -> controller.servers.services.v1.StatusRequest
|
||||
12, // 14: controller.servers.services.v1.ServerCoordinationService.Status:output_type -> controller.servers.services.v1.StatusResponse
|
||||
14, // [14:15] is the sub-list for method output_type
|
||||
13, // [13:14] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_controller_servers_services_v1_server_coordination_service_proto_init() }
|
||||
@@ -876,7 +1017,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init(
|
||||
}
|
||||
}
|
||||
file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StatusRequest); i {
|
||||
switch v := v.(*UpstreamServer); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -888,7 +1029,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init(
|
||||
}
|
||||
}
|
||||
file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*JobChangeRequest); i {
|
||||
switch v := v.(*StatusRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -900,6 +1041,18 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init(
|
||||
}
|
||||
}
|
||||
file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*JobChangeRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StatusResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -920,8 +1073,8 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init(
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_controller_servers_services_v1_server_coordination_service_proto_rawDesc,
|
||||
NumEnums: 4,
|
||||
NumMessages: 7,
|
||||
NumEnums: 5,
|
||||
NumMessages: 8,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -32,6 +32,9 @@ type LookupSessionRequest struct {
|
||||
// The name of the requesting worker, used for filtering to ensure this
|
||||
// worker is allowed to handle this session.
|
||||
ServerId string `protobuf:"bytes,20,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// The key id of the requesting worker, used for filtering
|
||||
// if the server name is not provided
|
||||
WorkerKeyId string `protobuf:"bytes,30,opt,name=worker_key_id,json=workerKeyId,proto3" json:"worker_key_id,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *LookupSessionRequest) Reset() {
|
||||
@@ -80,6 +83,13 @@ func (x *LookupSessionRequest) GetServerId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *LookupSessionRequest) GetWorkerKeyId() string {
|
||||
if x != nil {
|
||||
return x.WorkerKeyId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// LookupSessionResponse contains information necessary for a client to
|
||||
// establish a session.
|
||||
type LookupSessionResponse struct {
|
||||
@@ -947,216 +957,218 @@ var file_controller_servers_services_v1_session_service_proto_rawDesc = []byte{
|
||||
0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x52, 0x0a, 0x14,
|
||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x76, 0x0a, 0x14,
|
||||
0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64,
|
||||
0x22, 0xe8, 0x04, 0x0a, 0x15, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0d, 0x61, 0x75,
|
||||
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41,
|
||||
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61,
|
||||
0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x14, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52,
|
||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x46, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x65, 0x66, 0x74, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73,
|
||||
0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73,
|
||||
0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x78,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x0b,
|
||||
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x82, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0b,
|
||||
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0xd4, 0x01, 0x0a, 0x16,
|
||||
0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, 0x54,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
|
||||
0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x28, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x06, 0x73,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53,
|
||||
0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x22, 0x60, 0x0a, 0x17, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a,
|
||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53,
|
||||
0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x5e, 0x0a, 0x15, 0x43,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a,
|
||||
0x12, 0x22, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b,
|
||||
0x65, 0x79, 0x49, 0x64, 0x22, 0xe8, 0x04, 0x0a, 0x15, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63,
|
||||
0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
|
||||
0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x44, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65,
|
||||
0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1e, 0x20,
|
||||
0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x3c,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41,
|
||||
0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x58, 0x0a, 0x1a, 0x41,
|
||||
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x1b, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
|
||||
0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18,
|
||||
0x46, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x65, 0x66,
|
||||
0x74, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x5a, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x09, 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
|
||||
0x12, 0x4d, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18,
|
||||
0x82, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x61, 0x6c, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22,
|
||||
0xd4, 0x01, 0x0a, 0x16, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
|
||||
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66,
|
||||
0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74,
|
||||
0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12,
|
||||
0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x60, 0x0a, 0x17, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28,
|
||||
0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22,
|
||||
0x5e, 0x0a, 0x15, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f,
|
||||
0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22,
|
||||
0x58, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x1b, 0x41, 0x75,
|
||||
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48,
|
||||
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x1e, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c,
|
||||
0x65, 0x66, 0x74, 0x22, 0xad, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
|
||||
0x74, 0x63, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x41, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x63,
|
||||
0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x6c,
|
||||
0x69, 0x65, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x65,
|
||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a,
|
||||
0x11, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69,
|
||||
0x6e, 0x74, 0x54, 0x63, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a,
|
||||
0x0e, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18,
|
||||
0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x49, 0x70, 0x22, 0x65, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54,
|
||||
0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x1a, 0x43,
|
||||
0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19,
|
||||
0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x55, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74,
|
||||
0x65, 0x73, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62,
|
||||
0x79, 0x74, 0x65, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73,
|
||||
0x6f, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||
0x22, 0x82, 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x68, 0x0a, 0x12, 0x63,
|
||||
0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74,
|
||||
0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44,
|
||||
0x61, 0x74, 0x61, 0x52, 0x10, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8c, 0x01, 0x0a, 0x1b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e,
|
||||
0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f,
|
||||
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x65, 0x66, 0x74, 0x22,
|
||||
0xad, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d,
|
||||
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
|
||||
0x64, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x63, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
|
||||
0x26, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x54, 0x63, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
|
||||
0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54,
|
||||
0x63, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x6e, 0x64,
|
||||
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x32,
|
||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x63,
|
||||
0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x3c, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x46, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x22,
|
||||
0x65, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f,
|
||||
0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x1a, 0x43, 0x6c, 0x6f, 0x73, 0x65,
|
||||
0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x79,
|
||||
0x74, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x62, 0x79,
|
||||
0x74, 0x65, 0x73, 0x55, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64,
|
||||
0x6f, 0x77, 0x6e, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, 0x73,
|
||||
0x44, 0x6f, 0x77, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x28,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x82, 0x01, 0x0a,
|
||||
0x16, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x68, 0x0a, 0x12, 0x63, 0x6c, 0x6f, 0x73, 0x65,
|
||||
0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52,
|
||||
0x10, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74,
|
||||
0x61, 0x22, 0x8c, 0x01, 0x0a, 0x1b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74,
|
||||
0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49,
|
||||
0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x22, 0x86, 0x01, 0x0a, 0x17, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x13,
|
||||
0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x64,
|
||||
0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65,
|
||||
0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x11, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x32, 0xbe, 0x06, 0x0a, 0x0e, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x0d,
|
||||
0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e,
|
||||
0x61, 0x74, 0x75, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x17, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x6b, 0x0a, 0x13, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
||||
0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a,
|
||||
0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43,
|
||||
0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x11, 0x63, 0x6c, 0x6f, 0x73,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x32, 0xbe, 0x06,
|
||||
0x0a, 0x0e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x12, 0x7e, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x84, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, 0x13, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
|
||||
0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x2e, 0x63, 0x6f,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63,
|
||||
0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c,
|
||||
0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, 0x13, 0x41, 0x75, 0x74, 0x68,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||
0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74,
|
||||
0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
|
||||
0x7a, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8a, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
|
||||
0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8a, 0x01, 0x0a, 0x11, 0x43,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e,
|
||||
0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, 0x73,
|
||||
0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f,
|
||||
0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x51,
|
||||
0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73,
|
||||
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -27,6 +27,9 @@ const (
|
||||
// KeyPurposeWorkerAuth is used for worker auth
|
||||
KeyPurposeWorkerAuth
|
||||
|
||||
// KeyPurposeWorkerAuthStorage is used for worker credential storage
|
||||
KeyPurposeWorkerAuthStorage
|
||||
|
||||
// KeyPurposeTokens is used for token encryption
|
||||
KeyPurposeTokens
|
||||
|
||||
@@ -56,6 +59,8 @@ func (k KeyPurpose) String() string {
|
||||
return "recovery"
|
||||
case KeyPurposeWorkerAuth:
|
||||
return "workerauth"
|
||||
case KeyPurposeWorkerAuthStorage:
|
||||
return "workerauthstorage"
|
||||
case KeyPurposeTokens:
|
||||
return "tokens"
|
||||
case KeyPurposeSessions:
|
||||
|
||||
@@ -20,9 +20,10 @@ func TestExternalWrappers(t *testing.T) {
|
||||
rootWrapper := db.TestWrapper(t)
|
||||
recoveryWrapper := db.TestWrapper(t)
|
||||
workerAuthWrapper := db.TestWrapper(t)
|
||||
workerAuthStorageWrapper := db.TestWrapper(t)
|
||||
|
||||
k := TestKms(t, conn, rootWrapper)
|
||||
err := k.AddExternalWrappers(testCtx, WithRecoveryWrapper(recoveryWrapper), WithWorkerAuthWrapper(workerAuthWrapper))
|
||||
err := k.AddExternalWrappers(testCtx, WithRecoveryWrapper(recoveryWrapper), WithWorkerAuthWrapper(workerAuthWrapper), WithWorkerAuthStorageWrapper(workerAuthStorageWrapper))
|
||||
require.NoError(err)
|
||||
|
||||
assert.Equal(rootWrapper, k.GetExternalWrappers(testCtx).Root())
|
||||
|
||||
+2
-1
@@ -258,7 +258,8 @@ func stdNewKmsPurposes() []wrappingKms.KeyPurpose {
|
||||
for _, p := range ValidDekPurposes() {
|
||||
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
|
||||
}
|
||||
purposes = append(purposes, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), wrappingKms.KeyPurpose(KeyPurposeRecovery.String()))
|
||||
purposes = append(purposes, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), wrappingKms.KeyPurpose(KeyPurposeWorkerAuthStorage.String()),
|
||||
wrappingKms.KeyPurpose(KeyPurposeRecovery.String()))
|
||||
return purposes
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ func Test_New(t *testing.T) {
|
||||
for _, p := range ValidDekPurposes() {
|
||||
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
|
||||
}
|
||||
purposes = append(purposes, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), wrappingKms.KeyPurpose(KeyPurposeRecovery.String()))
|
||||
purposes = append(purposes, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()),
|
||||
wrappingKms.KeyPurpose(KeyPurposeWorkerAuthStorage.String()), wrappingKms.KeyPurpose(KeyPurposeRecovery.String()))
|
||||
|
||||
r := dbw.New(rw.UnderlyingDB())
|
||||
w := dbw.New(rw.UnderlyingDB())
|
||||
|
||||
+19
-10
@@ -21,16 +21,17 @@ type Option func(*options)
|
||||
|
||||
// options = how options are represented
|
||||
type options struct {
|
||||
withLimit int
|
||||
withRootWrapper wrapping.Wrapper
|
||||
withWorkerAuthWrapper wrapping.Wrapper
|
||||
withRecoveryWrapper wrapping.Wrapper
|
||||
withOrderByVersion db.OrderBy
|
||||
withKeyId string
|
||||
withScopeIds []string
|
||||
withRandomReader io.Reader
|
||||
withReader db.Reader
|
||||
withWriter db.Writer
|
||||
withLimit int
|
||||
withRootWrapper wrapping.Wrapper
|
||||
withWorkerAuthWrapper wrapping.Wrapper
|
||||
withWorkerAuthStorageWrapper wrapping.Wrapper
|
||||
withRecoveryWrapper wrapping.Wrapper
|
||||
withOrderByVersion db.OrderBy
|
||||
withKeyId string
|
||||
withScopeIds []string
|
||||
withRandomReader io.Reader
|
||||
withReader db.Reader
|
||||
withWriter db.Writer
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
@@ -61,6 +62,14 @@ func WithWorkerAuthWrapper(w wrapping.Wrapper) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithWorkerAuthStorageWrapper sets the external pki worker storage wrapper for a
|
||||
// given scope
|
||||
func WithWorkerAuthStorageWrapper(w wrapping.Wrapper) Option {
|
||||
return func(o *options) {
|
||||
o.withWorkerAuthStorageWrapper = w
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecoveryWrapper sets the recovery wrapper for a given scope
|
||||
func WithRecoveryWrapper(w wrapping.Wrapper) Option {
|
||||
return func(o *options) {
|
||||
|
||||
@@ -143,7 +143,9 @@ func newFilter(f string) (*filter, error) {
|
||||
if f == "" {
|
||||
return nil, fmt.Errorf("%s: missing filter: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
e, err := bexpr.CreateEvaluator(f, bexpr.WithHookFn(filterpkg.WellKnownTypeFilterHook))
|
||||
// explicitly tell the filter to use the "json" tags so we don't have to
|
||||
// re-tag everything with a mapstructure tag via bexpr.WithTagName("json")
|
||||
e, err := bexpr.CreateEvaluator(f, bexpr.WithHookFn(filterpkg.WellKnownTypeFilterHook), bexpr.WithTagName("json"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ func TestNode_Process(t *testing.T) {
|
||||
testNode, err := newCloudEventsFormatterFilter(testUrl, cloudevents.FormatJSON, WithSchema(testUrl))
|
||||
require.NoError(t, err)
|
||||
|
||||
f, err := newFilter(`Data == "match-filter"`)
|
||||
f, err := newFilter(`data == "match-filter"`)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
|
||||
@@ -517,25 +517,25 @@ func Test_Filtering(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "allowed",
|
||||
allow: []string{`"/Data/list" contains "1"`},
|
||||
allow: []string{`"/data/list" contains "1"`},
|
||||
hdr: []interface{}{"list", []string{"1", "2"}},
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "not-allowed",
|
||||
allow: []string{`"/Data/list" contains "22"`},
|
||||
allow: []string{`"/data/list" contains "22"`},
|
||||
hdr: []interface{}{"list", []string{"1", "2"}},
|
||||
found: false,
|
||||
},
|
||||
{
|
||||
name: "deny",
|
||||
deny: []string{`"/Data/list" contains "1"`},
|
||||
deny: []string{`"/data/list" contains "1"`},
|
||||
hdr: []interface{}{"list", []string{"1", "2"}},
|
||||
found: false,
|
||||
},
|
||||
{
|
||||
name: "not-deny",
|
||||
deny: []string{`"/Data/list" contains "22"`},
|
||||
deny: []string{`"/data/list" contains "22"`},
|
||||
hdr: []interface{}{"list", []string{"1", "2"}},
|
||||
found: true,
|
||||
},
|
||||
|
||||
@@ -36,7 +36,7 @@ type hclogFormatterFilter struct {
|
||||
}
|
||||
|
||||
func newHclogFormatterFilter(jsonFormat bool, opt ...Option) (*hclogFormatterFilter, error) {
|
||||
const op = "event.NewHclogFormatter"
|
||||
const op = "event.newHclogFormatterFilter"
|
||||
opts := getOpts(opt...)
|
||||
var s signer
|
||||
n := hclogFormatterFilter{
|
||||
@@ -147,7 +147,9 @@ func (f *hclogFormatterFilter) Process(ctx context.Context, e *eventlogger.Event
|
||||
var m map[string]interface{}
|
||||
switch string(e.Type) {
|
||||
case string(ErrorType), string(AuditType), string(SystemType):
|
||||
m = structs.Map(e.Payload)
|
||||
s := structs.New(e.Payload)
|
||||
s.TagName = "json"
|
||||
m = s.Map()
|
||||
case string(ObservationType):
|
||||
m = e.Payload.(map[string]interface{})
|
||||
default:
|
||||
|
||||
@@ -15,7 +15,7 @@ func TestHclogFormatter_Process(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
f, e := newFilter(`Op == "match-filter"`)
|
||||
f, e := newFilter(`op == "match-filter"`)
|
||||
require.NoError(t, e)
|
||||
|
||||
testPredicate := newPredicate([]*filter{f}, nil)
|
||||
@@ -60,10 +60,9 @@ func TestHclogFormatter_Process(t *testing.T) {
|
||||
},
|
||||
want: []string{
|
||||
"[INFO] system event:",
|
||||
"Data:msg=hello",
|
||||
"Id=1",
|
||||
"Version=v0.1",
|
||||
"Op=text",
|
||||
"data:msg=hello",
|
||||
"version=v0.1",
|
||||
"op=text",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -122,10 +121,10 @@ func TestHclogFormatter_Process(t *testing.T) {
|
||||
},
|
||||
want: []string{
|
||||
"[ERROR] error event:",
|
||||
"Error=\"invalid parameter\"",
|
||||
"Id=1",
|
||||
"Version=v0.1",
|
||||
"Op=text",
|
||||
"error=\"invalid parameter\"",
|
||||
"id=1",
|
||||
"version=v0.1",
|
||||
"op=text",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -144,10 +143,10 @@ func TestHclogFormatter_Process(t *testing.T) {
|
||||
},
|
||||
want: []string{
|
||||
"{\"@level\":\"error\",\"@message\":\"error event\"",
|
||||
"\"Error\":\"invalid parameter\"",
|
||||
"\"Id\":\"1\"",
|
||||
"\"Version\":\"v0.1\"",
|
||||
"\"Op\":\"text\"",
|
||||
"\"error\":\"invalid parameter\"",
|
||||
"\"id\":\"1\"",
|
||||
"\"version\":\"v0.1\"",
|
||||
"\"op\":\"text\"",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -167,11 +166,11 @@ func TestHclogFormatter_Process(t *testing.T) {
|
||||
},
|
||||
want: []string{
|
||||
"[ERROR] error event:",
|
||||
"Error=\"invalid parameter\"",
|
||||
"Id=1",
|
||||
"Version=v0.1",
|
||||
"Info:name=alice",
|
||||
"Op=text",
|
||||
"error=\"invalid parameter\"",
|
||||
"id=1",
|
||||
"version=v0.1",
|
||||
"info:name=alice",
|
||||
"op=text",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -193,10 +192,9 @@ func TestHclogFormatter_Process(t *testing.T) {
|
||||
},
|
||||
want: []string{
|
||||
"[INFO] system event:",
|
||||
"Data:msg=hello",
|
||||
"Id=1",
|
||||
"Version=v0.1",
|
||||
"Op=match-filter",
|
||||
"data:msg=hello",
|
||||
"version=v0.1",
|
||||
"op=match-filter",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Loaded 100 of 195 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user