Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for preflight check configuration #900

Merged
merged 1 commit into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkg/kapp/cmd/app/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ func (o *DeployOptions) Run() error {
}

if o.PreflightChecks != nil {
err = o.PreflightChecks.SetConfig(conf.PreflightRules())
if err != nil {
return fmt.Errorf("preflight configuration settings failed: %w", err)
}
err = o.PreflightChecks.Run(context.Background(), clusterChangesGraph)
if err != nil {
return fmt.Errorf("preflight checks failed: %w", err)
Expand Down
8 changes: 8 additions & 0 deletions pkg/kapp/config/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ func (c Conf) TemplateRules() []TemplateRule {
return result
}

func (c Conf) PreflightRules() []PreflightRule {
var result []PreflightRule
for _, config := range c.configs {
result = append(result, config.PreflightRules...)
}
return result
}

func (c Conf) DiffMaskRules() []DiffMaskRule {
var result []DiffMaskRule
for _, config := range c.configs {
Expand Down
6 changes: 6 additions & 0 deletions pkg/kapp/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type Config struct {
LabelScopingRules []LabelScopingRule
TemplateRules []TemplateRule
DiffMaskRules []DiffMaskRule
PreflightRules []PreflightRule

AdditionalLabels map[string]string
DiffAgainstLastAppliedFieldExclusionRules []DiffAgainstLastAppliedFieldExclusionRule
Expand Down Expand Up @@ -145,6 +146,11 @@ type ChangeRuleBinding struct {
ResourceMatchers []ResourceMatcher
}

type PreflightRule struct {
Name string
Config map[string]any
}

func NewConfigFromResource(res ctlres.Resource) (Config, error) {
if res.APIVersion() != configAPIVersion {
return Config{}, fmt.Errorf(
Expand Down
4 changes: 4 additions & 0 deletions pkg/kapp/permissions/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ func (p *Preflight) SetEnabled(enabled bool) {
p.enabled = enabled
}

func (p *Preflight) SetConfig(_ preflight.CheckConfig) error {
return nil
}

func (p *Preflight) Run(ctx context.Context, changeGraph *ctldgraph.ChangeGraph) error {
client, err := p.depsFactory.CoreClient()
if err != nil {
Expand Down
25 changes: 20 additions & 5 deletions pkg/kapp/preflight/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@ import (
ctldgraph "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/diffgraph"
)

type CheckFunc func(context.Context, *ctldgraph.ChangeGraph) error
type CheckFunc func(context.Context, *ctldgraph.ChangeGraph, CheckConfig) error
type CheckConfig map[string]any
type ConfigFunc func(CheckConfig) error

type Check interface {
Enabled() bool
SetEnabled(bool)
SetConfig(CheckConfig) error
Run(context.Context, *ctldgraph.ChangeGraph) error
}

type checkImpl struct {
enabled bool
checkFunc CheckFunc

config CheckConfig
configFunc ConfigFunc
}

func NewCheck(cf CheckFunc, enabled bool) Check {
func NewCheck(cf CheckFunc, sf ConfigFunc, enabled bool) Check {
return &checkImpl{
enabled: enabled,
checkFunc: cf,
enabled: enabled,
checkFunc: cf,
configFunc: sf,
}
}

Expand All @@ -37,6 +44,14 @@ func (cf *checkImpl) SetEnabled(enabled bool) {
cf.enabled = enabled
}

func (cf *checkImpl) SetConfig(config CheckConfig) error {
cf.config = config
if cf.configFunc != nil {
return cf.configFunc(config)
}
return nil
}

func (cf *checkImpl) Run(ctx context.Context, changeGraph *ctldgraph.ChangeGraph) error {
return cf.checkFunc(ctx, changeGraph)
return cf.checkFunc(ctx, changeGraph, cf.config)
}
66 changes: 57 additions & 9 deletions pkg/kapp/preflight/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/spf13/pflag"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/config"
ctldgraph "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/diffgraph"
)

Expand All @@ -17,6 +18,8 @@ const preflightFlag = "preflight"
// Registry is a collection of preflight checks
type Registry struct {
known map[string]Check
// Stores the enabled values from the command line
enabledFlag map[string]bool
}

// NewRegistry will return a new *Registry with the
Expand Down Expand Up @@ -59,25 +62,23 @@ func (c *Registry) Type() string {
// Returns an error if there is a problem
// parsing the preflight checks
func (c *Registry) Set(s string) error {
if c.known == nil {
if c.known == nil || c.enabledFlag == nil {
return nil
}

enabled := map[string]struct{}{}
// enable those specified
// Using enabledFlag allows multiple --preflight check flags to be specified
mappings := strings.Split(s, ",")
for _, key := range mappings {
if _, ok := c.known[key]; !ok {
return fmt.Errorf("unknown preflight check %q specified", key)
}
c.known[key].SetEnabled(true)
enabled[key] = struct{}{}
c.enabledFlag[key] = true
}
// disable unspecified validators

// enable/disabled based on validators specified
for key := range c.known {
if _, ok := enabled[key]; !ok {
c.known[key].SetEnabled(false)
}
enabled, ok := c.enabledFlag[key]
c.known[key].SetEnabled(ok && enabled)
}
return nil
}
Expand All @@ -101,9 +102,56 @@ func (c *Registry) AddCheck(name string, check Check) {
if c.known == nil {
c.known = make(map[string]Check)
}
if c.enabledFlag == nil {
c.enabledFlag = make(map[string]bool)
}
c.known[name] = check
}

// Validate the configuration provided; the rules are:
// 1. Unknown validator = error
// 2. Duplicate validator = error
func (c *Registry) validateConfig(conf []config.PreflightRule) error {
haveConfig := map[string]bool{}
for _, rule := range conf {
if _, ok := c.known[rule.Name]; !ok {
return fmt.Errorf("unknown preflight check in configuration: %q", rule.Name)
}
if _, ok := haveConfig[rule.Name]; ok {
return fmt.Errorf("duplicate preflight check in configuration: %q", rule.Name)
}
haveConfig[rule.Name] = true
}
return nil
}

func (c *Registry) SetConfig(conf []config.PreflightRule) error {
// We get the --preflight cmdline flag _before_ the configuration from the file.
// So, we need to evaluate the config that we've gotten in light of the enabledFlag
if err := c.validateConfig(conf); err != nil {
return err
}
// map the configuration by name
config := map[string]map[string]any{}
for _, rule := range conf {
config[rule.Name] = rule.Config
}
if len(c.enabledFlag) == 0 {
// no --preflight flag, so enable validators according to their presence in the config
for name, check := range c.known {
_, ok := config[name]
check.SetEnabled(ok)
}
}
for name, check := range c.known {
err := check.SetConfig(config[name])
if err != nil {
return fmt.Errorf("setting preflight config %q: %w", name, err)
}
}
return nil
}

// Run will execute any enabled preflight checks. The provided
// Context and ChangeGraph will be passed to the preflight checks
// that are being executed.
Expand Down
Loading
Loading