This adds a new requirement onto subtypes to register a NewFunc. Previously the subtypes where implementing this function anyway, but the target package was not including them in the registry. This resulted in packages that use the target package needing to import the subtypes directly, which we want to avoid. This refactor will require the subtypes to register their NewFunc which can then be used by `target.New` so packages that need to create targets can do so by only using the target package. This also updates the tcp subpackage to register a NewFunc.
156 lines
4.0 KiB
Go
156 lines
4.0 KiB
Go
package target
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/types/subtypes"
|
|
)
|
|
|
|
// NewFunc is a function that creates a Target with the provided scope and options.
|
|
type NewFunc func(scopeId string, opt ...Option) (Target, error)
|
|
|
|
// AllocFunc is a function that creates an in-memory Target.
|
|
type AllocFunc func() Target
|
|
|
|
// VetFunc is a function that checks the given Target to ensure it can
|
|
// be used by the Repository.
|
|
type VetFunc func(context.Context, Target) error
|
|
|
|
// VetCredentialLibrariesFunc is a function that checks the given CredentialLibraries
|
|
// to ensure that they are valid for a Target subtype.
|
|
type VetCredentialLibrariesFunc func(context.Context, []*CredentialLibrary) error
|
|
|
|
type registryEntry struct {
|
|
newFunc NewFunc
|
|
alloc AllocFunc
|
|
vet VetFunc
|
|
vetCredentialLibraries VetCredentialLibrariesFunc
|
|
prefix string
|
|
}
|
|
|
|
type registry struct {
|
|
m map[subtypes.Subtype]*registryEntry
|
|
subtypes *subtypes.Registry
|
|
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (r *registry) set(s subtypes.Subtype, entry *registryEntry) {
|
|
r.Lock()
|
|
defer r.Unlock()
|
|
|
|
_, previouslySet := r.m[s]
|
|
if previouslySet {
|
|
panic(fmt.Sprintf("target subtype %s already registered", s))
|
|
}
|
|
|
|
if err := r.subtypes.Register(s, entry.prefix); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
r.m[s] = entry
|
|
}
|
|
|
|
func (r *registry) get(s subtypes.Subtype) (*registryEntry, bool) {
|
|
r.RLock()
|
|
defer r.RUnlock()
|
|
|
|
entry, ok := r.m[s]
|
|
if ok {
|
|
return entry, ok
|
|
}
|
|
return nil, ok
|
|
}
|
|
|
|
func (r *registry) newFunc(s subtypes.Subtype) (NewFunc, bool) {
|
|
entry, ok := r.get(s)
|
|
if !ok {
|
|
return nil, ok
|
|
}
|
|
return entry.newFunc, ok
|
|
}
|
|
|
|
func (r *registry) allocFunc(s subtypes.Subtype) (AllocFunc, bool) {
|
|
entry, ok := r.get(s)
|
|
if !ok {
|
|
return nil, ok
|
|
}
|
|
return entry.alloc, ok
|
|
}
|
|
|
|
func (r *registry) vetFunc(s subtypes.Subtype) (VetFunc, bool) {
|
|
entry, ok := r.get(s)
|
|
if !ok {
|
|
return nil, ok
|
|
}
|
|
return entry.vet, ok
|
|
}
|
|
|
|
func (r *registry) vetCredentialLibrariesFunc(s subtypes.Subtype) (VetCredentialLibrariesFunc, bool) {
|
|
entry, ok := r.get(s)
|
|
if !ok {
|
|
return nil, ok
|
|
}
|
|
return entry.vetCredentialLibraries, ok
|
|
}
|
|
|
|
func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) {
|
|
entry, ok := r.get(s)
|
|
if !ok {
|
|
return "", ok
|
|
}
|
|
return entry.prefix, ok
|
|
}
|
|
|
|
var subtypeRegistry = registry{
|
|
m: make(map[subtypes.Subtype]*registryEntry),
|
|
subtypes: subtypes.NewRegistry(),
|
|
}
|
|
|
|
// SubtypeFromType returns the Subtype from the provided string or if
|
|
// no Subtype was registered with that string Unknown is returned.
|
|
func SubtypeFromType(t string) subtypes.Subtype {
|
|
subtypeRegistry.RLock()
|
|
defer subtypeRegistry.RUnlock()
|
|
return subtypeRegistry.subtypes.SubtypeFromType(t)
|
|
}
|
|
|
|
// SubtypeFromId returns the Subtype from the provided id if the id's prefix
|
|
// was registered with a Subtype. Otherwise Unknown is returned.
|
|
func SubtypeFromId(id string) subtypes.Subtype {
|
|
subtypeRegistry.RLock()
|
|
defer subtypeRegistry.RUnlock()
|
|
return subtypeRegistry.subtypes.SubtypeFromId(id)
|
|
}
|
|
|
|
// Prefixes returns the list of all known target Prefixes.
|
|
func Prefixes() []string {
|
|
return subtypeRegistry.subtypes.Prefixes()
|
|
}
|
|
|
|
// New creates a Target of the given subtype and scopeId.
|
|
func New(ctx context.Context, subtype subtypes.Subtype, scopeId string, opt ...Option) (Target, error) {
|
|
const op = "target.New"
|
|
nf, ok := subtypeRegistry.newFunc(subtype)
|
|
if !ok {
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "unsupported subtype")
|
|
}
|
|
return nf(scopeId, opt...)
|
|
}
|
|
|
|
// Register registers repository hooks and the prefixes for a provided Subtype. Register
|
|
// panics if the subtype has already been registered or if any of the
|
|
// prefixes are associated with another subtype.
|
|
func Register(s subtypes.Subtype, nf NewFunc, af AllocFunc, vf VetFunc, vclf VetCredentialLibrariesFunc, prefix string) {
|
|
subtypeRegistry.set(s, ®istryEntry{
|
|
newFunc: nf,
|
|
alloc: af,
|
|
vet: vf,
|
|
vetCredentialLibraries: vclf,
|
|
prefix: prefix,
|
|
})
|
|
}
|