diff --git a/dagger/maintenance/dagger.json b/dagger/maintenance/dagger.json index 016457b..40159ae 100644 --- a/dagger/maintenance/dagger.json +++ b/dagger/maintenance/dagger.json @@ -1,6 +1,6 @@ { "name": "maintenance", - "engineVersion": "v0.19.7", + "engineVersion": "v0.19.10", "sdk": { "source": "go" } diff --git a/dagger/maintenance/go.mod b/dagger/maintenance/go.mod index e1300e6..51f7f42 100644 --- a/dagger/maintenance/go.mod +++ b/dagger/maintenance/go.mod @@ -88,7 +88,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 @@ -130,7 +130,7 @@ require ( golang.org/x/net v0.44.0 // indirect golang.org/x/sync v0.17.0 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 diff --git a/dagger/maintenance/main.go b/dagger/maintenance/main.go index 3a03261..d8261aa 100644 --- a/dagger/maintenance/main.go +++ b/dagger/maintenance/main.go @@ -185,14 +185,20 @@ func (m *Maintenance) GenerateTestingValues( return nil, err } + databaseConfig, err := generateDatabaseConfig(ctx, source, extensions) + if err != nil { + return nil, err + } + // 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, + Extensions: extensions, + DatabaseConfig: databaseConfig, } 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..73111fc 100644 --- a/dagger/maintenance/testingvalues.go +++ b/dagger/maintenance/testingvalues.go @@ -7,8 +7,34 @@ 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 ExpectedStatus struct { + Applied bool `yaml:"applied"` + Name string `yaml:"name"` +} + +type DatabaseConfig struct { + ExtensionsSpec []ExtensionSpec `yaml:"extensions_spec"` + ExpectedStatus []ExpectedStatus `yaml:"expected_status"` +} + +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"` + Extensions []*ExtensionConfiguration `yaml:"extensions"` + DatabaseConfig *DatabaseConfig `yaml:"database_config"` +} + +func generateTestingValuesExtensions(ctx context.Context, source *dagger.Directory, metadata *extensionMetadata, extensionImage string) ([]*ExtensionConfiguration, error) { + var out []*ExtensionConfiguration configuration, err := generateExtensionConfiguration(metadata, extensionImage) if err != nil { return nil, err @@ -24,21 +50,21 @@ 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) } - depsConfiguration, extErr := generateExtensionConfiguration(depMetadata, "") - if extErr != nil { - return nil, extErr + depConfiguration, err := generateExtensionConfiguration(depMetadata, "") + if err != nil { + return nil, err } - out = append(out, depsConfiguration) + out = append(out, depConfiguration) } 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 +74,56 @@ 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(ctx context.Context, source *dagger.Directory, extensionsConfig []*ExtensionConfiguration) (*DatabaseConfig, error) { + var databaseConfig DatabaseConfig + for _, extension := range extensionsConfig { + extMetadata, err := parseExtensionMetadata(ctx, source.Directory(extension.Name)) + if err != nil { + return nil, fmt.Errorf("failed to parse dependency metadata %q: %w", extension.Name, err) + } + + extAnnotations, err := getImageAnnotations(extension.ImageVolumeSource.Reference) + if err != nil { + return nil, err + } + + extVersion := extAnnotations["org.opencontainers.image.version"] + if extVersion == "" { + return nil, fmt.Errorf( + "extension image %s doesn't have an 'org.opencontainers.image.version' annotation", + extension.ImageVolumeSource.Reference) + } + + ensureOption := "absent" + if extMetadata.CreateExtension { + ensureOption = "present" + } + + databaseConfig.ExtensionsSpec = append(databaseConfig.ExtensionsSpec, + ExtensionSpec{ + Ensure: ensureOption, + Name: extMetadata.SQLName, + Version: extVersion, + }, + ) + databaseConfig.ExpectedStatus = append(databaseConfig.ExpectedStatus, + ExpectedStatus{ + Name: extMetadata.SQLName, + Applied: true, + }, + ) + } + + return &databaseConfig, nil +} 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 9f2156c..123a4a0 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 cffc0ea..7208947 100644 --- a/templates/metadata.hcl.tmpl +++ b/templates/metadata.hcl.tmpl @@ -10,6 +10,7 @@ metadata = { ld_library_path = [] auto_update_os_libs = false required_extensions = [] + create_extension = true versions = { {{- range $distro := .Distros}} 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..56badd3 100644 --- a/test/database-assert.yaml +++ b/test/database-assert.yaml @@ -4,7 +4,5 @@ metadata: name: (join('-', [$values.name, 'app'])) status: applied: true - extensions: - - applied: true - name: ($values.sql_name) + extensions: ($values.database_config.expected_status) observedGeneration: 1 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)