hashedTokenSecretStatus |
object |
diff --git a/internal/controller/humiobootstraptoken_controller.go b/internal/controller/humiobootstraptoken_controller.go
index 5bed5428..448fed5e 100644
--- a/internal/controller/humiobootstraptoken_controller.go
+++ b/internal/controller/humiobootstraptoken_controller.go
@@ -25,6 +25,8 @@ import (
"strings"
"time"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
"github.com/go-logr/logr"
humiov1alpha1 "github.com/humio/humio-operator/api/v1alpha1"
"github.com/humio/humio-operator/internal/helpers"
@@ -143,6 +145,11 @@ func (r *HumioBootstrapTokenReconciler) updateStatus(ctx context.Context, hbt *h
return r.Client.Status().Update(ctx, hbt)
}
+func (r *HumioBootstrapTokenReconciler) updateStatusImage(ctx context.Context, hbt *humiov1alpha1.HumioBootstrapToken, image string) error {
+ hbt.Status.BootstrapImage = image
+ return r.Client.Status().Update(ctx, hbt)
+}
+
func (r *HumioBootstrapTokenReconciler) execCommand(ctx context.Context, pod *corev1.Pod, args []string) (string, error) {
configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
@@ -209,7 +216,10 @@ func (r *HumioBootstrapTokenReconciler) createPod(ctx context.Context, hbt *humi
}
}
humioBootstrapTokenConfig := NewHumioBootstrapTokenConfig(hbt, humioCluster)
- pod := ConstructBootstrapPod(&humioBootstrapTokenConfig)
+ pod, err := r.constructBootstrapPod(ctx, &humioBootstrapTokenConfig)
+ if err != nil {
+ return pod, r.logErrorAndReturn(err, "could not construct pod")
+ }
if err := r.Get(ctx, types.NamespacedName{
Namespace: pod.Namespace,
Name: pod.Name,
@@ -231,7 +241,10 @@ func (r *HumioBootstrapTokenReconciler) createPod(ctx context.Context, hbt *humi
func (r *HumioBootstrapTokenReconciler) deletePod(ctx context.Context, hbt *humiov1alpha1.HumioBootstrapToken, hc *humiov1alpha1.HumioCluster) error {
existingPod := &corev1.Pod{}
humioBootstrapTokenConfig := NewHumioBootstrapTokenConfig(hbt, hc)
- pod := ConstructBootstrapPod(&humioBootstrapTokenConfig)
+ pod, err := r.constructBootstrapPod(ctx, &humioBootstrapTokenConfig)
+ if err != nil {
+ return r.logErrorAndReturn(err, "could not construct pod")
+ }
if err := r.Get(ctx, types.NamespacedName{
Namespace: pod.Namespace,
Name: pod.Name,
@@ -385,6 +398,11 @@ func (r *HumioBootstrapTokenReconciler) ensureBootstrapTokenHashedToken(ctx cont
if err = r.Update(ctx, updatedSecret); err != nil {
return r.logErrorAndReturn(err, "failed to update secret with hashedToken data")
}
+
+ if err := r.updateStatusImage(ctx, hbt, pod.Spec.Containers[0].Image); err != nil {
+ return r.logErrorAndReturn(err, "failed to update bootstrap token image status")
+ }
+
return nil
}
@@ -398,6 +416,59 @@ func (r *HumioBootstrapTokenReconciler) getBootstrapTokenSecret(ctx context.Cont
return existingSecret, err
}
+func (r *HumioBootstrapTokenReconciler) constructBootstrapPod(ctx context.Context, bootstrapConfig *HumioBootstrapTokenConfig) (*corev1.Pod, error) {
+ userID := int64(65534)
+ var image string
+
+ if bootstrapConfig.imageSource() == nil {
+ image = bootstrapConfig.image()
+ } else {
+ configMap, err := kubernetes.GetConfigMap(ctx, r, bootstrapConfig.imageSource().ConfigMapRef.Name, bootstrapConfig.namespace())
+ if err != nil {
+ return &corev1.Pod{}, r.logErrorAndReturn(err, "failed to get imageFromSource")
+ }
+ if imageValue, ok := configMap.Data[bootstrapConfig.imageSource().ConfigMapRef.Key]; ok {
+ image = imageValue
+ }
+ }
+
+ return &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: bootstrapConfig.podName(),
+ Namespace: bootstrapConfig.namespace(),
+ },
+ Spec: corev1.PodSpec{
+ ImagePullSecrets: bootstrapConfig.imagePullSecrets(),
+ Affinity: bootstrapConfig.affinity(),
+ Containers: []corev1.Container{
+ {
+ Name: HumioContainerName,
+ Image: image,
+ Command: []string{"/bin/sleep", "900"},
+ Env: []corev1.EnvVar{
+ {
+ Name: "HUMIO_LOG4J_CONFIGURATION",
+ Value: "log4j2-json-stdout.xml",
+ },
+ },
+ Resources: bootstrapConfig.resources(),
+ SecurityContext: &corev1.SecurityContext{
+ Privileged: helpers.BoolPtr(false),
+ AllowPrivilegeEscalation: helpers.BoolPtr(false),
+ ReadOnlyRootFilesystem: helpers.BoolPtr(true),
+ RunAsUser: &userID,
+ Capabilities: &corev1.Capabilities{
+ Drop: []corev1.Capability{
+ "ALL",
+ },
+ },
+ },
+ },
+ },
+ },
+ }, nil
+}
+
// SetupWithManager sets up the controller with the Manager.
func (r *HumioBootstrapTokenReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
diff --git a/internal/controller/humiobootstraptoken_defaults.go b/internal/controller/humiobootstraptoken_defaults.go
index c605fd7d..b460c7ed 100644
--- a/internal/controller/humiobootstraptoken_defaults.go
+++ b/internal/controller/humiobootstraptoken_defaults.go
@@ -60,12 +60,29 @@ func (b *HumioBootstrapTokenConfig) image() string {
}
if b.ManagedHumioCluster != nil {
if len(b.ManagedHumioCluster.Spec.NodePools) > 0 {
- return b.ManagedHumioCluster.Spec.NodePools[0].Image
+ if b.ManagedHumioCluster.Spec.NodePools[0].Image != "" {
+ return b.ManagedHumioCluster.Spec.NodePools[0].Image
+ }
}
}
return versions.DefaultHumioImageVersion()
}
+func (b *HumioBootstrapTokenConfig) imageSource() *humiov1alpha1.HumioImageSource {
+
+ if b.ManagedHumioCluster.Spec.ImageSource != nil {
+ return b.ManagedHumioCluster.Spec.ImageSource
+ }
+ if b.ManagedHumioCluster != nil {
+ if len(b.ManagedHumioCluster.Spec.NodePools) > 0 {
+ if b.ManagedHumioCluster.Spec.NodePools[0].ImageSource != nil {
+ return b.ManagedHumioCluster.Spec.NodePools[0].ImageSource
+ }
+ }
+ }
+ return nil
+}
+
func (b *HumioBootstrapTokenConfig) imagePullSecrets() []corev1.LocalObjectReference {
if len(b.BootstrapToken.Spec.ImagePullSecrets) > 0 {
return b.BootstrapToken.Spec.ImagePullSecrets
diff --git a/internal/controller/humiobootstraptoken_pods.go b/internal/controller/humiobootstraptoken_pods.go
index c9117617..56c57635 100644
--- a/internal/controller/humiobootstraptoken_pods.go
+++ b/internal/controller/humiobootstraptoken_pods.go
@@ -1,12 +1,14 @@
package controller
import (
+ "context"
+
"github.com/humio/humio-operator/internal/helpers"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
-func ConstructBootstrapPod(bootstrapConfig *HumioBootstrapTokenConfig) *corev1.Pod {
+func ConstructBootstrapPod(ctx context.Context, bootstrapConfig *HumioBootstrapTokenConfig) *corev1.Pod {
userID := int64(65534)
return &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
diff --git a/internal/controller/suite/clusters/humiocluster_controller_test.go b/internal/controller/suite/clusters/humiocluster_controller_test.go
index 375ba73b..e3665a07 100644
--- a/internal/controller/suite/clusters/humiocluster_controller_test.go
+++ b/internal/controller/suite/clusters/humiocluster_controller_test.go
@@ -975,6 +975,56 @@ var _ = Describe("HumioCluster Controller", func() {
})
})
+ Context("Humio Cluster Create with Image Source", Label("envtest", "dummy", "real"), func() {
+ It("Should correctly create cluster from image source", func() {
+ key := types.NamespacedName{
+ Name: "humiocluster-create-image-source",
+ Namespace: testProcessNamespace,
+ }
+ toCreate := suite.ConstructBasicSingleNodeHumioCluster(key, true)
+ toCreate.Spec.Image = ""
+ toCreate.Spec.NodeCount = 2
+ toCreate.Spec.ImageSource = &humiov1alpha1.HumioImageSource{
+ ConfigMapRef: &corev1.ConfigMapKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "image-source-create",
+ },
+ Key: "tag",
+ },
+ }
+
+ ctx := context.Background()
+ var updatedHumioCluster humiov1alpha1.HumioCluster
+
+ suite.UsingClusterBy(key.Name, "Creating the imageSource configmap")
+ updatedImage := versions.UpgradePatchBestEffortNewVersion()
+ envVarSourceConfigMap := corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "image-source-create",
+ Namespace: key.Namespace,
+ },
+ Data: map[string]string{"tag": updatedImage},
+ }
+ Expect(k8sClient.Create(ctx, &envVarSourceConfigMap)).To(Succeed())
+
+ suite.UsingClusterBy(key.Name, "Creating the cluster successfully")
+ suite.CreateAndBootstrapCluster(ctx, k8sClient, testHumioClient, toCreate, true, humiov1alpha1.HumioClusterStateRunning, testTimeout)
+ defer suite.CleanupCluster(ctx, k8sClient, toCreate)
+
+ Eventually(func() string {
+ updatedHumioCluster = humiov1alpha1.HumioCluster{}
+ Expect(k8sClient.Get(ctx, key, &updatedHumioCluster)).Should(Succeed())
+ return updatedHumioCluster.Status.State
+ }, testTimeout, suite.TestInterval).Should(BeIdenticalTo(humiov1alpha1.HumioClusterStateRunning))
+
+ Eventually(func() error {
+ bootstrapToken, err := suite.GetHumioBootstrapToken(ctx, key, k8sClient)
+ Expect(bootstrapToken.Status.BootstrapImage).To(BeEquivalentTo(updatedImage))
+ return err
+ }, testTimeout, suite.TestInterval).Should(Succeed())
+ })
+ })
+
Context("Humio Cluster Update Image Source", Label("envtest", "dummy", "real"), func() {
It("Update should correctly replace pods to use new image", func() {
key := types.NamespacedName{
@@ -4012,7 +4062,7 @@ var _ = Describe("HumioCluster Controller", func() {
return k8sClient.Update(ctx, &updatedHumioCluster)
}, testTimeout, suite.TestInterval).Should(Succeed())
- suite.SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx, key, k8sClient, testTimeout)
+ suite.SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx, key, k8sClient, testTimeout, &updatedHumioCluster)
suite.UsingClusterBy(key.Name, "Confirming we only created ingresses with expected hostname")
foundIngressList = []networkingv1.Ingress{}
diff --git a/internal/controller/suite/common.go b/internal/controller/suite/common.go
index 0fa6d4f1..31edd4d4 100644
--- a/internal/controller/suite/common.go
+++ b/internal/controller/suite/common.go
@@ -422,7 +422,7 @@ func CreateAndBootstrapCluster(ctx context.Context, k8sClient client.Client, hum
return
}
- SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx, key, k8sClient, testTimeout)
+ SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx, key, k8sClient, testTimeout, cluster)
UsingClusterBy(key.Name, "Confirming cluster enters running state")
var updatedHumioCluster humiov1alpha1.HumioCluster
@@ -718,21 +718,41 @@ func CreateDockerRegredSecret(ctx context.Context, namespace corev1.Namespace, k
Expect(k8sClient.Create(ctx, ®credSecret)).To(Succeed())
}
-func SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx context.Context, key types.NamespacedName, k8sClient client.Client, testTimeout time.Duration) {
+func SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx context.Context, key types.NamespacedName, k8sClient client.Client, testTimeout time.Duration, cluster *humiov1alpha1.HumioCluster) {
UsingClusterBy(key.Name, "Simulating HumioBootstrapToken Controller running and adding the secret and status")
Eventually(func() error {
- hbtList, err := kubernetes.ListHumioBootstrapTokens(ctx, k8sClient, key.Namespace, kubernetes.LabelsForHumioBootstrapToken(key.Name))
- if err != nil {
- return err
+ var bootstrapImage string
+ bootstrapImage = "test"
+ if cluster.Spec.Image != "" {
+ bootstrapImage = cluster.Spec.Image
}
- if len(hbtList) == 0 {
- return fmt.Errorf("no humiobootstraptokens for cluster %s", key.Name)
+ if cluster.Spec.ImageSource != nil {
+ configMap, err := kubernetes.GetConfigMap(ctx, k8sClient, cluster.Spec.ImageSource.ConfigMapRef.Name, cluster.Namespace)
+ if err != nil && !k8serrors.IsNotFound(err) {
+ Expect(err).Should(Succeed())
+ } else {
+ bootstrapImage = configMap.Data[cluster.Spec.ImageSource.ConfigMapRef.Key]
+ }
}
- if len(hbtList) > 1 {
- return fmt.Errorf("too many humiobootstraptokens for cluster %s. found list : %+v", key.Name, hbtList)
+ for _, nodePool := range cluster.Spec.NodePools {
+ if nodePool.HumioNodeSpec.Image != "" {
+ bootstrapImage = nodePool.HumioNodeSpec.Image
+ break
+ }
+ if nodePool.ImageSource != nil {
+ configMap, err := kubernetes.GetConfigMap(ctx, k8sClient, nodePool.ImageSource.ConfigMapRef.Name, cluster.Namespace)
+ if err != nil && !k8serrors.IsNotFound(err) {
+ Expect(err).Should(Succeed())
+ } else {
+ bootstrapImage = configMap.Data[nodePool.ImageSource.ConfigMapRef.Key]
+ break
+ }
+ }
+ }
+ updatedHumioBootstrapToken, err := GetHumioBootstrapToken(ctx, key, k8sClient)
+ if err != nil {
+ return err
}
-
- updatedHumioBootstrapToken := hbtList[0]
updatedHumioBootstrapToken.Status.State = humiov1alpha1.HumioBootstrapTokenStateReady
updatedHumioBootstrapToken.Status.TokenSecretKeyRef = humiov1alpha1.HumioTokenSecretStatus{
SecretKeyRef: &corev1.SecretKeySelector{
@@ -750,6 +770,21 @@ func SimulateHumioBootstrapTokenCreatingSecretAndUpdatingStatus(ctx context.Cont
Key: "hashedToken",
},
}
+ updatedHumioBootstrapToken.Status.BootstrapImage = bootstrapImage
return k8sClient.Status().Update(ctx, &updatedHumioBootstrapToken)
}, testTimeout, TestInterval).Should(Succeed())
}
+
+func GetHumioBootstrapToken(ctx context.Context, key types.NamespacedName, k8sClient client.Client) (humiov1alpha1.HumioBootstrapToken, error) {
+ hbtList, err := kubernetes.ListHumioBootstrapTokens(ctx, k8sClient, key.Namespace, kubernetes.LabelsForHumioBootstrapToken(key.Name))
+ if err != nil {
+ return humiov1alpha1.HumioBootstrapToken{}, err
+ }
+ if len(hbtList) == 0 {
+ return humiov1alpha1.HumioBootstrapToken{}, fmt.Errorf("no humiobootstraptokens for cluster %s", key.Name)
+ }
+ if len(hbtList) > 1 {
+ return humiov1alpha1.HumioBootstrapToken{}, fmt.Errorf("too many humiobootstraptokens for cluster %s. found list : %+v", key.Name, hbtList)
+ }
+ return hbtList[0], nil
+}
|