Skip to content

Commit ed28ba8

Browse files
committed
feat(spec): add additionalContainerArgs
Signed-off-by: Armando Ruocco <[email protected]>
1 parent de58d0a commit ed28ba8

File tree

5 files changed

+170
-12
lines changed

5 files changed

+170
-12
lines changed

api/v1/objectstore_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ type InstanceSidecarConfiguration struct {
3737
// Resources define cpu/memory requests and limits for the sidecar that runs in the instance pods.
3838
// +optional
3939
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
40+
41+
// AdditionalContainerArgs defines additional arguments to be passed to the sidecar container
42+
// +optional
43+
AdditionalContainerArgs []string `json:"additionalContainerArgs,omitempty"`
4044
}
4145

4246
// ObjectStoreSpec defines the desired state of ObjectStore.

api/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/barmancloud.cnpg.io_objectstores.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,12 @@ spec:
391391
description: The configuration for the sidecar that runs in the instance
392392
pods
393393
properties:
394+
additionalContainerArgs:
395+
description: AdditionalContainerArgs defines additional arguments
396+
to be passed to the sidecar container
397+
items:
398+
type: string
399+
type: array
394400
env:
395401
description: The environment to be explicitly passed to the sidecar
396402
items:

internal/cnpgi/operator/lifecycle.go

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"k8s.io/utils/ptr"
1818
"sigs.k8s.io/controller-runtime/pkg/client"
1919

20+
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
2021
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
2122
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
2223
)
@@ -133,9 +134,10 @@ func (impl LifecycleImplementation) reconcileJob(
133134
}
134135

135136
type sidecarConfiguration struct {
136-
env []corev1.EnvVar
137-
certificates []corev1.VolumeProjection
138-
resources corev1.ResourceRequirements
137+
env []corev1.EnvVar
138+
certificates []corev1.VolumeProjection
139+
resources corev1.ResourceRequirements
140+
additionalArgs []string
139141
}
140142

141143
func reconcileJob(
@@ -217,14 +219,47 @@ func (impl LifecycleImplementation) reconcilePod(
217219
return nil, err
218220
}
219221

220-
return reconcilePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{
221-
env: env,
222-
certificates: certificates,
223-
resources: resources,
222+
additionalArgs, err := impl.collectAdditionalInstanceArgs(ctx, pluginConfiguration)
223+
if err != nil {
224+
return nil, err
225+
}
226+
227+
return reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{
228+
env: env,
229+
certificates: certificates,
230+
resources: resources,
231+
additionalArgs: additionalArgs,
224232
})
225233
}
226234

227-
func reconcilePod(
235+
func (impl LifecycleImplementation) collectAdditionalInstanceArgs(
236+
ctx context.Context,
237+
pluginConfiguration *config.PluginConfiguration,
238+
) ([]string, error) {
239+
// Prefer the cluster object store (backup/archive). If not set, fallback to the recovery object store.
240+
// If neither is configured, no additional args are provided.
241+
if len(pluginConfiguration.BarmanObjectName) > 0 {
242+
var barmanObjectStore barmancloudv1.ObjectStore
243+
if err := impl.Client.Get(ctx, pluginConfiguration.GetBarmanObjectKey(), &barmanObjectStore); err != nil {
244+
return nil, fmt.Errorf("while getting barman object store %s: %w",
245+
pluginConfiguration.GetBarmanObjectKey().String(), err)
246+
}
247+
return barmanObjectStore.Spec.InstanceSidecarConfiguration.AdditionalContainerArgs, nil
248+
}
249+
250+
if len(pluginConfiguration.RecoveryBarmanObjectName) > 0 {
251+
var barmanObjectStore barmancloudv1.ObjectStore
252+
if err := impl.Client.Get(ctx, pluginConfiguration.GetRecoveryBarmanObjectKey(), &barmanObjectStore); err != nil {
253+
return nil, fmt.Errorf("while getting recovery barman object store %s: %w",
254+
pluginConfiguration.GetRecoveryBarmanObjectKey().String(), err)
255+
}
256+
return barmanObjectStore.Spec.InstanceSidecarConfiguration.AdditionalContainerArgs, nil
257+
}
258+
259+
return nil, nil
260+
}
261+
262+
func reconcileInstancePod(
228263
ctx context.Context,
229264
cluster *cnpgv1.Cluster,
230265
request *lifecycle.OperatorLifecycleRequest,
@@ -332,6 +367,7 @@ func reconcilePodSpec(
332367
}
333368
sidecarTemplate.RestartPolicy = ptr.To(corev1.ContainerRestartPolicyAlways)
334369
sidecarTemplate.Resources = config.resources
370+
sidecarTemplate.Args = append(sidecarTemplate.Args, config.additionalArgs...)
335371

336372
// merge the main container envs if they aren't already set
337373
for _, container := range spec.Containers {

internal/cnpgi/operator/lifecycle_test.go

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package operator
22

33
import (
4+
"context"
45
"encoding/json"
56

67
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
78
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
89
"github.com/cloudnative-pg/cnpg-i/pkg/lifecycle"
10+
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
911
batchv1 "k8s.io/api/batch/v1"
1012
corev1 "k8s.io/api/core/v1"
1113
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/apimachinery/pkg/runtime"
15+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1216

1317
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
1418

@@ -18,7 +22,6 @@ import (
1822

1923
var _ = Describe("LifecycleImplementation", func() {
2024
var (
21-
lifecycleImpl LifecycleImplementation
2225
pluginConfiguration *config.PluginConfiguration
2326
cluster *cnpgv1.Cluster
2427
jobTypeMeta = metav1.TypeMeta{
@@ -31,6 +34,26 @@ var _ = Describe("LifecycleImplementation", func() {
3134
}
3235
)
3336

37+
// helper to build a fake client with our scheme and optional objects
38+
buildClientFunc := func(objs ...runtime.Object) *fake.ClientBuilder {
39+
s := runtime.NewScheme()
40+
_ = barmancloudv1.AddToScheme(s)
41+
return fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...)
42+
}
43+
44+
// helper to create an ObjectStore with given args
45+
makeStoreFunc := func(ns, name string, args []string) *barmancloudv1.ObjectStore {
46+
return &barmancloudv1.ObjectStore{
47+
TypeMeta: metav1.TypeMeta{Kind: "ObjectStore", APIVersion: barmancloudv1.GroupVersion.String()},
48+
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
49+
Spec: barmancloudv1.ObjectStoreSpec{
50+
InstanceSidecarConfiguration: barmancloudv1.InstanceSidecarConfiguration{
51+
AdditionalContainerArgs: args,
52+
},
53+
},
54+
}
55+
}
56+
3457
BeforeEach(func() {
3558
pluginConfiguration = &config.PluginConfiguration{
3659
BarmanObjectName: "minio-store-dest",
@@ -67,6 +90,7 @@ var _ = Describe("LifecycleImplementation", func() {
6790

6891
Describe("GetCapabilities", func() {
6992
It("returns the correct capabilities", func(ctx SpecContext) {
93+
var lifecycleImpl LifecycleImplementation
7094
response, err := lifecycleImpl.GetCapabilities(ctx, &lifecycle.OperatorLifecycleCapabilitiesRequest{})
7195
Expect(err).NotTo(HaveOccurred())
7296
Expect(response).NotTo(BeNil())
@@ -76,6 +100,7 @@ var _ = Describe("LifecycleImplementation", func() {
76100

77101
Describe("LifecycleHook", func() {
78102
It("returns an error if object definition is invalid", func(ctx SpecContext) {
103+
var lifecycleImpl LifecycleImplementation
79104
request := &lifecycle.OperatorLifecycleRequest{
80105
ObjectDefinition: []byte("invalid-json"),
81106
}
@@ -171,7 +196,7 @@ var _ = Describe("LifecycleImplementation", func() {
171196
})
172197
})
173198

174-
Describe("reconcilePod", func() {
199+
Describe("reconcileInstancePod", func() {
175200
It("returns a patch for a valid pod", func(ctx SpecContext) {
176201
pod := &corev1.Pod{
177202
TypeMeta: podTypeMeta,
@@ -185,7 +210,7 @@ var _ = Describe("LifecycleImplementation", func() {
185210
ObjectDefinition: podJSON,
186211
}
187212

188-
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{})
213+
response, err := reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{})
189214
Expect(err).NotTo(HaveOccurred())
190215
Expect(response).NotTo(BeNil())
191216
Expect(response.JsonPatch).NotTo(BeEmpty())
@@ -203,11 +228,93 @@ var _ = Describe("LifecycleImplementation", func() {
203228
ObjectDefinition: []byte("invalid-json"),
204229
}
205230

206-
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{})
231+
response, err := reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{})
207232
Expect(err).To(HaveOccurred())
208233
Expect(response).To(BeNil())
209234
})
210235
})
236+
237+
Describe("collectAdditionalInstanceArgs", func() {
238+
It("prefers cluster object store when both are configured", func() {
239+
ns := "test-ns"
240+
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
241+
pc := &config.PluginConfiguration{
242+
Cluster: cluster,
243+
BarmanObjectName: "primary-store",
244+
RecoveryBarmanObjectName: "recovery-store",
245+
}
246+
primaryArgs := []string{"--primary-a", "--primary-b"}
247+
recoveryArgs := []string{"--reco-a"}
248+
cli := buildClientFunc(
249+
makeStoreFunc(ns, pc.BarmanObjectName, primaryArgs),
250+
makeStoreFunc(ns, pc.RecoveryBarmanObjectName, recoveryArgs),
251+
).Build()
252+
253+
impl := LifecycleImplementation{Client: cli}
254+
args, err := impl.collectAdditionalInstanceArgs(context.Background(), pc)
255+
Expect(err).NotTo(HaveOccurred())
256+
Expect(args).To(Equal(primaryArgs))
257+
})
258+
259+
It("falls back to recovery object store when primary not set", func() {
260+
ns := "test-ns"
261+
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
262+
pc := &config.PluginConfiguration{
263+
Cluster: cluster,
264+
BarmanObjectName: "",
265+
RecoveryBarmanObjectName: "recovery-store",
266+
}
267+
recoveryArgs := []string{"--reco-x", "--reco-y"}
268+
cli := buildClientFunc(
269+
makeStoreFunc(ns, pc.RecoveryBarmanObjectName, recoveryArgs),
270+
).Build()
271+
272+
impl := LifecycleImplementation{Client: cli}
273+
args, err := impl.collectAdditionalInstanceArgs(context.Background(), pc)
274+
Expect(err).NotTo(HaveOccurred())
275+
Expect(args).To(Equal(recoveryArgs))
276+
})
277+
278+
It("returns nil when neither object name is configured", func() {
279+
ns := "test-ns"
280+
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
281+
pc := &config.PluginConfiguration{Cluster: cluster}
282+
cli := buildClientFunc().Build()
283+
284+
impl := LifecycleImplementation{Client: cli}
285+
args, err := impl.collectAdditionalInstanceArgs(context.Background(), pc)
286+
Expect(err).NotTo(HaveOccurred())
287+
Expect(args).To(BeNil())
288+
})
289+
290+
It("returns error if primary object store cannot be retrieved", func() {
291+
ns := "test-ns"
292+
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
293+
pc := &config.PluginConfiguration{Cluster: cluster, BarmanObjectName: "missing-store"}
294+
cli := buildClientFunc().Build()
295+
296+
impl := LifecycleImplementation{Client: cli}
297+
args, err := impl.collectAdditionalInstanceArgs(context.Background(), pc)
298+
Expect(err).To(HaveOccurred())
299+
Expect(err.Error()).To(ContainSubstring("while getting barman object store"))
300+
Expect(err.Error()).To(ContainSubstring(ns + "/" + pc.BarmanObjectName))
301+
Expect(args).To(BeNil())
302+
})
303+
304+
It("returns error if recovery object store cannot be retrieved", func() {
305+
ns := "test-ns"
306+
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
307+
pc := &config.PluginConfiguration{Cluster: cluster, RecoveryBarmanObjectName: "missing-reco"}
308+
cli := buildClientFunc().Build()
309+
310+
impl := LifecycleImplementation{Client: cli}
311+
args, err := impl.collectAdditionalInstanceArgs(context.Background(), pc)
312+
Expect(err).To(HaveOccurred())
313+
Expect(err.Error()).To(ContainSubstring("while getting recovery barman object store"))
314+
Expect(err.Error()).To(ContainSubstring(ns + "/" + pc.RecoveryBarmanObjectName))
315+
Expect(args).To(BeNil())
316+
})
317+
})
211318
})
212319

213320
var _ = Describe("Volume utilities", func() {

0 commit comments

Comments
 (0)