diff --git a/dagger/maintenance/dagger.json b/dagger/maintenance/dagger.json index 016457b..33ad24c 100644 --- a/dagger/maintenance/dagger.json +++ b/dagger/maintenance/dagger.json @@ -1,6 +1,6 @@ { "name": "maintenance", - "engineVersion": "v0.19.7", + "engineVersion": "v0.19.11", "sdk": { "source": "go" } diff --git a/dagger/maintenance/go.mod b/dagger/maintenance/go.mod index e1300e6..dab3782 100644 --- a/dagger/maintenance/go.mod +++ b/dagger/maintenance/go.mod @@ -8,12 +8,14 @@ require ( github.com/hashicorp/hcl/v2 v2.24.0 github.com/vektah/gqlparser/v2 v2.5.30 go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 ) +require go.opentelemetry.io/otel/sdk v1.38.0 + require ( - github.com/99designs/gqlgen v0.17.81 + dagger.io/dagger v0.19.11 + github.com/99designs/gqlgen v0.17.81 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Khan/genqlient v0.8.1 github.com/Microsoft/go-winio v0.6.2 // indirect @@ -88,7 +90,7 @@ require ( github.com/moby/term v0.5.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/opencontainers/image-spec v1.1.1 github.com/pelletier/go-toml v1.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect @@ -112,30 +114,30 @@ require ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 - go.opentelemetry.io/otel/log v0.14.0 - go.opentelemetry.io/otel/metric v1.38.0 - go.opentelemetry.io/otel/sdk/log v0.14.0 - go.opentelemetry.io/otel/sdk/metric v1.38.0 - go.opentelemetry.io/proto/otlp v1.8.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.8.0 // indirect go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.42.0 // indirect golang.org/x/mod v0.29.0 // indirect golang.org/x/net v0.44.0 // indirect - golang.org/x/sync v0.17.0 + golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/text v0.29.0 // indirect + golang.org/x/text v0.29.0 golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.37.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect - google.golang.org/grpc v1.76.0 + google.golang.org/grpc v1.76.0 // indirect google.golang.org/protobuf v1.36.10 // indirect ) diff --git a/dagger/maintenance/go.sum b/dagger/maintenance/go.sum index 05e6495..9ed10c7 100644 --- a/dagger/maintenance/go.sum +++ b/dagger/maintenance/go.sum @@ -1,3 +1,5 @@ +dagger.io/dagger v0.19.11 h1:Cra3wL1oaZsqXJcnPydocx3bIDD5tM7XCuwcn2Uh+2Q= +dagger.io/dagger v0.19.11/go.mod h1:BjAJWl4Lx7XRW7nooNjBi0ZAC5Ici2pkthkdBIZdbTI= github.com/99designs/gqlgen v0.17.81 h1:kCkN/xVyRb5rEQpuwOHRTYq83i0IuTQg9vdIiwEerTs= github.com/99designs/gqlgen v0.17.81/go.mod h1:vgNcZlLwemsUhYim4dC1pvFP5FX0pr2Y+uYUoHFb1ig= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= diff --git a/dagger/maintenance/main.go b/dagger/maintenance/main.go index 3a03261..6ef5b9b 100644 --- a/dagger/maintenance/main.go +++ b/dagger/maintenance/main.go @@ -180,19 +180,30 @@ func (m *Maintenance) GenerateTestingValues( targetExtensionImage) } - extensions, err := generateTestingValuesExtensions(ctx, source, metadata, targetExtensionImage) + extensionInfos, err := generateTestingValuesExtensions(ctx, source, metadata, targetExtensionImage, version) if err != nil { return nil, err } + extensions := make([]*ExtensionConfiguration, len(extensionInfos)) + for i, info := range extensionInfos { + extensions[i] = info.Configuration + } + + databaseConfig := generateDatabaseConfig(extensionInfos) + databaseAssertStatus := generateDatabaseAssertStatus(extensionInfos) + // Build values.yaml content - values := map[string]any{ - "name": metadata.Name, - "sql_name": metadata.SQLName, - "shared_preload_libraries": metadata.SharedPreloadLibraries, - "pg_image": pgImage, - "version": version, - "extensions": extensions, + values := TestingValues{ + Name: metadata.Name, + SQLName: metadata.SQLName, + SharedPreloadLibraries: metadata.SharedPreloadLibraries, + PgImage: pgImage, + Version: version, + CreateExtension: metadata.CreateExtension, + Extensions: extensions, + DatabaseConfig: databaseConfig, + DatabaseAssertStatus: databaseAssertStatus, } valuesYaml, err := yaml.Marshal(values) if err != nil { diff --git a/dagger/maintenance/parse.go b/dagger/maintenance/parse.go index 82611b9..600fcf4 100644 --- a/dagger/maintenance/parse.go +++ b/dagger/maintenance/parse.go @@ -30,6 +30,7 @@ type extensionMetadata struct { LdLibraryPath []string `hcl:"ld_library_path" cty:"ld_library_path"` AutoUpdateOsLibs bool `hcl:"auto_update_os_libs" cty:"auto_update_os_libs"` RequiredExtensions []string `hcl:"required_extensions" cty:"required_extensions"` + CreateExtension bool `hcl:"create_extension" cty:"create_extension"` Versions versionMap `hcl:"versions" cty:"versions"` Remain hcl.Body `hcl:",remain"` } diff --git a/dagger/maintenance/testingvalues.go b/dagger/maintenance/testingvalues.go index 33ec68c..0ff3065 100644 --- a/dagger/maintenance/testingvalues.go +++ b/dagger/maintenance/testingvalues.go @@ -7,13 +7,47 @@ import ( "dagger/maintenance/internal/dagger" ) -func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directory, metadata *extensionMetadata, extensionImage string) ([]map[string]any, error) { - var out []map[string]any +type ExtensionSpec struct { + Ensure string `yaml:"ensure"` + Name string `yaml:"name"` + Version string `yaml:"version"` +} + +type DatabaseConfig struct { + ExtensionsSpec []ExtensionSpec `yaml:"extensions_spec,omitempty"` +} + +type TestingValues struct { + Name string `yaml:"name"` + SQLName string `yaml:"sql_name"` + SharedPreloadLibraries []string `yaml:"shared_preload_libraries"` + PgImage string `yaml:"pg_image"` + Version string `yaml:"version"` + CreateExtension bool `yaml:"create_extension"` + Extensions []*ExtensionConfiguration `yaml:"extensions"` + DatabaseConfig *DatabaseConfig `yaml:"database_config"` + DatabaseAssertStatus map[string]any `yaml:"database_assert_status"` +} + +type testingExtensionInfo struct { + Configuration *ExtensionConfiguration + SQLName string + Version string + CreateExtension bool +} + +func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directory, metadata *extensionMetadata, extensionImage string, version string) ([]*testingExtensionInfo, error) { + var out []*testingExtensionInfo configuration, err := generateExtensionConfiguration(metadata, extensionImage) if err != nil { return nil, err } - out = append(out, configuration) + out = append(out, &testingExtensionInfo{ + Configuration: configuration, + SQLName: metadata.SQLName, + Version: version, + CreateExtension: metadata.CreateExtension, + }) for _, dep := range metadata.RequiredExtensions { depExists, err := source.Exists(ctx, dep) @@ -24,21 +58,38 @@ func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directo return nil, fmt.Errorf("required dependency %q not found", dep) } - depMetadata, parseErr := parseExtensionMetadata(ctx, source.Directory(dep)) - if parseErr != nil { - return nil, fmt.Errorf("failed to parse dependency metadata %q: %w", dep, parseErr) + depMetadata, err := parseExtensionMetadata(ctx, source.Directory(dep)) + if err != nil { + return nil, fmt.Errorf("failed to parse dependency metadata %q: %w", dep, err) + } + depConfiguration, err := generateExtensionConfiguration(depMetadata, "") + if err != nil { + return nil, err + } + + depAnnotations, err := getImageAnnotations(depConfiguration.ImageVolumeSource.Reference) + if err != nil { + return nil, err } - depsConfiguration, extErr := generateExtensionConfiguration(depMetadata, "") - if extErr != nil { - return nil, extErr + depVersion := depAnnotations["org.opencontainers.image.version"] + if depVersion == "" { + return nil, fmt.Errorf( + "extension image %s doesn't have an 'org.opencontainers.image.version' annotation", + depConfiguration.ImageVolumeSource.Reference) } - out = append(out, depsConfiguration) + + out = append(out, &testingExtensionInfo{ + Configuration: depConfiguration, + SQLName: depMetadata.SQLName, + Version: depVersion, + CreateExtension: depMetadata.CreateExtension, + }) } return out, nil } -func generateExtensionConfiguration(metadata *extensionMetadata, extensionImage string) (map[string]any, error) { +func generateExtensionConfiguration(metadata *extensionMetadata, extensionImage string) (*ExtensionConfiguration, error) { targetExtensionImage := extensionImage if targetExtensionImage == "" { var err error @@ -48,13 +99,55 @@ func generateExtensionConfiguration(metadata *extensionMetadata, extensionImage } } - return map[string]any{ - "name": metadata.Name, - "image": map[string]string{ - "reference": targetExtensionImage, + return &ExtensionConfiguration{ + Name: metadata.Name, + ImageVolumeSource: ImageVolumeSource{ + Reference: targetExtensionImage, }, - "extension_control_path": metadata.ExtensionControlPath, - "dynamic_library_path": metadata.DynamicLibraryPath, - "ld_library_path": metadata.LdLibraryPath, + ExtensionControlPath: metadata.ExtensionControlPath, + DynamicLibraryPath: metadata.DynamicLibraryPath, + LdLibraryPath: metadata.LdLibraryPath, }, nil } + +func generateDatabaseConfig(extensionInfos []*testingExtensionInfo) *DatabaseConfig { + var databaseConfig DatabaseConfig + for _, info := range extensionInfos { + if !info.CreateExtension { + continue + } + + databaseConfig.ExtensionsSpec = append(databaseConfig.ExtensionsSpec, + ExtensionSpec{ + Ensure: "present", + Name: info.SQLName, + Version: info.Version, + }, + ) + } + + return &databaseConfig +} + +func generateDatabaseAssertStatus(extensionInfos []*testingExtensionInfo) map[string]any { + status := map[string]any{ + "applied": true, + "observedGeneration": 1, + } + + var extensions []map[string]any + for _, info := range extensionInfos { + if !info.CreateExtension { + continue + } + extensions = append(extensions, map[string]any{ + "applied": true, + "name": info.SQLName, + }) + } + if len(extensions) > 0 { + status["extensions"] = extensions + } + + return status +} diff --git a/pgaudit/metadata.hcl b/pgaudit/metadata.hcl index ba2a970..35a4670 100644 --- a/pgaudit/metadata.hcl +++ b/pgaudit/metadata.hcl @@ -8,6 +8,7 @@ metadata = { ld_library_path = [] auto_update_os_libs = false required_extensions = [] + create_extension = true versions = { bookworm = { diff --git a/pgvector/metadata.hcl b/pgvector/metadata.hcl index 965b403..afb37f3 100644 --- a/pgvector/metadata.hcl +++ b/pgvector/metadata.hcl @@ -8,6 +8,7 @@ metadata = { ld_library_path = [] auto_update_os_libs = false required_extensions = [] + create_extension = true versions = { bookworm = { diff --git a/postgis/metadata.hcl b/postgis/metadata.hcl index 448ad6c..cf9c76a 100644 --- a/postgis/metadata.hcl +++ b/postgis/metadata.hcl @@ -8,6 +8,7 @@ metadata = { ld_library_path = ["system"] auto_update_os_libs = true required_extensions = [] + create_extension = true versions = { bookworm = { diff --git a/templates/metadata.hcl.tmpl b/templates/metadata.hcl.tmpl index 84fad8e..e34eaf3 100644 --- a/templates/metadata.hcl.tmpl +++ b/templates/metadata.hcl.tmpl @@ -48,6 +48,13 @@ metadata = { # folders in this repository that contain a required extension. required_extensions = [] + # TODO: Remove this comment block after customizing the file. + # `create_extension`: if set to `true` (default), the test suite will + # automatically run `CREATE EXTENSION` for this project during E2E tests. + # Set to `false` if the image only provides libraries or tools without + # a formal Postgres extension object. + create_extension = true + versions = { {{- range $distro := .Distros}} {{ $distro }} = { diff --git a/test/check-extension.yaml b/test/check-extension.yaml index d0f2241..4194a4a 100644 --- a/test/check-extension.yaml +++ b/test/check-extension.yaml @@ -13,6 +13,8 @@ spec: value: ($values.sql_name) - name: EXT_VERSION value: ($values.version) + - name: CREATE_EXTENSION + value: (to_string($values.create_extension)) - name: DB_URI valueFrom: secretKeyRef: @@ -23,6 +25,10 @@ spec: args: - | set -e + if [ "$CREATE_EXTENSION" != "true" ]; then + echo "Skipping extension check (create_extension=false)" + exit 0 + fi DB_URI=$(echo $DB_URI | sed "s|/\*|/|") test "$(psql "$DB_URI" -tAc "SELECT EXISTS (SELECT FROM pg_catalog.pg_extension WHERE extname = '${EXT_SQL_NAME}' AND extversion = '${EXT_VERSION}')" -q)" = "t" echo "Extension '${EXT_SQL_NAME} v${EXT_VERSION}' is installed!" diff --git a/test/database-assert.yaml b/test/database-assert.yaml index dcc0f42..9417b87 100644 --- a/test/database-assert.yaml +++ b/test/database-assert.yaml @@ -2,9 +2,4 @@ apiVersion: postgresql.cnpg.io/v1 kind: Database metadata: name: (join('-', [$values.name, 'app'])) -status: - applied: true - extensions: - - applied: true - name: ($values.sql_name) - observedGeneration: 1 +status: ($values.database_assert_status) diff --git a/test/database.yaml b/test/database.yaml index fd61499..2d6810c 100644 --- a/test/database.yaml +++ b/test/database.yaml @@ -7,6 +7,4 @@ spec: owner: app cluster: name: ($values.name) - extensions: - - name: ($values.sql_name) - version: ($values.version) + extensions: ($values.database_config.extensions_spec)