Skip to content

Commit 32c46fe

Browse files
authored
choose whether to pull images or not, add strict TOML validation with helpful hints (#1239)
* choose whether to pull images or not add strict TOML validation with helpful hints
1 parent 3bb0113 commit 32c46fe

File tree

7 files changed

+53
-24
lines changed

7 files changed

+53
-24
lines changed

framework/COMPONENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ Each component can define inputs and outputs, following these rules:
4141
- `if input.Out != nil && framework.UseCache()` should be added if you'd like to use caching
4242

4343
### Docker components good practices for [testcontainers-go](https://golang.testcontainers.org/):
44+
45+
An example [simple component](components/blockchain/anvil.go)
46+
47+
An example of [complex component](components/clnode/clnode.go)
48+
49+
An example of [composite component](components/don/don.go)
50+
51+
- Inputs should include at least `image`, `tag` and `pull_image` field
52+
```
53+
Image string `toml:"image" validate:"required"`
54+
Tag string `toml:"tag" validate:"required"`
55+
PullImage bool `toml:"pull_image" validate:"required"`
56+
```
57+
4458
- `ContainerRequest` must contain labels, network and alias required for local observability stack and deployment isolation
4559
```
4660
Labels: framework.DefaultTCLabels(),

framework/components/blockchain/anvil.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ func deployAnvil(in *Input) (*Output, error) {
2323
containerName := framework.DefaultTCName("anvil")
2424

2525
req := testcontainers.ContainerRequest{
26-
Image: fmt.Sprintf("%s:%s", in.Image, in.Tag),
27-
Labels: framework.DefaultTCLabels(),
28-
Name: containerName,
29-
ExposedPorts: []string{bindPort},
30-
Networks: []string{framework.DefaultNetworkName},
26+
AlwaysPullImage: in.PullImage,
27+
Image: fmt.Sprintf("%s:%s", in.Image, in.Tag),
28+
Labels: framework.DefaultTCLabels(),
29+
Name: containerName,
30+
ExposedPorts: []string{bindPort},
31+
Networks: []string{framework.DefaultNetworkName},
3132
NetworkAliases: map[string][]string{
3233
framework.DefaultNetworkName: {containerName},
3334
},

framework/components/blockchain/blockchain.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type Input struct {
1010
Type string `toml:"type" validate:"required,oneof=anvil geth" envconfig:"net_type"`
1111
Image string `toml:"image" validate:"required"`
1212
Tag string `toml:"tag" validate:"required"`
13+
PullImage bool `toml:"pull_image" validate:"required"`
1314
Port string `toml:"port" validate:"required"`
1415
ChainID string `toml:"chain_id" validate:"required"`
1516
DockerCmdParamsOverrides []string `toml:"docker_cmd_params"`

framework/components/clnode/clnode.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type Input struct {
2626
type NodeInput struct {
2727
Image string `toml:"image" validate:"required"`
2828
Tag string `toml:"tag" validate:"required"`
29+
PullImage bool `toml:"pull_image" validate:"required"`
2930
Port string `toml:"port" validate:"required"`
3031
TestConfigOverrides string `toml:"test_config_overrides"`
3132
UserConfigOverrides string `toml:"user_config_overrides"`
@@ -107,10 +108,11 @@ func newNode(in *Input, pgOut *postgres.Output) (*NodeOut, error) {
107108
containerName := framework.DefaultTCName("clnode")
108109

109110
req := tc.ContainerRequest{
110-
Image: fmt.Sprintf("%s:%s", in.Node.Image, in.Node.Tag),
111-
Name: containerName,
112-
Labels: framework.DefaultTCLabels(),
113-
Networks: []string{framework.DefaultNetworkName},
111+
AlwaysPullImage: in.Node.PullImage,
112+
Image: fmt.Sprintf("%s:%s", in.Node.Image, in.Node.Tag),
113+
Name: containerName,
114+
Labels: framework.DefaultTCLabels(),
115+
Networks: []string{framework.DefaultNetworkName},
114116
NetworkAliases: map[string][]string{
115117
framework.DefaultNetworkName: {containerName},
116118
},

framework/components/postgres/postgres.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ import (
1111
)
1212

1313
type Input struct {
14-
User string `toml:"user" validate:"required"`
15-
Password string `toml:"password" validate:"required"`
16-
Database string `toml:"database" validate:"required"`
17-
Port string `toml:"port" validate:"required"`
18-
Out *Output `toml:"out"`
14+
Image string `toml:"image" validate:"required"`
15+
Tag string `toml:"tag" validate:"required"`
16+
PullImage bool `toml:"pull_image" validate:"required"`
17+
User string `toml:"user" validate:"required"`
18+
Password string `toml:"password" validate:"required"`
19+
Database string `toml:"database" validate:"required"`
20+
Port string `toml:"port" validate:"required"`
21+
Out *Output `toml:"out"`
1922
}
2023

2124
type Output struct {
@@ -31,11 +34,12 @@ func NewPostgreSQL(in *Input) (*Output, error) {
3134
containerName := framework.DefaultTCName("postgresql")
3235

3336
req := testcontainers.ContainerRequest{
34-
Image: "postgres:15.6",
35-
Name: containerName,
36-
Labels: framework.DefaultTCLabels(),
37-
ExposedPorts: []string{bindPort},
38-
Networks: []string{framework.DefaultNetworkName},
37+
AlwaysPullImage: in.PullImage,
38+
Image: fmt.Sprintf("%s:%s", in.Image, in.Tag),
39+
Name: containerName,
40+
Labels: framework.DefaultTCLabels(),
41+
ExposedPorts: []string{bindPort},
42+
Networks: []string{framework.DefaultNetworkName},
3943
NetworkAliases: map[string][]string{
4044
framework.DefaultNetworkName: {containerName},
4145
},

framework/input.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package framework
33
import (
44
"bytes"
55
"context"
6+
"errors"
67
"fmt"
78
"github.com/davecgh/go-spew/spew"
89
"github.com/go-playground/validator/v10"
@@ -63,17 +64,23 @@ func mergeInputs[T any]() (*T, error) {
6364
}
6465
for _, path := range paths {
6566
L.Info().Str("Path", path).Msg("Loading configuration input")
66-
file, err := os.ReadFile(filepath.Join(DefaultConfigDir, path))
67+
data, err := os.ReadFile(filepath.Join(DefaultConfigDir, path))
6768
if err != nil {
6869
return nil, fmt.Errorf("error reading promtailConfig file %s: %w", path, err)
6970
}
7071
if L.GetLevel() == zerolog.DebugLevel {
71-
fmt.Println(string(file))
72+
fmt.Println(string(data))
7273
}
7374

74-
err = toml.Unmarshal(file, &config)
75-
if err != nil {
76-
return nil, fmt.Errorf("error parsing config file %s: %w", path, err)
75+
decoder := toml.NewDecoder(strings.NewReader(string(data)))
76+
decoder.DisallowUnknownFields()
77+
78+
if err := decoder.Decode(&config); err != nil {
79+
var details *toml.StrictMissingError
80+
if errors.As(err, &details) {
81+
fmt.Println(details.String())
82+
}
83+
return nil, fmt.Errorf("failed to decode TOML config, strict mode: %s", err)
7784
}
7885
}
7986
if L.GetLevel() == zerolog.DebugLevel {

0 commit comments

Comments
 (0)