diff --git a/config/crd/bases/pgbackrest.cnpg.opera.com_archives.yaml b/config/crd/bases/pgbackrest.cnpg.opera.com_archives.yaml index 19ea7aa..6e3e2f0 100644 --- a/config/crd/bases/pgbackrest.cnpg.opera.com_archives.yaml +++ b/config/crd/bases/pgbackrest.cnpg.opera.com_archives.yaml @@ -279,8 +279,13 @@ spec: - name type: object uriStyle: - description: S3 Repository URI style, either "host" - (default) or "path". + description: |- + S3 Repository URI style. Use "path" for S3-compatible stores (e.g. MinIO) at + internal endpoints that cannot resolve virtual-hosted-style DNS names. + Defaults to pgbackrest's own default ("host") when unset. + enum: + - host + - path type: string type: object required: diff --git a/internal/pgbackrest/api/config.go b/internal/pgbackrest/api/config.go index 38b87d5..994495c 100644 --- a/internal/pgbackrest/api/config.go +++ b/internal/pgbackrest/api/config.go @@ -71,6 +71,18 @@ const ( KeyTypeWebID = KeyType("web-id") ) +// URIStyleType is the URI addressing style for S3-compatible repositories +type URIStyleType string + +const ( + // URIStyleHost uses virtual-hosted-style URIs (default): ./key + URIStyleHost = URIStyleType("host") + // URIStylePath uses path-style URIs: //key + // Required for S3-compatible stores (e.g. MinIO) hosted at internal cluster endpoints + // that do not resolve virtual-hosted-style DNS names. + URIStylePath = URIStyleType("path") +) + // S3Credentials is the type for the credentials to be used to upload // files to S3. It can be provided in two alternative ways: // @@ -96,10 +108,12 @@ type S3Credentials struct { // +kubebuilder:validation:MinLength=1 Region string `json:"region,omitempty"` - // S3 Repository URI style, either "host" (default) or "path". - // TODO: Enforce values via Enum like iin compression. + // S3 Repository URI style. Use "path" for S3-compatible stores (e.g. MinIO) at + // internal endpoints that cannot resolve virtual-hosted-style DNS names. + // Defaults to pgbackrest's own default ("host") when unset. + // +kubebuilder:validation:Enum=host;path // +optional - URIStyle string `json:"uriStyle,omitempty"` + URIStyle URIStyleType `json:"uriStyle,omitempty"` } // PgbackrestCredentials an object containing the potential credentials for each cloud provider diff --git a/internal/pgbackrest/command/commandbuilder.go b/internal/pgbackrest/command/commandbuilder.go index 23f1a08..975271d 100644 --- a/internal/pgbackrest/command/commandbuilder.go +++ b/internal/pgbackrest/command/commandbuilder.go @@ -181,7 +181,7 @@ func appendCloudProviderOptions( options = append( options, utils.FormatRepoFlag(repoIndex, "s3-uri-style"), - repository.AWS.URIStyle) + string(repository.AWS.URIStyle)) } } return options, nil diff --git a/internal/pgbackrest/command/commandbuilder_test.go b/internal/pgbackrest/command/commandbuilder_test.go index 0f6ce4b..1eb1a39 100644 --- a/internal/pgbackrest/command/commandbuilder_test.go +++ b/internal/pgbackrest/command/commandbuilder_test.go @@ -64,6 +64,63 @@ var _ = Describe("pgbackrestWalRestoreOptions", func() { }) }) +var _ = Describe("appendCloudProviderOptions", func() { + It("should include s3-uri-style flag when URIStyle is set to path", func(ctx SpecContext) { + conf := &pgbackrestApi.PgbackrestConfiguration{ + Repositories: []pgbackrestApi.PgbackrestRepository{ + { + Bucket: "my-bucket", + DestinationPath: "/", + PgbackrestCredentials: pgbackrestApi.PgbackrestCredentials{ + AWS: &pgbackrestApi.S3Credentials{ + URIStyle: pgbackrestApi.URIStylePath, + }, + }, + }, + }, + } + var empty []string + options, err := AppendCloudProviderOptionsFromConfiguration(ctx, empty, conf) + Expect(err).ToNot(HaveOccurred()) + Expect(strings.Join(options, " ")).To(ContainSubstring("--repo1-s3-uri-style path")) + }) + + It("should include s3-uri-style flag when URIStyle is set to host", func(ctx SpecContext) { + conf := &pgbackrestApi.PgbackrestConfiguration{ + Repositories: []pgbackrestApi.PgbackrestRepository{ + { + Bucket: "my-bucket", + DestinationPath: "/", + PgbackrestCredentials: pgbackrestApi.PgbackrestCredentials{ + AWS: &pgbackrestApi.S3Credentials{ + URIStyle: pgbackrestApi.URIStyleHost, + }, + }, + }, + }, + } + var empty []string + options, err := AppendCloudProviderOptionsFromConfiguration(ctx, empty, conf) + Expect(err).ToNot(HaveOccurred()) + Expect(strings.Join(options, " ")).To(ContainSubstring("--repo1-s3-uri-style host")) + }) + + It("should omit s3-uri-style flag when URIStyle is empty", func(ctx SpecContext) { + conf := &pgbackrestApi.PgbackrestConfiguration{ + Repositories: []pgbackrestApi.PgbackrestRepository{ + { + Bucket: "my-bucket", + DestinationPath: "/", + }, + }, + } + var empty []string + options, err := AppendCloudProviderOptionsFromConfiguration(ctx, empty, conf) + Expect(err).ToNot(HaveOccurred()) + Expect(strings.Join(options, " ")).NotTo(ContainSubstring("s3-uri-style")) + }) +}) + var _ = Describe("PgbackrestRetention", func() { var config *pgbackrestApi.PgbackrestConfiguration var history int32 = 8 diff --git a/test/e2e/internal/objectstore/minio.go b/test/e2e/internal/objectstore/minio.go index 4fbe332..f4213b5 100644 --- a/test/e2e/internal/objectstore/minio.go +++ b/test/e2e/internal/objectstore/minio.go @@ -334,7 +334,7 @@ func NewMinioArchive(namespace, name, minioOSName string, maxParallel int) *plug Region: "dummy", // There is no ingress that would provide domain-based // routing. - URIStyle: "path", + URIStyle: pgbackrestApi.URIStylePath, }, }, EndpointURL: net.JoinHostPort(minioOSName, "9000"),