exposing authority configuration for provisioner cli commands

This commit is contained in:
max furman 2022-04-25 10:23:07 -07:00
parent 3424442c50
commit b91affdd34
6 changed files with 115 additions and 48 deletions

View file

@ -71,6 +71,52 @@ type DB interface {
DeleteAdmin(ctx context.Context, id string) error DeleteAdmin(ctx context.Context, id string) error
} }
type NoDB struct{}
func NewNoDB() *NoDB {
return &NoDB{}
}
func (n *NoDB) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
return nil
}
func (n *NoDB) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error) {
return nil, nil
}
func (n *NoDB) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
return nil, nil
}
func (n *NoDB) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
return nil
}
func (n *NoDB) DeleteProvisioner(ctx context.Context, id string) error {
return nil
}
func (n *NoDB) CreateAdmin(ctx context.Context, admin *linkedca.Admin) error {
return nil
}
func (n *NoDB) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) {
return nil, nil
}
func (n *NoDB) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
return nil, nil
}
func (n *NoDB) UpdateAdmin(ctx context.Context, prov *linkedca.Admin) error {
return nil
}
func (n *NoDB) DeleteAdmin(ctx context.Context, id string) error {
return nil
}
// MockDB is an implementation of the DB interface that should only be used as // MockDB is an implementation of the DB interface that should only be used as
// a mock in tests. // a mock in tests.
type MockDB struct { type MockDB struct {

View file

@ -49,7 +49,7 @@ func (a *Authority) StoreAdmin(ctx context.Context, adm *linkedca.Admin, prov pr
return admin.WrapErrorISE(err, "error creating admin") return admin.WrapErrorISE(err, "error creating admin")
} }
if err := a.admins.Store(adm, prov); err != nil { if err := a.admins.Store(adm, prov); err != nil {
if err := a.reloadAdminResources(ctx); err != nil { if err := a.ReloadAdminResources(ctx); err != nil {
return admin.WrapErrorISE(err, "error reloading admin resources on failed admin store") return admin.WrapErrorISE(err, "error reloading admin resources on failed admin store")
} }
return admin.WrapErrorISE(err, "error storing admin in authority cache") return admin.WrapErrorISE(err, "error storing admin in authority cache")
@ -66,7 +66,7 @@ func (a *Authority) UpdateAdmin(ctx context.Context, id string, nu *linkedca.Adm
return nil, admin.WrapErrorISE(err, "error updating cached admin %s", id) return nil, admin.WrapErrorISE(err, "error updating cached admin %s", id)
} }
if err := a.adminDB.UpdateAdmin(ctx, adm); err != nil { if err := a.adminDB.UpdateAdmin(ctx, adm); err != nil {
if err := a.reloadAdminResources(ctx); err != nil { if err := a.ReloadAdminResources(ctx); err != nil {
return nil, admin.WrapErrorISE(err, "error reloading admin resources on failed admin update") return nil, admin.WrapErrorISE(err, "error reloading admin resources on failed admin update")
} }
return nil, admin.WrapErrorISE(err, "error updating admin %s", id) return nil, admin.WrapErrorISE(err, "error updating admin %s", id)
@ -88,7 +88,7 @@ func (a *Authority) removeAdmin(ctx context.Context, id string) error {
return admin.WrapErrorISE(err, "error removing admin %s from authority cache", id) return admin.WrapErrorISE(err, "error removing admin %s from authority cache", id)
} }
if err := a.adminDB.DeleteAdmin(ctx, id); err != nil { if err := a.adminDB.DeleteAdmin(ctx, id); err != nil {
if err := a.reloadAdminResources(ctx); err != nil { if err := a.ReloadAdminResources(ctx); err != nil {
return admin.WrapErrorISE(err, "error reloading admin resources on failed admin remove") return admin.WrapErrorISE(err, "error reloading admin resources on failed admin remove")
} }
return admin.WrapErrorISE(err, "error deleting admin %s", id) return admin.WrapErrorISE(err, "error deleting admin %s", id)

View file

@ -115,6 +115,20 @@ func New(cfg *config.Config, opts ...Option) (*Authority, error) {
return a, nil return a, nil
} }
// FromOptions creates an Authority exclusively using the passed in options
// and does not intialize the Authority.
func FromOptions(opts ...Option) (*Authority, error) {
var a = new(Authority)
// Apply options.
for _, fn := range opts {
if err := fn(a); err != nil {
return nil, err
}
}
return a, nil
}
// NewEmbedded initializes an authority that can be embedded in a different // NewEmbedded initializes an authority that can be embedded in a different
// project without the limitations of the config. // project without the limitations of the config.
func NewEmbedded(opts ...Option) (*Authority, error) { func NewEmbedded(opts ...Option) (*Authority, error) {
@ -153,8 +167,8 @@ func NewEmbedded(opts ...Option) (*Authority, error) {
return a, nil return a, nil
} }
// reloadAdminResources reloads admins and provisioners from the DB. // ReloadAdminResources reloads admins and provisioners from the DB.
func (a *Authority) reloadAdminResources(ctx context.Context) error { func (a *Authority) ReloadAdminResources(ctx context.Context) error {
var ( var (
provList provisioner.List provList provisioner.List
adminList []*linkedca.Admin adminList []*linkedca.Admin
@ -551,7 +565,7 @@ func (a *Authority) init() error {
} }
// Load Provisioners and Admins // Load Provisioners and Admins
if err := a.reloadAdminResources(context.Background()); err != nil { if err := a.ReloadAdminResources(context.Background()); err != nil {
return err return err
} }
@ -587,6 +601,12 @@ func (a *Authority) GetAdminDatabase() admin.DB {
return a.adminDB return a.adminDB
} }
// GetConfig returns the config.
func (a *Authority) GetConfig() *config.Config {
return a.config
}
// GetInfo returns information about the authority.
func (a *Authority) GetInfo() Info { func (a *Authority) GetInfo() Info {
ai := Info{ ai := Info{
StartTime: a.startTime, StartTime: a.startTime,

View file

@ -145,7 +145,7 @@ func (a *Authority) generateProvisionerConfig(ctx context.Context) (provisioner.
} }
// StoreProvisioner stores an provisioner.Interface to the authority. // StoreProvisioner stores a provisioner to the authority.
func (a *Authority) StoreProvisioner(ctx context.Context, prov *linkedca.Provisioner) error { func (a *Authority) StoreProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
a.adminMutex.Lock() a.adminMutex.Lock()
defer a.adminMutex.Unlock() defer a.adminMutex.Unlock()
@ -191,7 +191,7 @@ func (a *Authority) StoreProvisioner(ctx context.Context, prov *linkedca.Provisi
} }
if err := a.provisioners.Store(certProv); err != nil { if err := a.provisioners.Store(certProv); err != nil {
if err := a.reloadAdminResources(ctx); err != nil { if err := a.ReloadAdminResources(ctx); err != nil {
return admin.WrapErrorISE(err, "error reloading admin resources on failed provisioner store") return admin.WrapErrorISE(err, "error reloading admin resources on failed provisioner store")
} }
return admin.WrapErrorISE(err, "error storing provisioner in authority cache") return admin.WrapErrorISE(err, "error storing provisioner in authority cache")
@ -223,7 +223,7 @@ func (a *Authority) UpdateProvisioner(ctx context.Context, nu *linkedca.Provisio
return admin.WrapErrorISE(err, "error updating provisioner '%s' in authority cache", nu.Name) return admin.WrapErrorISE(err, "error updating provisioner '%s' in authority cache", nu.Name)
} }
if err := a.adminDB.UpdateProvisioner(ctx, nu); err != nil { if err := a.adminDB.UpdateProvisioner(ctx, nu); err != nil {
if err := a.reloadAdminResources(ctx); err != nil { if err := a.ReloadAdminResources(ctx); err != nil {
return admin.WrapErrorISE(err, "error reloading admin resources on failed provisioner update") return admin.WrapErrorISE(err, "error reloading admin resources on failed provisioner update")
} }
return admin.WrapErrorISE(err, "error updating provisioner '%s'", nu.Name) return admin.WrapErrorISE(err, "error updating provisioner '%s'", nu.Name)
@ -267,7 +267,7 @@ func (a *Authority) RemoveProvisioner(ctx context.Context, id string) error {
} }
// Remove provisioner from database. // Remove provisioner from database.
if err := a.adminDB.DeleteProvisioner(ctx, provID); err != nil { if err := a.adminDB.DeleteProvisioner(ctx, provID); err != nil {
if err := a.reloadAdminResources(ctx); err != nil { if err := a.ReloadAdminResources(ctx); err != nil {
return admin.WrapErrorISE(err, "error reloading admin resources on failed provisioner remove") return admin.WrapErrorISE(err, "error reloading admin resources on failed provisioner remove")
} }
return admin.WrapErrorISE(err, "error deleting provisioner %s", provName) return admin.WrapErrorISE(err, "error deleting provisioner %s", provName)

View file

@ -363,19 +363,19 @@ retry:
// GetProvisioner performs the GET /admin/provisioners/{name} request to the CA. // GetProvisioner performs the GET /admin/provisioners/{name} request to the CA.
func (c *AdminClient) GetProvisioner(opts ...ProvisionerOption) (*linkedca.Provisioner, error) { func (c *AdminClient) GetProvisioner(opts ...ProvisionerOption) (*linkedca.Provisioner, error) {
var retried bool var retried bool
o := new(provisionerOptions) o := new(ProvisionerOptions)
if err := o.apply(opts); err != nil { if err := o.Apply(opts); err != nil {
return nil, err return nil, err
} }
var u *url.URL var u *url.URL
switch { switch {
case len(o.id) > 0: case len(o.ID) > 0:
u = c.endpoint.ResolveReference(&url.URL{ u = c.endpoint.ResolveReference(&url.URL{
Path: "/admin/provisioners/id", Path: "/admin/provisioners/id",
RawQuery: o.rawQuery(), RawQuery: o.rawQuery(),
}) })
case len(o.name) > 0: case len(o.Name) > 0:
u = c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", o.name)}) u = c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", o.Name)})
default: default:
return nil, errors.New("must set either name or id in method options") return nil, errors.New("must set either name or id in method options")
} }
@ -410,8 +410,8 @@ retry:
// GetProvisionersPaginate performs the GET /admin/provisioners request to the CA. // GetProvisionersPaginate performs the GET /admin/provisioners request to the CA.
func (c *AdminClient) GetProvisionersPaginate(opts ...ProvisionerOption) (*adminAPI.GetProvisionersResponse, error) { func (c *AdminClient) GetProvisionersPaginate(opts ...ProvisionerOption) (*adminAPI.GetProvisionersResponse, error) {
var retried bool var retried bool
o := new(provisionerOptions) o := new(ProvisionerOptions)
if err := o.apply(opts); err != nil { if err := o.Apply(opts); err != nil {
return nil, err return nil, err
} }
u := c.endpoint.ResolveReference(&url.URL{ u := c.endpoint.ResolveReference(&url.URL{
@ -472,19 +472,19 @@ func (c *AdminClient) RemoveProvisioner(opts ...ProvisionerOption) error {
retried bool retried bool
) )
o := new(provisionerOptions) o := new(ProvisionerOptions)
if err := o.apply(opts); err != nil { if err := o.Apply(opts); err != nil {
return err return err
} }
switch { switch {
case len(o.id) > 0: case len(o.ID) > 0:
u = c.endpoint.ResolveReference(&url.URL{ u = c.endpoint.ResolveReference(&url.URL{
Path: path.Join(adminURLPrefix, "provisioners/id"), Path: path.Join(adminURLPrefix, "provisioners/id"),
RawQuery: o.rawQuery(), RawQuery: o.rawQuery(),
}) })
case len(o.name) > 0: case len(o.Name) > 0:
u = c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", o.name)}) u = c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", o.Name)})
default: default:
return errors.New("must set either name or id in method options") return errors.New("must set either name or id in method options")
} }

View file

@ -425,16 +425,17 @@ func parseEndpoint(endpoint string) (*url.URL, error) {
} }
// ProvisionerOption is the type of options passed to the Provisioner method. // ProvisionerOption is the type of options passed to the Provisioner method.
type ProvisionerOption func(o *provisionerOptions) error type ProvisionerOption func(o *ProvisionerOptions) error
type provisionerOptions struct { // ProvisionerOptions stores options for the provisioner CRUD API.
cursor string type ProvisionerOptions struct {
limit int Cursor string
id string Limit int
name string ID string
Name string
} }
func (o *provisionerOptions) apply(opts []ProvisionerOption) (err error) { func (o *ProvisionerOptions) Apply(opts []ProvisionerOption) (err error) {
for _, fn := range opts { for _, fn := range opts {
if err = fn(o); err != nil { if err = fn(o); err != nil {
return return
@ -443,51 +444,51 @@ func (o *provisionerOptions) apply(opts []ProvisionerOption) (err error) {
return return
} }
func (o *provisionerOptions) rawQuery() string { func (o *ProvisionerOptions) rawQuery() string {
v := url.Values{} v := url.Values{}
if len(o.cursor) > 0 { if len(o.Cursor) > 0 {
v.Set("cursor", o.cursor) v.Set("cursor", o.Cursor)
} }
if o.limit > 0 { if o.Limit > 0 {
v.Set("limit", strconv.Itoa(o.limit)) v.Set("limit", strconv.Itoa(o.Limit))
} }
if len(o.id) > 0 { if len(o.ID) > 0 {
v.Set("id", o.id) v.Set("id", o.ID)
} }
if len(o.name) > 0 { if len(o.Name) > 0 {
v.Set("name", o.name) v.Set("name", o.Name)
} }
return v.Encode() return v.Encode()
} }
// WithProvisionerCursor will request the provisioners starting with the given cursor. // WithProvisionerCursor will request the provisioners starting with the given cursor.
func WithProvisionerCursor(cursor string) ProvisionerOption { func WithProvisionerCursor(cursor string) ProvisionerOption {
return func(o *provisionerOptions) error { return func(o *ProvisionerOptions) error {
o.cursor = cursor o.Cursor = cursor
return nil return nil
} }
} }
// WithProvisionerLimit will request the given number of provisioners. // WithProvisionerLimit will request the given number of provisioners.
func WithProvisionerLimit(limit int) ProvisionerOption { func WithProvisionerLimit(limit int) ProvisionerOption {
return func(o *provisionerOptions) error { return func(o *ProvisionerOptions) error {
o.limit = limit o.Limit = limit
return nil return nil
} }
} }
// WithProvisionerID will request the given provisioner. // WithProvisionerID will request the given provisioner.
func WithProvisionerID(id string) ProvisionerOption { func WithProvisionerID(id string) ProvisionerOption {
return func(o *provisionerOptions) error { return func(o *ProvisionerOptions) error {
o.id = id o.ID = id
return nil return nil
} }
} }
// WithProvisionerName will request the given provisioner. // WithProvisionerName will request the given provisioner.
func WithProvisionerName(name string) ProvisionerOption { func WithProvisionerName(name string) ProvisionerOption {
return func(o *provisionerOptions) error { return func(o *ProvisionerOptions) error {
o.name = name o.Name = name
return nil return nil
} }
} }
@ -810,8 +811,8 @@ retry:
// paginate the provisioners. // paginate the provisioners.
func (c *Client) Provisioners(opts ...ProvisionerOption) (*api.ProvisionersResponse, error) { func (c *Client) Provisioners(opts ...ProvisionerOption) (*api.ProvisionersResponse, error) {
var retried bool var retried bool
o := new(provisionerOptions) o := new(ProvisionerOptions)
if err := o.apply(opts); err != nil { if err := o.Apply(opts); err != nil {
return nil, err return nil, err
} }
u := c.endpoint.ResolveReference(&url.URL{ u := c.endpoint.ResolveReference(&url.URL{