Skip to content

Commit 4437369

Browse files
feat(operator): Mount CA into Upgrade Artifacts Job Container (#2200)
use new hostcabundle functionality for upgrade arifacts job
1 parent 3fa75ea commit 4437369

File tree

4 files changed

+223
-32
lines changed

4 files changed

+223
-32
lines changed

operator/charts/embedded-cluster-operator/values.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,3 @@ serviceAccount:
7171
labels: {}
7272

7373
terminationGracePeriodSeconds: 10
74-
75-
privateCAs:
76-
enabled: true
77-
configmapName: "private-cas"

operator/charts/embedded-cluster-operator/values.yaml.tmpl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,3 @@ serviceAccount:
7373
labels: {}
7474

7575
terminationGracePeriodSeconds: 10
76-
77-
privateCAs:
78-
enabled: true
79-
configmapName: "private-cas"

operator/pkg/artifacts/upgrade.go

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,39 +64,17 @@ var copyArtifactsJob = &batchv1.Job{
6464
},
6565
},
6666
},
67-
{
68-
Name: "private-cas",
69-
VolumeSource: corev1.VolumeSource{
70-
ConfigMap: &corev1.ConfigMapVolumeSource{
71-
LocalObjectReference: corev1.LocalObjectReference{
72-
Name: "private-cas",
73-
},
74-
Optional: ptr.To[bool](true),
75-
},
76-
},
77-
},
7867
},
7968
RestartPolicy: corev1.RestartPolicyNever,
8069
Containers: []corev1.Container{
8170
{
8271
Name: "embedded-cluster-updater",
83-
Env: []corev1.EnvVar{
84-
{
85-
Name: "SSL_CERT_DIR",
86-
Value: "/certs",
87-
},
88-
},
8972
VolumeMounts: []corev1.VolumeMount{
9073
{
9174
Name: "host",
9275
MountPath: "/embedded-cluster",
9376
ReadOnly: false,
9477
},
95-
{
96-
Name: "private-cas",
97-
MountPath: "/certs",
98-
ReadOnly: true,
99-
},
10078
},
10179
},
10280
},
@@ -259,7 +237,7 @@ func ensureArtifactsJobForNode(
259237
localArtifactMirrorImage, appSlug, channelID, appVersion string,
260238
cfghash string,
261239
) (*batchv1.Job, error) {
262-
job, err := getArtifactJobForNode(cli, in, node, localArtifactMirrorImage, appSlug, channelID, appVersion)
240+
job, err := getArtifactJobForNode(ctx, cli, in, node, localArtifactMirrorImage, appSlug, channelID, appVersion)
263241
if err != nil {
264242
return nil, fmt.Errorf("get job for node: %w", err)
265243
}
@@ -284,7 +262,7 @@ func ensureArtifactsJobForNode(
284262
}
285263

286264
func getArtifactJobForNode(
287-
cli client.Client, in *clusterv1beta1.Installation,
265+
ctx context.Context, cli client.Client, in *clusterv1beta1.Installation,
288266
node corev1.Node,
289267
localArtifactMirrorImage, appSlug, channelID, appVersion string,
290268
) (*batchv1.Job, error) {
@@ -335,6 +313,48 @@ func getArtifactJobForNode(
335313
)
336314
}
337315

316+
// Add the host CA bundle volume, mount, and env var if it's available in the installation
317+
log := ctrl.LoggerFrom(ctx)
318+
hostCABundlePath := ""
319+
if in.Spec.RuntimeConfig != nil {
320+
hostCABundlePath = in.Spec.RuntimeConfig.HostCABundlePath
321+
}
322+
323+
if hostCABundlePath != "" {
324+
log.Info("Using host CA bundle from installation", "path", hostCABundlePath)
325+
326+
// Add the CA bundle volume
327+
job.Spec.Template.Spec.Volumes = append(job.Spec.Template.Spec.Volumes, corev1.Volume{
328+
Name: "host-ca-bundle",
329+
VolumeSource: corev1.VolumeSource{
330+
HostPath: &corev1.HostPathVolumeSource{
331+
Path: hostCABundlePath,
332+
Type: ptr.To(corev1.HostPathFileOrCreate),
333+
},
334+
},
335+
})
336+
337+
// Add the CA bundle mount
338+
job.Spec.Template.Spec.Containers[0].VolumeMounts = append(
339+
job.Spec.Template.Spec.Containers[0].VolumeMounts,
340+
corev1.VolumeMount{
341+
Name: "host-ca-bundle",
342+
MountPath: "/certs/ca-certificates.crt",
343+
},
344+
)
345+
346+
// Add the SSL_CERT_DIR environment variable
347+
job.Spec.Template.Spec.Containers[0].Env = append(
348+
job.Spec.Template.Spec.Containers[0].Env,
349+
corev1.EnvVar{
350+
Name: "SSL_CERT_DIR",
351+
Value: "/certs",
352+
},
353+
)
354+
} else {
355+
log.Info("No host CA bundle path found in installation, no CA bundle will be used")
356+
}
357+
338358
if !in.Spec.AirGap && in.Spec.Config != nil && in.Spec.Config.Domains.ProxyRegistryDomain != "" {
339359
localArtifactMirrorImage = strings.Replace(
340360
localArtifactMirrorImage,

operator/pkg/artifacts/upgrade_test.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import (
1515
batchv1 "k8s.io/api/batch/v1"
1616
corev1 "k8s.io/api/core/v1"
1717
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18+
"k8s.io/apimachinery/pkg/runtime"
1819
"sigs.k8s.io/controller-runtime/pkg/client"
20+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1921
"sigs.k8s.io/controller-runtime/pkg/envtest"
2022
)
2123

@@ -435,3 +437,180 @@ func TestListArtifactsJobForNodes(t *testing.T) {
435437
})
436438
}
437439
}
440+
441+
func TestGetArtifactJobForNode_HostCABundle(t *testing.T) {
442+
// Test with HostCABundlePath set
443+
t.Run("with HostCABundlePath set", func(t *testing.T) {
444+
log := testr.NewWithOptions(t, testr.Options{Verbosity: 10})
445+
ctx := logr.NewContext(context.Background(), log)
446+
447+
scheme := runtime.NewScheme()
448+
require.NoError(t, clusterv1beta1.AddToScheme(scheme))
449+
require.NoError(t, batchv1.AddToScheme(scheme))
450+
require.NoError(t, corev1.AddToScheme(scheme))
451+
452+
// CA path used for testing
453+
testCAPath := "/etc/ssl/certs/ca-certificates.crt"
454+
455+
// Create a minimal installation CR with RuntimeConfig.HostCABundlePath set
456+
installation := &clusterv1beta1.Installation{
457+
ObjectMeta: metav1.ObjectMeta{
458+
Name: "test-installation",
459+
},
460+
Spec: clusterv1beta1.InstallationSpec{
461+
AirGap: true,
462+
Artifacts: &clusterv1beta1.ArtifactsLocation{
463+
Images: "images",
464+
HelmCharts: "helm-charts",
465+
EmbeddedClusterBinary: "embedded-cluster-binary",
466+
EmbeddedClusterMetadata: "embedded-cluster-metadata",
467+
},
468+
RuntimeConfig: &clusterv1beta1.RuntimeConfigSpec{
469+
HostCABundlePath: testCAPath,
470+
},
471+
},
472+
}
473+
474+
// Create a fake client
475+
cli := fake.NewClientBuilder().
476+
WithScheme(scheme).
477+
WithObjects(installation).
478+
Build()
479+
480+
// Create a test node
481+
node := corev1.Node{
482+
ObjectMeta: metav1.ObjectMeta{
483+
Name: "test-node",
484+
},
485+
}
486+
487+
// Call the function under test
488+
job, err := getArtifactJobForNode(
489+
ctx, cli, installation, node,
490+
"local-artifact-mirror:latest",
491+
"app-slug",
492+
"channel-id",
493+
"1.0.0",
494+
)
495+
require.NoError(t, err)
496+
497+
// Verify that the host CA bundle volume exists
498+
var hostCABundleVolumeFound bool
499+
for _, volume := range job.Spec.Template.Spec.Volumes {
500+
if volume.Name == "host-ca-bundle" {
501+
hostCABundleVolumeFound = true
502+
// Verify the volume properties
503+
require.NotNil(t, volume.HostPath, "Host CA bundle volume should be a hostPath volume")
504+
assert.Equal(t, testCAPath, volume.HostPath.Path, "Host CA bundle path should match RuntimeConfig.HostCABundlePath")
505+
assert.Equal(t, corev1.HostPathFileOrCreate, *volume.HostPath.Type, "Host CA bundle type should be FileOrCreate")
506+
break
507+
}
508+
}
509+
assert.True(t, hostCABundleVolumeFound, "Host CA bundle volume should exist")
510+
511+
// Verify that the volume mount exists
512+
var hostCABundleMountFound bool
513+
for _, mount := range job.Spec.Template.Spec.Containers[0].VolumeMounts {
514+
if mount.Name == "host-ca-bundle" {
515+
hostCABundleMountFound = true
516+
// Verify the mount properties
517+
assert.Equal(t, "/certs/ca-certificates.crt", mount.MountPath, "Host CA bundle mount path should be correct")
518+
break
519+
}
520+
}
521+
assert.True(t, hostCABundleMountFound, "Host CA bundle mount should exist")
522+
523+
// Verify that the SSL_CERT_DIR environment variable exists
524+
var sslCertDirEnvFound bool
525+
for _, env := range job.Spec.Template.Spec.Containers[0].Env {
526+
if env.Name == "SSL_CERT_DIR" {
527+
sslCertDirEnvFound = true
528+
// Verify the env var value
529+
assert.Equal(t, "/certs", env.Value, "SSL_CERT_DIR value should be correct")
530+
break
531+
}
532+
}
533+
assert.True(t, sslCertDirEnvFound, "SSL_CERT_DIR environment variable should exist")
534+
})
535+
536+
// Test without HostCABundlePath set
537+
t.Run("without HostCABundlePath set", func(t *testing.T) {
538+
log := testr.NewWithOptions(t, testr.Options{Verbosity: 10})
539+
ctx := logr.NewContext(context.Background(), log)
540+
541+
scheme := runtime.NewScheme()
542+
require.NoError(t, clusterv1beta1.AddToScheme(scheme))
543+
require.NoError(t, batchv1.AddToScheme(scheme))
544+
require.NoError(t, corev1.AddToScheme(scheme))
545+
546+
// Create a minimal installation CR without RuntimeConfig.HostCABundlePath
547+
installation := &clusterv1beta1.Installation{
548+
ObjectMeta: metav1.ObjectMeta{
549+
Name: "test-installation",
550+
},
551+
Spec: clusterv1beta1.InstallationSpec{
552+
AirGap: true,
553+
Artifacts: &clusterv1beta1.ArtifactsLocation{
554+
Images: "images",
555+
HelmCharts: "helm-charts",
556+
EmbeddedClusterBinary: "embedded-cluster-binary",
557+
EmbeddedClusterMetadata: "embedded-cluster-metadata",
558+
},
559+
// No RuntimeConfig or empty RuntimeConfig
560+
},
561+
}
562+
563+
// Create a fake client
564+
cli := fake.NewClientBuilder().
565+
WithScheme(scheme).
566+
WithObjects(installation).
567+
Build()
568+
569+
// Create a test node
570+
node := corev1.Node{
571+
ObjectMeta: metav1.ObjectMeta{
572+
Name: "test-node",
573+
},
574+
}
575+
576+
// Call the function under test
577+
job, err := getArtifactJobForNode(
578+
ctx, cli, installation, node,
579+
"local-artifact-mirror:latest",
580+
"app-slug",
581+
"channel-id",
582+
"1.0.0",
583+
)
584+
require.NoError(t, err)
585+
586+
// Verify that the host CA bundle volume does NOT exist
587+
var hostCABundleVolumeFound bool
588+
for _, volume := range job.Spec.Template.Spec.Volumes {
589+
if volume.Name == "host-ca-bundle" {
590+
hostCABundleVolumeFound = true
591+
break
592+
}
593+
}
594+
assert.False(t, hostCABundleVolumeFound, "Host CA bundle volume should not exist when HostCABundlePath is not set")
595+
596+
// Verify that the volume mount does NOT exist
597+
var hostCABundleMountFound bool
598+
for _, mount := range job.Spec.Template.Spec.Containers[0].VolumeMounts {
599+
if mount.Name == "host-ca-bundle" {
600+
hostCABundleMountFound = true
601+
break
602+
}
603+
}
604+
assert.False(t, hostCABundleMountFound, "Host CA bundle mount should not exist when HostCABundlePath is not set")
605+
606+
// Verify that the SSL_CERT_DIR environment variable does NOT exist
607+
var sslCertDirEnvFound bool
608+
for _, env := range job.Spec.Template.Spec.Containers[0].Env {
609+
if env.Name == "SSL_CERT_DIR" {
610+
sslCertDirEnvFound = true
611+
break
612+
}
613+
}
614+
assert.False(t, sslCertDirEnvFound, "SSL_CERT_DIR environment variable should not exist when HostCABundlePath is not set")
615+
})
616+
}

0 commit comments

Comments
 (0)