Skip to content

Commit be40375

Browse files
leonardocefcanovai
andauthored
feat: additional environment variables (#81)
Signed-off-by: Leonardo Cecchi <[email protected]> Signed-off-by: Francesco Canovai <[email protected]> Co-authored-by: Francesco Canovai <[email protected]>
1 parent e30edd2 commit be40375

File tree

5 files changed

+237
-12
lines changed

5 files changed

+237
-12
lines changed

api/v1/objectstore_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1
1818

1919
import (
2020
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
21+
corev1 "k8s.io/api/core/v1"
2122
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2223
)
2324

@@ -29,6 +30,10 @@ type InstanceSidecarConfiguration struct {
2930
// +kubebuilder:validation:Maximum=3600
3031
// +kubebuilder:default=180
3132
CacheTTL *int `json:"cacheTTL,omitempty"`
33+
34+
// The environment to be explicitly passed to the sidecar
35+
// +optional
36+
Env []corev1.EnvVar `json:"env,omitempty"`
3237
}
3338

3439
// GetCacheTTL returns the cache TTL value, defaulting to 180 seconds if not set.

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

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,136 @@ spec:
389389
maximum: 3600
390390
minimum: 0
391391
type: integer
392+
env:
393+
description: The environment to be explicitly passed to the sidecar
394+
items:
395+
description: EnvVar represents an environment variable present
396+
in a Container.
397+
properties:
398+
name:
399+
description: Name of the environment variable. Must be a
400+
C_IDENTIFIER.
401+
type: string
402+
value:
403+
description: |-
404+
Variable references $(VAR_NAME) are expanded
405+
using the previously defined environment variables in the container and
406+
any service environment variables. If a variable cannot be resolved,
407+
the reference in the input string will be unchanged. Double $$ are reduced
408+
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
409+
"$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
410+
Escaped references will never be expanded, regardless of whether the variable
411+
exists or not.
412+
Defaults to "".
413+
type: string
414+
valueFrom:
415+
description: Source for the environment variable's value.
416+
Cannot be used if value is not empty.
417+
properties:
418+
configMapKeyRef:
419+
description: Selects a key of a ConfigMap.
420+
properties:
421+
key:
422+
description: The key to select.
423+
type: string
424+
name:
425+
default: ""
426+
description: |-
427+
Name of the referent.
428+
This field is effectively required, but due to backwards compatibility is
429+
allowed to be empty. Instances of this type with an empty value here are
430+
almost certainly wrong.
431+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
432+
type: string
433+
optional:
434+
description: Specify whether the ConfigMap or its
435+
key must be defined
436+
type: boolean
437+
required:
438+
- key
439+
type: object
440+
x-kubernetes-map-type: atomic
441+
fieldRef:
442+
description: |-
443+
Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
444+
spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
445+
properties:
446+
apiVersion:
447+
description: Version of the schema the FieldPath
448+
is written in terms of, defaults to "v1".
449+
type: string
450+
fieldPath:
451+
description: Path of the field to select in the
452+
specified API version.
453+
type: string
454+
required:
455+
- fieldPath
456+
type: object
457+
x-kubernetes-map-type: atomic
458+
resourceFieldRef:
459+
description: |-
460+
Selects a resource of the container: only resources limits and requests
461+
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
462+
properties:
463+
containerName:
464+
description: 'Container name: required for volumes,
465+
optional for env vars'
466+
type: string
467+
divisor:
468+
anyOf:
469+
- type: integer
470+
- type: string
471+
description: Specifies the output format of the
472+
exposed resources, defaults to "1"
473+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
474+
x-kubernetes-int-or-string: true
475+
resource:
476+
description: 'Required: resource to select'
477+
type: string
478+
required:
479+
- resource
480+
type: object
481+
x-kubernetes-map-type: atomic
482+
secretKeyRef:
483+
description: Selects a key of a secret in the pod's
484+
namespace
485+
properties:
486+
key:
487+
description: The key of the secret to select from. Must
488+
be a valid secret key.
489+
type: string
490+
name:
491+
default: ""
492+
description: |-
493+
Name of the referent.
494+
This field is effectively required, but due to backwards compatibility is
495+
allowed to be empty. Instances of this type with an empty value here are
496+
almost certainly wrong.
497+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
498+
type: string
499+
optional:
500+
description: Specify whether the Secret or its key
501+
must be defined
502+
type: boolean
503+
required:
504+
- key
505+
type: object
506+
x-kubernetes-map-type: atomic
507+
type: object
508+
required:
509+
- name
510+
type: object
511+
type: array
392512
type: object
393513
required:
394514
- configuration
395515
type: object
396516
status:
397517
description: ObjectStoreStatus defines the observed state of ObjectStore.
398518
type: object
519+
required:
520+
- metadata
521+
- spec
399522
type: object
400523
served: true
401524
storage: true

internal/cnpgi/operator/lifecycle.go

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,19 @@ import (
1414
"github.com/spf13/viper"
1515
batchv1 "k8s.io/api/batch/v1"
1616
corev1 "k8s.io/api/core/v1"
17+
"k8s.io/apimachinery/pkg/types"
1718
"k8s.io/utils/ptr"
19+
"sigs.k8s.io/controller-runtime/pkg/client"
1820

21+
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
1922
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
2023
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
2124
)
2225

2326
// LifecycleImplementation is the implementation of the lifecycle handler
2427
type LifecycleImplementation struct {
2528
lifecycle.UnimplementedOperatorLifecycleServer
29+
Client client.Client
2630
}
2731

2832
// GetCapabilities exposes the lifecycle capabilities
@@ -94,20 +98,85 @@ func (impl LifecycleImplementation) LifecycleHook(
9498
switch kind {
9599
case "Pod":
96100
contextLogger.Info("Reconciling pod")
97-
return reconcilePod(ctx, &cluster, request, pluginConfiguration)
101+
return impl.reconcilePod(ctx, &cluster, request, pluginConfiguration)
98102
case "Job":
99103
contextLogger.Info("Reconciling job")
100-
return reconcileJob(ctx, &cluster, request, pluginConfiguration)
104+
return impl.reconcileJob(ctx, &cluster, request, pluginConfiguration)
101105
default:
102106
return nil, fmt.Errorf("unsupported kind: %s", kind)
103107
}
104108
}
105109

110+
func (impl LifecycleImplementation) collectAdditionalEnvs(
111+
ctx context.Context,
112+
namespace string,
113+
pluginConfiguration *config.PluginConfiguration,
114+
) ([]corev1.EnvVar, error) {
115+
var result []corev1.EnvVar
116+
117+
if len(pluginConfiguration.BarmanObjectName) > 0 {
118+
envs, err := impl.collectObjectStoreEnvs(
119+
ctx,
120+
types.NamespacedName{
121+
Name: pluginConfiguration.BarmanObjectName,
122+
Namespace: namespace,
123+
},
124+
)
125+
if err != nil {
126+
return nil, err
127+
}
128+
result = append(result, envs...)
129+
}
130+
131+
if len(pluginConfiguration.RecoveryBarmanObjectName) > 0 {
132+
envs, err := impl.collectObjectStoreEnvs(
133+
ctx,
134+
types.NamespacedName{
135+
Name: pluginConfiguration.RecoveryBarmanObjectName,
136+
Namespace: namespace,
137+
},
138+
)
139+
if err != nil {
140+
return nil, err
141+
}
142+
result = append(result, envs...)
143+
}
144+
145+
return result, nil
146+
}
147+
148+
func (impl LifecycleImplementation) collectObjectStoreEnvs(
149+
ctx context.Context,
150+
barmanObjectKey types.NamespacedName,
151+
) ([]corev1.EnvVar, error) {
152+
var objectStore barmancloudv1.ObjectStore
153+
if err := impl.Client.Get(ctx, barmanObjectKey, &objectStore); err != nil {
154+
return nil, err
155+
}
156+
157+
return objectStore.Spec.InstanceSidecarConfiguration.Env, nil
158+
}
159+
160+
func (impl LifecycleImplementation) reconcileJob(
161+
ctx context.Context,
162+
cluster *cnpgv1.Cluster,
163+
request *lifecycle.OperatorLifecycleRequest,
164+
pluginConfiguration *config.PluginConfiguration,
165+
) (*lifecycle.OperatorLifecycleResponse, error) {
166+
env, err := impl.collectAdditionalEnvs(ctx, cluster.Namespace, pluginConfiguration)
167+
if err != nil {
168+
return nil, nil
169+
}
170+
171+
return reconcileJob(ctx, cluster, request, pluginConfiguration, env)
172+
}
173+
106174
func reconcileJob(
107175
ctx context.Context,
108176
cluster *cnpgv1.Cluster,
109177
request *lifecycle.OperatorLifecycleRequest,
110178
pluginConfiguration *config.PluginConfiguration,
179+
env []corev1.EnvVar,
111180
) (*lifecycle.OperatorLifecycleResponse, error) {
112181
contextLogger := log.FromContext(ctx).WithName("lifecycle")
113182
if pluginConfig := cluster.GetRecoverySourcePlugin(); pluginConfig == nil || pluginConfig.Name != metadata.PluginName {
@@ -144,6 +213,7 @@ func reconcileJob(
144213
corev1.Container{
145214
Args: []string{"restore"},
146215
},
216+
env,
147217
); err != nil {
148218
return nil, fmt.Errorf("while reconciling pod spec for job: %w", err)
149219
}
@@ -159,11 +229,26 @@ func reconcileJob(
159229
}, nil
160230
}
161231

232+
func (impl LifecycleImplementation) reconcilePod(
233+
ctx context.Context,
234+
cluster *cnpgv1.Cluster,
235+
request *lifecycle.OperatorLifecycleRequest,
236+
pluginConfiguration *config.PluginConfiguration,
237+
) (*lifecycle.OperatorLifecycleResponse, error) {
238+
env, err := impl.collectAdditionalEnvs(ctx, cluster.Namespace, pluginConfiguration)
239+
if err != nil {
240+
return nil, nil
241+
}
242+
243+
return reconcilePod(ctx, cluster, request, pluginConfiguration, env)
244+
}
245+
162246
func reconcilePod(
163247
ctx context.Context,
164248
cluster *cnpgv1.Cluster,
165249
request *lifecycle.OperatorLifecycleRequest,
166250
pluginConfiguration *config.PluginConfiguration,
251+
env []corev1.EnvVar,
167252
) (*lifecycle.OperatorLifecycleResponse, error) {
168253
pod, err := decoder.DecodePodJSON(request.GetObjectDefinition())
169254
if err != nil {
@@ -176,9 +261,16 @@ func reconcilePod(
176261
mutatedPod := pod.DeepCopy()
177262

178263
if len(pluginConfiguration.BarmanObjectName) != 0 {
179-
if err := reconcilePodSpec(pluginConfiguration, cluster, &mutatedPod.Spec, "postgres", corev1.Container{
180-
Args: []string{"instance"},
181-
}); err != nil {
264+
if err := reconcilePodSpec(
265+
pluginConfiguration,
266+
cluster,
267+
&mutatedPod.Spec,
268+
"postgres",
269+
corev1.Container{
270+
Args: []string{"instance"},
271+
},
272+
env,
273+
); err != nil {
182274
return nil, fmt.Errorf("while reconciling pod spec for pod: %w", err)
183275
}
184276
} else {
@@ -202,6 +294,7 @@ func reconcilePodSpec(
202294
spec *corev1.PodSpec,
203295
mainContainerName string,
204296
sidecarConfig corev1.Container,
297+
additionalEnvs []corev1.EnvVar,
205298
) error {
206299
envs := []corev1.EnvVar{
207300
{
@@ -246,6 +339,8 @@ func reconcilePodSpec(
246339
)
247340
}
248341

342+
envs = append(envs, additionalEnvs...)
343+
249344
baseProbe := &corev1.Probe{
250345
FailureThreshold: 3,
251346
ProbeHandler: corev1.ProbeHandler{

internal/cnpgi/operator/lifecycle_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ var _ = Describe("LifecycleImplementation", func() {
107107
ObjectDefinition: jobJSON,
108108
}
109109

110-
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration)
110+
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration, nil)
111111
Expect(err).NotTo(HaveOccurred())
112112
Expect(response).NotTo(BeNil())
113113
Expect(response.JsonPatch).NotTo(BeEmpty())
@@ -128,7 +128,7 @@ var _ = Describe("LifecycleImplementation", func() {
128128
ObjectDefinition: jobJSON,
129129
}
130130

131-
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration)
131+
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration, nil)
132132
Expect(err).NotTo(HaveOccurred())
133133
Expect(response).To(BeNil())
134134
})
@@ -138,7 +138,7 @@ var _ = Describe("LifecycleImplementation", func() {
138138
ObjectDefinition: []byte("invalid-json"),
139139
}
140140

141-
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration)
141+
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration, nil)
142142
Expect(err).To(HaveOccurred())
143143
Expect(response).To(BeNil())
144144
})
@@ -165,7 +165,7 @@ var _ = Describe("LifecycleImplementation", func() {
165165
ObjectDefinition: jobJSON,
166166
}
167167

168-
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration)
168+
response, err := reconcileJob(ctx, cluster, request, pluginConfiguration, nil)
169169
Expect(err).NotTo(HaveOccurred())
170170
Expect(response).To(BeNil())
171171
})
@@ -185,7 +185,7 @@ var _ = Describe("LifecycleImplementation", func() {
185185
ObjectDefinition: podJSON,
186186
}
187187

188-
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration)
188+
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, nil)
189189
Expect(err).NotTo(HaveOccurred())
190190
Expect(response).NotTo(BeNil())
191191
Expect(response.JsonPatch).NotTo(BeEmpty())
@@ -203,7 +203,7 @@ var _ = Describe("LifecycleImplementation", func() {
203203
ObjectDefinition: []byte("invalid-json"),
204204
}
205205

206-
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration)
206+
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, nil)
207207
Expect(err).To(HaveOccurred())
208208
Expect(response).To(BeNil())
209209
})

0 commit comments

Comments
 (0)