Skip to content

Commit

Permalink
Updates to ADDITIONAL_VARS are not applied to existing clusters. Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanemerson committed Dec 1, 2023
1 parent 588dab2 commit c502123
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,6 @@ func StatefulSetRollingUpgrade(i *ispnv1.Infinispan, ctx pipeline.Context) {
updateNeeded = true
}

// Validate ConfigMap changes (by the hash of the i.yaml key value)
updateNeeded = updateStatefulSetEnv(container, statefulSet, "CONFIG_HASH", hash.HashString(configFiles.ServerBaseConfig, configFiles.ServerAdminConfig)) || updateNeeded
updateNeeded = updateStatefulSetEnv(container, statefulSet, "ADMIN_IDENTITIES_HASH", hash.HashByte(configFiles.AdminIdentities.IdentitiesFile)) || updateNeeded

if updateCmdArgs, err := updateStartupArgs(container, configFiles); err != nil {
ctx.Requeue(err)
return
Expand All @@ -127,6 +123,11 @@ func StatefulSetRollingUpgrade(i *ispnv1.Infinispan, ctx pipeline.Context) {
}
updateNeeded = updateStatefulSetAnnotations(statefulSet, "checksum/overlayConfig", hashVal) || updateNeeded
updateNeeded = updateStatefulSetAnnotations(statefulSet, "checksum/credentialStore", hash.HashMap(configFiles.CredentialStoreEntries)) || updateNeeded
podEnvs, podEnvHash := provision.PodEnvsAndHash(i, configFiles)
if updateStatefulSetAnnotations(statefulSet, "checksum/podEnvs", podEnvHash) {
updateNeeded = true
container.Env = podEnvs
}
updateNeeded = applyOverlayConfigVolume(container, i.Spec.ConfigMapName, spec) || updateNeeded

externalArtifactsUpd, err := provision.ApplyExternalArtifactsDownload(i, container, spec)
Expand Down Expand Up @@ -166,14 +167,6 @@ func StatefulSetRollingUpgrade(i *ispnv1.Infinispan, ctx pipeline.Context) {
}
}

// Validate extra Java options changes
if updateStatefulSetEnv(container, statefulSet, "JAVA_OPTIONS", i.GetJavaOptions()) {
updateNeeded = true
}
if updateStatefulSetEnv(container, statefulSet, "CLI_JAVA_OPTIONS", ispnContr.CliExtraJvmOpts) {
updateNeeded = true
}

if updateNeeded {
log.Info("updateNeeded")
// If updating the parameters results in a rolling upgrade, we can update the labels here too
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package provision

import (
"crypto/sha1"
"encoding/hex"
"fmt"
"strings"
"time"
Expand Down Expand Up @@ -70,8 +72,10 @@ func ClusterStatefulSetSpec(statefulSetName string, i *ispnv1.Infinispan, ctx pi
labelsForSelector[consts.StatefulSetPodLabel] = statefulSetName

configFiles := ctx.ConfigFiles()
podEnvs, podEnvsHash := PodEnvsAndHash(i, configFiles)
statefulSetAnnotations := consts.DeploymentAnnotations
statefulSetAnnotations["checksum/credentialStore"] = hash.HashMap(configFiles.CredentialStoreEntries)
statefulSetAnnotations["checksum/podEnvs"] = podEnvsHash
annotationsForPod := i.PodAnnotations()
annotationsForPod["updateDate"] = time.Now().String()

Expand Down Expand Up @@ -102,14 +106,10 @@ func ClusterStatefulSetSpec(statefulSetName string, i *ispnv1.Infinispan, ctx pi
Spec: corev1.PodSpec{
Affinity: i.Affinity(),
Containers: []corev1.Container{{
Image: i.ImageName(),
Args: BuildServerContainerArgs(ctx.ConfigFiles()),
Name: InfinispanContainer,
Env: PodEnv(i, &[]corev1.EnvVar{
{Name: "CONFIG_HASH", Value: hash.HashString(configFiles.ServerBaseConfig, configFiles.ServerAdminConfig)},
{Name: "ADMIN_IDENTITIES_HASH", Value: hash.HashByte(configFiles.AdminIdentities.IdentitiesFile)},
{Name: "IDENTITIES_BATCH", Value: consts.ServerOperatorSecurity + "/" + consts.ServerIdentitiesBatchFilename},
}),
Image: i.ImageName(),
Args: BuildServerContainerArgs(ctx.ConfigFiles()),
Name: InfinispanContainer,
Env: podEnvs,
Lifecycle: PodLifecycle(),
LivenessProbe: PodLivenessProbe(),
Ports: PodPortsWithXsite(i),
Expand Down Expand Up @@ -165,6 +165,20 @@ func ClusterStatefulSetSpec(statefulSetName string, i *ispnv1.Infinispan, ctx pi
return statefulSet, nil
}

func PodEnvsAndHash(i *ispnv1.Infinispan, configFiles *pipeline.ConfigFiles) ([]corev1.EnvVar, string) {
envs := PodEnv(i, &[]corev1.EnvVar{
{Name: "CONFIG_HASH", Value: hash.HashString(configFiles.ServerBaseConfig, configFiles.ServerAdminConfig)},
{Name: "ADMIN_IDENTITIES_HASH", Value: hash.HashByte(configFiles.AdminIdentities.IdentitiesFile)},
{Name: "IDENTITIES_BATCH", Value: consts.ServerOperatorSecurity + "/" + consts.ServerIdentitiesBatchFilename},
})
hash := sha1.New()
for _, e := range envs {
hash.Write([]byte(e.Name))
hash.Write([]byte(e.Value))
}
return envs, hex.EncodeToString(hash.Sum(nil))
}

func StatefulSetPodLabels(statefulSetName string, i *ispnv1.Infinispan) map[string]string {
labelsForPod := i.PodLabels()
labelsForPod[consts.StatefulSetPodLabel] = statefulSetName
Expand Down
63 changes: 63 additions & 0 deletions test/e2e/infinispan/additional_vars_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package infinispan

import (
"fmt"
"os"
"testing"

ispnv1 "github.com/infinispan/infinispan-operator/api/v1"
kube "github.com/infinispan/infinispan-operator/pkg/kubernetes"
"github.com/infinispan/infinispan-operator/pkg/reconcile/pipeline/infinispan/handler/provision"
tutils "github.com/infinispan/infinispan-operator/test/e2e/utils"
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
)

func TestAdditionalVarsUpdated(t *testing.T) {
// The Operator must be running locall in order for changes to the ADDITIONAL_VAR env
// variable to take effect
if tutils.RunLocalOperator != "TRUE" {
t.SkipNow()
}
defer testKube.CleanNamespaceAndLogOnPanic(t, tutils.Namespace)

val1 := "value1"
tutils.ExpectNoError(os.Setenv("ADDITIONAL_VARS", "[\"VAR1\"]"))
tutils.ExpectNoError(os.Setenv("VAR1", val1))

spec := tutils.DefaultSpec(t, testKube, nil)
testKube.CreateInfinispan(spec, tutils.Namespace)
testKube.WaitForInfinispanCondition(spec.Name, spec.Namespace, ispnv1.ConditionWellFormed)
podList := testKube.WaitForInfinispanPods(1, tutils.SinglePodTimeout, spec.Name, tutils.Namespace)

assert.Equal(t, val1, getEnvVar("VAR1", &podList.Items[0].Spec))

// Update the ADDITIONAL_VARS
val2 := "value2"
tutils.ExpectNoError(os.Setenv("ADDITIONAL_VARS", "[\"VAR1\", \"VAR2\"]"))
tutils.ExpectNoError(os.Setenv("VAR2", val2))
// Add an annotation to the Infinispan CR to trigger a new reconciliation that would not ordernarily cause a
// StatefulSet rolling upgrade. This is necessary to simulate the restarting of the Operator Pod by OLM when the
// ADDITIONAL_VARS env is updated in a Subscription
var modifier = func(ispn *ispnv1.Infinispan) {
ispn.Annotations = map[string]string{
"ignore": "me",
}
}
var verifier = func(ispn *ispnv1.Infinispan, ss *appsv1.StatefulSet) {
assert.Equal(t, val1, getEnvVar("VAR1", &ss.Spec.Template.Spec))
assert.Equal(t, val2, getEnvVar("VAR2", &ss.Spec.Template.Spec))
}
verifyStatefulSetUpdate(*spec, modifier, verifier)
}

func getEnvVar(env string, podSpec *corev1.PodSpec) string {
container := kube.GetContainer(provision.InfinispanContainer, podSpec)
for _, e := range container.Env {
if env == e.Name {
return e.Value
}
}
panic(fmt.Sprintf("ENV '%s' not found in container", env))
}

0 comments on commit c502123

Please sign in to comment.