You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/server/worker.go

205 lines
6.6 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package server
import (
"context"
"github.com/fatih/structs"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/server/store"
"github.com/hashicorp/boundary/sdk/pbs/plugin"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
type (
WorkerType string
OperationalState string
LocalStorageState string
)
const (
UnknownWorkerType WorkerType = "unknown"
KmsWorkerType WorkerType = "kms"
PkiWorkerType WorkerType = "pki"
ActiveOperationalState OperationalState = "active"
ShutdownOperationalState OperationalState = "shutdown"
UnknownOperationalState OperationalState = "unknown"
AvailableLocalStorageState LocalStorageState = "available"
LowStorageLocalStorageState LocalStorageState = "low storage"
CriticallyLowStorageLocalStorageState LocalStorageState = "critically low storage"
OutOfStorageLocalStorageState LocalStorageState = "out of storage"
NotConfiguredLocalStorageState LocalStorageState = "not configured"
UnknownLocalStorageState LocalStorageState = "unknown"
)
func (t WorkerType) Valid() bool {
switch t {
case KmsWorkerType, PkiWorkerType:
return true
}
return false
}
func (t WorkerType) String() string {
switch t {
case KmsWorkerType, PkiWorkerType:
return string(t)
}
return string(UnknownWorkerType)
}
type workerAuthWorkerId struct {
WorkerId string `mapstructure:"worker_id"`
}
func ValidOperationalState(s string) bool {
switch s {
case ActiveOperationalState.String(), ShutdownOperationalState.String():
return true
}
return false
}
func (t OperationalState) String() string {
switch t {
case ActiveOperationalState, ShutdownOperationalState:
return string(t)
}
return string(UnknownOperationalState)
}
func ValidLocalStorageState(s string) bool {
switch s {
case AvailableLocalStorageState.String(), LowStorageLocalStorageState.String(),
CriticallyLowStorageLocalStorageState.String(), OutOfStorageLocalStorageState.String(),
NotConfiguredLocalStorageState.String(), UnknownLocalStorageState.String():
return true
}
return false
}
func (t LocalStorageState) String() string {
switch t {
case AvailableLocalStorageState, LowStorageLocalStorageState,
OutOfStorageLocalStorageState, NotConfiguredLocalStorageState,
CriticallyLowStorageLocalStorageState:
return string(t)
}
return string(UnknownLocalStorageState)
}
// AttachWorkerIdToState accepts a workerId and creates a struct for use with the Nodeenrollment lib
// This is intended for use in worker authorization; AuthorizeNode in the lib accepts the option WithState
// so that the workerId is passed through to storage and associated with a WorkerAuth record
func AttachWorkerIdToState(ctx context.Context, workerId string) (*structpb.Struct, error) {
const op = "server.(Worker).AttachWorkerIdToState"
if workerId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing workerId")
}
workerMap := &workerAuthWorkerId{WorkerId: workerId}
s := structs.New(workerMap)
s.TagName = "mapstructure"
return structpb.NewStruct(s.Map())
}
// A Worker is a server that provides an address which can be used to proxy
// session connections. It can be tagged with custom tags and is used when
// authorizing and establishing a session. It is owned by a scope.
type Worker struct {
*store.Worker
ApiTags Tags `json:"api_tags" gorm:"->"`
ConfigTags Tags `json:"config_tags" gorm:"->"`
ActiveConnectionCount uint32 `gorm:"->"`
// inputTags is not specified to be api or config tags and is not intended
// to be read by clients. Since config tags and api tags are applied in
// mutually exclusive contexts, inputTags is interpreted to be one or the
// other based on the context in which the worker is passed. As such
// inputTags should only be read when performing mutations on the database.
inputTags []*Tag `gorm:"-"`
// This is used to pass the token back to the calling function
ControllerGeneratedActivationToken string `gorm:"-"`
// RemoteStorageStates is a map of storage buckets and their storage bucket credential states
RemoteStorageStates map[string]*plugin.StorageBucketCredentialState `gorm:"-"`
}
// NewWorker returns a new Worker. Valid options are WithName, WithDescription
// WithAddress, and WithWorkerTags. All other options are ignored. This does
// not set any of the worker reported values.
func NewWorker(scopeId string, opt ...Option) *Worker {
opts := GetOpts(opt...)
worker := &Worker{
Worker: &store.Worker{
ScopeId: scopeId,
Name: opts.withName,
Description: opts.withDescription,
Address: opts.withAddress,
ReleaseVersion: opts.withReleaseVersion,
OperationalState: opts.withOperationalState,
LocalStorageState: opts.withLocalStorageState,
},
inputTags: opts.withWorkerTags,
}
if opts.withTestUseInputTagsAsApiTags {
worker.ApiTags = convertToTags(worker.inputTags)
}
return worker
}
// allocWorker will allocate a Worker
func allocWorker() Worker {
return Worker{Worker: &store.Worker{}}
}
func (w *Worker) clone() *Worker {
if w == nil {
return nil
}
cw := proto.Clone(w.Worker)
cWorker := &Worker{
Worker: cw.(*store.Worker),
}
if w.ApiTags != nil {
cWorker.ApiTags = w.ApiTags.clone()
}
if w.ConfigTags != nil {
cWorker.ConfigTags = w.ConfigTags.clone()
}
if w.inputTags != nil {
cWorker.inputTags = make([]*Tag, 0, len(w.inputTags))
for _, t := range w.inputTags {
cWorker.inputTags = append(cWorker.inputTags, &Tag{Key: t.Key, Value: t.Value})
}
}
return cWorker
}
// CanonicalTags is the deduplicated set of tags contained on both the resource
// set over the API as well as the tags reported by the worker itself. This
// function is guaranteed to return a non-nil map.
func (w *Worker) CanonicalTags() Tags {
return compactTags(&w.ApiTags, &w.ConfigTags)
}
// GetLastStatusTime contains the last time the worker has reported to the
// controller its connection status. If the worker has never reported to a
// controller then nil is returned.
func (w *Worker) GetLastStatusTime() *timestamp.Timestamp {
if w == nil || w.Worker == nil || w.Worker.GetLastStatusTime().AsTime() == timestamp.NegativeInfinityTS {
return nil
}
return w.Worker.GetLastStatusTime()
}
// TableName overrides the table name used by Worker to `server_worker`
func (Worker) TableName() string {
return "server_worker"
}