Skip to content

Commit 88f22a9

Browse files
committed
config: add top-level server configuration objects
Signed-off-by: Hank Donnay <hdonnay@redhat.com>
1 parent 320c953 commit 88f22a9

4 files changed

Lines changed: 195 additions & 11 deletions

File tree

config/api.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package config
2+
3+
import (
4+
"slices"
5+
"time"
6+
)
7+
8+
// API holds configuration for the Clair API services.
9+
type API struct {
10+
// V1 is the configuration for the HTTP v1 API.
11+
V1 APIv1 `yaml:"v1,omitempty" json:"v1,omitempty"`
12+
}
13+
14+
func (a *API) validate(_ Mode) ([]Warning, error) {
15+
// TODO(hank) When there's an "UpdaterMode," don't bother with validating
16+
// the API configurations.
17+
18+
enabled := slices.ContainsFunc([]*bool{}, func(e *bool) bool {
19+
return e != nil && *e
20+
})
21+
// With multiple versions, the highest one should be the default, probably.
22+
if !enabled {
23+
a.V1.Enabled = &[]bool{true}[0] // TODO(go1.26) Use the "new(true)" syntax.
24+
}
25+
26+
return nil, nil
27+
}
28+
29+
// APIv1 holds configuration values for the HTTP v1 API.
30+
type APIv1 struct {
31+
// Enabled configures enabling the API server at all.
32+
// The set of API endpoints served by any one process depends on the mode
33+
// the process is started in.
34+
//
35+
// If unset, defaults to "true".
36+
Enabled *bool `yaml:"enabled" json:"enabled"`
37+
38+
// Network configures the network type to be used for serving API requests.
39+
//
40+
// If unset, [DefaultAPIv1Network] will be used.
41+
// See also: [net.Dial].
42+
Network string `yaml:"network" json:"network"`
43+
44+
// Address configures the address to listen on for serving API requests.
45+
// The format depends on the "network" member.
46+
//
47+
// If unset, [DefaultAPIv1Address] will be used.
48+
// See also: [net.Dial].
49+
Address string `yaml:"address" json:"address"`
50+
51+
// IdleTimeout configures whether the Clair process should exit after not
52+
// handling any requests for a specified non-zero duration.
53+
IdleTimeout Duration `yaml:"idle_timeout" json:"idle_timeout"`
54+
55+
// TLS configures HTTPS support.
56+
//
57+
// Note that any non-trivial deployment means the certificate provided here
58+
// will need to be for the name the load balancer used to connect to a given
59+
// Clair instance.
60+
TLS *TLS `yaml:"tls,omitempty" json:"tls,omitempty"`
61+
}
62+
63+
func (a *APIv1) validate(_ Mode) ([]Warning, error) {
64+
if a.Enabled == nil || !*a.Enabled {
65+
return nil, nil
66+
}
67+
if a.Network == "" {
68+
a.Network = DefaultAPIv1Network
69+
}
70+
if a.Address == "" {
71+
a.Address = DefaultAPIv1Address
72+
}
73+
74+
return a.lint()
75+
}
76+
77+
func (a *APIv1) lint() (ws []Warning, err error) {
78+
if a.Network == "" {
79+
ws = append(ws, Warning{
80+
path: ".network",
81+
msg: `listen network not provided, default will be used`,
82+
})
83+
}
84+
if a.Address == "" {
85+
ws = append(ws, Warning{
86+
path: ".address",
87+
msg: `listen address not provided, default will be used`,
88+
})
89+
}
90+
91+
switch dur := time.Duration(a.IdleTimeout); {
92+
case dur == 0: // OK, disabled.
93+
case dur < (2 * time.Minute):
94+
ws = append(ws, Warning{
95+
path: ".idle_timeout",
96+
msg: `idle timeout seems short, may cause frequent startups`,
97+
})
98+
default: // OK, reasonably long.
99+
}
100+
101+
return ws, nil
102+
}

config/config.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,17 @@ type Config struct {
3131
// exposes Clair's metrics and health endpoints.
3232
IntrospectionAddr string `yaml:"introspection_addr" json:"introspection_addr"`
3333
// Set the logging level.
34-
LogLevel LogLevel `yaml:"log_level" json:"log_level"`
35-
Indexer Indexer `yaml:"indexer,omitempty" json:"indexer,omitempty"`
36-
Matcher Matcher `yaml:"matcher,omitempty" json:"matcher,omitempty"`
37-
Matchers Matchers `yaml:"matchers,omitempty" json:"matchers,omitempty"`
38-
Updaters Updaters `yaml:"updaters,omitempty" json:"updaters,omitempty"`
39-
Notifier Notifier `yaml:"notifier,omitempty" json:"notifier,omitempty"`
40-
Auth Auth `yaml:"auth,omitempty" json:"auth,omitempty"`
41-
Trace Trace `yaml:"trace,omitempty" json:"trace,omitempty"`
42-
Metrics Metrics `yaml:"metrics,omitempty" json:"metrics,omitempty"`
34+
LogLevel LogLevel `yaml:"log_level" json:"log_level"`
35+
Indexer Indexer `yaml:"indexer,omitempty" json:"indexer,omitempty"`
36+
Matcher Matcher `yaml:"matcher,omitempty" json:"matcher,omitempty"`
37+
Matchers Matchers `yaml:"matchers,omitempty" json:"matchers,omitempty"`
38+
Updaters Updaters `yaml:"updaters,omitempty" json:"updaters,omitempty"`
39+
Notifier Notifier `yaml:"notifier,omitempty" json:"notifier,omitempty"`
40+
Auth Auth `yaml:"auth,omitempty" json:"auth,omitempty"`
41+
Trace Trace `yaml:"trace,omitempty" json:"trace,omitempty"`
42+
Metrics Metrics `yaml:"metrics,omitempty" json:"metrics,omitempty"`
43+
API API `yaml:"api,omitempty" json:"api,omitempty"`
44+
Introspection Introspection `yaml:"introspection,omitempty" json:"introspection,omitempty"`
4345
}
4446

4547
func (c *Config) validate(mode Mode) ([]Warning, error) {

config/defaults.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,20 @@ import "time"
44

55
// These are defaults, used in the documented spots.
66
const (
7-
// DefaultAddress is used if an "http_listen_addr" is not provided in the config.
8-
DefaultAddress = ":6060"
7+
// DefaultAPIv1Network is used if a network for the v1 API is not provided
8+
// in the config.
9+
DefaultAPIv1Network = "tcp"
10+
// DefaultAPIv1Address is used if an address for the v1 API is not provided
11+
// in the config.
12+
DefaultAPIv1Address = ":6060"
13+
14+
// DefaultIntrospectionNetwork is used if a network for the Introspection
15+
// server is not provided in the config.
16+
DefaultIntrospectionNetwork = "tcp"
17+
// DefaultIntrospectionAddress is used if an address for the Introspection
18+
// server is not provided in the config.
19+
DefaultIntrospectionAddress = ":8089"
20+
921
// DefaultScanLockRetry is the default retry period for attempting locks
1022
// during the indexing process. Its name is a historical accident.
1123
DefaultScanLockRetry = 1
@@ -23,3 +35,8 @@ const (
2335
// outstanding notifications at this rate.
2436
DefaultNotifierDeliveryInterval = 1 * time.Hour
2537
)
38+
39+
// DefaultAddress is the previous name of [DefaultAPIv1Address].
40+
//
41+
// Deprecated: Refer to [DefaultAPIv1Address] directly.
42+
const DefaultAddress = DefaultAPIv1Address

config/introspection.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,69 @@ package config
22

33
import "fmt"
44

5+
// Introspection is the configuration for Clair's introspection and debugging
6+
// endpoints.
7+
type Introspection struct {
8+
// Enabled configures enabling the Introspection server at all.
9+
//
10+
// If unset, defaults to "true".
11+
Enabled *bool `yaml:"enabled" json:"enabled"`
12+
13+
// Required configures Clair to exit with an error if the Introspection
14+
// server fails to start.
15+
//
16+
// Defaults to "false".
17+
Required bool `yaml:"required" json:"required"`
18+
19+
// Network configures the network type to be used for serving Introspection
20+
// requests.
21+
//
22+
// If unset, [DefaultIntrospectionNetwork] will be used.
23+
// See also: [net.Dial].
24+
Network string `yaml:"network" json:"network"`
25+
26+
// Address configures the address to listen on for serving Introspection
27+
// requests. The format depends on the "network" member.
28+
//
29+
// If unset, [DefaultIntrospectionAddress] will be used.
30+
// See also: [net.Dial].
31+
Address string `yaml:"address" json:"address"`
32+
}
33+
34+
func (i *Introspection) validate(_ Mode) ([]Warning, error) {
35+
switch {
36+
case i.Enabled == nil:
37+
i.Enabled = &[]bool{true}[0] // TODO(go1.26) Use the "new(true)" syntax.
38+
case !*i.Enabled:
39+
return nil, nil
40+
}
41+
if i.Network == "" {
42+
i.Network = DefaultIntrospectionNetwork
43+
}
44+
if i.Address == "" {
45+
i.Address = DefaultIntrospectionAddress
46+
}
47+
48+
return i.lint()
49+
}
50+
51+
func (i *Introspection) lint() (ws []Warning, err error) {
52+
if i.Network == "" {
53+
ws = append(ws, Warning{
54+
path: ".network",
55+
msg: `listen network not provided, default will be used`,
56+
})
57+
}
58+
if i.Address == "" {
59+
ws = append(ws, Warning{
60+
path: ".address",
61+
msg: `listen address not provided, default will be used`,
62+
})
63+
}
64+
65+
return ws, nil
66+
}
67+
568
// Trace specifies how to configure Clair's tracing support.
669
//
770
// The "Name" key must match the provider to use.

0 commit comments

Comments
 (0)