mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-01-11 21:23:12 +01:00
feat: support custom CA certificates
This patch enables the use of custom CA certificates when connecting to the object store in the barman-cloud plugin. The certificates are injected into the sidecar via a projected volume and used by the barman-cloud tool suite. If the barman object name or the key name changes, users must trigger a Pod rollout to apply the new values. Signed-off-by: Leonardo Cecchi <leonardo.cecchi@enterprisedb.com>
This commit is contained in:
parent
0872cf2013
commit
7761e2fd7e
@ -4,8 +4,11 @@ metadata:
|
|||||||
name: minio-store
|
name: minio-store
|
||||||
spec:
|
spec:
|
||||||
configuration:
|
configuration:
|
||||||
|
endpointCA:
|
||||||
|
name: minio-server-tls
|
||||||
|
key: tls.crt
|
||||||
destinationPath: s3://backups/
|
destinationPath: s3://backups/
|
||||||
endpointURL: http://minio:9000
|
endpointURL: https://minio:9000
|
||||||
s3Credentials:
|
s3Credentials:
|
||||||
accessKeyId:
|
accessKeyId:
|
||||||
name: minio
|
name: minio
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -136,3 +136,5 @@ require (
|
|||||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace github.com/cloudnative-pg/barman-cloud => github.com/leonardoce/barman-cloud v0.0.0-20250310163530-1a3fac818111
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -20,8 +20,6 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudnative-pg/api v1.25.1 h1:uNjKiB0MIspUeH9l651SnFDcuflr1crB3t6LjxUCafQ=
|
github.com/cloudnative-pg/api v1.25.1 h1:uNjKiB0MIspUeH9l651SnFDcuflr1crB3t6LjxUCafQ=
|
||||||
github.com/cloudnative-pg/api v1.25.1/go.mod h1:fwF5g4XkuNZqYXIeRR3AJvUfWlqWig+r2DXc5bEmw6U=
|
github.com/cloudnative-pg/api v1.25.1/go.mod h1:fwF5g4XkuNZqYXIeRR3AJvUfWlqWig+r2DXc5bEmw6U=
|
||||||
github.com/cloudnative-pg/barman-cloud v0.1.0 h1:e/z52CehMBIh1LjZqNBJnncWJbS+1JYvRMBR8Js6Uiw=
|
|
||||||
github.com/cloudnative-pg/barman-cloud v0.1.0/go.mod h1:rJUJO/f1yNckLZiVxHAyRmKY+4EPJkYRJsGbTZRJQSY=
|
|
||||||
github.com/cloudnative-pg/cloudnative-pg v1.25.1 h1:Yc6T7ikQ1AiWXBQht+6C3DoihrIpUN2OkM1dIwqadTo=
|
github.com/cloudnative-pg/cloudnative-pg v1.25.1 h1:Yc6T7ikQ1AiWXBQht+6C3DoihrIpUN2OkM1dIwqadTo=
|
||||||
github.com/cloudnative-pg/cloudnative-pg v1.25.1/go.mod h1:96b9bRFLSr3uFWHjhytPdcvKIKwy9H6AG7cH0O6jefs=
|
github.com/cloudnative-pg/cloudnative-pg v1.25.1/go.mod h1:96b9bRFLSr3uFWHjhytPdcvKIKwy9H6AG7cH0O6jefs=
|
||||||
github.com/cloudnative-pg/cnpg-i v0.1.0 h1:QH2xTsrODMhEEc6B25GbOYe7ZIttDmSkYvXotfU5dfs=
|
github.com/cloudnative-pg/cnpg-i v0.1.0 h1:QH2xTsrODMhEEc6B25GbOYe7ZIttDmSkYvXotfU5dfs=
|
||||||
@ -116,6 +114,8 @@ github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 h1:Q3jQ1NkFqv5o+
|
|||||||
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
|
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/leonardoce/barman-cloud v0.0.0-20250310163530-1a3fac818111 h1:opN3VCteYluh6R1OUvt1AU5SuiBdYa4ZzrMf0prRHXk=
|
||||||
|
github.com/leonardoce/barman-cloud v0.0.0-20250310163530-1a3fac818111/go.mod h1:rJUJO/f1yNckLZiVxHAyRmKY+4EPJkYRJsGbTZRJQSY=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
|||||||
@ -77,12 +77,14 @@ func (w WALServiceImplementation) Archive(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
envArchive, err := barmanCredentials.EnvSetBackupCloudCredentials(
|
envArchive, err := barmanCredentials.EnvSetCloudCredentialsAndCertificates(
|
||||||
ctx,
|
ctx,
|
||||||
w.Client,
|
w.Client,
|
||||||
objectStore.Namespace,
|
objectStore.Namespace,
|
||||||
&objectStore.Spec.Configuration,
|
&objectStore.Spec.Configuration,
|
||||||
os.Environ())
|
os.Environ(),
|
||||||
|
path.Join(metadata.BarmanCertificatesPath, objectStore.Name, metadata.BarmanCertificatesFileName),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apierrors.IsForbidden(err) {
|
if apierrors.IsForbidden(err) {
|
||||||
return nil, errors.New("backup credentials don't yet have access permissions. Will retry reconciliation loop")
|
return nil, errors.New("backup credentials don't yet have access permissions. Will retry reconciliation loop")
|
||||||
@ -191,12 +193,13 @@ func (w WALServiceImplementation) restoreFromBarmanObjectStore(
|
|||||||
barmanConfiguration := &objectStore.Spec.Configuration
|
barmanConfiguration := &objectStore.Spec.Configuration
|
||||||
|
|
||||||
env := GetRestoreCABundleEnv(barmanConfiguration)
|
env := GetRestoreCABundleEnv(barmanConfiguration)
|
||||||
credentialsEnv, err := barmanCredentials.EnvSetBackupCloudCredentials(
|
credentialsEnv, err := barmanCredentials.EnvSetCloudCredentialsAndCertificates(
|
||||||
ctx,
|
ctx,
|
||||||
w.Client,
|
w.Client,
|
||||||
objectStore.Namespace,
|
objectStore.Namespace,
|
||||||
&objectStore.Spec.Configuration,
|
&objectStore.Spec.Configuration,
|
||||||
os.Environ(),
|
os.Environ(),
|
||||||
|
path.Join(metadata.BarmanCertificatesPath, objectStore.Name, metadata.BarmanCertificatesFileName),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("while getting recover credentials: %w", err)
|
return fmt.Errorf("while getting recover credentials: %w", err)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -98,12 +99,14 @@ func (b BackupServiceImplementation) Backup(
|
|||||||
// PGHOST (and the like) to be available
|
// PGHOST (and the like) to be available
|
||||||
osEnvironment := os.Environ()
|
osEnvironment := os.Environ()
|
||||||
caBundleEnvironment := common.GetRestoreCABundleEnv(&objectStore.Spec.Configuration)
|
caBundleEnvironment := common.GetRestoreCABundleEnv(&objectStore.Spec.Configuration)
|
||||||
env, err := barmanCredentials.EnvSetBackupCloudCredentials(
|
env, err := barmanCredentials.EnvSetCloudCredentialsAndCertificates(
|
||||||
ctx,
|
ctx,
|
||||||
b.Client,
|
b.Client,
|
||||||
objectStore.Namespace,
|
objectStore.Namespace,
|
||||||
&objectStore.Spec.Configuration,
|
&objectStore.Spec.Configuration,
|
||||||
common.MergeEnv(osEnvironment, caBundleEnvironment))
|
common.MergeEnv(osEnvironment, caBundleEnvironment),
|
||||||
|
path.Join(metadata.BarmanCertificatesPath, objectStore.Name, metadata.BarmanCertificatesFileName),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contextLogger.Error(err, "while setting backup cloud credentials")
|
contextLogger.Error(err, "while setting backup cloud credentials")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -11,6 +11,14 @@ const (
|
|||||||
// if present, requires the WAL archiver to check that the backup object
|
// if present, requires the WAL archiver to check that the backup object
|
||||||
// store is empty.
|
// store is empty.
|
||||||
CheckEmptyWalArchiveFile = ".check-empty-wal-archive"
|
CheckEmptyWalArchiveFile = ".check-empty-wal-archive"
|
||||||
|
|
||||||
|
// BarmanCertificatesPath is the path where the Barman
|
||||||
|
// certificates will be installed
|
||||||
|
BarmanCertificatesPath = "/barman-certificates"
|
||||||
|
|
||||||
|
// BarmanCertificatesFileName is the path where the Barman
|
||||||
|
// certificates will be used
|
||||||
|
BarmanCertificatesFileName = "barman-ca.crt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Data is the metadata of this plugin.
|
// Data is the metadata of this plugin.
|
||||||
|
|||||||
@ -14,11 +14,9 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/utils/ptr"
|
"k8s.io/utils/ptr"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
|
||||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
|
||||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
||||||
)
|
)
|
||||||
@ -107,56 +105,6 @@ func (impl LifecycleImplementation) LifecycleHook(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (impl LifecycleImplementation) collectAdditionalEnvs(
|
|
||||||
ctx context.Context,
|
|
||||||
namespace string,
|
|
||||||
pluginConfiguration *config.PluginConfiguration,
|
|
||||||
) ([]corev1.EnvVar, error) {
|
|
||||||
var result []corev1.EnvVar
|
|
||||||
|
|
||||||
if len(pluginConfiguration.BarmanObjectName) > 0 {
|
|
||||||
envs, err := impl.collectObjectStoreEnvs(
|
|
||||||
ctx,
|
|
||||||
types.NamespacedName{
|
|
||||||
Name: pluginConfiguration.BarmanObjectName,
|
|
||||||
Namespace: namespace,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result = append(result, envs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pluginConfiguration.RecoveryBarmanObjectName) > 0 {
|
|
||||||
envs, err := impl.collectObjectStoreEnvs(
|
|
||||||
ctx,
|
|
||||||
types.NamespacedName{
|
|
||||||
Name: pluginConfiguration.RecoveryBarmanObjectName,
|
|
||||||
Namespace: namespace,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result = append(result, envs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (impl LifecycleImplementation) collectObjectStoreEnvs(
|
|
||||||
ctx context.Context,
|
|
||||||
barmanObjectKey types.NamespacedName,
|
|
||||||
) ([]corev1.EnvVar, error) {
|
|
||||||
var objectStore barmancloudv1.ObjectStore
|
|
||||||
if err := impl.Client.Get(ctx, barmanObjectKey, &objectStore); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return objectStore.Spec.InstanceSidecarConfiguration.Env, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (impl LifecycleImplementation) reconcileJob(
|
func (impl LifecycleImplementation) reconcileJob(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
cluster *cnpgv1.Cluster,
|
cluster *cnpgv1.Cluster,
|
||||||
@ -165,10 +113,15 @@ func (impl LifecycleImplementation) reconcileJob(
|
|||||||
) (*lifecycle.OperatorLifecycleResponse, error) {
|
) (*lifecycle.OperatorLifecycleResponse, error) {
|
||||||
env, err := impl.collectAdditionalEnvs(ctx, cluster.Namespace, pluginConfiguration)
|
env, err := impl.collectAdditionalEnvs(ctx, cluster.Namespace, pluginConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return reconcileJob(ctx, cluster, request, env)
|
certificates, err := impl.collectAdditionalCertificates(ctx, cluster.Namespace, pluginConfiguration)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reconcileJob(ctx, cluster, request, env, certificates)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reconcileJob(
|
func reconcileJob(
|
||||||
@ -176,6 +129,7 @@ func reconcileJob(
|
|||||||
cluster *cnpgv1.Cluster,
|
cluster *cnpgv1.Cluster,
|
||||||
request *lifecycle.OperatorLifecycleRequest,
|
request *lifecycle.OperatorLifecycleRequest,
|
||||||
env []corev1.EnvVar,
|
env []corev1.EnvVar,
|
||||||
|
certificates []corev1.VolumeProjection,
|
||||||
) (*lifecycle.OperatorLifecycleResponse, error) {
|
) (*lifecycle.OperatorLifecycleResponse, error) {
|
||||||
contextLogger := log.FromContext(ctx).WithName("lifecycle")
|
contextLogger := log.FromContext(ctx).WithName("lifecycle")
|
||||||
if pluginConfig := cluster.GetRecoverySourcePlugin(); pluginConfig == nil || pluginConfig.Name != metadata.PluginName {
|
if pluginConfig := cluster.GetRecoverySourcePlugin(); pluginConfig == nil || pluginConfig.Name != metadata.PluginName {
|
||||||
@ -212,6 +166,7 @@ func reconcileJob(
|
|||||||
Args: []string{"restore"},
|
Args: []string{"restore"},
|
||||||
},
|
},
|
||||||
env,
|
env,
|
||||||
|
certificates,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, fmt.Errorf("while reconciling pod spec for job: %w", err)
|
return nil, fmt.Errorf("while reconciling pod spec for job: %w", err)
|
||||||
}
|
}
|
||||||
@ -235,10 +190,15 @@ func (impl LifecycleImplementation) reconcilePod(
|
|||||||
) (*lifecycle.OperatorLifecycleResponse, error) {
|
) (*lifecycle.OperatorLifecycleResponse, error) {
|
||||||
env, err := impl.collectAdditionalEnvs(ctx, cluster.Namespace, pluginConfiguration)
|
env, err := impl.collectAdditionalEnvs(ctx, cluster.Namespace, pluginConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return reconcilePod(ctx, cluster, request, pluginConfiguration, env)
|
certificates, err := impl.collectAdditionalCertificates(ctx, cluster.Namespace, pluginConfiguration)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reconcilePod(ctx, cluster, request, pluginConfiguration, env, certificates)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reconcilePod(
|
func reconcilePod(
|
||||||
@ -247,6 +207,7 @@ func reconcilePod(
|
|||||||
request *lifecycle.OperatorLifecycleRequest,
|
request *lifecycle.OperatorLifecycleRequest,
|
||||||
pluginConfiguration *config.PluginConfiguration,
|
pluginConfiguration *config.PluginConfiguration,
|
||||||
env []corev1.EnvVar,
|
env []corev1.EnvVar,
|
||||||
|
certificates []corev1.VolumeProjection,
|
||||||
) (*lifecycle.OperatorLifecycleResponse, error) {
|
) (*lifecycle.OperatorLifecycleResponse, error) {
|
||||||
pod, err := decoder.DecodePodJSON(request.GetObjectDefinition())
|
pod, err := decoder.DecodePodJSON(request.GetObjectDefinition())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -267,6 +228,7 @@ func reconcilePod(
|
|||||||
Args: []string{"instance"},
|
Args: []string{"instance"},
|
||||||
},
|
},
|
||||||
env,
|
env,
|
||||||
|
certificates,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, fmt.Errorf("while reconciling pod spec for pod: %w", err)
|
return nil, fmt.Errorf("while reconciling pod spec for pod: %w", err)
|
||||||
}
|
}
|
||||||
@ -291,6 +253,7 @@ func reconcilePodSpec(
|
|||||||
mainContainerName string,
|
mainContainerName string,
|
||||||
sidecarConfig corev1.Container,
|
sidecarConfig corev1.Container,
|
||||||
additionalEnvs []corev1.EnvVar,
|
additionalEnvs []corev1.EnvVar,
|
||||||
|
certificates []corev1.VolumeProjection,
|
||||||
) error {
|
) error {
|
||||||
envs := []corev1.EnvVar{
|
envs := []corev1.EnvVar{
|
||||||
{
|
{
|
||||||
@ -360,10 +323,22 @@ func reconcilePodSpec(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := InjectPluginSidecarPodSpec(spec, &sidecarConfig, mainContainerName, true); err != nil {
|
if err := injectPluginSidecarPodSpec(spec, &sidecarConfig, mainContainerName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inject the volume containing the certificates if needed
|
||||||
|
if !volumeListHasVolume(spec.Volumes, barmanCertificatesVolumeName) {
|
||||||
|
spec.Volumes = append(spec.Volumes, corev1.Volume{
|
||||||
|
Name: barmanCertificatesVolumeName,
|
||||||
|
VolumeSource: corev1.VolumeSource{
|
||||||
|
Projected: &corev1.ProjectedVolumeSource{
|
||||||
|
Sources: certificates,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,16 +382,15 @@ func InjectPluginVolumePodSpec(spec *corev1.PodSpec, mainContainerName string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectPluginSidecarPodSpec injects a plugin sidecar into a CNPG Pod spec.
|
// injectPluginSidecarPodSpec injects a plugin sidecar into a CNPG Pod spec.
|
||||||
//
|
//
|
||||||
// If the "injectMainContainerVolumes" flag is true, this will append all the volume
|
// If the "injectMainContainerVolumes" flag is true, this will append all the volume
|
||||||
// mounts that are used in the instance manager Pod to the passed sidecar
|
// mounts that are used in the instance manager Pod to the passed sidecar
|
||||||
// container, granting it superuser access to the PostgreSQL instance.
|
// container, granting it superuser access to the PostgreSQL instance.
|
||||||
func InjectPluginSidecarPodSpec(
|
func injectPluginSidecarPodSpec(
|
||||||
spec *corev1.PodSpec,
|
spec *corev1.PodSpec,
|
||||||
sidecar *corev1.Container,
|
sidecar *corev1.Container,
|
||||||
mainContainerName string,
|
mainContainerName string,
|
||||||
injectMainContainerVolumes bool,
|
|
||||||
) error {
|
) error {
|
||||||
sidecar = sidecar.DeepCopy()
|
sidecar = sidecar.DeepCopy()
|
||||||
InjectPluginVolumePodSpec(spec, mainContainerName)
|
InjectPluginVolumePodSpec(spec, mainContainerName)
|
||||||
@ -447,11 +421,27 @@ func InjectPluginSidecarPodSpec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do not modify the passed sidecar definition
|
// Do not modify the passed sidecar definition
|
||||||
if injectMainContainerVolumes {
|
sidecar.VolumeMounts = append(
|
||||||
sidecar.VolumeMounts = append(sidecar.VolumeMounts, volumeMounts...)
|
sidecar.VolumeMounts,
|
||||||
}
|
corev1.VolumeMount{
|
||||||
|
Name: barmanCertificatesVolumeName,
|
||||||
|
MountPath: metadata.BarmanCertificatesPath,
|
||||||
|
})
|
||||||
|
sidecar.VolumeMounts = append(sidecar.VolumeMounts, volumeMounts...)
|
||||||
sidecar.RestartPolicy = ptr.To(corev1.ContainerRestartPolicyAlways)
|
sidecar.RestartPolicy = ptr.To(corev1.ContainerRestartPolicyAlways)
|
||||||
spec.InitContainers = append(spec.InitContainers, *sidecar)
|
spec.InitContainers = append(spec.InitContainers, *sidecar)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// volumeListHasVolume check if a volume with a known name exists
|
||||||
|
// in the volume list
|
||||||
|
func volumeListHasVolume(volumes []corev1.Volume, name string) bool {
|
||||||
|
for i := range volumes {
|
||||||
|
if volumes[i].Name == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
89
internal/cnpgi/operator/lifecycle_certificates.go
Normal file
89
internal/cnpgi/operator/lifecycle_certificates.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package operator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||||
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
|
||||||
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// barmanCertificatesVolumeName is the name of the volume that hosts
|
||||||
|
// the barman certificates to be used
|
||||||
|
const barmanCertificatesVolumeName = "barman-certificates"
|
||||||
|
|
||||||
|
func (impl LifecycleImplementation) collectAdditionalCertificates(
|
||||||
|
ctx context.Context,
|
||||||
|
namespace string,
|
||||||
|
pluginConfiguration *config.PluginConfiguration,
|
||||||
|
) ([]corev1.VolumeProjection, error) {
|
||||||
|
var result []corev1.VolumeProjection
|
||||||
|
|
||||||
|
if len(pluginConfiguration.BarmanObjectName) > 0 {
|
||||||
|
envs, err := impl.collectObjectStoreCertificates(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Name: pluginConfiguration.BarmanObjectName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, envs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pluginConfiguration.RecoveryBarmanObjectName) > 0 {
|
||||||
|
envs, err := impl.collectObjectStoreCertificates(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Name: pluginConfiguration.RecoveryBarmanObjectName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, envs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (impl LifecycleImplementation) collectObjectStoreCertificates(
|
||||||
|
ctx context.Context,
|
||||||
|
barmanObjectKey types.NamespacedName,
|
||||||
|
) ([]corev1.VolumeProjection, error) {
|
||||||
|
var objectStore barmancloudv1.ObjectStore
|
||||||
|
if err := impl.Client.Get(ctx, barmanObjectKey, &objectStore); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpointCA := objectStore.Spec.Configuration.EndpointCA
|
||||||
|
if endpointCA == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []corev1.VolumeProjection{
|
||||||
|
{
|
||||||
|
Secret: &corev1.SecretProjection{
|
||||||
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
|
Name: endpointCA.Name,
|
||||||
|
},
|
||||||
|
Items: []corev1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: endpointCA.Key,
|
||||||
|
Path: path.Join(
|
||||||
|
barmanObjectKey.Name,
|
||||||
|
metadata.BarmanCertificatesFileName,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
61
internal/cnpgi/operator/lifecycle_envs.go
Normal file
61
internal/cnpgi/operator/lifecycle_envs.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package operator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||||
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (impl LifecycleImplementation) collectAdditionalEnvs(
|
||||||
|
ctx context.Context,
|
||||||
|
namespace string,
|
||||||
|
pluginConfiguration *config.PluginConfiguration,
|
||||||
|
) ([]corev1.EnvVar, error) {
|
||||||
|
var result []corev1.EnvVar
|
||||||
|
|
||||||
|
if len(pluginConfiguration.BarmanObjectName) > 0 {
|
||||||
|
envs, err := impl.collectObjectStoreEnvs(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Name: pluginConfiguration.BarmanObjectName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, envs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pluginConfiguration.RecoveryBarmanObjectName) > 0 {
|
||||||
|
envs, err := impl.collectObjectStoreEnvs(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Name: pluginConfiguration.RecoveryBarmanObjectName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, envs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (impl LifecycleImplementation) collectObjectStoreEnvs(
|
||||||
|
ctx context.Context,
|
||||||
|
barmanObjectKey types.NamespacedName,
|
||||||
|
) ([]corev1.EnvVar, error) {
|
||||||
|
var objectStore barmancloudv1.ObjectStore
|
||||||
|
if err := impl.Client.Get(ctx, barmanObjectKey, &objectStore); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return objectStore.Spec.InstanceSidecarConfiguration.Env, nil
|
||||||
|
}
|
||||||
@ -107,7 +107,7 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
ObjectDefinition: jobJSON,
|
ObjectDefinition: jobJSON,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := reconcileJob(ctx, cluster, request, nil)
|
response, err := reconcileJob(ctx, cluster, request, nil, nil)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(response).NotTo(BeNil())
|
Expect(response).NotTo(BeNil())
|
||||||
Expect(response.JsonPatch).NotTo(BeEmpty())
|
Expect(response.JsonPatch).NotTo(BeEmpty())
|
||||||
@ -128,7 +128,7 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
ObjectDefinition: jobJSON,
|
ObjectDefinition: jobJSON,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := reconcileJob(ctx, cluster, request, nil)
|
response, err := reconcileJob(ctx, cluster, request, nil, nil)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(response).To(BeNil())
|
Expect(response).To(BeNil())
|
||||||
})
|
})
|
||||||
@ -138,7 +138,7 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
ObjectDefinition: []byte("invalid-json"),
|
ObjectDefinition: []byte("invalid-json"),
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := reconcileJob(ctx, cluster, request, nil)
|
response, err := reconcileJob(ctx, cluster, request, nil, nil)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(response).To(BeNil())
|
Expect(response).To(BeNil())
|
||||||
})
|
})
|
||||||
@ -165,7 +165,7 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
ObjectDefinition: jobJSON,
|
ObjectDefinition: jobJSON,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := reconcileJob(ctx, cluster, request, nil)
|
response, err := reconcileJob(ctx, cluster, request, nil, nil)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(response).To(BeNil())
|
Expect(response).To(BeNil())
|
||||||
})
|
})
|
||||||
@ -185,7 +185,7 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
ObjectDefinition: podJSON,
|
ObjectDefinition: podJSON,
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, nil)
|
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, nil, nil)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(response).NotTo(BeNil())
|
Expect(response).NotTo(BeNil())
|
||||||
Expect(response.JsonPatch).NotTo(BeEmpty())
|
Expect(response.JsonPatch).NotTo(BeEmpty())
|
||||||
@ -203,7 +203,7 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
ObjectDefinition: []byte("invalid-json"),
|
ObjectDefinition: []byte("invalid-json"),
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, nil)
|
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, nil, nil)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(response).To(BeNil())
|
Expect(response).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|||||||
@ -87,7 +87,12 @@ func (impl JobHookImpl) Restore(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := impl.checkBackupDestination(ctx, configuration.Cluster, &targetObjectStore.Spec.Configuration); err != nil {
|
if err := impl.checkBackupDestination(
|
||||||
|
ctx,
|
||||||
|
configuration.Cluster,
|
||||||
|
&targetObjectStore.Spec.Configuration,
|
||||||
|
targetObjectStore.Name,
|
||||||
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,6 +103,7 @@ func (impl JobHookImpl) Restore(
|
|||||||
impl.Client,
|
impl.Client,
|
||||||
configuration.Cluster,
|
configuration.Cluster,
|
||||||
&recoveryObjectStore.Spec.Configuration,
|
&recoveryObjectStore.Spec.Configuration,
|
||||||
|
recoveryObjectStore.Name,
|
||||||
configuration.RecoveryServerName,
|
configuration.RecoveryServerName,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -220,13 +226,16 @@ func (impl *JobHookImpl) checkBackupDestination(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
cluster *cnpgv1.Cluster,
|
cluster *cnpgv1.Cluster,
|
||||||
barmanConfiguration *cnpgv1.BarmanObjectStoreConfiguration,
|
barmanConfiguration *cnpgv1.BarmanObjectStoreConfiguration,
|
||||||
|
objectStoreName string,
|
||||||
) error {
|
) error {
|
||||||
// Get environment from cache
|
// Get environment from cache
|
||||||
env, err := barmanCredentials.EnvSetRestoreCloudCredentials(ctx,
|
env, err := barmanCredentials.EnvSetCloudCredentialsAndCertificates(ctx,
|
||||||
impl.Client,
|
impl.Client,
|
||||||
cluster.Namespace,
|
cluster.Namespace,
|
||||||
barmanConfiguration,
|
barmanConfiguration,
|
||||||
os.Environ())
|
os.Environ(),
|
||||||
|
path.Join(metadata.BarmanCertificatesPath, objectStoreName, metadata.BarmanCertificatesFileName),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't get credentials for cluster %v: %w", cluster.Name, err)
|
return fmt.Errorf("can't get credentials for cluster %v: %w", cluster.Name, err)
|
||||||
}
|
}
|
||||||
@ -329,6 +338,7 @@ func loadBackupObjectFromExternalCluster(
|
|||||||
typedClient client.Client,
|
typedClient client.Client,
|
||||||
cluster *cnpgv1.Cluster,
|
cluster *cnpgv1.Cluster,
|
||||||
recoveryObjectStore *api.BarmanObjectStoreConfiguration,
|
recoveryObjectStore *api.BarmanObjectStoreConfiguration,
|
||||||
|
recoveryObjectStoreName string,
|
||||||
serverName string,
|
serverName string,
|
||||||
) (*cnpgv1.Backup, []string, error) {
|
) (*cnpgv1.Backup, []string, error) {
|
||||||
contextLogger := log.FromContext(ctx)
|
contextLogger := log.FromContext(ctx)
|
||||||
@ -337,12 +347,13 @@ func loadBackupObjectFromExternalCluster(
|
|||||||
"serverName", serverName,
|
"serverName", serverName,
|
||||||
"objectStore", recoveryObjectStore)
|
"objectStore", recoveryObjectStore)
|
||||||
|
|
||||||
env, err := barmanCredentials.EnvSetRestoreCloudCredentials(
|
env, err := barmanCredentials.EnvSetCloudCredentialsAndCertificates(
|
||||||
ctx,
|
ctx,
|
||||||
typedClient,
|
typedClient,
|
||||||
cluster.Namespace,
|
cluster.Namespace,
|
||||||
recoveryObjectStore,
|
recoveryObjectStore,
|
||||||
os.Environ())
|
os.Environ(),
|
||||||
|
path.Join(metadata.BarmanCertificatesPath, recoveryObjectStoreName, metadata.BarmanCertificatesFileName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user