Skip to content

Commit

Permalink
config: rework into specific validators
Browse files Browse the repository at this point in the history
Signed-off-by: ldelossa <ldelossa@redhat.com>
  • Loading branch information
ldelossa authored and ldelossa committed Feb 4, 2021
1 parent 8105b03 commit f2d7313
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 85 deletions.
2 changes: 1 addition & 1 deletion cmd/clair/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func main() {
golog.Fatalf("failed to decode yaml config: %v", err)
}
conf.Mode = runMode.String()
err = config.Validate(conf)
err = config.Validate(&conf)
if err != nil {
golog.Fatalf("failed to validate config: %v", err)
}
Expand Down
66 changes: 16 additions & 50 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package config

import (
"fmt"
"net/url"
"strings"
"time"

"github.com/quay/claircore/libvuln/driver"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -108,64 +106,32 @@ func (u *Updaters) FilterSets(m map[string]driver.UpdaterSetFactory) {

// Validate confirms the necessary values to support
// the desired Clair Mode exist
func Validate(conf Config) error {
func Validate(conf *Config) error {
if conf.HTTPListenAddr == "" {
conf.HTTPListenAddr = DefaultAddress
}
switch strings.ToLower(conf.Mode) {
case ComboMode:
if conf.HTTPListenAddr == "" {
conf.HTTPListenAddr = DefaultAddress
}
if conf.Indexer.ConnString == "" {
return fmt.Errorf("indexer mode requires a database connection string")
}
if conf.Matcher.ConnString == "" {
return fmt.Errorf("matcher mode requires a database connection string")
}
if conf.Notifier.ConnString == "" {
return fmt.Errorf("notifier mode requires a database connection string")
if err := conf.Indexer.Validate(); err != nil {
return err
}
if conf.Matcher.Period == 0 {
conf.Matcher.Period = 30 * time.Minute
if err := conf.Matcher.Validate(); err != nil {
return err
}
if conf.Matcher.UpdateRetention < 2 {
conf.Matcher.UpdateRetention = 10
if err := conf.Notifier.Validate(); err != nil {
return err
}
case IndexerMode:
if conf.HTTPListenAddr == "" {
conf.HTTPListenAddr = DefaultAddress
}
if conf.Indexer.ConnString == "" {
return fmt.Errorf("indexer mode requires a database connection string")
if err := conf.Indexer.Validate(); err != nil {
return err
}
case MatcherMode:
if conf.HTTPListenAddr == "" {
conf.HTTPListenAddr = DefaultAddress
}
if conf.Matcher.ConnString == "" {
return fmt.Errorf("matcher mode requires a database connection string")
}

if conf.Matcher.IndexerAddr == "" {
return fmt.Errorf("matcher mode requires a remote Indexer address")
}
_, err := url.Parse(conf.Matcher.IndexerAddr)
if err != nil {
return fmt.Errorf("failed to url parse matcher mode IndexAddr string: %v", err)
}
if conf.Matcher.Period == 0 {
conf.Matcher.Period = 30 * time.Minute
}
if conf.Matcher.UpdateRetention < 2 {
conf.Matcher.UpdateRetention = 10
if err := conf.Matcher.Validate(); err != nil {
return err
}
case NotifierMode:
if conf.Notifier.ConnString == "" {
return fmt.Errorf("notifier mode requires a database connection string")
}
if conf.Notifier.IndexerAddr == "" {
return fmt.Errorf("notifier mode requires a remote Indexer")
}
if conf.Notifier.MatcherAddr == "" {
return fmt.Errorf("notifier mode requires a remote Matcher")
if err := conf.Notifier.Validate(); err != nil {
return err
}
default:
return fmt.Errorf("unknown mode received: %v", conf.Mode)
Expand Down
2 changes: 1 addition & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func Test_Config_Validate_Failure(t *testing.T) {

for _, tab := range table {
t.Run(tab.name, func(t *testing.T) {
if err := config.Validate(tab.conf); err == nil {
if err := config.Validate(&tab.conf); err == nil {
log.Fatalf("expected error for test case: %s", tab.name)
}
})
Expand Down
19 changes: 18 additions & 1 deletion config/indexer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package config

import "gopkg.in/yaml.v3"
import (
"fmt"

"gopkg.in/yaml.v3"
)

// Indexer provides Clair Indexer node configuration
type Indexer struct {
Expand Down Expand Up @@ -33,6 +37,19 @@ type Indexer struct {
Airgap bool `yaml:"airgap" json:"airgap"`
}

func (i *Indexer) Validate() error {
const (
DefaultScanLockRetry = 1
)
if i.ConnString == "" {
return fmt.Errorf("indexer mode requires a database connection string")
}
if i.ScanLockRetry == 0 {
i.ScanLockRetry = 1
}
return nil
}

type ScannerConfig struct {
Package map[string]yaml.Node `yaml:"package" json:"package"`
Dist map[string]yaml.Node `yaml:"dist" json:"dist"`
Expand Down
31 changes: 30 additions & 1 deletion config/matcher.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package config

import "time"
import (
"fmt"
"net/url"
"time"
)

type Matcher struct {
// A Postgres connection string.
Expand Down Expand Up @@ -41,3 +45,28 @@ type Matcher struct {
// purposes.
UpdateRetention int `yaml:"update_retention" json:"update_retention"`
}

func (m *Matcher) Validate() error {
const (
DefaultPeriod = 30 * time.Minute
DefaultRetention = 10
)
if m.ConnString == "" {
return fmt.Errorf("matcher requies a database connection string")
}
if m.IndexerAddr == "" {
return fmt.Errorf("matcher mode requires a remote Indexer address")
}

_, err := url.Parse(m.IndexerAddr)
if err != nil {
return fmt.Errorf("failed to url parse matcher mode IndexAddr string: %v", err)
}
if m.Period == 0 {
m.Period = DefaultPeriod
}
if m.UpdateRetention < 2 {
m.UpdateRetention = DefaultRetention
}
return nil
}
34 changes: 32 additions & 2 deletions config/notifier.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package config

import (
"fmt"
"time"

"github.com/quay/clair/v4/notifier/amqp"
"github.com/quay/clair/v4/notifier/stomp"
"github.com/quay/clair/v4/notifier/webhook"
Expand Down Expand Up @@ -32,12 +35,16 @@ type Notifier struct {
// A time.ParseDuration parsable string
//
// The frequency at which the notifier will query at Matcher for Update Operations.
PollInterval string `yaml:"poll_interval" json:"poll_interval"`
// If a value smaller then 1 second is provided it will be replaced with the
// default 5 second poll interval.
PollInterval time.Duration `yaml:"poll_interval" json:"poll_interval"`
// A time.ParseDuration parsable string
//
// The frequency at which the notifier attempt delivery of created or previously failed
// notifications
DeliveryInterval string `yaml:"delivery_interval" json:"delivery_interval"`
// If a value smaller then 1 second is provided it will be replaced with the
// default 5 second delivery interval.
DeliveryInterval time.Duration `yaml:"delivery_interval" json:"delivery_interval"`
// DisableSummary disables summarizing vulnerabilities per-manifest.
//
// The default is to summarize any new vulnerabilities to the most severe
Expand All @@ -57,3 +64,26 @@ type Notifier struct {
// Configures the notifier for STOMP delivery.
STOMP *stomp.Config `yaml:"stomp" json:"stomp"`
}

func (n *Notifier) Validate() error {
const (
DefaultPollInterval = 5 * time.Second
DefaultDeliveryInterval = 5 * time.Second
)
if n.ConnString == "" {
return fmt.Errorf("notifier mode requires a database connection string")
}
if n.IndexerAddr == "" {
return fmt.Errorf("notifier mode requires a remote Indexer")
}
if n.MatcherAddr == "" {
return fmt.Errorf("notifier mode requires a remote Matcher")
}
if n.PollInterval < 1*time.Second {
n.PollInterval = DefaultPollInterval
}
if n.DeliveryInterval < 1*time.Second {
n.DeliveryInterval = DefaultDeliveryInterval
}
return nil
}
33 changes: 4 additions & 29 deletions initialize/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,32 +83,19 @@ func (i *Init) Services() error {
return fmt.Errorf("failed to initialize libvuln: %v", err)
}

// configure notifier service
dInterval, err := time.ParseDuration(i.conf.Notifier.DeliveryInterval)
if err != nil {
return &clairerror.ErrNotInitialized{
Msg: "notifier: failed to parse delivery interval: " + err.Error(),
}
}
pInterval, err := time.ParseDuration(i.conf.Notifier.PollInterval)
if err != nil {
return &clairerror.ErrNotInitialized{
Msg: "notifier: failed to parse poll interval: " + err.Error(),
}
}
c, _, err := i.conf.Client(nil, notifierClaim)
if err != nil {
return err
}

n, err := notifier.New(i.GlobalCTX, notifier.Opts{
DeliveryInterval: dInterval,
DeliveryInterval: i.conf.Notifier.DeliveryInterval,
ConnString: i.conf.Notifier.ConnString,
Indexer: libI,
Matcher: libV,
Client: c,
Migrations: i.conf.Notifier.Migrations,
PollInterval: pInterval,
PollInterval: i.conf.Notifier.PollInterval,
DisableSummary: i.conf.Notifier.DisableSummary,
Webhook: i.conf.Notifier.Webhook,
AMQP: i.conf.Notifier.AMQP,
Expand Down Expand Up @@ -220,31 +207,19 @@ func (i *Init) Services() error {
return err
}

dInterval, err := time.ParseDuration(i.conf.Notifier.DeliveryInterval)
if err != nil {
return &clairerror.ErrNotInitialized{
Msg: "notifier: failed to parse delivery interval: " + err.Error(),
}
}
pInterval, err := time.ParseDuration(i.conf.Notifier.PollInterval)
if err != nil {
return &clairerror.ErrNotInitialized{
Msg: "notifier: failed to parse poll interval: " + err.Error(),
}
}
c, _, err = i.conf.Client(nil, notifierClaim)
if err != nil {
return err
}

n, err := notifier.New(i.GlobalCTX, notifier.Opts{
DeliveryInterval: dInterval,
DeliveryInterval: i.conf.Notifier.DeliveryInterval,
ConnString: i.conf.Notifier.ConnString,
Indexer: remoteIndexer,
Matcher: remoteMatcher,
Client: c,
Migrations: i.conf.Notifier.Migrations,
PollInterval: pInterval,
PollInterval: i.conf.Notifier.PollInterval,
Webhook: i.conf.Notifier.Webhook,
AMQP: i.conf.Notifier.AMQP,
STOMP: i.conf.Notifier.STOMP,
Expand Down

0 comments on commit f2d7313

Please sign in to comment.