Skip to content

Commit 4179216

Browse files
mbiagettiNiccoloFeigbartolinimnencia
authored
feat: make CREATE EXTENSION tests optional (#92)
Adds a `create_extension` boolean field to extension metadata so that extensions providing only libraries or tools (e.g. wal2json) can skip `CREATE EXTENSION` tests. When `create_extension` is `false`, the extension is omitted entirely from the Database CR's `extensions_spec` and the status assertion skips the `extensions` field. The generated `database_assert_status` map conditionally includes or excludes the `extensions` key, avoiding the Chainsaw limitation where `extensions: null` would require the field to exist in the actual resource. The psql verification job in `check-extension.yaml` also reads `create_extension` and skips when false. Closes #85 Signed-off-by: Matteo <matteo.biagetti@enterprisedb.com> Signed-off-by: Niccolò Fei <niccolo.fei@enterprisedb.com> Signed-off-by: Gabriele Bartolini <gabriele.bartolini@enterprisedb.com> Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com> Co-authored-by: Niccolò Fei <niccolo.fei@enterprisedb.com> Co-authored-by: Gabriele Bartolini <gabriele.bartolini@enterprisedb.com> Co-authored-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
1 parent c919e81 commit 4179216

File tree

13 files changed

+171
-53
lines changed

13 files changed

+171
-53
lines changed

dagger/maintenance/dagger.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "maintenance",
3-
"engineVersion": "v0.19.7",
3+
"engineVersion": "v0.19.11",
44
"sdk": {
55
"source": "go"
66
}

dagger/maintenance/go.mod

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ require (
88
github.com/hashicorp/hcl/v2 v2.24.0
99
github.com/vektah/gqlparser/v2 v2.5.30
1010
go.opentelemetry.io/otel v1.38.0
11-
go.opentelemetry.io/otel/sdk v1.38.0
1211
go.opentelemetry.io/otel/trace v1.38.0
1312
)
1413

14+
require go.opentelemetry.io/otel/sdk v1.38.0
15+
1516
require (
16-
github.com/99designs/gqlgen v0.17.81
17+
dagger.io/dagger v0.19.11
18+
github.com/99designs/gqlgen v0.17.81 // indirect
1719
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
1820
github.com/Khan/genqlient v0.8.1
1921
github.com/Microsoft/go-winio v0.6.2 // indirect
@@ -88,7 +90,7 @@ require (
8890
github.com/moby/term v0.5.2 // indirect
8991
github.com/morikuni/aec v1.0.0 // indirect
9092
github.com/opencontainers/go-digest v1.0.0 // indirect
91-
github.com/opencontainers/image-spec v1.1.1 // indirect
93+
github.com/opencontainers/image-spec v1.1.1
9294
github.com/pelletier/go-toml v1.9.5 // indirect
9395
github.com/pkg/errors v0.9.1 // indirect
9496
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
@@ -112,30 +114,30 @@ require (
112114
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
113115
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect
114116
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
115-
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0
116-
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0
117-
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0
118-
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0
117+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect
118+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect
119+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
120+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect
119121
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
120-
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
121-
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0
122-
go.opentelemetry.io/otel/log v0.14.0
123-
go.opentelemetry.io/otel/metric v1.38.0
124-
go.opentelemetry.io/otel/sdk/log v0.14.0
125-
go.opentelemetry.io/otel/sdk/metric v1.38.0
126-
go.opentelemetry.io/proto/otlp v1.8.0
122+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
123+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
124+
go.opentelemetry.io/otel/log v0.14.0 // indirect
125+
go.opentelemetry.io/otel/metric v1.38.0 // indirect
126+
go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect
127+
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
128+
go.opentelemetry.io/proto/otlp v1.8.0 // indirect
127129
go.yaml.in/yaml/v3 v3.0.4
128130
golang.org/x/crypto v0.42.0 // indirect
129131
golang.org/x/mod v0.29.0 // indirect
130132
golang.org/x/net v0.44.0 // indirect
131-
golang.org/x/sync v0.17.0
133+
golang.org/x/sync v0.17.0 // indirect
132134
golang.org/x/sys v0.37.0 // indirect
133-
golang.org/x/text v0.29.0 // indirect
135+
golang.org/x/text v0.29.0
134136
golang.org/x/time v0.14.0 // indirect
135137
golang.org/x/tools v0.37.0 // indirect
136138
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
137139
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
138-
google.golang.org/grpc v1.76.0
140+
google.golang.org/grpc v1.76.0 // indirect
139141
google.golang.org/protobuf v1.36.10 // indirect
140142
)
141143

dagger/maintenance/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
dagger.io/dagger v0.19.11 h1:Cra3wL1oaZsqXJcnPydocx3bIDD5tM7XCuwcn2Uh+2Q=
2+
dagger.io/dagger v0.19.11/go.mod h1:BjAJWl4Lx7XRW7nooNjBi0ZAC5Ici2pkthkdBIZdbTI=
13
github.com/99designs/gqlgen v0.17.81 h1:kCkN/xVyRb5rEQpuwOHRTYq83i0IuTQg9vdIiwEerTs=
24
github.com/99designs/gqlgen v0.17.81/go.mod h1:vgNcZlLwemsUhYim4dC1pvFP5FX0pr2Y+uYUoHFb1ig=
35
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=

dagger/maintenance/main.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,30 @@ func (m *Maintenance) GenerateTestingValues(
180180
targetExtensionImage)
181181
}
182182

183-
extensions, err := generateTestingValuesExtensions(ctx, source, metadata, targetExtensionImage)
183+
extensionInfos, err := generateTestingValuesExtensions(ctx, source, metadata, targetExtensionImage, version)
184184
if err != nil {
185185
return nil, err
186186
}
187187

188+
extensions := make([]*ExtensionConfiguration, len(extensionInfos))
189+
for i, info := range extensionInfos {
190+
extensions[i] = info.Configuration
191+
}
192+
193+
databaseConfig := generateDatabaseConfig(extensionInfos)
194+
databaseAssertStatus := generateDatabaseAssertStatus(extensionInfos)
195+
188196
// Build values.yaml content
189-
values := map[string]any{
190-
"name": metadata.Name,
191-
"sql_name": metadata.SQLName,
192-
"shared_preload_libraries": metadata.SharedPreloadLibraries,
193-
"pg_image": pgImage,
194-
"version": version,
195-
"extensions": extensions,
197+
values := TestingValues{
198+
Name: metadata.Name,
199+
SQLName: metadata.SQLName,
200+
SharedPreloadLibraries: metadata.SharedPreloadLibraries,
201+
PgImage: pgImage,
202+
Version: version,
203+
CreateExtension: metadata.CreateExtension,
204+
Extensions: extensions,
205+
DatabaseConfig: databaseConfig,
206+
DatabaseAssertStatus: databaseAssertStatus,
196207
}
197208
valuesYaml, err := yaml.Marshal(values)
198209
if err != nil {

dagger/maintenance/parse.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type extensionMetadata struct {
3030
LdLibraryPath []string `hcl:"ld_library_path" cty:"ld_library_path"`
3131
AutoUpdateOsLibs bool `hcl:"auto_update_os_libs" cty:"auto_update_os_libs"`
3232
RequiredExtensions []string `hcl:"required_extensions" cty:"required_extensions"`
33+
CreateExtension bool `hcl:"create_extension" cty:"create_extension"`
3334
Versions versionMap `hcl:"versions" cty:"versions"`
3435
Remain hcl.Body `hcl:",remain"`
3536
}

dagger/maintenance/testingvalues.go

Lines changed: 111 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,47 @@ import (
77
"dagger/maintenance/internal/dagger"
88
)
99

10-
func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directory, metadata *extensionMetadata, extensionImage string) ([]map[string]any, error) {
11-
var out []map[string]any
10+
type ExtensionSpec struct {
11+
Ensure string `yaml:"ensure"`
12+
Name string `yaml:"name"`
13+
Version string `yaml:"version"`
14+
}
15+
16+
type DatabaseConfig struct {
17+
ExtensionsSpec []ExtensionSpec `yaml:"extensions_spec,omitempty"`
18+
}
19+
20+
type TestingValues struct {
21+
Name string `yaml:"name"`
22+
SQLName string `yaml:"sql_name"`
23+
SharedPreloadLibraries []string `yaml:"shared_preload_libraries"`
24+
PgImage string `yaml:"pg_image"`
25+
Version string `yaml:"version"`
26+
CreateExtension bool `yaml:"create_extension"`
27+
Extensions []*ExtensionConfiguration `yaml:"extensions"`
28+
DatabaseConfig *DatabaseConfig `yaml:"database_config"`
29+
DatabaseAssertStatus map[string]any `yaml:"database_assert_status"`
30+
}
31+
32+
type testingExtensionInfo struct {
33+
Configuration *ExtensionConfiguration
34+
SQLName string
35+
Version string
36+
CreateExtension bool
37+
}
38+
39+
func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directory, metadata *extensionMetadata, extensionImage string, version string) ([]*testingExtensionInfo, error) {
40+
var out []*testingExtensionInfo
1241
configuration, err := generateExtensionConfiguration(metadata, extensionImage)
1342
if err != nil {
1443
return nil, err
1544
}
16-
out = append(out, configuration)
45+
out = append(out, &testingExtensionInfo{
46+
Configuration: configuration,
47+
SQLName: metadata.SQLName,
48+
Version: version,
49+
CreateExtension: metadata.CreateExtension,
50+
})
1751

1852
for _, dep := range metadata.RequiredExtensions {
1953
depExists, err := source.Exists(ctx, dep)
@@ -24,21 +58,38 @@ func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directo
2458
return nil, fmt.Errorf("required dependency %q not found", dep)
2559
}
2660

27-
depMetadata, parseErr := parseExtensionMetadata(ctx, source.Directory(dep))
28-
if parseErr != nil {
29-
return nil, fmt.Errorf("failed to parse dependency metadata %q: %w", dep, parseErr)
61+
depMetadata, err := parseExtensionMetadata(ctx, source.Directory(dep))
62+
if err != nil {
63+
return nil, fmt.Errorf("failed to parse dependency metadata %q: %w", dep, err)
64+
}
65+
depConfiguration, err := generateExtensionConfiguration(depMetadata, "")
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
depAnnotations, err := getImageAnnotations(depConfiguration.ImageVolumeSource.Reference)
71+
if err != nil {
72+
return nil, err
3073
}
31-
depsConfiguration, extErr := generateExtensionConfiguration(depMetadata, "")
32-
if extErr != nil {
33-
return nil, extErr
74+
depVersion := depAnnotations["org.opencontainers.image.version"]
75+
if depVersion == "" {
76+
return nil, fmt.Errorf(
77+
"extension image %s doesn't have an 'org.opencontainers.image.version' annotation",
78+
depConfiguration.ImageVolumeSource.Reference)
3479
}
35-
out = append(out, depsConfiguration)
80+
81+
out = append(out, &testingExtensionInfo{
82+
Configuration: depConfiguration,
83+
SQLName: depMetadata.SQLName,
84+
Version: depVersion,
85+
CreateExtension: depMetadata.CreateExtension,
86+
})
3687
}
3788

3889
return out, nil
3990
}
4091

41-
func generateExtensionConfiguration(metadata *extensionMetadata, extensionImage string) (map[string]any, error) {
92+
func generateExtensionConfiguration(metadata *extensionMetadata, extensionImage string) (*ExtensionConfiguration, error) {
4293
targetExtensionImage := extensionImage
4394
if targetExtensionImage == "" {
4495
var err error
@@ -48,13 +99,55 @@ func generateExtensionConfiguration(metadata *extensionMetadata, extensionImage
4899
}
49100
}
50101

51-
return map[string]any{
52-
"name": metadata.Name,
53-
"image": map[string]string{
54-
"reference": targetExtensionImage,
102+
return &ExtensionConfiguration{
103+
Name: metadata.Name,
104+
ImageVolumeSource: ImageVolumeSource{
105+
Reference: targetExtensionImage,
55106
},
56-
"extension_control_path": metadata.ExtensionControlPath,
57-
"dynamic_library_path": metadata.DynamicLibraryPath,
58-
"ld_library_path": metadata.LdLibraryPath,
107+
ExtensionControlPath: metadata.ExtensionControlPath,
108+
DynamicLibraryPath: metadata.DynamicLibraryPath,
109+
LdLibraryPath: metadata.LdLibraryPath,
59110
}, nil
60111
}
112+
113+
func generateDatabaseConfig(extensionInfos []*testingExtensionInfo) *DatabaseConfig {
114+
var databaseConfig DatabaseConfig
115+
for _, info := range extensionInfos {
116+
if !info.CreateExtension {
117+
continue
118+
}
119+
120+
databaseConfig.ExtensionsSpec = append(databaseConfig.ExtensionsSpec,
121+
ExtensionSpec{
122+
Ensure: "present",
123+
Name: info.SQLName,
124+
Version: info.Version,
125+
},
126+
)
127+
}
128+
129+
return &databaseConfig
130+
}
131+
132+
func generateDatabaseAssertStatus(extensionInfos []*testingExtensionInfo) map[string]any {
133+
status := map[string]any{
134+
"applied": true,
135+
"observedGeneration": 1,
136+
}
137+
138+
var extensions []map[string]any
139+
for _, info := range extensionInfos {
140+
if !info.CreateExtension {
141+
continue
142+
}
143+
extensions = append(extensions, map[string]any{
144+
"applied": true,
145+
"name": info.SQLName,
146+
})
147+
}
148+
if len(extensions) > 0 {
149+
status["extensions"] = extensions
150+
}
151+
152+
return status
153+
}

pgaudit/metadata.hcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ metadata = {
88
ld_library_path = []
99
auto_update_os_libs = false
1010
required_extensions = []
11+
create_extension = true
1112

1213
versions = {
1314
bookworm = {

pgvector/metadata.hcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ metadata = {
88
ld_library_path = []
99
auto_update_os_libs = false
1010
required_extensions = []
11+
create_extension = true
1112

1213
versions = {
1314
bookworm = {

postgis/metadata.hcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ metadata = {
88
ld_library_path = ["system"]
99
auto_update_os_libs = true
1010
required_extensions = []
11+
create_extension = true
1112

1213
versions = {
1314
bookworm = {

templates/metadata.hcl.tmpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ metadata = {
4848
# folders in this repository that contain a required extension.
4949
required_extensions = []
5050

51+
# TODO: Remove this comment block after customizing the file.
52+
# `create_extension`: if set to `true` (default), the test suite will
53+
# automatically run `CREATE EXTENSION` for this project during E2E tests.
54+
# Set to `false` if the image only provides libraries or tools without
55+
# a formal Postgres extension object.
56+
create_extension = true
57+
5158
versions = {
5259
{{- range $distro := .Distros}}
5360
{{ $distro }} = {

0 commit comments

Comments
 (0)