Skip to content

Commit 73dd46e

Browse files
committed
Hard-fail on config parsing errors
Signed-off-by: David Son <davbson@amazon.com>
1 parent 3aa90d1 commit 73dd46e

4 files changed

Lines changed: 79 additions & 6 deletions

File tree

config/config.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
package config
4040

4141
import (
42+
"errors"
4243
"fmt"
4344
"os"
4445

@@ -84,8 +85,8 @@ func NewConfig() *Config {
8485

8586
// Set any defaults which do not align with Go zero values.
8687
var initParsers = []configParser{defaultPullModes, defaultDirectoryCacheConfig}
87-
for _, p := range append(initParsers, parsers...) {
88-
p(cfg)
88+
if err := parseConfig(cfg, append(initParsers, parsers...)); err != nil {
89+
return nil
8990
}
9091

9192
return cfg
@@ -102,18 +103,26 @@ func NewConfigFromToml(cfgPath string) (*Config, error) {
102103
defer f.Close()
103104

104105
cfg := NewConfig()
106+
if cfg == nil {
107+
return nil, errors.New("error creating default config")
108+
}
105109
// Get configuration from specified file
106110
if err = toml.NewDecoder(f).Decode(cfg); err != nil {
107111
return nil, fmt.Errorf("failed to load config file %q: %w", cfgPath, err)
108112
}
109-
parseConfig(cfg)
113+
if err := parseConfig(cfg, parsers); err != nil {
114+
return nil, fmt.Errorf("config file at %q: %w", cfgPath, err)
115+
}
110116
return cfg, nil
111117
}
112118

113-
func parseConfig(cfg *Config) {
114-
for _, p := range parsers {
115-
p(cfg)
119+
func parseConfig(cfg *Config, cfgParsers []configParser) error {
120+
for _, p := range cfgParsers {
121+
if err := p(cfg); err != nil {
122+
return fmt.Errorf("failed to parse config: %v", err)
123+
}
116124
}
125+
return nil
117126
}
118127

119128
func parseRootConfig(cfg *Config) error {

config/config_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@ concurrent_download_chunk_size = "1MB"
265265
}
266266
},
267267
},
268+
{
269+
name: "IncorrectChunkConfig",
270+
config: []byte(`
271+
[pull_modes.parallel_pull_unpack]
272+
concurrent_download_chunk_size = "badchunksize"
273+
`),
274+
assert: func(t *testing.T, actual *Config, err error) {
275+
if err == nil {
276+
t.Error("Expected error, got none")
277+
}
278+
},
279+
},
268280
}
269281

270282
for _, test := range tests {

integration/startup_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import (
2121
"regexp"
2222
"strings"
2323
"testing"
24+
"time"
2425

2526
"github.com/awslabs/soci-snapshotter/config"
2627
shell "github.com/awslabs/soci-snapshotter/util/dockershell"
28+
"github.com/awslabs/soci-snapshotter/util/testutil"
2729
"github.com/rs/xid"
2830
)
2931

@@ -137,3 +139,47 @@ func TestSnapshotterSystemdStartup(t *testing.T) {
137139
})
138140
}
139141
}
142+
143+
// TestSnapshotterStartupWithBadConfig ensures snapshotter does not start if snapshotter values are incorrect.
144+
// Note that incorrect fields are ignored by TOML and thus are expected to work
145+
func TestSnapshotterStartupWithBadConfig(t *testing.T) {
146+
tests := []struct {
147+
name string
148+
opts []snapshotterConfigOpt
149+
expectedErrStr string
150+
}{
151+
{
152+
name: "Bad parallel pull size",
153+
opts: []snapshotterConfigOpt{withParallelPullMode(), withConcurrentDownloadChunkSizeStr("badstring")},
154+
expectedErrStr: "invalid size format",
155+
},
156+
}
157+
158+
for _, tc := range tests {
159+
t.Run(tc.name, func(tt *testing.T) {
160+
sh, cleanup := newSnapshotterBaseShell(t)
161+
defer cleanup()
162+
// rebootContainerd would be ideal here, but that always uses a config,
163+
// so we just manually start SOCI with/without a config file.
164+
err := testutil.KillMatchingProcess(sh, "soci-snapshotter-grpc")
165+
if err != nil {
166+
sh.Fatal("failed to kill soci: %v", err)
167+
}
168+
configToml := getSnapshotterConfigToml(t, tc.opts...)
169+
snRunCmd := []string{"/usr/local/bin/soci-snapshotter-grpc", "--log-level", sociLogLevel}
170+
snRunCmd = addConfig(t, sh, configToml, snRunCmd...)
171+
172+
errCh := make(chan error, 1)
173+
go func() {
174+
_, err := sh.OLog(snRunCmd...)
175+
errCh <- err
176+
}()
177+
178+
select {
179+
case <-errCh:
180+
case <-time.After(2 * time.Second):
181+
t.Fatalf("expected err %s but snapshotter did not fail within 2 seconds", tc.expectedErrStr)
182+
}
183+
})
184+
}
185+
}

integration/util_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,12 @@ func withConcurrentDownloadChunkSize(chunkSize int64) snapshotterConfigOpt {
383383
}
384384
}
385385

386+
func withConcurrentDownloadChunkSizeStr(chunkSizeStr string) snapshotterConfigOpt {
387+
return func(c *config.Config) {
388+
c.PullModes.Parallel.ConcurrentDownloadChunkSizeStr = chunkSizeStr
389+
}
390+
}
391+
386392
func withConcurrentUnpacks(n int64) snapshotterConfigOpt {
387393
return func(c *config.Config) {
388394
c.PullModes.Parallel.MaxConcurrentUnpacks = n

0 commit comments

Comments
 (0)