Skip to content

Commit

Permalink
Work to align to Agustin's design goals.
Browse files Browse the repository at this point in the history
Signed-off-by: Edwin Buck <edwbuck@gmail.com>
  • Loading branch information
edwbuck committed Dec 10, 2024
1 parent d05c2d1 commit 4f2cafa
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 23 deletions.
16 changes: 10 additions & 6 deletions cmd/spire-server/cli/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,24 @@ func (c *validateCommand) Run(args []string) int {
ctx = context.Background()
}

err = s.Run(ctx)
result, err := s.ValidateConfig(ctx)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / unit-test (macos-latest)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / unit-test (ubuntu-22.04)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / lint (linux)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)) (typecheck)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / lint (linux)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / artifacts (windows)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / unit-test (linux with race detection)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)

Check failure on line 71 in cmd/spire-server/cli/validate/validate.go

View workflow job for this annotation

GitHub Actions / unit-test (windows)

s.ValidateConfig undefined (type *"github.com/spiffe/spire/pkg/server".Server has no field or method ValidateConfig)
if err != nil {
config.Log.WithError(err).Error("Validation failed: validation server crashed")
config.Log.WithError(err).Errorf("Validation failed: %s", err)
return 1
}

// required to add Valid json output flag
err = c.printer.PrintStruct(&validateResult{
Valid: config.ValidationError == "",
Error: config.ValidationError,
Notes: config.ValidationNotes,
Valid: result.ValidationError == "",
Error: result.ValidationError,
Notes: result.ValidationNotes,
})


if err != nil {
return 1
}

return 0
}

Expand All @@ -98,7 +102,7 @@ func (c *validateCommand) prettyPrintValidate(env *commoncli.Env, results ...any
return errors.New("unexpected type")
}
// pretty print error section
if !result.Valid {
if result.Error != "" {
if err := env.Printf("Validation error:\n"); err != nil {
return err
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/common/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,13 @@ func Load(ctx context.Context, config *Config, repo Repository) (_ *Catalog, err
}, nil
}

func GetPluginConfigString(c PluginConfig) (string, error) {
if c.DataSource == nil {
return "", nil
}
return c.DataSource.Load()
}

func makePluginLog(log logrus.FieldLogger, pluginConfig PluginConfig) logrus.FieldLogger {
return log.WithFields(logrus.Fields{
telemetry.PluginName: pluginConfig.Name,
Expand Down
61 changes: 61 additions & 0 deletions pkg/common/validation/validationResult.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package validation

import (
"errors"
"fmt"
)

/* Captures the result of a configuration validation */
// TODO: make ValidationError validationError
// TODO: make ValidationNotes validationNotes
type ValidationResult struct {
ValidationError string `json:"error"`
ValidationNotes []string `json:"notes"`
}

func (v *ValidationResult) Error() error {
if v.ValidationError != "" {
return errors.New(v.ValidationError)
}
return nil
}

func (v *ValidationResult) HasError() bool {
return v.ValidationError != ""
}

func (v *ValidationResult) ReportError(message string) {
if v.ValidationError == "" {
v.ValidationError = message
}
v.ValidationNotes = append(v.ValidationNotes, message)
}

func (v *ValidationResult) ReportErrorf(format string, params ...any) {
v.ReportError(fmt.Sprintf(format, params...))
}

func (v *ValidationResult) ReportInfo(message string) {
v.ValidationNotes = append(v.ValidationNotes, message)
}

func (v *ValidationResult) ReportInfof(format string, params ...any) {
v.ReportInfo(fmt.Sprintf(format, params...))
}

func (v *ValidationResult) Merge(other ValidationResult) {
if v.ValidationError == "" {
v.ValidationError = other.ValidationError
}
v.ValidationNotes = append(v.ValidationNotes, other.ValidationNotes...)
}

func (v *ValidationResult) MergeWithFormat(format string, other ValidationResult) {
if v.ValidationError == "" && other.ValidationError != "" {
v.ValidationError = fmt.Sprintf(format, other.ValidationError)
}
for _, note := range other.ValidationNotes {
v.ValidationNotes = append(v.ValidationNotes, fmt.Sprintf(format, note))
}
}

75 changes: 59 additions & 16 deletions pkg/server/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package catalog

import (
"context"
"errors"
"fmt"
"io"

"github.com/andres-erbsen/clock"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/spiffe/go-spiffe/v2/spiffeid"
"github.com/spiffe/spire-plugin-sdk/pluginsdk"
metricsv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/common/metrics/v1"
Expand All @@ -17,6 +17,7 @@ import (
"github.com/spiffe/spire/pkg/common/health"
"github.com/spiffe/spire/pkg/common/hostservice/metricsservice"
"github.com/spiffe/spire/pkg/common/telemetry"
"github.com/spiffe/spire/pkg/common/validation"
ds_telemetry "github.com/spiffe/spire/pkg/common/telemetry/server/datastore"
km_telemetry "github.com/spiffe/spire/pkg/common/telemetry/server/keymanager"
"github.com/spiffe/spire/pkg/server/cache/dscache"
Expand Down Expand Up @@ -208,40 +209,41 @@ func Load(ctx context.Context, config *Config) (_ *Repository, err error) {
return repo, nil
}

func validateSQLConfig(config *Config) (catalog.PluginConfig, PluginConfigs, error) {
func validateSQLConfig(config *Config) (catalog.PluginConfig, PluginConfigs, validation.ValidationResult) {
vr := validation.ValidationResult{}
datastoreConfigs, pluginConfigs := config.PluginConfigs.FilterByType(dataStoreType)

switch {
case len(datastoreConfigs) == 0:
config.ReportError("expecting a DataStore plugin")
return catalog.PluginConfig{}, PluginConfigs(nil), errors.New("expecting a DataStore plugin")
vr.ReportError("expecting a DataStore plugin")
case len(datastoreConfigs) > 1:
config.ReportError("only one DataStore plugin is allowed")
return catalog.PluginConfig{}, PluginConfigs(nil), errors.New("only one DataStore plugin is allowed")
vr.ReportError("only one DataStore plugin is allowed")
}

datastoreConfig := datastoreConfigs[0]

if datastoreConfig.Name != ds_sql.PluginName {
config.ReportErrorf("pluggability for the DataStore is deprecated; only the built-in %q plugin is supported", ds_sql.PluginName)
return catalog.PluginConfig{}, PluginConfigs(nil), fmt.Errorf("pluggability for the DataStore is deprecated; only the built-in %q plugin is supported", ds_sql.PluginName)
vr.ReportErrorf("pluggability for the DataStore is deprecated; only the built-in %q plugin is supported", ds_sql.PluginName)
}
if datastoreConfig.IsExternal() {
config.ReportErrorf("pluggability for the DataStore is deprecated; only the built-in %q plugin is supported", ds_sql.PluginName)
return catalog.PluginConfig{}, PluginConfigs(nil), fmt.Errorf("pluggability for the DataStore is deprecated; only the built-in %q plugin is supported", ds_sql.PluginName)
vr.ReportErrorf("pluggability for the DataStore is deprecated; only the built-in %q plugin is supported", ds_sql.PluginName)
}
if datastoreConfig.DataSource == nil {
config.ReportError("internal: DataStore is missing a configuration data source")
vr.ReportError("internal: DataStore is missing a configuration data source")
} else if datastoreConfig.DataSource.IsDynamic() {
config.ReportInfo("DataStore is not reconfigurable even with a dynamic data source")
vr.ReportInfo("DataStore is not reconfigurable even with a dynamic data source")
}

return datastoreConfig, pluginConfigs, nil
if vr.HasError() {
return catalog.PluginConfig{}, PluginConfigs(nil), vr
}
return datastoreConfig, pluginConfigs, vr
}

func loadSQLDataStore(ctx context.Context, config *Config, coreConfig catalog.CoreConfig) (*ds_sql.Plugin, PluginConfigs, error) {
dataStoreConfig, pluginConfigs, err := validateSQLConfig(config)
if err != nil {
return nil, nil, err
dataStoreConfig, pluginConfigs, result := validateSQLConfig(config)
if result.HasError() {
return nil, nil, result.Error()
}
if dataStoreConfig.DataSource == nil {
dataStoreConfig.DataSource = catalog.FixedData("")
Expand All @@ -256,3 +258,44 @@ func loadSQLDataStore(ctx context.Context, config *Config, coreConfig catalog.Co
config.Log.WithField(telemetry.Reconfigurable, false).Info("Configured DataStore")
return ds, pluginConfigs, nil
}

func ValidateConfig(ctx context.Context, config *Config) (*validation.ValidationResult, error) {
validationResult := &validation.ValidationResult{}
if c, ok := config.PluginConfigs.Find(nodeAttestorType, jointoken.PluginName); ok && c.IsEnabled() && c.IsExternal() {
validationResult.ReportError("server catalog: the built-in join_token node attestor cannot be overridden by an external plugin")
// TODO: filter out plugin and continue
}

nullLogger, _ := test.NewNullLogger()
repo := &Repository{
log: nullLogger,
}
defer func() {
repo.Close()
}()

coreConfig := catalog.CoreConfig{
TrustDomain: config.TrustDomain,
}

dataStoreConfig, _, result := validateSQLConfig(config)
validationResult.MergeWithFormat("server catalog: %s", result)
if result.HasError() {
return validationResult, nil
}

ds := ds_sql.New(nullLogger)
dsConfigString, err := dataStoreConfig.DataSource.Load()
if err != nil {
validationResult.ReportError("server catalog: error loading sql datastore plugin config")
}
resp, err := ds.Validate(ctx, coreConfig, dsConfigString)
fmt.Printf("edwin: %+v, config=%s\n", ds, dsConfigString)
fmt.Printf("edwin: %+v, error=%+v\n", resp, err)

if err != nil {
validationResult.ReportError("server catalog: error validating sql datastore plugin config")
}

return validationResult, nil
}
2 changes: 1 addition & 1 deletion pkg/server/datastore/sqlstore/sqlstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ func (ds *Plugin) Configure(_ context.Context, _ catalog.CoreConfig, hclConfigur
}

func (ds *Plugin) Validate(_ context.Context, _ catalog.CoreConfig, hclConfiguration string) (*catalog.ValidateResult, error) {
return nil, nil
return nil, fmt.Errorf("%s", "edwin")
}

func (ds *Plugin) openConnections(config *configuration) error {
Expand Down

0 comments on commit 4f2cafa

Please sign in to comment.