From 8547c7e5a5be88b1150031e22e4e81a2dfbe8388 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 8 Mar 2025 16:19:12 +0300 Subject: [PATCH 01/33] Use Coherence environment variable names --- api/v1/common_test.go | 34 ++-- api/v1/constants.go | 149 +++++++++--------- api/v1/create_job_applicationspec_test.go | 4 +- ...reate_job_coherencespec_management_test.go | 72 ++++----- .../create_job_coherencespec_metrics_test.go | 72 ++++----- ...create_statefulset_applicationspec_test.go | 4 +- ...atefulset_coherencespec_management_test.go | 72 ++++----- ..._statefulset_coherencespec_metrics_test.go | 72 ++++----- 8 files changed, 241 insertions(+), 238 deletions(-) diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 42f01447c..55e6c35ba 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -269,7 +269,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe envVars := []corev1.EnvVar{ { - Name: "COH_CLUSTER_NAME", + Name: "COHERENCE_CLUSTER", Value: deployment.GetName(), }, { @@ -281,11 +281,11 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Value: fmt.Sprintf("%d", coh.DefaultUnicastPortAdjust), }, { - Name: "COH_HEALTH_PORT", + Name: "COHERENCE_HEALTH_HTTP_PORT", Value: fmt.Sprintf("%d", spec.GetHealthPort()), }, { - Name: "COH_MACHINE_NAME", + Name: "COHERENCE_MACHINE", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "spec.nodeName", @@ -293,7 +293,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "COH_MEMBER_NAME", + Name: "COHERENCE_MEMBER", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "metadata.name", @@ -301,15 +301,15 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "COH_METRICS_ENABLED", + Name: "COHERENCE_METRICS_ENABLED", Value: "false", }, { - Name: "COH_MGMT_ENABLED", + Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "false", }, { - Name: "COH_POD_UID", + Name: "COHERENCE_OPERATOR_POD_UID", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "metadata.uid", @@ -317,23 +317,23 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "COH_RACK_INFO_LOCATION", + Name: "COHERENCE_OPERATOR_RACK_INFO_LOCATION", Value: "http://$(OPERATOR_HOST)/rack/$(COH_MACHINE_NAME)", }, { - Name: "COH_ROLE", + Name: "COHERENCE_ROLE", Value: deployment.GetRoleName(), }, { - Name: "COH_SITE_INFO_LOCATION", + Name: "COHERENCE_OPERATOR_SITE_INFO_LOCATION", Value: "http://$(OPERATOR_HOST)/site/$(COH_MACHINE_NAME)", }, { - Name: "COH_UTIL_DIR", + Name: "COHERENCE_OPERATOR_UTIL_DIR", Value: coh.VolumeMountPathUtils, }, { - Name: "COH_WKA", + Name: "COHERENCE_WKA", Value: deployment.GetWKA(), }, { @@ -345,7 +345,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Value: "true", }, { - Name: "OPERATOR_HOST", + Name: "COHERENCE_OPERATOR_HOST", ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{Name: coh.OperatorConfigName}, @@ -355,14 +355,14 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "OPERATOR_REQUEST_TIMEOUT", + Name: "COHERENCE_OPERATOR_REQUEST_TIMEOUT", Value: "120", }, } if deployment.GetType() == coh.CoherenceTypeJob { envVars = append(envVars, corev1.EnvVar{ - Name: "COH_STORAGE_ENABLED", + Name: "COHERENCE_DISTRIBUTED_LOCALSTORAGE", Value: "false", }) } @@ -424,11 +424,11 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Command: []string{coh.RunnerInitCommand, coh.RunnerInit}, Env: []corev1.EnvVar{ { - Name: "COH_CLUSTER_NAME", + Name: "COHERENCE_CLUSTER", Value: deployment.GetName(), }, { - Name: "COH_UTIL_DIR", + Name: "COHERENCE_OPERATOR_UTIL_DIR", Value: coh.VolumeMountPathUtils, }, }, diff --git a/api/v1/constants.go b/api/v1/constants.go index 37ce40ef4..ba4ce3c8d 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -179,50 +179,55 @@ const ( // DefaultCnbpLauncher is the Cloud Native Build Pack launcher executable DefaultCnbpLauncher = "/cnb/lifecycle/launcher" - EnvVarAppType = "COH_APP_TYPE" - EnvVarAppMainClass = "COH_MAIN_CLASS" - EnvVarAppMainArgs = "COH_MAIN_ARGS" - EnvVarOperatorHost = "OPERATOR_HOST" - EnvVarOperatorTimeout = "OPERATOR_REQUEST_TIMEOUT" - EnvVarOperatorAllowResume = "OPERATOR_ALLOW_RESUME" - EnvVarOperatorResumeServices = "OPERATOR_RESUME_SERVICES" - EnvVarUseOperatorHealthCheck = "OPERATOR_HEALTH_CHECK" - EnvVarCoherenceHome = "COHERENCE_HOME" - EnvVarCohDependencyModules = "DEPENDENCY_MODULES" - EnvVarCohSkipVersionCheck = "COH_SKIP_VERSION_CHECK" - EnvVarCohClusterName = "COH_CLUSTER_NAME" - EnvVarCohIdentity = "COH_IDENTITY" - EnvVarCohWka = "COH_WKA" - EnvVarCohAppDir = "COH_APP_DIR" - EnvVarCohMachineName = "COH_MACHINE_NAME" - EnvVarCohMemberName = "COH_MEMBER_NAME" - EnvVarCohPodUID = "COH_POD_UID" - EnvVarCohSkipSite = "COH_SKIP_SITE" - EnvVarCohSite = "COH_SITE_INFO_LOCATION" - EnvVarCoherenceSite = "COHERENCE_SITE" - EnvVarCohRack = "COH_RACK_INFO_LOCATION" - EnvVarCoherenceRack = "COHERENCE_RACK" - EnvVarCohRole = "COH_ROLE" - EnvVarCohUtilDir = "COH_UTIL_DIR" - EnvVarCohUtilLibDir = "COH_UTIL_LIB_DIR" - EnvVarCohHealthPort = "COH_HEALTH_PORT" - EnvVarCohCacheConfig = "COH_CACHE_CONFIG" - EnvVarCohOverride = "COH_OVERRIDE_CONFIG" - EnvVarCohLogLevel = "COH_LOG_LEVEL" - EnvVarCohStorage = "COH_STORAGE_ENABLED" - EnvVarCohPersistenceMode = "COH_PERSISTENCE_MODE" - EnvVarCohPersistenceDir = "COH_PERSISTENCE_DIR" - EnvVarCohSnapshotDir = "COH_SNAPSHOT_DIR" - EnvVarCohTracingRatio = "COH_TRACING_RATIO" - EnvVarCohAllowEndangered = "COH_ALLOW_ENDANGERED" - EnvVarCohMgmtPrefix = "COH_MGMT" - EnvVarCohMetricsPrefix = "COH_METRICS" + EnvVarAppType = "COHERENCE_OPERATOR_APP_TYPE" + EnvVarAppMainClass = "COHERENCE_OPERATOR_MAIN_CLASS" + EnvVarAppMainArgs = "COHERENCE_OPERATOR_MAIN_ARGS" + EnvVarOperatorHost = "COHERENCE_OPERATOR_HOST" + EnvVarOperatorTimeout = "COHERENCE_OPERATOR_REQUEST_TIMEOUT" + EnvVarOperatorAllowResume = "COHERENCE_OPERATOR_ALLOW_RESUME" + EnvVarOperatorResumeServices = "COHERENCE_OPERATOR_RESUME_SERVICES" + EnvVarUseOperatorHealthCheck = "COHERENCE_OPERATOR_HEALTH_CHECK" + EnvVarCohDependencyModules = "COHERENCE_OPERATOR_DEPENDENCY_MODULES" + EnvVarCohSkipVersionCheck = "COHERENCE_OPERATOR_SKIP_VERSION_CHECK" + EnvVarCohPodUID = "COHERENCE_OPERATOR_POD_UID" + EnvVarCohIdentity = "COHERENCE_OPERATOR_IDENTITY" + EnvVarCohAppDir = "COHERENCE_OPERATOR_APP_DIR" + EnvVarCohSkipSite = "COHERENCE_OPERATOR_SKIP_SITE" + EnvVarCohSite = "COHERENCE_OPERATOR_SITE_INFO_LOCATION" + EnvVarCohRack = "COHERENCE_OPERATOR_RACK_INFO_LOCATION" + EnvVarCohUtilDir = "COHERENCE_OPERATOR_UTIL_DIR" + EnvVarCohUtilLibDir = "COHERENCE_OPERATOR_UTIL_LIB_DIR" + EnvVarCohAllowEndangered = "COHERENCE_OPERATOR_ALLOW_ENDANGERED" + EnvVarSpringBootFatJar = "COHERENCE_OPERATOR_SPRING_BOOT_FAT_JAR" + EnvVarCnbpEnabled = "COHERENCE_OPERATOR_CNBP_ENABLED" + EnvVarCnbpLauncher = "COHERENCE_OPERATOR_CNBP_LAUNCHER" + EnvVarCohForceExit = "COHERENCE_OPERATOR_FORCE_EXIT" + + EnvVarCoherenceHome = "COHERENCE_HOME" + EnvVarCohClusterName = "COHERENCE_CLUSTER" + EnvVarCohWka = "COHERENCE_WKA" + EnvVarCohMachineName = "COHERENCE_MACHINE" + EnvVarCohMemberName = "COHERENCE_MEMBER" + EnvVarCoherenceSite = "COHERENCE_SITE" + EnvVarCoherenceRack = "COHERENCE_RACK" + EnvVarCohRole = "COHERENCE_ROLE" + EnvVarCohHealthPort = "COHERENCE_HEALTH_HTTP_PORT" + EnvVarCohCacheConfig = "COHERENCE_CACHECONFIG" + EnvVarCohOverride = "COHERENCE_OVERRIDE" + EnvVarCohLogLevel = "COHERENCE_LOG_LEVEL" + EnvVarCohStorage = "COHERENCE_DISTRIBUTED_LOCALSTORAGE" + EnvVarCohPersistenceMode = "COHERENCE_DISTRIBUTED_PERSISTENCE_MODE" + EnvVarCohPersistenceDir = "COHERENCE_DISTRIBUTED_PERSISTENCE_BASE_DIR" + EnvVarCohSnapshotDir = "COHERENCE_DISTRIBUTED_PERSISTENCE_SNAPSHOT_DIR" + EnvVarCohTracingRatio = "COHERENCE_TRACING_RATIO" + EnvVarCohMgmtPrefix = "COHERENCE_MANAGEMENT" + EnvVarCohMetricsPrefix = "COHERENCE_METRICS" + EnvVarCoherenceLocalPort = "COHERENCE_LOCALPORT" + EnvVarCoherenceLocalPortAdjust = "COHERENCE_LOCALPORT_ADJUST" + EnvVarCohEnabledSuffix = "_ENABLED" EnvVarCohPortSuffix = "_PORT" - EnvVarCohForceExit = "COH_FORCE_EXIT" - EnvVarCoherenceLocalPort = "COHERENCE_LOCALPORT" - EnvVarCoherenceLocalPortAdjust = "COHERENCE_LOCALPORT_ADJUST" - EnvVarEnableIPMonitor = "COH_ENABLE_IPMONITOR" + EnvVarEnableIPMonitor = "COHERENCE_ENABLE_IPMONITOR" EnvVarSuffixSSLEnabled = "_SSL_ENABLED" EnvVarSuffixSSLCerts = "_SSL_CERTS" EnvVarSuffixSSLKeyStore = "_SSL_KEYSTORE" @@ -237,37 +242,35 @@ const ( EnvVarSuffixSSLTrustStoreProvider = "_SSL_TRUSTSTORE_PROVIDER" EnvVarSuffixSSLTrustStoreType = "_SSL_TRUSTSTORE_TYPE" EnvVarSuffixSSLRequireClientCert = "_SSL_REQUIRE_CLIENT_CERT" - EnvVarJavaHome = "JAVA_HOME" - EnvVarJavaClasspath = "CLASSPATH" - EnvVarJvmClasspathJib = "JVM_USE_JIB_CLASSPATH" - EnvVarJvmExtraClasspath = "JVM_EXTRA_CLASSPATH" - EnvVarJvmArgs = "JVM_ARGS" - EnvVarJvmUseContainerLimits = "JVM_USE_CONTAINER_LIMITS" - EnvVarJvmShowSettings = "JVM_SHOW_SETTINGS" - EnvVarJvmDebugEnabled = "JVM_DEBUG_ENABLED" - EnvVarJvmDebugPort = "JVM_DEBUG_PORT" - EnvVarJvmDebugSuspended = "JVM_DEBUG_SUSPEND" - EnvVarJvmDebugAttach = "JVM_DEBUG_ATTACH" - EnvVarJvmGcArgs = "JVM_GC_ARGS" - EnvVarJvmGcCollector = "JVM_GC_COLLECTOR" - EnvVarJvmGcLogging = "JVM_GC_LOGGING" - EnvVarJvmMemoryHeap = "JVM_HEAP_SIZE" - EnvVarJvmMemoryInitialHeap = "JVM_INITIAL_HEAP_SIZE" - EnvVarJvmMemoryMaxHeap = "JVM_MAX_HEAP_SIZE" - EnvVarJvmMaxRAM = "JVM_MAX_RAM" - EnvVarJvmRAMPercentage = "JVM_RAM_PERCENTAGE" - EnvVarJvmInitialRAMPercentage = "JVM_INITIAL_RAM_PERCENTAGE" - EnvVarJvmMaxRAMPercentage = "JVM_MAX_RAM_PERCENTAGE" - EnvVarJvmMinRAMPercentage = "JVM_MIN_RAM_PERCENTAGE" - EnvVarJvmMemoryDirect = "JVM_DIRECT_MEMORY_SIZE" - EnvVarJvmMemoryStack = "JVM_STACK_SIZE" - EnvVarJvmMemoryMeta = "JVM_METASPACE_SIZE" - EnvVarJvmMemoryNativeTracking = "JVM_NATIVE_MEMORY_TRACKING" - EnvVarJvmOomExit = "JVM_OOM_EXIT" - EnvVarJvmOomHeapDump = "JVM_OOM_HEAP_DUMP" - EnvVarSpringBootFatJar = "COH_SPRING_BOOT_FAT_JAR" - EnvVarCnbpEnabled = "COH_CNBP_ENABLED" - EnvVarCnbpLauncher = "COH_CNBP_LAUNCHER" + + EnvVarJavaHome = "JAVA_HOME" + EnvVarJavaClasspath = "CLASSPATH" + EnvVarJvmClasspathJib = "JVM_USE_JIB_CLASSPATH" + EnvVarJvmExtraClasspath = "JVM_EXTRA_CLASSPATH" + EnvVarJvmArgs = "JVM_ARGS" + EnvVarJvmUseContainerLimits = "JVM_USE_CONTAINER_LIMITS" + EnvVarJvmShowSettings = "JVM_SHOW_SETTINGS" + EnvVarJvmDebugEnabled = "JVM_DEBUG_ENABLED" + EnvVarJvmDebugPort = "JVM_DEBUG_PORT" + EnvVarJvmDebugSuspended = "JVM_DEBUG_SUSPEND" + EnvVarJvmDebugAttach = "JVM_DEBUG_ATTACH" + EnvVarJvmGcArgs = "JVM_GC_ARGS" + EnvVarJvmGcCollector = "JVM_GC_COLLECTOR" + EnvVarJvmGcLogging = "JVM_GC_LOGGING" + EnvVarJvmMemoryHeap = "JVM_HEAP_SIZE" + EnvVarJvmMemoryInitialHeap = "JVM_INITIAL_HEAP_SIZE" + EnvVarJvmMemoryMaxHeap = "JVM_MAX_HEAP_SIZE" + EnvVarJvmMaxRAM = "JVM_MAX_RAM" + EnvVarJvmRAMPercentage = "JVM_RAM_PERCENTAGE" + EnvVarJvmInitialRAMPercentage = "JVM_INITIAL_RAM_PERCENTAGE" + EnvVarJvmMaxRAMPercentage = "JVM_MAX_RAM_PERCENTAGE" + EnvVarJvmMinRAMPercentage = "JVM_MIN_RAM_PERCENTAGE" + EnvVarJvmMemoryDirect = "JVM_DIRECT_MEMORY_SIZE" + EnvVarJvmMemoryStack = "JVM_STACK_SIZE" + EnvVarJvmMemoryMeta = "JVM_METASPACE_SIZE" + EnvVarJvmMemoryNativeTracking = "JVM_NATIVE_MEMORY_TRACKING" + EnvVarJvmOomExit = "JVM_OOM_EXIT" + EnvVarJvmOomHeapDump = "JVM_OOM_HEAP_DUMP" ) var ( diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index db67ee083..d65d73949 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -45,7 +45,7 @@ func TestCreateJobWithApplicationMain(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MAIN_CLASS", Value: mainClass}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_job_coherencespec_management_test.go b/api/v1/create_job_coherencespec_management_test.go index 093a539e1..a36681114 100644 --- a/api/v1/create_job_coherencespec_management_test.go +++ b/api/v1/create_job_coherencespec_management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateJobWithCoherenceManagementEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -102,8 +102,8 @@ func TestCreateJobWithCoherenceManagementEnabledWithPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: "1234"}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -139,21 +139,21 @@ func TestCreateJobWithCoherenceManagementWithSSLEnabledWithoutSecret(t *testing. // Create expected Job jobExpected := createMinimalExpectedJob(deployment) addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -192,22 +192,22 @@ func TestCreateJobWithCoherenceManagementWithSSLEnabledWithSecret(t *testing.T) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the management ConfigMap volume mount jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_job_coherencespec_metrics_test.go b/api/v1/create_job_coherencespec_metrics_test.go index bedd60b24..d43c84a77 100644 --- a/api/v1/create_job_coherencespec_metrics_test.go +++ b/api/v1/create_job_coherencespec_metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateJobWithCoherenceMetricsEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -102,8 +102,8 @@ func TestCreateJobWithCoherenceMetricsEnabledWithPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: "1234"}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -139,21 +139,21 @@ func TestCreateJobWithCoherenceMetricsWithSSLEnabledWithoutSecret(t *testing.T) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -192,22 +192,22 @@ func TestCreateJobWithCoherenceMetricsWithSSLEnabledWithSecret(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the metrics ConfigMap volume mount jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index dd9bfe4db..b4fcfdf72 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -45,7 +45,7 @@ func TestCreateStatefulSetWithApplicationMain(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MAIN_CLASS", Value: mainClass}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_coherencespec_management_test.go b/api/v1/create_statefulset_coherencespec_management_test.go index d2008e6e4..ec15b2867 100644 --- a/api/v1/create_statefulset_coherencespec_management_test.go +++ b/api/v1/create_statefulset_coherencespec_management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateStatefulSetWithCoherenceManagementEnabledTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -102,8 +102,8 @@ func TestCreateStatefulSetWithCoherenceManagementEnabledWithPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: "1234"}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -139,21 +139,21 @@ func TestCreateStatefulSetWithCoherenceManagementWithSSLEnabledWithoutSecret(t * // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -192,22 +192,22 @@ func TestCreateStatefulSetWithCoherenceManagementWithSSLEnabledWithSecret(t *tes // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the management ConfigMap volume mount stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_statefulset_coherencespec_metrics_test.go b/api/v1/create_statefulset_coherencespec_metrics_test.go index 29c1487c6..38a698f46 100644 --- a/api/v1/create_statefulset_coherencespec_metrics_test.go +++ b/api/v1/create_statefulset_coherencespec_metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateStatefulSetWithCoherenceMetricsEnabledTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -102,8 +102,8 @@ func TestCreateStatefulSetWithCoherenceMetricsEnabledWithPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: "1234"}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -139,21 +139,21 @@ func TestCreateStatefulSetWithCoherenceMetricsWithSSLEnabledWithoutSecret(t *tes // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -192,22 +192,22 @@ func TestCreateStatefulSetWithCoherenceMetricsWithSSLEnabledWithSecret(t *testin // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the metrics ConfigMap volume mount stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ From 6700a3cd5395ef4bfb5b914caa3f1a5d194f567e Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 9 Mar 2025 10:19:58 +0300 Subject: [PATCH 02/33] Use Coherence environment variable names --- Makefile | 6 +++--- api/v1/common_test.go | 4 ++-- api/v1/constants.go | 4 ++-- docs/logging/020_logging.adoc | 6 +++--- test/e2e/local/deployment-cli-home.yaml | 2 +- test/e2e/local/deployment-cli.yaml | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index e8c63ac02..4f7a2bcfa 100644 --- a/Makefile +++ b/Makefile @@ -1229,7 +1229,7 @@ e2e-local-test: export TEST_APPLICATION_IMAGE_SPRING_FAT_2 := $(TEST_APPLICATION e2e-local-test: export TEST_APPLICATION_IMAGE_SPRING_CNBP_2 := $(TEST_APPLICATION_IMAGE_SPRING_CNBP_2) e2e-local-test: export TEST_COHERENCE_IMAGE := $(TEST_COHERENCE_IMAGE) e2e-local-test: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) -e2e-local-test: export COH_SKIP_SITE := true +e2e-local-test: export COHERENCE_OPERATOR_SKIP_SITE := true e2e-local-test: export TEST_IMAGE_PULL_POLICY := $(IMAGE_PULL_POLICY) e2e-local-test: export TEST_STORAGE_CLASS := $(TEST_STORAGE_CLASS) e2e-local-test: export GO_TEST_FLAGS_E2E := $(strip $(GO_TEST_FLAGS_E2E)) @@ -1315,7 +1315,7 @@ e2e-k3d-test: export TEST_APPLICATION_IMAGE_SPRING_FAT_2 := $(TEST_APPLICATION_I e2e-k3d-test: export TEST_APPLICATION_IMAGE_SPRING_CNBP_2 := $(TEST_APPLICATION_IMAGE_SPRING_CNBP_2) e2e-k3d-test: export TEST_COHERENCE_IMAGE := $(TEST_COHERENCE_IMAGE) e2e-k3d-test: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) -e2e-k3d-test: export COH_SKIP_SITE := true +e2e-k3d-test: export COHERENCE_OPERATOR_SKIP_SITE := true e2e-k3d-test: export TEST_IMAGE_PULL_POLICY := $(IMAGE_PULL_POLICY) e2e-k3d-test: export TEST_STORAGE_CLASS := $(TEST_STORAGE_CLASS) e2e-k3d-test: export GO_TEST_FLAGS_E2E := $(strip $(GO_TEST_FLAGS_E2E)) @@ -1341,7 +1341,7 @@ e2e-client-test: export TEST_APPLICATION_IMAGE := $(TEST_APPLICATION_IMAGE) e2e-client-test: export TEST_APPLICATION_IMAGE_CLIENT := $(TEST_APPLICATION_IMAGE_CLIENT) e2e-client-test: export TEST_COHERENCE_IMAGE := $(TEST_COHERENCE_IMAGE) e2e-client-test: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) -e2e-client-test: export COH_SKIP_SITE := true +e2e-client-test: export COHERENCE_OPERATOR_SKIP_SITE := true e2e-client-test: export TEST_IMAGE_PULL_POLICY := $(IMAGE_PULL_POLICY) e2e-client-test: export GO_TEST_FLAGS_E2E := $(strip $(GO_TEST_FLAGS_E2E)) e2e-client-test: export VERSION := $(VERSION) diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 55e6c35ba..c4561fe8f 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -318,7 +318,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, { Name: "COHERENCE_OPERATOR_RACK_INFO_LOCATION", - Value: "http://$(OPERATOR_HOST)/rack/$(COH_MACHINE_NAME)", + Value: "http://$(COHERENCE_OPERATOR_HOST)/rack/$(COHERENCE_MACHINE)", }, { Name: "COHERENCE_ROLE", @@ -326,7 +326,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, { Name: "COHERENCE_OPERATOR_SITE_INFO_LOCATION", - Value: "http://$(OPERATOR_HOST)/site/$(COH_MACHINE_NAME)", + Value: "http://$(COHERENCE_OPERATOR_HOST)/site/$(COHERENCE_MACHINE)", }, { Name: "COHERENCE_OPERATOR_UTIL_DIR", diff --git a/api/v1/constants.go b/api/v1/constants.go index ba4ce3c8d..d42b0e2c7 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -167,9 +167,9 @@ const ( // OperatorConfigKeyHost is the key used in the Operator configuration Secret OperatorConfigKeyHost = "operatorhost" // OperatorSiteURL is the default Operator site query URL - OperatorSiteURL = "http://$(OPERATOR_HOST)/site/$(COH_MACHINE_NAME)" + OperatorSiteURL = "http://$(COHERENCE_OPERATOR_HOST)/site/$(COHERENCE_MACHINE)" // OperatorRackURL is the default Operator rack query URL - OperatorRackURL = "http://$(OPERATOR_HOST)/rack/$(COH_MACHINE_NAME)" + OperatorRackURL = "http://$(COHERENCE_OPERATOR_HOST)/rack/$(COHERENCE_MACHINE)" // DefaultReadinessPath is the default readiness endpoint path DefaultReadinessPath = "/ready" diff --git a/docs/logging/020_logging.adoc b/docs/logging/020_logging.adoc index f8d886be6..875e381c7 100644 --- a/docs/logging/020_logging.adoc +++ b/docs/logging/020_logging.adoc @@ -212,10 +212,10 @@ data: # <3> @type record_transformer - cluster "#{ENV['COH_CLUSTER_NAME']}" - role "#{ENV['COH_ROLE']}" + cluster "#{ENV['COHERENCE_CLUSTER']}" + role "#{ENV['COHERENCE_ROLE']}" host "#{ENV['HOSTNAME']}" - pod-uid "#{ENV['COH_POD_UID']}" + pod-uid "#{ENV['COHERENCE_OPERATOR__POD_UID']}" diff --git a/test/e2e/local/deployment-cli-home.yaml b/test/e2e/local/deployment-cli-home.yaml index a125fec84..b81f0cfe8 100644 --- a/test/e2e/local/deployment-cli-home.yaml +++ b/test/e2e/local/deployment-cli-home.yaml @@ -4,7 +4,7 @@ metadata: name: storage spec: env: - - name: COH_SKIP_SITE + - name: COHERENCE_OPERATOR_SKIP_SITE value: "true" - name: COHCTL_HOME value: /test/cli diff --git a/test/e2e/local/deployment-cli.yaml b/test/e2e/local/deployment-cli.yaml index e441c0feb..51bd3d846 100644 --- a/test/e2e/local/deployment-cli.yaml +++ b/test/e2e/local/deployment-cli.yaml @@ -4,7 +4,7 @@ metadata: name: storage spec: env: - - name: COH_SKIP_SITE + - name: COHERENCE_OPERATOR_SKIP_SITE value: "true" From daa4e20dcfdf2a259129934b1a2585379eb1beea Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 9 Mar 2025 13:58:50 +0300 Subject: [PATCH 03/33] Use Coherence environment variable names --- api/v1/coherence_types.go | 14 +++++++- api/v1/coherence_webhook.go | 9 ----- api/v1/coherence_webhook_image_test.go | 32 ----------------- api/v1/coherence_webhook_job_test.go | 35 ------------------- api/v1/coherence_webhook_test.go | 35 ------------------- api/v1/coherenceresourcespec_types.go | 28 ++------------- api/v1/common_test.go | 4 --- api/v1/create_job_coherenceutils_test.go | 25 ++----------- .../create_statefulset_coherenceutils_test.go | 25 ++----------- api/v1/zz_generated.deepcopy.go | 22 +++++++++++- controllers/job/job_controller.go | 8 ----- .../statefulset/statefulset_controller.go | 8 ----- docs/about/04_coherence_spec.adoc | 15 +++++++- 13 files changed, 56 insertions(+), 204 deletions(-) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 49d732022..444f9355d 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -755,9 +755,21 @@ type ImageSpec struct { ImagePullPolicy *corev1.PullPolicy `json:"imagePullPolicy,omitempty"` } +// ----- ImageSpec struct --------------------------------------------------- + +// CoherenceUtilsSpec defines the settings for the Coherence Operator utilities image +// +k8s:openapi-gen=true +type CoherenceUtilsSpec struct { + // Image pull policy. + // One of Always, Never, IfNotPresent. + // More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + // +optional + ImagePullPolicy *corev1.PullPolicy `json:"imagePullPolicy,omitempty"` +} + // EnsureImage ensures that the image value is set. func (in *ImageSpec) EnsureImage(image *string) bool { - if in != nil && in.Image == nil { + if in != nil && (in.Image == nil || *in.Image != *image) { in.Image = image return true } diff --git a/api/v1/coherence_webhook.go b/api/v1/coherence_webhook.go index 52f51faea..5535f15dd 100644 --- a/api/v1/coherence_webhook.go +++ b/api/v1/coherence_webhook.go @@ -123,8 +123,6 @@ func SetCommonDefaults(in CoherenceResource) { // only set defaults for image names in new Coherence instances coherenceImage := operator.GetDefaultCoherenceImage() spec.EnsureCoherenceImage(&coherenceImage) - operatorImage := operator.GetDefaultOperatorImage() - spec.EnsureCoherenceOperatorImage(&operatorImage) // Set the features supported by this version in.AddAnnotation(AnnotationFeatureSuspend, "true") @@ -278,13 +276,6 @@ func (in *CommonWebHook) validateImages(c CoherenceResource) error { return errors.Errorf("invalid spec.image field, %s", err.Error()) } } - img = spec.GetCoherenceOperatorImage() - if img != nil { - _, err = reference.Parse(*img) - if err != nil { - return errors.Errorf("invalid spec.coherenceUtils.image field, %s", err.Error()) - } - } for _, c := range spec.InitContainers { _, err = reference.Parse(c.Image) if err != nil { diff --git a/api/v1/coherence_webhook_image_test.go b/api/v1/coherence_webhook_image_test.go index a3f7d0cb5..0aa76693a 100644 --- a/api/v1/coherence_webhook_image_test.go +++ b/api/v1/coherence_webhook_image_test.go @@ -66,38 +66,6 @@ func TestCoherenceCreateWithImageNameWithTrailingSpace(t *testing.T) { g.Expect(err).To(HaveOccurred()) } -func TestCoherenceCreateWithValidOperatorImageName(t *testing.T) { - g := NewGomegaWithT(t) - - c := coh.Coherence{ - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("test/coherence:1.0"), - }, - }, - }, - } - _, err := c.ValidateCreate(context.Background(), &c) - g.Expect(err).NotTo(HaveOccurred()) -} - -func TestCoherenceCreateWithInvalidOperatorImageName(t *testing.T) { - g := NewGomegaWithT(t) - - c := coh.Coherence{ - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("test/bad image name:1.0"), - }, - }, - }, - } - _, err := c.ValidateCreate(context.Background(), &c) - g.Expect(err).To(HaveOccurred()) -} - func TestCoherenceUpdateWithInvalidImageName(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1/coherence_webhook_job_test.go b/api/v1/coherence_webhook_job_test.go index 9eb2cf582..46558bce1 100644 --- a/api/v1/coherence_webhook_job_test.go +++ b/api/v1/coherence_webhook_job_test.go @@ -213,41 +213,6 @@ func TestJobCoherenceImageIsNotOverriddenWhenAlreadySet(t *testing.T) { g.Expect(*c.Spec.Image).To(Equal(image)) } -func TestJobUtilsImageIsSet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - - c := coh.CoherenceJob{} - err := c.Default(context.Background(), &c) - g.Expect(err).To(BeNil()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal("foo")) -} - -func TestJobUtilsImageIsNotOverriddenWhenAlreadySet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - image := "bar" - c := coh.CoherenceJob{ - Spec: coh.CoherenceJobResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: &image, - }, - }, - }, - } - - err := c.Default(context.Background(), &c) - g.Expect(err).To(BeNil()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal(image)) -} - func TestJobPersistenceModeChangeNotAllowed(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1/coherence_webhook_test.go b/api/v1/coherence_webhook_test.go index 5adb1dd7d..2f6370aee 100644 --- a/api/v1/coherence_webhook_test.go +++ b/api/v1/coherence_webhook_test.go @@ -233,41 +233,6 @@ func TestCoherenceImageIsNotOverriddenWhenAlreadySet(t *testing.T) { g.Expect(*c.Spec.Image).To(Equal(image)) } -func TestUtilsImageIsSet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - - c := coh.Coherence{} - err := c.Default(context.Background(), &c) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal("foo")) -} - -func TestUtilsImageIsNotOverriddenWhenAlreadySet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - image := "bar" - c := coh.Coherence{ - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: &image, - }, - }, - }, - } - - err := c.Default(context.Background(), &c) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal(image)) -} - func TestPersistenceModeChangeNotAllowed(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 6ae9372a6..96784bd20 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -215,7 +215,7 @@ type CoherenceResourceSpec struct { Network *NetworkSpec `json:"network,omitempty"` // The configuration for the Coherence operator image name // +optional - CoherenceUtils *ImageSpec `json:"coherenceUtils,omitempty"` + CoherenceUtils *CoherenceUtilsSpec `json:"coherenceUtils,omitempty"` // The name to use for the service account to use when RBAC is enabled // The role bindings must already have been created as this chart does not create them it just // sets the serviceAccountName value in the Pod spec. @@ -374,25 +374,6 @@ func (in *CoherenceResourceSpec) EnsureCoherenceImage(coherenceImage *string) bo return false } -// GetCoherenceOperatorImage returns the name of the Operator image to use. -func (in *CoherenceResourceSpec) GetCoherenceOperatorImage() *string { - if in != nil && in.CoherenceUtils != nil { - return in.CoherenceUtils.Image - } - return nil -} - -// EnsureCoherenceOperatorImage ensures that the Coherence Operator image is set for the deployment. -// This ensures that the image is fixed to either that specified in the cluster spec or to the current default -// and means that the Helm controller does not upgrade the images if the Operator is upgraded. -func (in *CoherenceResourceSpec) EnsureCoherenceOperatorImage(imageName *string) bool { - if in.CoherenceUtils == nil { - in.CoherenceUtils = &ImageSpec{} - } - - return in.CoherenceUtils.EnsureImage(imageName) -} - // GetHealthPort returns the port that the health check endpoint will bind to. func (in *CoherenceResourceSpec) GetHealthPort() int32 { if in == nil || in.HealthPort == nil || *in.HealthPort <= 0 { @@ -1050,12 +1031,7 @@ func (in *CoherenceResourceSpec) UpdateDefaultLivenessProbeAction(probe *corev1. // CreateOperatorInitContainer creates the Operator init-container spec. func (in *CoherenceResourceSpec) CreateOperatorInitContainer(deployment CoherenceResource) corev1.Container { - var image string - if in.CoherenceUtils == nil || in.CoherenceUtils.Image == nil { - image = operator.GetDefaultOperatorImage() - } else { - image = *in.CoherenceUtils.Image - } + image := operator.GetDefaultOperatorImage() vm := in.CreateCommonVolumeMounts() diff --git a/api/v1/common_test.go b/api/v1/common_test.go index c4561fe8f..1f19338f1 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -446,10 +446,6 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, } - if operatorImage := spec.GetCoherenceOperatorImage(); operatorImage != nil { - initContainer.Image = *operatorImage - } - annotations := make(map[string]string) annotations[coh.AnnotationIstioConfig] = coh.DefaultIstioConfigAnnotationValue diff --git a/api/v1/create_job_coherenceutils_test.go b/api/v1/create_job_coherenceutils_test.go index c71254fea..0de85ab1a 100644 --- a/api/v1/create_job_coherenceutils_test.go +++ b/api/v1/create_job_coherenceutils_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -15,7 +15,7 @@ import ( func TestCreateJobWithCoherenceUtilsEmpty(t *testing.T) { spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{}, + CoherenceUtils: &coh.CoherenceUtilsSpec{}, } // Create the test deployment @@ -27,29 +27,10 @@ func TestCreateJobWithCoherenceUtilsEmpty(t *testing.T) { assertJobCreation(t, deployment, jobExpected) } -func TestCreateJobWithCoherenceUtilsWithImage(t *testing.T) { - - spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("utils:1.0"), - }, - } - - // Create the test deployment - deployment := createTestCoherenceJob(spec) - // Create expected Job - jobExpected := createMinimalExpectedJob(deployment) - // Set the expected Operator image name - jobExpected.Spec.Template.Spec.InitContainers[0].Image = "utils:1.0" - - // assert that the Job is as expected - assertJobCreation(t, deployment, jobExpected) -} - func TestCreateJobWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { policy := corev1.PullAlways spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ + CoherenceUtils: &coh.CoherenceUtilsSpec{ ImagePullPolicy: &policy, }, } diff --git a/api/v1/create_statefulset_coherenceutils_test.go b/api/v1/create_statefulset_coherenceutils_test.go index 01390e26b..da4d241c6 100644 --- a/api/v1/create_statefulset_coherenceutils_test.go +++ b/api/v1/create_statefulset_coherenceutils_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -15,7 +15,7 @@ import ( func TestCreateStatefulSetWithCoherenceUtilsEmpty(t *testing.T) { spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{}, + CoherenceUtils: &coh.CoherenceUtilsSpec{}, } // Create the test deployment @@ -27,29 +27,10 @@ func TestCreateStatefulSetWithCoherenceUtilsEmpty(t *testing.T) { assertStatefulSetCreation(t, deployment, stsExpected) } -func TestCreateStatefulSetWithCoherenceUtilsWithImage(t *testing.T) { - - spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("utils:1.0"), - }, - } - - // Create the test deployment - deployment := createTestDeployment(spec) - // Create expected StatefulSet - stsExpected := createMinimalExpectedStatefulSet(deployment) - // Set the expected Operator image name - stsExpected.Spec.Template.Spec.InitContainers[0].Image = "utils:1.0" - - // assert that the StatefulSet is as expected - assertStatefulSetCreation(t, deployment, stsExpected) -} - func TestCreateStatefulSetWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { policy := corev1.PullAlways spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ + CoherenceUtils: &coh.CoherenceUtilsSpec{ ImagePullPolicy: &policy, }, } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 177df9ee9..7d95a990a 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -622,7 +622,7 @@ func (in *CoherenceResourceSpec) DeepCopyInto(out *CoherenceResourceSpec) { } if in.CoherenceUtils != nil { in, out := &in.CoherenceUtils, &out.CoherenceUtils - *out = new(ImageSpec) + *out = new(CoherenceUtilsSpec) (*in).DeepCopyInto(*out) } if in.AutomountServiceAccountToken != nil { @@ -959,6 +959,26 @@ func (in *CoherenceTracingSpec) DeepCopy() *CoherenceTracingSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CoherenceUtilsSpec) DeepCopyInto(out *CoherenceUtilsSpec) { + *out = *in + if in.ImagePullPolicy != nil { + in, out := &in.ImagePullPolicy, &out.ImagePullPolicy + *out = new(corev1.PullPolicy) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoherenceUtilsSpec. +func (in *CoherenceUtilsSpec) DeepCopy() *CoherenceUtilsSpec { + if in == nil { + return nil + } + out := new(CoherenceUtilsSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CoherenceWKASpec) DeepCopyInto(out *CoherenceWKASpec) { *out = *in diff --git a/controllers/job/job_controller.go b/controllers/job/job_controller.go index 69c50018c..7ffbec07f 100644 --- a/controllers/job/job_controller.go +++ b/controllers/job/job_controller.go @@ -293,14 +293,6 @@ func (in *ReconcileJob) patchJob(ctx context.Context, deployment coh.CoherenceRe in.SetCoherenceImage(¤tPodSpec, cohImage) } - // ensure the Operator image is present so that we do not patch on a Coherence resource - // from pre-3.1.x that does not have images set - if spec.CoherenceUtils == nil || spec.CoherenceUtils.Image == nil { - operatorImage := in.GetOperatorImage(&desiredPodSpec) - in.SetOperatorImage(&originalPodSpec, operatorImage) - in.SetOperatorImage(¤tPodSpec, operatorImage) - } - // a callback function that the 3-way patch method will call just before it applies a patch // if there is any patch to apply, this will check StatusHA if required and update the deployment status callback := func() { diff --git a/controllers/statefulset/statefulset_controller.go b/controllers/statefulset/statefulset_controller.go index edfdb3ae0..75b846ebe 100644 --- a/controllers/statefulset/statefulset_controller.go +++ b/controllers/statefulset/statefulset_controller.go @@ -458,14 +458,6 @@ func (in *ReconcileStatefulSet) patchStatefulSet(ctx context.Context, deployment in.SetCoherenceImage(¤tPodSpec, cohImage) } - // ensure the Operator image is present so that we do not patch on a Coherence resource - // from pre-3.1.x that does not have images set - if deploymentSpec.CoherenceUtils == nil || deploymentSpec.CoherenceUtils.Image == nil { - operatorImage := in.GetOperatorImage(&desiredPodSpec) - in.SetOperatorImage(&originalPodSpec, operatorImage) - in.SetOperatorImage(¤tPodSpec, operatorImage) - } - // a callback function that the 3-way patch method will call just before it applies a patch // if there is any patch to apply, this will check StatusHA if required and update the deployment status callback := func() { diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index 4743f9e28..e6a4ca235 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -68,6 +68,7 @@ m| status |   m| <> | fals * <> * <> * <> +* <> * <> * <> * <> @@ -332,7 +333,7 @@ m| containerSecurityContext | ContainerSecurityContext is the SecurityContext th m| shareProcessNamespace | Share a single process namespace between all the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. m| *bool | false m| hostIPC | Use the host's ipc namespace. Optional: Default to false. m| *bool | false m| network | Configure various networks and DNS settings for Pods in this role. m| *<> | false -m| coherenceUtils | The configuration for the Coherence operator image name m| *<> | false +m| coherenceUtils | The configuration for the Coherence operator image name m| *<> | false m| serviceAccountName | The name to use for the service account to use when RBAC is enabled The role bindings must already have been created as this chart does not create them it just sets the serviceAccountName value in the Pod spec. m| string | false m| automountServiceAccountToken | Whether to auto-mount the Kubernetes API credentials for a service account m| *bool | false m| operatorRequestTimeout | The timeout to apply to REST requests made back to the Operator from Coherence Pods. These requests are typically to obtain site and rack information for the Pod. m| *int32 | false @@ -474,6 +475,18 @@ NOTE: This field is a k8s resource.Quantity value as CRDs do not support decimal <> +=== CoherenceUtilsSpec + +CoherenceUtilsSpec defines the settings for the Coherence Operator utilities image + +[cols="1,10,1,1"options="header"] +|=== +| Field | Description | Type | Required +m| imagePullPolicy | Image pull policy. One of Always, Never, IfNotPresent. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images m| *https://pkg.go.dev/k8s.io/api/core/v1#PullPolicy | false +|=== + +<
> + === CoherenceWKASpec CoherenceWKASpec configures Coherence well-known-addressing to use an existing Coherence deployment for WKA. From ce54fdf9e56fe3f89193f5a4c8b9df4489d8929d Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 9 Mar 2025 21:52:14 +0300 Subject: [PATCH 04/33] Use Coherence environment variable names --- controllers/reconciler/base_controller.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/controllers/reconciler/base_controller.go b/controllers/reconciler/base_controller.go index 0664f2d80..6c5eb30e6 100644 --- a/controllers/reconciler/base_controller.go +++ b/controllers/reconciler/base_controller.go @@ -649,14 +649,6 @@ func (in *CommonReconciler) BlankCoherenceContainerFields(template *corev1.PodTe // This is the Coherence Container // blank out the container command field c.Command = []string{} - // blank the WKA env var - for e := range c.Env { - ev := c.Env[e] - if ev.Name == coh.EnvVarCohWka { - ev.Value = "" - c.Env[e] = ev - } - } // set the updated container back into the StatefulSet template.Spec.Containers[i] = c } From 28b2a368ed7eeaf7375be556fe296e6f01ddef49 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Mon, 10 Mar 2025 14:13:15 +0300 Subject: [PATCH 05/33] Use Coherence environment variable names --- api/v1/coherence_types.go | 3 + api/v1/coherenceresourcespec_types.go | 1 + api/v1/common_test.go | 58 +++++++++++++++++++ api/v1/constants.go | 4 +- api/v1/create_job_coherencespec_test.go | 3 +- .../create_statefulset_coherencespec_test.go | 3 +- docs/jvm/030_jvm_args.adoc | 2 +- .../CoherenceOperatorLifecycleListener.java | 4 +- .../coherence/k8s/CoherenceOperatorMBean.java | 2 +- .../java/com/oracle/coherence/k8s/Main.java | 2 +- .../oracle/coherence/k8s/OperatorLogger.java | 2 +- .../coherence/k8s/OperatorRestServer.java | 40 ++++++------- .../coherence/k8s/OperatorRestServerIT.java | 4 +- pkg/runner/cmd_console.go | 2 +- pkg/runner/cmd_jshell.go | 2 +- pkg/runner/cmd_query_plus.go | 2 +- pkg/runner/cmd_sleep.go | 2 +- pkg/runner/runner.go | 22 +++---- pkg/runner/runner_coherence_test.go | 4 +- pkg/runner/runner_spring_test.go | 12 ++-- pkg/runner/runner_test.go | 8 +-- .../persistence-active-1.yaml | 2 +- .../persistence-active-3.yaml | 2 +- .../persistence-active-snapshot-security.yaml | 2 +- .../remote/persistence-active-snapshot.yaml | 2 +- test/e2e/remote/persistence-active.yaml | 2 +- test/e2e/remote/persistence-on-demand.yaml | 2 +- test/e2e/remote/persistence-snapshot.yaml | 2 +- .../rolling-upgrade-with-persistence.yaml | 2 +- test/e2e/remote/rolling-upgrade.yaml | 2 +- 30 files changed, 133 insertions(+), 67 deletions(-) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 444f9355d..a144beb7e 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -466,6 +466,7 @@ func (in *CoherenceSpec) UpdatePodTemplateSpec(podTemplate *corev1.PodTemplateSp c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCoherenceLocalPort, Value: localPort}) c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCoherenceLocalPortAdjust, Value: localPortAdjust}) + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarIPMonitorPingTimeout, Value: "0"}) return } @@ -508,6 +509,8 @@ func (in *CoherenceSpec) UpdatePodTemplateSpec(podTemplate *corev1.PodTemplateSp if in.EnableIPMonitor != nil && *in.EnableIPMonitor { c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarEnableIPMonitor, Value: "TRUE"}) + } else { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarIPMonitorPingTimeout, Value: "0"}) } in.Management.AddSSLVolumesForPod(podTemplate, c, VolumeNameManagementSSL, VolumeMountPathManagementCerts) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 96784bd20..ee2693cce 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -961,6 +961,7 @@ func (in *CoherenceResourceSpec) CreateDefaultEnv(deployment CoherenceResource) corev1.EnvVar{Name: EnvVarCohUtilDir, Value: VolumeMountPathUtils}, corev1.EnvVar{Name: EnvVarOperatorTimeout, Value: Int32PtrToStringWithDefault(in.OperatorRequestTimeout, 120)}, corev1.EnvVar{Name: EnvVarCohHealthPort, Value: Int32ToString(in.GetHealthPort())}, + corev1.EnvVar{Name: EnvVarCoherenceTTL, Value: "0"}, ) ann := deployment.GetAnnotations() diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 1f19338f1..398a3ceb2 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -358,6 +358,14 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Name: "COHERENCE_OPERATOR_REQUEST_TIMEOUT", Value: "120", }, + { + Name: "COHERENCE_TTL", + Value: "0", + }, + { + Name: "COHERENCE_IPMONITOR_PINGTIMEOUT", + Value: "0", + }, } if deployment.GetType() == coh.CoherenceTypeJob { @@ -613,6 +621,56 @@ func addEnvVarsToContainer(c *corev1.Container, envVars ...corev1.EnvVar) { } } +func removeEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...string) { + if sts != nil { + removeEnvVarsFromPodSpec(&sts.Spec.Template, containerName, envVars...) + } +} + +func removeEnvVarsFromJob(job *batchv1.Job, containerName string, envVars ...string) { + if job != nil { + removeEnvVarsFromPodSpec(&job.Spec.Template, containerName, envVars...) + } +} + +func removeEnvVarsFromPodSpec(template *corev1.PodTemplateSpec, containerName string, envVars ...string) { + for i, c := range template.Spec.InitContainers { + if c.Name == containerName { + removeEnvVarsFromContainer(&c, envVars...) + template.Spec.InitContainers[i] = c + } + } + for i, c := range template.Spec.Containers { + if c.Name == containerName { + removeEnvVarsFromContainer(&c, envVars...) + template.Spec.Containers[i] = c + } + } +} + +func removeEnvVarsFromContainer(c *corev1.Container, envVars ...string) { + env := c.Env + if c.Env == nil || len(env) == 0 { + return + } + + for _, name := range envVars { + for e, ev := range c.Env { + if ev.Name == name { + if e == 0 { + env = env[:1] + } else if (e + 1) == len(env) { + env = env[:e] + } else { + env = append(env[:e], env[e+1:]...) + } + break + } + } + } + c.Env = env +} + func addEnvVarsFrom(sts *appsv1.StatefulSet, containerName string, envVars ...corev1.EnvFromSource) { if sts != nil { addEnvVarsFromToPodSpec(&sts.Spec.Template, containerName, envVars...) diff --git a/api/v1/constants.go b/api/v1/constants.go index d42b0e2c7..97afee717 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -224,10 +224,12 @@ const ( EnvVarCohMetricsPrefix = "COHERENCE_METRICS" EnvVarCoherenceLocalPort = "COHERENCE_LOCALPORT" EnvVarCoherenceLocalPortAdjust = "COHERENCE_LOCALPORT_ADJUST" + EnvVarCoherenceTTL = "COHERENCE_TTL" + EnvVarEnableIPMonitor = "COHERENCE_ENABLE_IPMONITOR" + EnvVarIPMonitorPingTimeout = "COHERENCE_IPMONITOR_PINGTIMEOUT" EnvVarCohEnabledSuffix = "_ENABLED" EnvVarCohPortSuffix = "_PORT" - EnvVarEnableIPMonitor = "COHERENCE_ENABLE_IPMONITOR" EnvVarSuffixSSLEnabled = "_SSL_ENABLED" EnvVarSuffixSSLCerts = "_SSL_CERTS" EnvVarSuffixSSLKeyStore = "_SSL_KEYSTORE" diff --git a/api/v1/create_job_coherencespec_test.go b/api/v1/create_job_coherencespec_test.go index fb8ec0094..8ecafe8b3 100644 --- a/api/v1/create_job_coherencespec_test.go +++ b/api/v1/create_job_coherencespec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -328,6 +328,7 @@ func TestCreateJobWithCoherenceSpecWithIpMonitorEnabled(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + removeEnvVarsFromJob(jobExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_statefulset_coherencespec_test.go b/api/v1/create_statefulset_coherencespec_test.go index 4001ebb01..0c1e07573 100644 --- a/api/v1/create_statefulset_coherencespec_test.go +++ b/api/v1/create_statefulset_coherencespec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -328,6 +328,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithIpMonitorEnabled(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + removeEnvVars(stsExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/docs/jvm/030_jvm_args.adoc b/docs/jvm/030_jvm_args.adoc index 018b3a732..508ca6f83 100644 --- a/docs/jvm/030_jvm_args.adoc +++ b/docs/jvm/030_jvm_args.adoc @@ -69,7 +69,7 @@ The Coherence Operator will add the following JVM arguments by default: -Dcoherence.role= -Dcoherence.wka=-wka.svc -Dcoherence.cacheconfig=coherence-cache-config.xml --Dcoherence.k8s.operator.health.port=6676 +-Dcoherence.operator.health.port=6676 -Dcoherence.management.http.port=30000 -Dcoherence.metrics.http.port=9612 -Dcoherence.distributed.persistence-mode=on-demand diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java index 7049d7090..2cee9f1e1 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java @@ -49,12 +49,12 @@ public class CoherenceOperatorLifecycleListener /** * The system property to enable or disable the Operator resuming services. */ - public static final String PROP_CAN_RESUME = "coherence.k8s.operator.can.resume.services"; + public static final String PROP_CAN_RESUME = "coherence.operator.can.resume.services"; /** * The system property to enable or disable the Operator resuming individual services. */ - public static final String PROP_RESUME_SERVICES = "coherence.k8s.operator.resume.services"; + public static final String PROP_RESUME_SERVICES = "coherence.operator.resume.services"; /** * A flag that when {@code true}, allows the Operator to resume suspended services on start-up. diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java index 05a1e3e6d..1b4fa39c4 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java @@ -20,7 +20,7 @@ public interface CoherenceOperatorMBean { /** * The System property that is used to set this members identity. */ - String PROP_IDENTITY = "coherence.k8s.operator.identity"; + String PROP_IDENTITY = "coherence.operator.identity"; /** * The name of the Identity MBean attribute. diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java index 5cbb1670c..607ae6060 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java @@ -19,7 +19,7 @@ public class Main { private static final String DEFAULT_MAIN = "$DEFAULT$"; - private static final String PROP_FORCE_EXIT = "coherence.k8s.operator.force.exit"; + private static final String PROP_FORCE_EXIT = "coherence.operator.force.exit"; private static boolean initialised = false; diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java index 0541fc22d..ca4ccebf4 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java @@ -21,7 +21,7 @@ public interface OperatorLogger { /** * The system property to use to set the health logging should use Java logger. */ - String PROP_LOGGER = "coherence.k8s.operator.health.logger"; + String PROP_LOGGER = "coherence.operator.health.logger"; /** * The {@link #PROP_LOGGER} value to log to std-err. diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java index de2172a6f..d68e582a4 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java @@ -61,7 +61,7 @@ public class OperatorRestServer implements AutoCloseable { /** * The system property to use to set the health logging. */ - public static final String PROP_HEALTH_LOG = "coherence.k8s.operator.health.logs"; + public static final String PROP_HEALTH_LOG = "coherence.operator.health.logs"; /** * A flag indicating whether debug logging is enabled. @@ -71,92 +71,92 @@ public class OperatorRestServer implements AutoCloseable { /** * The system property to use to enable the health server. */ - public static final String PROP_HEALTH_ENABLED = "coherence.k8s.operator.health.enabled"; + public static final String PROP_HEALTH_ENABLED = "coherence.operator.health.enabled"; /** * The system property to use to set the health port. */ - public static final String PROP_HEALTH_PORT = "coherence.k8s.operator.health.port"; + public static final String PROP_HEALTH_PORT = "coherence.operator.health.port"; /** * The system property to use to determine whether to wait for DCS to start. */ - public static final String PROP_WAIT_FOR_DCS = "coherence.k8s.operator.health.wait.dcs"; + public static final String PROP_WAIT_FOR_DCS = "coherence.operator.health.wait.dcs"; /** * The system property for the TLS keystore file name. */ - public static final String PROP_TLS_KEYSTORE = "coherence.k8s.operator.health.tls.keystore.file"; + public static final String PROP_TLS_KEYSTORE = "coherence.operator.health.tls.keystore.file"; /** * The system property for the TLS keystore type. */ - public static final String PROP_TLS_KEYSTORE_TYPE = "coherence.k8s.operator.health.tls.keystore.type"; + public static final String PROP_TLS_KEYSTORE_TYPE = "coherence.operator.health.tls.keystore.type"; /** * The system property for the TLS keystore algorithm. */ - public static final String PROP_TLS_KEYSTORE_ALGORITHM = "coherence.k8s.operator.health.tls.keystore.algorithm"; + public static final String PROP_TLS_KEYSTORE_ALGORITHM = "coherence.operator.health.tls.keystore.algorithm"; /** * The system property for the TLS keystore password. */ - public static final String PROP_TLS_KEYSTORE_PASSWORD = "coherence.k8s.operator.health.tls.keystore.password.plain"; + public static final String PROP_TLS_KEYSTORE_PASSWORD = "coherence.operator.health.tls.keystore.password.plain"; /** * The system property for the TLS keystore password file name. */ - public static final String PROP_TLS_KEYSTORE_PASSWORD_FILE = "coherence.k8s.operator.health.tls.keystore.password.file"; + public static final String PROP_TLS_KEYSTORE_PASSWORD_FILE = "coherence.operator.health.tls.keystore.password.file"; /** * The system property for the TLS keystore key password. */ - public static final String PROP_TLS_KEY_PASSWORD = "coherence.k8s.operator.health.tls.key.password.plain"; + public static final String PROP_TLS_KEY_PASSWORD = "coherence.operator.health.tls.key.password.plain"; /** * The system property for the TLS keystore key password file name. */ - public static final String PROP_TLS_KEY_PASSWORD_FILE = "coherence.k8s.operator.health.tls.key.password.file"; + public static final String PROP_TLS_KEY_PASSWORD_FILE = "coherence.operator.health.tls.key.password.file"; /** * The system property for the TLS trust store file name. */ - public static final String PROP_TLS_TRUSTSTORE = "coherence.k8s.operator.health.tls.truststore.file"; + public static final String PROP_TLS_TRUSTSTORE = "coherence.operator.health.tls.truststore.file"; /** * The system property for the TLS trust store type. */ - public static final String PROP_TLS_TRUSTSTORE_TYPE = "coherence.k8s.operator.health.tls.truststore.type"; + public static final String PROP_TLS_TRUSTSTORE_TYPE = "coherence.operator.health.tls.truststore.type"; /** * The system property for the TLS trust store algorithm. */ - public static final String PROP_TLS_TRUSTSTORE_ALGORITHM = "coherence.k8s.operator.health.tls.truststore.algorithm"; + public static final String PROP_TLS_TRUSTSTORE_ALGORITHM = "coherence.operator.health.tls.truststore.algorithm"; /** * The system property for the TLS trust store password. */ - public static final String PROP_TLS_TRUSTSTORE_PASSWORD = "coherence.k8s.operator.health.tls.truststore.password.plain"; + public static final String PROP_TLS_TRUSTSTORE_PASSWORD = "coherence.operator.health.tls.truststore.password.plain"; /** * The system property for the TLS trust store password file name. */ - public static final String PROP_TLS_TRUSTSTORE_PASSWORD_FILE = "coherence.k8s.operator.health.tls.truststore.password.file"; + public static final String PROP_TLS_TRUSTSTORE_PASSWORD_FILE = "coherence.operator.health.tls.truststore.password.file"; /** * The system property for the TLS protocol. */ - public static final String PROP_TLS_PROTOCOL = "coherence.k8s.operator.health.tls.protocol"; + public static final String PROP_TLS_PROTOCOL = "coherence.operator.health.tls.protocol"; /** * The system property to indicate whether TLS is 2-way. */ - public static final String PROP_TLS_TWO_WAY = "coherence.k8s.operator.health.tls.twoway"; + public static final String PROP_TLS_TWO_WAY = "coherence.operator.health.tls.twoway"; /** * The system property to enable or disable TLS. */ - public static final String PROP_INSECURE = "coherence.k8s.operator.health.insecure"; + public static final String PROP_INSECURE = "coherence.operator.health.insecure"; /** * The path to the ready endpoint. @@ -206,7 +206,7 @@ public class OperatorRestServer implements AutoCloseable { /** * System property to specify service names to be skipped in the StatusHA test. */ - public static final String PROP_ALLOW_ENDANGERED = "coherence.k8s.operator.statusha.allowendangered"; + public static final String PROP_ALLOW_ENDANGERED = "coherence.operator.statusha.allowendangered"; // ----- data members --------------------------------------------------- diff --git a/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java b/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java index 60a646fdb..9590ab905 100644 --- a/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java +++ b/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java @@ -343,7 +343,7 @@ public void shouldBeStatusHAMultipleMembersStorageEnabledAndDisabledActivePersis DisplayName.of("storage"), SystemProperty.of("coherence.distributed.persistence-mode", "active"), SystemProperty.of("coherence.distributed.persistence.base.dir", activeDir.getAbsolutePath()), - SystemProperty.of("coherence.k8s.operator.health.logs", true), + SystemProperty.of("coherence.operator.health.logs", true), SystemProperty.of(OperatorRestServer.PROP_HEALTH_PORT, httpPort1))) { try (JavaApplication app2 = platform.launch(JavaApplication.class, ClassName.of(Main.class), @@ -354,7 +354,7 @@ public void shouldBeStatusHAMultipleMembersStorageEnabledAndDisabledActivePersis LocalHost.only(), testLogs.builder(), DisplayName.of("storage-disabled"), - SystemProperty.of("coherence.k8s.operator.health.logs", true), + SystemProperty.of("coherence.operator.health.logs", true), SystemProperty.of(OperatorRestServer.PROP_HEALTH_PORT, httpPort2))) { Eventually.assertDeferred(() -> this.isServiceOneRunning(app1), is(true)); diff --git a/pkg/runner/cmd_console.go b/pkg/runner/cmd_console.go index 3d5128356..78427899a 100644 --- a/pkg/runner/cmd_console.go +++ b/pkg/runner/cmd_console.go @@ -54,7 +54,7 @@ func console(details *RunDetails, args []string, v *viper.Viper) { details.addArg("-Dcoherence.management.http.port=0") details.addArg("-Dcoherence.metrics.http.enabled=false") details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") + details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.health.http.port=0") details.addArg("-Dcoherence.grpc.enabled=false") details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") diff --git a/pkg/runner/cmd_jshell.go b/pkg/runner/cmd_jshell.go index 9875e56c3..0db18d4cf 100644 --- a/pkg/runner/cmd_jshell.go +++ b/pkg/runner/cmd_jshell.go @@ -48,7 +48,7 @@ func jShell(details *RunDetails, args []string, v *viper.Viper) { details.addArg("-Dcoherence.metrics.http.port=0") details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") details.setenv(v1.EnvVarJvmUseContainerLimits, "false") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") + details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.health.http.port=0") details.addArg("-Dcoherence.grpc.enabled=false") details.setenv(v1.EnvVarCohRole, "jshell") diff --git a/pkg/runner/cmd_query_plus.go b/pkg/runner/cmd_query_plus.go index 5b2313504..35659f3a9 100644 --- a/pkg/runner/cmd_query_plus.go +++ b/pkg/runner/cmd_query_plus.go @@ -55,7 +55,7 @@ func queryPlus(details *RunDetails, args []string, v *viper.Viper) { details.addArg("-Dcoherence.management.http.port=0") details.addArg("-Dcoherence.metrics.http.enabled=false") details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") + details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.health.http.port=0") details.addArg("-Dcoherence.grpc.enabled=false") details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") diff --git a/pkg/runner/cmd_sleep.go b/pkg/runner/cmd_sleep.go index 72527eb0c..af4c2d6dd 100644 --- a/pkg/runner/cmd_sleep.go +++ b/pkg/runner/cmd_sleep.go @@ -56,7 +56,7 @@ func sleep(details *RunDetails, args []string, v *viper.Viper) { details.addArg("-Dcoherence.management.http.port=0") details.addArg("-Dcoherence.metrics.http.enabled=false") details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") + details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.grpc.enabled=false") details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") details.setenv(v1.EnvVarCohRole, "sleep") diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index fda98ed68..e0c98c9c2 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -321,9 +321,9 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { details.addArgFromEnvVar(v1.EnvVarCohMemberName, "-Dcoherence.member") details.addArgFromEnvVar(v1.EnvVarCohClusterName, "-Dcoherence.cluster") details.addArgFromEnvVar(v1.EnvVarCohCacheConfig, "-Dcoherence.cacheconfig") - details.addArgFromEnvVar(v1.EnvVarCohIdentity, "-Dcoherence.k8s.operator.identity") - details.addArgFromEnvVar(v1.EnvVarCohForceExit, "-Dcoherence.k8s.operator.force.exit") - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.k8s.operator.health.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.addArgFromEnvVar(v1.EnvVarCohIdentity, "-Dcoherence.operator.identity") + details.addArgFromEnvVar(v1.EnvVarCohForceExit, "-Dcoherence.operator.force.exit") + details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.operator.health.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.management.http.port", fmt.Sprintf("%d", v1.DefaultManagementPort)) details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.metrics.http.port", fmt.Sprintf("%d", v1.DefaultMetricsPort)) @@ -414,7 +414,7 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { allowEndangered := details.Getenv(v1.EnvVarCohAllowEndangered) if allowEndangered != "" { - details.addArg("-Dcoherence.k8s.operator.statusha.allowendangered=" + allowEndangered) + details.addArg("-Dcoherence.operator.statusha.allowendangered=" + allowEndangered) } // Get the K8s Pod UID @@ -437,18 +437,18 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { } } - details.addArg(fmt.Sprintf("-Dcoherence.k8s.operator.diagnostics.dir=%s", jvmDir)) + details.addArg(fmt.Sprintf("-Dcoherence.operator.diagnostics.dir=%s", jvmDir)) details.addArg(fmt.Sprintf("-XX:HeapDumpPath=%s/heap-dumps/%s-%s.hprof", jvmDir, member, podUID)) // set the flag that allows the operator to resume suspended services on start-up if !details.isEnvTrueOrBlank(v1.EnvVarOperatorAllowResume) { - details.addArg("-Dcoherence.k8s.operator.can.resume.services=false") + details.addArg("-Dcoherence.operator.can.resume.services=false") } else { - details.addArg("-Dcoherence.k8s.operator.can.resume.services=true") + details.addArg("-Dcoherence.operator.can.resume.services=true") } if svc := details.Getenv(v1.EnvVarOperatorResumeServices); svc != "" { - details.addArg("-Dcoherence.k8s.operator.resume.services=base64:" + svc) + details.addArg("-Dcoherence.operator.resume.services=base64:" + svc) } gc := strings.ToLower(details.Getenv(v1.EnvVarJvmGcCollector)) @@ -1057,13 +1057,13 @@ func cohPost12214(details *RunDetails) { func cohPost2206(details *RunDetails) { if details.UseOperatorHealth { - details.addArg("-Dcoherence.k8s.operator.health.enabled=true") + details.addArg("-Dcoherence.operator.health.enabled=true") } else { useOperator := details.getenvOrDefault(v1.EnvVarUseOperatorHealthCheck, "false") if strings.EqualFold("true", useOperator) { - details.addArg("-Dcoherence.k8s.operator.health.enabled=true") + details.addArg("-Dcoherence.operator.health.enabled=true") } else { - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") + details.addArg("-Dcoherence.operator.health.enabled=false") details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.health.http.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) } } diff --git a/pkg/runner/runner_coherence_test.go b/pkg/runner/runner_coherence_test.go index d2af76187..aa3f6b471 100644 --- a/pkg/runner/runner_coherence_test.go +++ b/pkg/runner/runner_coherence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -307,7 +307,7 @@ func TestCoherenceAllowEndangered(t *testing.T) { env := EnvVarsFromDeployment(d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.k8s.operator.statusha.allowendangered=foo,bar") + expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.operator.statusha.allowendangered=foo,bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index fdb5358a6..7dcb8b05c 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -163,16 +163,16 @@ func TestSpringBootFatJarConsole(t *testing.T) { expectedArgs := GetMinimalExpectedSpringBootFatJarArgsForRole(jar, ConsoleMain, "") expectedArgs = ReplaceArg(expectedArgs, "-XX:NativeMemoryTracking=summary", "-XX:NativeMemoryTracking=off") expectedArgs = ReplaceArg(expectedArgs, "-Dcoherence.health.http.port=6676", "-Dcoherence.health.http.port=0") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.k8s.operator.health.port=6676") + expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.operator.health.port=6676") expectedArgs = append(expectedArgs, "-Dcoherence.localport.adjust=true", "-Dcoherence.metrics.http.enabled=false", "-Dcoherence.management.http=none", "-Dcoherence.management.http.port=0", "-Dcoherence.metrics.http.port=0", - "-Dcoherence.k8s.operator.health.enabled=false", + "-Dcoherence.operator.health.enabled=false", "-Dcoherence.health.http.port=0", "-Dcoherence.grpc.enabled=false", - "-Dcoherence.k8s.operator.health.port=0") + "-Dcoherence.operator.health.port=0") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -207,15 +207,15 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { expectedArgs := GetMinimalExpectedSpringBootFatJarArgsForRole(jar, ConsoleMain, "") expectedArgs = ReplaceArg(expectedArgs, "-XX:NativeMemoryTracking=summary", "-XX:NativeMemoryTracking=off") expectedArgs = ReplaceArg(expectedArgs, "-Dcoherence.health.http.port=6676", "-Dcoherence.health.http.port=0") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.k8s.operator.health.port=6676") + expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.operator.health.port=6676") expectedArgs = append(expectedArgs, "-Dcoherence.localport.adjust=true", "-Dcoherence.metrics.http.enabled=false", "-Dcoherence.management.http=none", "-Dcoherence.management.http.port=0", "-Dcoherence.metrics.http.port=0", - "-Dcoherence.k8s.operator.health.enabled=false", + "-Dcoherence.operator.health.enabled=false", "-Dcoherence.grpc.enabled=false", - "-Dcoherence.k8s.operator.health.port=0", + "-Dcoherence.operator.health.port=0", "-Dcoherence.health.http.port=0", "foo", "bar") diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index bb294748a..7d0c7c247 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -62,7 +62,7 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { expectedCommand := GetJavaCommand() expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.override="), "-Dcoherence.override=k8s-coherence-override.xml", - "-Dcoherence.k8s.operator.health.enabled=false", + "-Dcoherence.operator.health.enabled=false", "-Dcoherence.health.http.port=6676") e, err := ExecuteWithArgsAndNewViper(env, args) @@ -158,15 +158,15 @@ func AppendCommonExpectedNonServerArgs(args []string, role string) []string { return append(args, "-Dcoherence.wka=test-wka..svc", "-Dcoherence.cluster=test", - "-Dcoherence.k8s.operator.health.port=6676", + "-Dcoherence.operator.health.port=6676", "-Dcoherence.management.http.port=30000", "-Dcoherence.metrics.http.port=9612", "-Dcoherence.distributed.persistence-mode=on-demand", "-Dcoherence.override=k8s-coherence-nossl-override.xml", "-Dcoherence.ipmonitor.pingtimeout=0", - "-Dcoherence.k8s.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown", + "-Dcoherence.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown", "-XX:HeapDumpPath=/coherence-operator/jvm/unknown/unknown/heap-dumps/unknown-unknown.hprof", - "-Dcoherence.k8s.operator.can.resume.services=true", + "-Dcoherence.operator.can.resume.services=true", "-XX:+UseG1GC", "-Dcoherence.ttl=0", "-XX:+UnlockDiagnosticVMOptions", diff --git a/test/coherence_compatibility/persistence-active-1.yaml b/test/coherence_compatibility/persistence-active-1.yaml index 2708cb52d..31d9e99a7 100644 --- a/test/coherence_compatibility/persistence-active-1.yaml +++ b/test/coherence_compatibility/persistence-active-1.yaml @@ -12,7 +12,7 @@ spec: periodSeconds: 10 jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" coherence: cacheConfig: test-cache-config.xml logLevel: 9 diff --git a/test/coherence_compatibility/persistence-active-3.yaml b/test/coherence_compatibility/persistence-active-3.yaml index 9fc09543b..4279449a5 100644 --- a/test/coherence_compatibility/persistence-active-3.yaml +++ b/test/coherence_compatibility/persistence-active-3.yaml @@ -12,7 +12,7 @@ spec: periodSeconds: 10 jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" coherence: cacheConfig: test-cache-config.xml logLevel: 9 diff --git a/test/e2e/remote/persistence-active-snapshot-security.yaml b/test/e2e/remote/persistence-active-snapshot-security.yaml index e811cf47d..4f25df21a 100644 --- a/test/e2e/remote/persistence-active-snapshot-security.yaml +++ b/test/e2e/remote/persistence-active-snapshot-security.yaml @@ -36,7 +36,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-active-snapshot.yaml b/test/e2e/remote/persistence-active-snapshot.yaml index 15a687843..7b15e8f60 100644 --- a/test/e2e/remote/persistence-active-snapshot.yaml +++ b/test/e2e/remote/persistence-active-snapshot.yaml @@ -31,7 +31,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-active.yaml b/test/e2e/remote/persistence-active.yaml index 0a7291347..6cfd9ee2c 100644 --- a/test/e2e/remote/persistence-active.yaml +++ b/test/e2e/remote/persistence-active.yaml @@ -25,7 +25,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-on-demand.yaml b/test/e2e/remote/persistence-on-demand.yaml index fbef9156a..9ae8d78bb 100644 --- a/test/e2e/remote/persistence-on-demand.yaml +++ b/test/e2e/remote/persistence-on-demand.yaml @@ -15,7 +15,7 @@ spec: port: 30000 jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-snapshot.yaml b/test/e2e/remote/persistence-snapshot.yaml index b492b34d2..60cf407a2 100644 --- a/test/e2e/remote/persistence-snapshot.yaml +++ b/test/e2e/remote/persistence-snapshot.yaml @@ -25,7 +25,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/rolling-upgrade-with-persistence.yaml b/test/e2e/remote/rolling-upgrade-with-persistence.yaml index cf1d4dc13..39f1e2a7e 100644 --- a/test/e2e/remote/rolling-upgrade-with-persistence.yaml +++ b/test/e2e/remote/rolling-upgrade-with-persistence.yaml @@ -12,7 +12,7 @@ spec: periodSeconds: 10 jvm: args: - - -Dcoherence.k8s.operator.health.logs=true + - -Dcoherence.operator.health.logs=true coherence: cacheConfig: test-cache-config.xml management: diff --git a/test/e2e/remote/rolling-upgrade.yaml b/test/e2e/remote/rolling-upgrade.yaml index 563c2d3dd..e62c11c48 100644 --- a/test/e2e/remote/rolling-upgrade.yaml +++ b/test/e2e/remote/rolling-upgrade.yaml @@ -7,7 +7,7 @@ spec: version: one jvm: args: - - -Dcoherence.k8s.operator.health.logs=true + - -Dcoherence.operator.health.logs=true memory: heapSize: 256m From 5d46e5c577627205f9d4a9c21963cff99f4394c0 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Mon, 10 Mar 2025 14:43:54 +0300 Subject: [PATCH 06/33] fix copyrights --- .../java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java | 2 +- .../src/main/java/com/oracle/coherence/k8s/Main.java | 2 +- .../src/main/java/com/oracle/coherence/k8s/OperatorLogger.java | 2 +- .../main/java/com/oracle/coherence/k8s/OperatorRestServer.java | 2 +- .../java/com/oracle/coherence/k8s/OperatorRestServerIT.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java index 1b4fa39c4..398742f24 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java index 607ae6060..bcdd81e5b 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java index ca4ccebf4..c1632776d 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java index d68e582a4..a2e59e8e9 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java b/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java index 9590ab905..ec87d4ee4 100644 --- a/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java +++ b/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ From ce33c493697ef2240c86710a1769b9fb13577a13 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 11 Mar 2025 18:05:57 +0300 Subject: [PATCH 07/33] Add init container to create class path and JVM args files --- Makefile | 271 ++++++++++-------- api/v1/coherence_types.go | 14 +- api/v1/coherenceresourcespec_types.go | 41 ++- api/v1/common_test.go | 51 +++- api/v1/constants.go | 15 +- api/v1/create_job_applicationspec_test.go | 8 +- ...reate_job_coherencespec_management_test.go | 12 +- .../create_job_coherencespec_metrics_test.go | 12 +- ...eate_job_coherencespec_persistence_test.go | 64 +++-- api/v1/create_job_coherencespec_test.go | 33 +-- api/v1/create_job_coherenceutils_test.go | 1 + api/v1/create_job_jvmspec_test.go | 50 ++-- ...create_statefulset_applicationspec_test.go | 8 +- ...atefulset_coherencespec_management_test.go | 12 +- ..._statefulset_coherencespec_metrics_test.go | 12 +- ...tefulset_coherencespec_persistence_test.go | 66 +++-- .../create_statefulset_coherencespec_test.go | 37 +-- .../create_statefulset_coherenceutils_test.go | 1 + api/v1/create_statefulset_jvmspec_test.go | 50 ++-- api/v1/create_statefulset_test.go | 8 +- pkg/runner/cmd_config.go | 87 ++++++ pkg/runner/cmd_server.go | 33 +++ pkg/runner/run_details.go | 14 + pkg/runner/runner.go | 34 ++- 24 files changed, 621 insertions(+), 313 deletions(-) create mode 100644 pkg/runner/cmd_config.go diff --git a/Makefile b/Makefile index 4f7a2bcfa..55544519c 100644 --- a/Makefile +++ b/Makefile @@ -273,7 +273,8 @@ endif IMAGE_PULL_POLICY ?= IfNotPresent # Env variable used by the kubectl test framework to locate the kubectl binary -TEST_ASSET_KUBECTL ?= $(shell which kubectl) +KUBECTL_CMD ?= kubectl +TEST_ASSET_KUBECTL ?= $(shell which $(KUBECTL_CMD)) # ---------------------------------------------------------------------------------------------------------------------- # Build output directories @@ -1030,30 +1031,30 @@ olm-deploy-catalog: ## Deploy the Operator Catalog into OLM mkdir -p $(BUILD_OUTPUT)/catalog || true cp $(SCRIPTS_DIR)/operator-catalog-source.yaml $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml $(SED) -e 's^IMAGE_NAME_PLACEHOLDER^$(CATALOG_IMAGE)^g' $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml - kubectl apply -f $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml - kubectl -n olm get catalogsource + $(KUBECTL_CMD) apply -f $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml + $(KUBECTL_CMD) -n olm get catalogsource .PHONY: wait-for-olm-deploy -wait-for-olm-deploy: export POD=$(shell kubectl -n olm get pod -l olm.catalogSource=coherence-operator-catalog -o name) +wait-for-olm-deploy: export POD=$(shell $(KUBECTL_CMD) -n olm get pod -l olm.catalogSource=coherence-operator-catalog -o name) wait-for-olm-deploy: ## Wait for the Operator Catalog to be deployed into OLM echo "Operator Catalog Source Pods:" - kubectl -n olm get pod -l olm.catalogSource=coherence-operator-catalog + $(KUBECTL_CMD) -n olm get pod -l olm.catalogSource=coherence-operator-catalog echo "Waiting for Operator Catalog Source to be ready. Pod: $(POD)" - kubectl -n olm wait --for condition=ready --timeout 480s $(POD) + $(KUBECTL_CMD) -n olm wait --for condition=ready --timeout 480s $(POD) .PHONY: olm-deploy olm-deploy: ## Deploy the Operator into the coherence namespace using OLM - kubectl create ns coherence || true - kubectl -n coherence apply -f $(SCRIPTS_DIR)/operator-group.yaml - kubectl -n coherence apply -f $(SCRIPTS_DIR)/operator-subscription.yaml + $(KUBECTL_CMD) create ns coherence || true + $(KUBECTL_CMD) -n coherence apply -f $(SCRIPTS_DIR)/operator-group.yaml + $(KUBECTL_CMD) -n coherence apply -f $(SCRIPTS_DIR)/operator-subscription.yaml sleep 10 - kubectl -n coherence get ip - kubectl -n coherence get csv - kubectl -n coherence wait --for condition=available deployment/coherence-operator-controller-manager -timeout 480s + $(KUBECTL_CMD) -n coherence get ip + $(KUBECTL_CMD) -n coherence get csv + $(KUBECTL_CMD) -n coherence wait --for condition=available deployment/coherence-operator-controller-manager -timeout 480s .PHONY: olm-undeploy olm-undeploy: ## Undeploy the Operator that was installed with OLM - kubectl -n coherence delete csv coherence-operator.v$(VERSION) + $(KUBECTL_CMD) -n coherence delete csv coherence-operator.v$(VERSION) # ====================================================================================================================== # Targets to run a local container registry @@ -1545,20 +1546,20 @@ install-network-policy-tests: $(BUILD_TARGETS)/build-operator reset-namespace in .PHONY: install-network-policies install-network-policies: install-operator-network-policies install-coherence-network-policies @echo "API Server info" - kubectl get svc -o wide - kubectl get endpoints kubernetes + $(KUBECTL_CMD) get svc -o wide + $(KUBECTL_CMD) get endpoints kubernetes @echo "Network policies installed in $(OPERATOR_NAMESPACE)" - kubectl get networkpolicy -n $(OPERATOR_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(OPERATOR_NAMESPACE) @echo "Network policies installed in $(CLUSTER_NAMESPACE)" - kubectl get networkpolicy -n $(CLUSTER_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(CLUSTER_NAMESPACE) # ---------------------------------------------------------------------------------------------------------------------- # Prepare a copy of the example network policies # ---------------------------------------------------------------------------------------------------------------------- .PHONY: prepare-network-policies -prepare-network-policies: export IP1=$(shell kubectl -n default get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}') -prepare-network-policies: export IP2=$(shell kubectl -n default get svc kubernetes -o jsonpath='{.spec.clusterIP}') -prepare-network-policies: export API_PORT=$(shell kubectl -n default get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}') +prepare-network-policies: export IP1=$(shell $(KUBECTL_CMD) -n default get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}') +prepare-network-policies: export IP2=$(shell $(KUBECTL_CMD) -n default get svc kubernetes -o jsonpath='{.spec.clusterIP}') +prepare-network-policies: export API_PORT=$(shell $(KUBECTL_CMD) -n default get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}') prepare-network-policies: mkdir -p $(BUILD_OUTPUT)/network-policies cp $(EXAMPLES_DIR)/095_network_policies/*.sh $(BUILD_OUTPUT)/network-policies @@ -1575,9 +1576,9 @@ prepare-network-policies: .PHONY: uninstall-network-policies uninstall-network-policies: uninstall-operator-network-policies uninstall-coherence-network-policies @echo "Network policies installed in $(OPERATOR_NAMESPACE)" - kubectl get networkpolicy -n $(OPERATOR_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(OPERATOR_NAMESPACE) @echo "Network policies installed in $(CLUSTER_NAMESPACE)" - kubectl get networkpolicy -n $(CLUSTER_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(CLUSTER_NAMESPACE) # ---------------------------------------------------------------------------------------------------------------------- # Install the Operator network policies from the examples @@ -1671,7 +1672,7 @@ cleanup-coherence-compatibility: undeploy uninstall-crds clean-namespace # ---------------------------------------------------------------------------------------------------------------------- .PHONY: install-crds install-crds: prepare-deploy uninstall-crds ## Install the CRDs - $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | kubectl create -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | $(KUBECTL_CMD) create -f - # ---------------------------------------------------------------------------------------------------------------------- # Uninstall CRDs from Kubernetes. @@ -1683,7 +1684,7 @@ uninstall-crds: $(BUILD_TARGETS)/manifests ## Uninstall the CRDs @echo "Uninstalling CRDs - calling prepare_deploy" $(call prepare_deploy,$(OPERATOR_IMAGE),$(OPERATOR_NAMESPACE)) @echo "Uninstalling CRDs - executing deletion" - $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | kubectl delete --force -f - || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | $(KUBECTL_CMD) delete --force -f - || true @echo "Uninstall CRDs completed" # ---------------------------------------------------------------------------------------------------------------------- @@ -1726,11 +1727,11 @@ endif ifeq (false,$(OPERATOR_HA)) cd $(BUILD_DEPLOY)/manager && $(KUSTOMIZE) edit add patch --kind Deployment --name controller-manager --path single-replica-patch.yaml endif - kubectl -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true ifeq ("$(OPERATOR_IMAGE_REGISTRY)","$(ORACLE_REGISTRY)") - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) apply -f - else - $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | $(KUBECTL_CMD) apply -f - endif sleep 5 @@ -1739,20 +1740,20 @@ endif just-deploy: ensure-pull-secret ## Deploy the Coherence Operator without rebuilding anything $(call prepare_deploy,$(OPERATOR_IMAGE),$(OPERATOR_NAMESPACE)) ifeq ("$(OPERATOR_IMAGE_REGISTRY)","$(ORACLE_REGISTRY)") - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) apply -f - else - $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | $(KUBECTL_CMD) apply -f - endif .PHONY: ensure-pull-secret ensure-pull-secret: ifneq ("$(DEPLOY_REGISTRY_CONFIG_PATH)","") - kubectl -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true - kubectl -n $(OPERATOR_NAMESPACE) create secret generic coherence-operator-pull-secret \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) create secret generic coherence-operator-pull-secret \ --from-file=.dockerconfigjson=$(DEPLOY_REGISTRY_CONFIG_PATH) \ --type=kubernetes.io/dockerconfigjson - kubectl -n $(OPERATOR_NAMESPACE) patch serviceaccount default -p '{"imagePullSecrets": [{"name": "coherence-operator-pull-secret"}]}' + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) patch serviceaccount default -p '{"imagePullSecrets": [{"name": "coherence-operator-pull-secret"}]}' endif @@ -1765,8 +1766,8 @@ deploy-debug: prepare-deploy-debug create-namespace $(TOOLS_BIN)/kustomize ## ifneq (,$(WATCH_NAMESPACE)) cd $(BUILD_DEPLOY)/manager && $(KUSTOMIZE) edit add configmap env-vars --from-literal WATCH_NAMESPACE=$(WATCH_NAMESPACE) endif - kubectl -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl apply -f - + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) apply -f - sleep 5 @echo "" @echo "Deployed a debug enabled Operator." @@ -1782,26 +1783,26 @@ endif .PHONY: port-forward-debug -port-forward-debug: export POD=$(shell kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) +port-forward-debug: export POD=$(shell $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) port-forward-debug: ## Run a port-forward process to forward localhost:2345 to port 2345 in the Operator Pod @echo "Starting port-forward to the Operator Pod on port 2345 - DO NOT stop this process until debugging is finished!" @echo "Connect your IDE debugger to localhost:2345 (which is the default remote debug setting in IDEs like Goland)" @echo "If your IDE immediately disconnects it may be that the Operator Pod was not yet started, so try again." @echo "" - kubectl -n $(OPERATOR_NAMESPACE) port-forward $(POD) 2345:2345 || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) port-forward $(POD) 2345:2345 || true .PHONY: prepare-deploy-debug prepare-deploy-debug: $(BUILD_TARGETS)/manifests build-operator-debug $(TOOLS_BIN)/kustomize $(call prepare_deploy,$(OPERATOR_IMAGE_DEBUG),$(OPERATOR_NAMESPACE)) .PHONY: wait-for-deploy -wait-for-deploy: export POD=$(shell kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) +wait-for-deploy: export POD=$(shell $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) wait-for-deploy: sleep 30 echo "Operator Pods:" - kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence echo "Waiting for Operator to be ready. Pod: $(POD)" - kubectl -n $(OPERATOR_NAMESPACE) wait --for condition=ready --timeout 480s $(POD) + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) wait --for condition=ready --timeout 480s $(POD) # ---------------------------------------------------------------------------------------------------------------------- # Prepare the deployment manifests - this is called by a number of other targets. @@ -1826,14 +1827,14 @@ endef undeploy: $(BUILD_PROPS) $(BUILD_TARGETS)/manifests $(TOOLS_BIN)/kustomize ## Undeploy the Coherence Operator @echo "Undeploy Coherence Operator..." $(call prepare_deploy,$(OPERATOR_IMAGE),$(OPERATOR_NAMESPACE)) - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl delete -f - || true - kubectl -n $(OPERATOR_NAMESPACE) delete secret coherence-webhook-server-cert || true - kubectl delete mutatingwebhookconfiguration coherence-operator-mutating-webhook-configuration || true - kubectl delete validatingwebhookconfiguration coherence-operator-validating-webhook-configuration || true - kubectl -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) delete -f - || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete secret coherence-webhook-server-cert || true + $(KUBECTL_CMD) delete mutatingwebhookconfiguration coherence-operator-mutating-webhook-configuration || true + $(KUBECTL_CMD) delete validatingwebhookconfiguration coherence-operator-validating-webhook-configuration || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true @echo "Undeploy Coherence Operator completed" @echo "Uninstalling CRDs - executing deletion" - $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | kubectl delete --force -f - || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | $(KUBECTL_CMD) delete --force -f - || true @echo "Uninstall CRDs completed" @@ -1841,9 +1842,9 @@ undeploy: $(BUILD_PROPS) $(BUILD_TARGETS)/manifests $(TOOLS_BIN)/kustomize ## U # Tail the deployed operator logs. # ---------------------------------------------------------------------------------------------------------------------- .PHONY: tail-logs -tail-logs: export POD=$(shell kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) +tail-logs: export POD=$(shell $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) tail-logs: ## Tail the Coherence Operator Pod logs (with follow) - kubectl -n $(OPERATOR_NAMESPACE) logs $(POD) -c manager -f + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) logs $(POD) -c manager -f $(BUILD_MANIFESTS_PKG): $(TOOLS_BIN)/kustomize $(TOOLS_BIN)/yq $(MANIFEST_FILES) @@ -1883,13 +1884,13 @@ $(BUILD_MANIFESTS_PKG): $(TOOLS_BIN)/kustomize $(TOOLS_BIN)/yq $(MANIFEST_FILES) create-namespace: export KUBECONFIG_PATH := $(KUBECONFIG_PATH) create-namespace: ## Create the test namespace ifeq ($(CREATE_OPERATOR_NAMESPACE),true) - kubectl get ns $(OPERATOR_NAMESPACE) -o name > /dev/null 2>&1 || kubectl create namespace $(OPERATOR_NAMESPACE) - kubectl get ns $(OPERATOR_NAMESPACE_CLIENT) -o name > /dev/null 2>&1 || kubectl create namespace $(OPERATOR_NAMESPACE_CLIENT) - kubectl get ns $(CLUSTER_NAMESPACE) -o name > /dev/null 2>&1 || kubectl create namespace $(CLUSTER_NAMESPACE) + $(KUBECTL_CMD) get ns $(OPERATOR_NAMESPACE) -o name > /dev/null 2>&1 || $(KUBECTL_CMD) create namespace $(OPERATOR_NAMESPACE) + $(KUBECTL_CMD) get ns $(OPERATOR_NAMESPACE_CLIENT) -o name > /dev/null 2>&1 || $(KUBECTL_CMD) create namespace $(OPERATOR_NAMESPACE_CLIENT) + $(KUBECTL_CMD) get ns $(CLUSTER_NAMESPACE) -o name > /dev/null 2>&1 || $(KUBECTL_CMD) create namespace $(CLUSTER_NAMESPACE) endif - kubectl label namespace $(OPERATOR_NAMESPACE) coherence.oracle.com/test=true --overwrite - kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) coherence.oracle.com/test=true --overwrite - kubectl label namespace $(CLUSTER_NAMESPACE) coherence.oracle.com/test=true --overwrite + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE) coherence.oracle.com/test=true --overwrite + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE_CLIENT) coherence.oracle.com/test=true --overwrite + $(KUBECTL_CMD) label namespace $(CLUSTER_NAMESPACE) coherence.oracle.com/test=true --overwrite # ---------------------------------------------------------------------------------------------------------------------- # Delete and re-create the test namespace @@ -1904,7 +1905,7 @@ reset-namespace: export OCR_DOCKER_PASSWORD := $(OCR_DOCKER_PASSWORD) reset-namespace: delete-namespace create-namespace ensure-pull-secret ## Reset the test namespace ifneq ($(DOCKER_SERVER),) @echo "Creating pull secrets for $(DOCKER_SERVER)" - kubectl create secret docker-registry coherence-k8s-operator-development-secret \ + $(KUBECTL_CMD) create secret docker-registry coherence-k8s-operator-development-secret \ --namespace $(OPERATOR_NAMESPACE) \ --docker-server "$(DOCKER_SERVER)" \ --docker-username "$(DOCKER_USERNAME)" \ @@ -1913,7 +1914,7 @@ ifneq ($(DOCKER_SERVER),) endif ifneq ("$(or $(OCR_DOCKER_USERNAME),$(OCR_DOCKER_PASSWORD))","") @echo "Creating pull secrets for container-registry.oracle.com" - kubectl create secret docker-registry ocr-k8s-operator-development-secret \ + $(KUBECTL_CMD) create secret docker-registry ocr-k8s-operator-development-secret \ --namespace $(OPERATOR_NAMESPACE) \ --docker-server container-registry.oracle.com \ --docker-username "$(OCR_DOCKER_USERNAME)" \ @@ -1931,13 +1932,13 @@ ifeq ($(CREATE_OPERATOR_NAMESPACE),true) $(call delete_ns,$(OPERATOR_NAMESPACE_CLIENT)) $(call delete_ns,$(CLUSTER_NAMESPACE)) endif - kubectl delete clusterrole operator-test-coherence-operator --force --ignore-not-found=true --grace-period=0 && echo "deleted namespace" || true - kubectl delete clusterrolebinding operator-test-coherence-operator --ignore-not-found=true --force --grace-period=0 && echo "deleted namespace" || true + $(KUBECTL_CMD) delete clusterrole operator-test-coherence-operator --force --ignore-not-found=true --grace-period=0 && echo "deleted namespace" || true + $(KUBECTL_CMD) delete clusterrolebinding operator-test-coherence-operator --ignore-not-found=true --force --grace-period=0 && echo "deleted namespace" || true define delete_ns - if kubectl get ns $(1); then \ + if $(KUBECTL_CMD) get ns $(1); then \ echo "Deleting test namespace $(1)" ;\ - kubectl delete namespace $(1) --force --ignore-not-found=true --grace-period=0 --timeout=600s ;\ + $(KUBECTL_CMD) delete namespace $(1) --force --ignore-not-found=true --grace-period=0 --timeout=600s ;\ echo "deleted namespace $(1)" || true ;\ fi endef @@ -1947,21 +1948,21 @@ endef # ---------------------------------------------------------------------------------------------------------------------- .PHONY: delete-coherence-clusters delete-coherence-clusters: ## Delete all running Coherence clusters in the test namespace - for i in $$(kubectl -n $(OPERATOR_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ - kubectl -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(OPERATOR_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(CLUSTER_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ - kubectl -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(CLUSTER_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(OPERATOR_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ - kubectl -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(OPERATOR_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(CLUSTER_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ - kubectl -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(CLUSTER_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) delete $${i}; \ done # ---------------------------------------------------------------------------------------------------------------------- @@ -1970,15 +1971,15 @@ delete-coherence-clusters: ## Delete all running Coherence clusters in the test .PHONY: clean-namespace clean-namespace: delete-coherence-clusters ## Clean-up deployments in the test namespace @echo "Cleaning Namespaces..." - kubectl delete --all networkpolicy --namespace=$(OPERATOR_NAMESPACE) || true - kubectl delete --all networkpolicy --namespace=$(CLUSTER_NAMESPACE) || true - for i in $$(kubectl -n $(OPERATOR_NAMESPACE) get all -o name); do \ + $(KUBECTL_CMD) delete --all networkpolicy --namespace=$(OPERATOR_NAMESPACE) || true + $(KUBECTL_CMD) delete --all networkpolicy --namespace=$(CLUSTER_NAMESPACE) || true + for i in $$($(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get all -o name); do \ echo "Deleting $${i} from test namespace $(OPERATOR_NAMESPACE)" \ - kubectl -n $(OPERATOR_NAMESPACE) delete $${i}; \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(CLUSTER_NAMESPACE) get all -o name); do \ + for i in $$($(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) get all -o name); do \ echo "Deleting $${i} from test namespace $(CLUSTER_NAMESPACE)" \ - kubectl -n $(CLUSTER_NAMESPACE) delete $${i}; \ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) delete $${i}; \ done @echo "Cleaning Namespaces completed" @@ -1988,9 +1989,9 @@ clean-namespace: delete-coherence-clusters ## Clean-up deployments in the test .PHONY: create-ssl-secrets create-ssl-secrets: $(BUILD_OUTPUT)/certs @echo "Deleting SSL secret $(TEST_SSL_SECRET)" - kubectl --namespace $(OPERATOR_NAMESPACE) delete secret $(TEST_SSL_SECRET) && echo "secret deleted" || true + $(KUBECTL_CMD) --namespace $(OPERATOR_NAMESPACE) delete secret $(TEST_SSL_SECRET) && echo "secret deleted" || true @echo "Creating SSL secret $(TEST_SSL_SECRET)" - kubectl create secret generic $(TEST_SSL_SECRET) \ + $(KUBECTL_CMD) create secret generic $(TEST_SSL_SECRET) \ --namespace $(OPERATOR_NAMESPACE) \ --from-file=keystore.jks=build/_output/certs/icarus.jks \ --from-file=storepass.txt=build/_output/certs/storepassword.txt \ @@ -2042,11 +2043,11 @@ kind-calico: export KIND_CONFIG=$(SCRIPTS_DIR)/kind-config-calico.yaml kind-calico: ## Run a KinD cluster with Calico kind create cluster --name $(KIND_CLUSTER) --config $(SCRIPTS_DIR)/kind-config-calico.yaml --image $(KIND_IMAGE) $(SCRIPTS_DIR)/kind-label-node.sh - kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/$(CALICO_VERSION)/manifests/calico.yaml - kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true + $(KUBECTL_CMD) apply -f https://raw.githubusercontent.com/projectcalico/calico/$(CALICO_VERSION)/manifests/calico.yaml + $(KUBECTL_CMD) -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true sleep 30 - kubectl -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=calico-node pod - kubectl -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=kube-dns pod + $(KUBECTL_CMD) -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=calico-node pod + $(KUBECTL_CMD) -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=kube-dns pod # ---------------------------------------------------------------------------------------------------------------------- # Stop and delete the Kind cluster @@ -2152,7 +2153,7 @@ MINIKUBE_K8S ?= 1.25.8 minikube: minikube-install ## Run a default minikube cluster with Calico $(MINIKUBE) start --driver docker --cni calico --kubernetes-version $(MINIKUBE_K8S) $(MINIKUBE) status - kubectl get nodes + $(KUBECTL_CMD) get nodes # ---------------------------------------------------------------------------------------------------------------------- # Stop Minikube @@ -2235,12 +2236,12 @@ $(TOOLS_BIN)/cmctl: .PHONY: install-cert-manager install-cert-manager: $(TOOLS_BIN)/cmctl ## Install Cert manager into the Kubernetes cluster - kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yam + $(KUBECTL_CMD) apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yam $(CMCTL) check api --wait=10m .PHONY: uninstall-cert-manager uninstall-cert-manager: ## Uninstall Cert manager from the Kubernetes cluster - kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yam + $(KUBECTL_CMD) delete -f https://github.com/cert-manager/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yam # ====================================================================================================================== @@ -2414,6 +2415,32 @@ $(BUILD_BIN_ARM64)/cohctl: ./hack/install-cli.sh chmod +x $(BUILD_BIN_ARM64)/cohctl +# ---------------------------------------------------------------------------------------------------------------------- +# Download the OpenShift CLI (oc) into build/tools/bin +# ---------------------------------------------------------------------------------------------------------------------- +.PHONY: oc +oc: $(TOOLS_BIN)/oc + +$(TOOLS_BIN)/oc: ## Download OpenShift oc CLI + mkdir -p oc-tmp || true + mkdir -p $(TOOLS_BIN) || true +ifeq (Darwin, $(UNAME_S)) +ifeq (x86_64, $(UNAME_M)) + curl -Ls https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/openshift-client-mac.tar.gz -o oc-tmp/openshift-client.tar.gz +else + curl -Ls https://mirror.openshift.com/pub/openshift-v4/aarch64/clients/ocp/stable/openshift-client-mac-arm64.tar.gz -o oc-tmp/openshift-client.tar.gz +endif +else +ifeq (x86_64, $(UNAME_M)) + curl -Ls https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/openshift-client-linux.tar.gz -o oc-tmp/openshift-client.tar.gz +else + curl -Ls https://mirror.openshift.com/pub/openshift-v4/aarch64/clients/ocp/stable/openshift-client-linux.tar.gz -o oc-tmp/openshift-client.tar.gz +endif +endif + cd oc-tmp && tar -xvf openshift-client.tar.gz + mv oc-tmp/oc $(TOOLS_BIN)/oc + chmod +x $(TOOLS_BIN)/oc + # ---------------------------------------------------------------------------------------------------------------------- # find or download gotestsum # ---------------------------------------------------------------------------------------------------------------------- @@ -2586,37 +2613,37 @@ endif .PHONY: install-prometheus install-prometheus: get-prometheus ## Install Prometheus and Grafana - kubectl create -f $(PROMETHEUS_HOME)/manifests/setup + $(KUBECTL_CMD) create -f $(PROMETHEUS_HOME)/manifests/setup sleep 10 - until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done + until $(KUBECTL_CMD) get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done # We create additional custom RBAC rules because the defaults do not work # in an RBAC enabled cluster such as KinD # See: https://prometheus-operator.dev/docs/operator/rbac/ - kubectl create -f hack/prometheus-rbac.yaml - kubectl create -f $(PROMETHEUS_HOME)/manifests + $(KUBECTL_CMD) create -f hack/prometheus-rbac.yaml + $(KUBECTL_CMD) create -f $(PROMETHEUS_HOME)/manifests sleep 10 - kubectl -n monitoring get all + $(KUBECTL_CMD) -n monitoring get all @echo "Waiting for Prometheus StatefulSet to be ready" - until kubectl -n monitoring get statefulset/prometheus-k8s ; do date; sleep 1; echo ""; done - kubectl -n monitoring rollout status statefulset/prometheus-k8s --timeout=5m + until $(KUBECTL_CMD) -n monitoring get statefulset/prometheus-k8s ; do date; sleep 1; echo ""; done + $(KUBECTL_CMD) -n monitoring rollout status statefulset/prometheus-k8s --timeout=5m @echo "Waiting for Grafana Deployment to be ready" - kubectl -n monitoring rollout status deployment/grafana --timeout=5m + $(KUBECTL_CMD) -n monitoring rollout status deployment/grafana --timeout=5m # ---------------------------------------------------------------------------------------------------------------------- # Uninstall Prometheus # ---------------------------------------------------------------------------------------------------------------------- .PHONY: uninstall-prometheus uninstall-prometheus: get-prometheus ## Uninstall Prometheus and Grafana - kubectl delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests || true - kubectl delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests/setup || true - kubectl delete --ignore-not-found=true -f hack/prometheus-rbac.yaml + $(KUBECTL_CMD) delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests || true + $(KUBECTL_CMD) delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests/setup || true + $(KUBECTL_CMD) delete --ignore-not-found=true -f hack/prometheus-rbac.yaml # ---------------------------------------------------------------------------------------------------------------------- # Install Prometheus Adapter used for k8s metrics and Horizontal Pod Autoscaler # ---------------------------------------------------------------------------------------------------------------------- .PHONY: install-prometheus-adapter install-prometheus-adapter: - kubectl create ns $(OPERATOR_NAMESPACE) || true + $(KUBECTL_CMD) create ns $(OPERATOR_NAMESPACE) || true helm repo add stable https://kubernetes-charts.storage.googleapis.com/ || true helm install --atomic --namespace $(OPERATOR_NAMESPACE) --version $(PROMETHEUS_ADAPTER_VERSION) --wait \ --set prometheus.url=http://prometheus.$(OPERATOR_NAMESPACE).svc \ @@ -2636,25 +2663,25 @@ uninstall-prometheus-adapter: port-forward-grafana: ## Run a port-forward to Grafana on http://127.0.0.1:3000 @echo "Reach Grafana on http://127.0.0.1:3000" @echo "User: admin Password: admin" - kubectl --namespace monitoring port-forward svc/grafana 3000 + $(KUBECTL_CMD) --namespace monitoring port-forward svc/grafana 3000 # ---------------------------------------------------------------------------------------------------------------------- # Install MetalLB # ---------------------------------------------------------------------------------------------------------------------- .PHONY: install-metallb install-metallb: ## Install MetalLB to allow services of type LoadBalancer - kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml - kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml - kubectl apply -f hack/metallb-config.yaml + $(KUBECTL_CMD) apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml + $(KUBECTL_CMD) apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml + $(KUBECTL_CMD) apply -f hack/metallb-config.yaml # ---------------------------------------------------------------------------------------------------------------------- # Uninstall MetalLB # ---------------------------------------------------------------------------------------------------------------------- .PHONY: uninstall-metallb uninstall-metallb: ## Uninstall MetalLB - kubectl delete -f hack/metallb-config.yaml || true - kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml || true - kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml || true + $(KUBECTL_CMD) delete -f hack/metallb-config.yaml || true + $(KUBECTL_CMD) delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml || true + $(KUBECTL_CMD) delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml || true # ---------------------------------------------------------------------------------------------------------------------- @@ -2664,23 +2691,23 @@ uninstall-metallb: ## Uninstall MetalLB install-istio: delete-istio-config get-istio ## Install the latest version of Istio into k8s (or override the version using the ISTIO_VERSION env var) ifeq (true,$(ISTIO_USE_CONFIG)) $(ISTIO_HOME)/bin/istioctl install -f $(BUILD_OUTPUT)/istio-config.yaml -y - kubectl -n istio-system wait --for condition=available deployment.apps/istiod-$(ISTIO_REVISION) + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istiod-$(ISTIO_REVISION) $(ISTIO_HOME)/bin/istioctl tag set default --revision $(ISTIO_REVISION) else $(ISTIO_HOME)/bin/istioctl install --set profile=demo -y - kubectl -n istio-system wait --for condition=available deployment.apps/istiod + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istiod endif - kubectl -n istio-system wait --for condition=available deployment.apps/istio-ingressgateway - kubectl -n istio-system wait --for condition=available deployment.apps/istio-egressgateway - kubectl apply -f $(SCRIPTS_DIR)/istio-strict.yaml - kubectl -n $(OPERATOR_NAMESPACE) apply -f $(SCRIPTS_DIR)/istio-operator.yaml - kubectl label namespace $(OPERATOR_NAMESPACE) istio-injection=enabled --overwrite=true - kubectl label namespace $(OPERATOR_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true - kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) istio-injection=enabled --overwrite=true - kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) istio.io/rev=$(ISTIO_REVISION) --overwrite=true - kubectl label namespace $(CLUSTER_NAMESPACE) istio-injection=enabled --overwrite=true - kubectl label namespace $(CLUSTER_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true - kubectl apply -f $(ISTIO_HOME)/samples/addons + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istio-ingressgateway + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istio-egressgateway + $(KUBECTL_CMD) apply -f $(SCRIPTS_DIR)/istio-strict.yaml + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) apply -f $(SCRIPTS_DIR)/istio-operator.yaml + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE) istio-injection=enabled --overwrite=true + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE_CLIENT) istio-injection=enabled --overwrite=true + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE_CLIENT) istio.io/rev=$(ISTIO_REVISION) --overwrite=true + $(KUBECTL_CMD) label namespace $(CLUSTER_NAMESPACE) istio-injection=enabled --overwrite=true + $(KUBECTL_CMD) label namespace $(CLUSTER_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true + $(KUBECTL_CMD) apply -f $(ISTIO_HOME)/samples/addons # ---------------------------------------------------------------------------------------------------------------------- # Upgrade Istio @@ -2694,8 +2721,8 @@ upgrade-istio: delete-istio-config $(BUILD_OUTPUT)/istio-config.yaml ## Upgrade # ---------------------------------------------------------------------------------------------------------------------- .PHONY: uninstall-istio uninstall-istio: delete-istio-config get-istio ## Uninstall Istio from k8s - kubectl -n $(OPERATOR_NAMESPACE) delete -f $(SCRIPTS_DIR)/istio-operator.yaml || true - kubectl delete -f ./hack/istio-strict.yaml || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete -f $(SCRIPTS_DIR)/istio-operator.yaml || true + $(KUBECTL_CMD) delete -f ./hack/istio-strict.yaml || true $(ISTIO_HOME)/bin/istioctl uninstall --purge -y $(BUILD_OUTPUT)/istio-config.yaml: $(BUILD_PROPS) @@ -2802,9 +2829,9 @@ release-dashboards: @echo "Releasing Dashboards $(VERSION)" mkdir -p $(BUILD_OUTPUT)/dashboards/$(VERSION) || true tar -czvf $(BUILD_OUTPUT)/dashboards/$(VERSION)/coherence-dashboards.tar.gz dashboards/ - kubectl create configmap coherence-grafana-dashboards --from-file=dashboards/grafana \ + $(KUBECTL_CMD) create configmap coherence-grafana-dashboards --from-file=dashboards/grafana \ --dry-run=client -o yaml > $(BUILD_OUTPUT)/dashboards/$(VERSION)/coherence-grafana-dashboards.yaml - kubectl create configmap coherence-kibana-dashboards --from-file=dashboards/kibana \ + $(KUBECTL_CMD) create configmap coherence-kibana-dashboards --from-file=dashboards/kibana \ --dry-run=client -o yaml > $(BUILD_OUTPUT)/dashboards/$(VERSION)/coherence-kibana-dashboards.yaml # ---------------------------------------------------------------------------------------------------------------------- diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index a144beb7e..1488bcb28 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -851,7 +851,10 @@ func (in *PersistenceSpec) AddVolumeMounts(c *corev1.Container) { if in.Volume != nil || in.PersistentVolumeClaim != nil { // Set the persistence location environment variable - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohPersistenceDir, Value: VolumeMountPathPersistence}) + if c.Name == ContainerNameCoherence { + // only do this for the Coherence container as it's env-vars are copied to the other containers + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohPersistenceDir, Value: VolumeMountPathPersistence}) + } // Add the persistence volume mount c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{ Name: VolumeNamePersistence, @@ -860,9 +863,12 @@ func (in *PersistenceSpec) AddVolumeMounts(c *corev1.Container) { } // Add the snapshot volume mount if required - if in != nil && in.Snapshots != nil && (in.Snapshots.Volume != nil || in.Snapshots.PersistentVolumeClaim != nil) { + if in.Snapshots != nil && (in.Snapshots.Volume != nil || in.Snapshots.PersistentVolumeClaim != nil) { // Set the snapshot location environment variable - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohSnapshotDir, Value: VolumeMountPathSnapshots}) + if c.Name == ContainerNameCoherence { + // only do this for the Coherence container as it's env-vars are copied to the other containers + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohSnapshotDir, Value: VolumeMountPathSnapshots}) + } // Add the snapshot volume mount c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{ Name: VolumeNameSnapshots, @@ -1291,7 +1297,7 @@ func (in *NamedPortSpec) GetServicePort(d CoherenceResource) int32 { switch { case in == nil: return 0 - case in != nil && in.Service != nil && in.Service.Port != nil: + case in.Service != nil && in.Service.Port != nil: return *in.Service.Port case in.Port == 0 && strings.ToLower(in.Name) == PortNameMetrics: // special case for well known port - metrics diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index ee2693cce..ea58080c8 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -688,6 +688,9 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou // append any additional VolumeMounts cohContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) + initContainer := in.CreateOperatorInitContainer(deployment) + jvmArgsInitContainer := in.CreateOperatorJvmArgsInitContainer(deployment) + podTemplate := corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: podLabels, @@ -711,16 +714,16 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou ShareProcessNamespace: in.ShareProcessNamespace, Tolerations: in.Tolerations, TopologySpreadConstraints: in.EnsureTopologySpreadConstraints(deployment), - InitContainers: []corev1.Container{ - in.CreateOperatorInitContainer(deployment), - }, - Containers: []corev1.Container{cohContainer}, Volumes: []corev1.Volume{ {Name: VolumeNameUtils, VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, }, } + // The order of this append is very important, the jvmArgs must come second + podTemplate.Spec.InitContainers = append(podTemplate.Spec.InitContainers, initContainer, jvmArgsInitContainer) + podTemplate.Spec.Containers = append(podTemplate.Spec.Containers, cohContainer) + // Add any network settings in.Network.UpdatePodTemplate(&podTemplate) // Add any JVM settings @@ -749,6 +752,9 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou sv.AddVolumes(&podTemplate) } + // FINALLY - Set the init-container environment variables to match the Coherence container + podTemplate.Spec.InitContainers[0].Env = append(podTemplate.Spec.InitContainers[0].Env, podTemplate.Spec.Containers[0].Env...) + podTemplate.Spec.InitContainers[1].Env = append(podTemplate.Spec.InitContainers[1].Env, podTemplate.Spec.Containers[0].Env...) return podTemplate } @@ -1033,23 +1039,30 @@ func (in *CoherenceResourceSpec) UpdateDefaultLivenessProbeAction(probe *corev1. // CreateOperatorInitContainer creates the Operator init-container spec. func (in *CoherenceResourceSpec) CreateOperatorInitContainer(deployment CoherenceResource) corev1.Container { image := operator.GetDefaultOperatorImage() + return in.createInitContainer(deployment, ContainerNameOperatorInit, image, []string{RunnerInitCommand, RunnerInit}) +} - vm := in.CreateCommonVolumeMounts() +// CreateOperatorJvmArgsInitContainer creates the JVM args file init-container spec. +func (in *CoherenceResourceSpec) CreateOperatorJvmArgsInitContainer(deployment CoherenceResource) corev1.Container { + var image string - env := []corev1.EnvVar{ - {Name: EnvVarCohUtilDir, Value: VolumeMountPathUtils}, + if in.Image == nil { + image = operator.GetDefaultCoherenceImage() + } else { + image = *in.Image } + return in.createInitContainer(deployment, ContainerNameOperatorArgs, image, []string{RunnerCommand, RunnerConfig}) +} - clusterName := deployment.GetCoherenceClusterName() - if clusterName != "" { - env = append(env, corev1.EnvVar{Name: EnvVarCohClusterName, Value: clusterName}) - } +// CreateOperatorInitContainer creates the Operator init-container spec. +func (in *CoherenceResourceSpec) createInitContainer(deployment CoherenceResource, name, image string, cmd []string) corev1.Container { + + vm := in.CreateCommonVolumeMounts() c := corev1.Container{ - Name: ContainerNameOperatorInit, + Name: name, Image: image, - Command: []string{RunnerInitCommand, RunnerInit}, - Env: env, + Command: cmd, SecurityContext: in.ContainerSecurityContext, VolumeMounts: vm, } diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 398a3ceb2..08cf6f83a 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -182,7 +182,6 @@ func assertJob(t *testing.T, res coh.Resource, expected *batchv1.Job) { err = os.WriteFile(fmt.Sprintf("%s%c%s-Expected.json", dir, os.PathSeparator, jobActual.Name), jsonExpected, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) - assertEnvironmentVariablesForJob(t, jobActual, expected) assertEnvironmentVariablesForJob(t, jobActual, expected) diffs := deep.Equal(*jobActual, *expected) @@ -418,7 +417,6 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe ReadOnly: false, }, }, - Env: envVars, } if cohImage := spec.GetCoherenceImage(); cohImage != nil { @@ -430,16 +428,25 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Name: coh.ContainerNameOperatorInit, Image: testOperatorImage, Command: []string{coh.RunnerInitCommand, coh.RunnerInit}, - Env: []corev1.EnvVar{ + VolumeMounts: []corev1.VolumeMount{ { - Name: "COHERENCE_CLUSTER", - Value: deployment.GetName(), + Name: coh.VolumeNameJVM, + MountPath: coh.VolumeMountPathJVM, + ReadOnly: false, }, { - Name: "COHERENCE_OPERATOR_UTIL_DIR", - Value: coh.VolumeMountPathUtils, + Name: coh.VolumeNameUtils, + MountPath: coh.VolumeMountPathUtils, + ReadOnly: false, }, }, + } + + // The Operator JVM Args Init-Container + argsContainer := corev1.Container{ + Name: coh.ContainerNameOperatorArgs, + Image: testCoherenceImage, + Command: []string{coh.RunnerCommand, coh.RunnerConfig}, VolumeMounts: []corev1.VolumeMount{ { Name: coh.VolumeNameJVM, @@ -454,6 +461,10 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, } + cohContainer.Env = append(cohContainer.Env, envVars...) + initContainer.Env = append(initContainer.Env, envVars...) + argsContainer.Env = append(argsContainer.Env, envVars...) + annotations := make(map[string]string) annotations[coh.AnnotationIstioConfig] = coh.DefaultIstioConfigAnnotationValue @@ -463,7 +474,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Annotations: annotations, }, Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{initContainer}, + InitContainers: []corev1.Container{initContainer, argsContainer}, Containers: []corev1.Container{cohContainer}, Volumes: []corev1.Volume{ { @@ -576,12 +587,24 @@ func sortPortsForPodTemplate(template *corev1.PodTemplateSpec) { } } +func addEnvVarsToAll(sts *appsv1.StatefulSet, envVars ...corev1.EnvVar) { + addEnvVars(sts, coh.ContainerNameCoherence, envVars...) + addEnvVars(sts, coh.ContainerNameOperatorInit, envVars...) + addEnvVars(sts, coh.ContainerNameOperatorArgs, envVars...) +} + func addEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...corev1.EnvVar) { if sts != nil { addEnvVarsToPodSpec(&sts.Spec.Template, containerName, envVars...) } } +func addEnvVarsToAllJobContainers(job *batchv1.Job, envVars ...corev1.EnvVar) { + addEnvVarsToJob(job, coh.ContainerNameCoherence, envVars...) + addEnvVarsToJob(job, coh.ContainerNameOperatorInit, envVars...) + addEnvVarsToJob(job, coh.ContainerNameOperatorArgs, envVars...) +} + func addEnvVarsToJob(job *batchv1.Job, containerName string, envVars ...corev1.EnvVar) { if job != nil { addEnvVarsToPodSpec(&job.Spec.Template, containerName, envVars...) @@ -621,12 +644,24 @@ func addEnvVarsToContainer(c *corev1.Container, envVars ...corev1.EnvVar) { } } +func removeEnvVarsFromAll(sts *appsv1.StatefulSet, envVars ...string) { + removeEnvVars(sts, coh.ContainerNameCoherence, envVars...) + removeEnvVars(sts, coh.ContainerNameOperatorInit, envVars...) + removeEnvVars(sts, coh.ContainerNameOperatorArgs, envVars...) +} + func removeEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...string) { if sts != nil { removeEnvVarsFromPodSpec(&sts.Spec.Template, containerName, envVars...) } } +func removeEnvVarsFromAllJobContainers(job *batchv1.Job, envVars ...string) { + removeEnvVarsFromJob(job, coh.ContainerNameCoherence, envVars...) + removeEnvVarsFromJob(job, coh.ContainerNameOperatorInit, envVars...) + removeEnvVarsFromJob(job, coh.ContainerNameOperatorArgs, envVars...) +} + func removeEnvVarsFromJob(job *batchv1.Job, containerName string, envVars ...string) { if job != nil { removeEnvVarsFromPodSpec(&job.Spec.Template, containerName, envVars...) diff --git a/api/v1/constants.go b/api/v1/constants.go index 97afee717..bf246e84b 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -78,6 +78,8 @@ const ( ContainerNameCoherence = "coherence" // ContainerNameOperatorInit is the Operator init-container name ContainerNameOperatorInit = "coherence-k8s-utils" + // ContainerNameOperatorArgs is the Operator JVM args init-container name + ContainerNameOperatorArgs = "coherence-k8s-jvm-args" // VolumeNamePersistence is the name of the persistence volume VolumeNamePersistence = "persistence-volume" @@ -115,8 +117,10 @@ const ( // RunnerInitCommand is the start command for the Operator init-container RunnerInitCommand = "/files/runner" - // RunnerInit is the command line argument for the Operator init-container + // RunnerInit is the command line argument for the Operator intialize init-container RunnerInit = "init" + // RunnerConfig is the command line argument for the Operator config init-container + RunnerConfig = "config" // ServiceMonitorKind is the Prometheus ServiceMonitor resource API Kind ServiceMonitorKind = "ServiceMonitor" @@ -171,6 +175,15 @@ const ( // OperatorRackURL is the default Operator rack query URL OperatorRackURL = "http://$(COHERENCE_OPERATOR_HOST)/rack/$(COHERENCE_MACHINE)" + // OperatorJvmArgsFile is the name of the file in the utils directory containing the JVM arguments + OperatorJvmArgsFile = "coherence-jvm-args.txt" + // OperatorClasspathFile is the name of the file in the utils directory containing the JVM class path + OperatorClasspathFile = "coherence-class-path.txt" + // OperatorJarFileSuffix is the suffix to append to the utils directory to locate the Operator jar file. + OperatorJarFileSuffix = "/lib/coherence-operator.jar" + // OperatorConfigDirSuffix is the suffix to append to the utils directory to locate the Operator config directory. + OperatorConfigDirSuffix = "/config" + // DefaultReadinessPath is the default readiness endpoint path DefaultReadinessPath = "/ready" // DefaultLivenessPath is the default liveness endpoint path diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index d65d73949..b9b8189b6 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -25,7 +25,7 @@ func TestCreateJobWithApplicationType(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -45,7 +45,7 @@ func TestCreateJobWithApplicationMain(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -64,7 +64,7 @@ func TestCreateJobWithApplicationMainArgs(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -100,7 +100,7 @@ func TestCreateJobWithWorkingDirectory(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_job_coherencespec_management_test.go b/api/v1/create_job_coherencespec_management_test.go index a36681114..25feb090f 100644 --- a/api/v1/create_job_coherencespec_management_test.go +++ b/api/v1/create_job_coherencespec_management_test.go @@ -80,8 +80,8 @@ func TestCreateJobWithCoherenceManagementEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -102,8 +102,8 @@ func TestCreateJobWithCoherenceManagementEnabledWithPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -138,7 +138,7 @@ func TestCreateJobWithCoherenceManagementWithSSLEnabledWithoutSecret(t *testing. deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, @@ -191,7 +191,7 @@ func TestCreateJobWithCoherenceManagementWithSSLEnabledWithSecret(t *testing.T) deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, diff --git a/api/v1/create_job_coherencespec_metrics_test.go b/api/v1/create_job_coherencespec_metrics_test.go index d43c84a77..60eef157c 100644 --- a/api/v1/create_job_coherencespec_metrics_test.go +++ b/api/v1/create_job_coherencespec_metrics_test.go @@ -80,8 +80,8 @@ func TestCreateJobWithCoherenceMetricsEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -102,8 +102,8 @@ func TestCreateJobWithCoherenceMetricsEnabledWithPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -138,7 +138,7 @@ func TestCreateJobWithCoherenceMetricsWithSSLEnabledWithoutSecret(t *testing.T) deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, @@ -191,7 +191,7 @@ func TestCreateJobWithCoherenceMetricsWithSSLEnabledWithSecret(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, diff --git a/api/v1/create_job_coherencespec_persistence_test.go b/api/v1/create_job_coherencespec_persistence_test.go index 265f7b3ac..ea70e49a9 100644 --- a/api/v1/create_job_coherencespec_persistence_test.go +++ b/api/v1/create_job_coherencespec_persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,7 +44,7 @@ func TestCreateJobWithPersistenceModeOnDemand(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -64,7 +64,7 @@ func TestCreateJobWithPersistenceModeActive(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -83,7 +83,7 @@ func TestCreateJobWithPersistenceModeActiveAsync(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -199,8 +199,7 @@ func TestCreateJobWithPersistenceSnapshotVolume(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -208,6 +207,12 @@ func TestCreateJobWithPersistenceSnapshotVolume(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -251,8 +256,7 @@ func TestCreateJobWithPersistenceSnapshotPVC(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -260,6 +264,12 @@ func TestCreateJobWithPersistenceSnapshotPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -302,8 +312,7 @@ func TestCreateJobWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -311,6 +320,12 @@ func TestCreateJobWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -352,16 +367,19 @@ func TestCreateJobWithPersistenceAndSnapshotVolume(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -417,16 +435,19 @@ func TestCreateJobWithPersistenceAndSnapshotPVC(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -445,6 +466,7 @@ func createResourcesForJob(spec coh.CoherenceResourceSpec) (*batchv1.Job, *coh.C // Add the expected environment variables addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorArgs, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -452,6 +474,12 @@ func createResourcesForJob(spec coh.CoherenceResourceSpec) (*batchv1.Job, *coh.C MountPath: coh.VolumeMountPathPersistence, }) + // add the expected volume mount to the Operator JVM args init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNamePersistence, + MountPath: coh.VolumeMountPathPersistence, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNamePersistence, diff --git a/api/v1/create_job_coherencespec_test.go b/api/v1/create_job_coherencespec_test.go index 8ecafe8b3..71d35f6df 100644 --- a/api/v1/create_job_coherencespec_test.go +++ b/api/v1/create_job_coherencespec_test.go @@ -40,6 +40,7 @@ func TestCreateJobWithImage(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.InitContainers[1].Image = "coherence:1.0" jobExpected.Spec.Template.Spec.Containers[0].Image = "coherence:1.0" // assert that the Job is as expected @@ -74,7 +75,7 @@ func TestCreateJobWithCoherenceSpecWithStorageEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -92,7 +93,7 @@ func TestCreateJobWithCoherenceLocalPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -110,7 +111,7 @@ func TestCreateJobWithCoherenceLocalPortAdjustTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -128,7 +129,7 @@ func TestCreateJobWithCoherenceLocalPortAdjustFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -146,7 +147,7 @@ func TestCreateJobWithCoherenceLocalPortAdjust(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -164,7 +165,7 @@ func TestCreateJobWithCoherenceSpecWithStorageEnabledFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -182,7 +183,7 @@ func TestCreateJobWithCoherenceSpecWithCacheConfig(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -200,7 +201,7 @@ func TestCreateJobWithCoherenceSpecWithOverrideConfig(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -218,7 +219,7 @@ func TestCreateJobWithCoherenceSpecWithLogLevel(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -275,7 +276,7 @@ func TestCreateJobWithCoherenceSpecWithTracingRatio(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -327,8 +328,8 @@ func TestCreateJobWithCoherenceSpecWithIpMonitorEnabled(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) - removeEnvVarsFromJob(jobExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + removeEnvVarsFromAllJobContainers(jobExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -349,7 +350,7 @@ func TestCreateJobWithCoherenceSpecWithWkaSameNamespace(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected @@ -373,7 +374,7 @@ func TestCreateJobWithCoherenceSpecWithWkaDifferentNamespace(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) expectedWka := deployment.GetWKA() - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected @@ -399,7 +400,7 @@ func TestCreateJobWithCoherenceSpecWithWkaAddress(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) expectedWka := "storage.foo.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected @@ -425,7 +426,7 @@ func TestCreateJobWithCoherenceSpecWithMultipleWkaAddresses(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) expectedWka := "storage.one.bar.local,storage.two.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected diff --git a/api/v1/create_job_coherenceutils_test.go b/api/v1/create_job_coherenceutils_test.go index 0de85ab1a..88e31a5c6 100644 --- a/api/v1/create_job_coherenceutils_test.go +++ b/api/v1/create_job_coherenceutils_test.go @@ -41,6 +41,7 @@ func TestCreateJobWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Set the expected Operator image pull policy jobExpected.Spec.Template.Spec.InitContainers[0].ImagePullPolicy = policy + jobExpected.Spec.Template.Spec.InitContainers[1].ImagePullPolicy = policy // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_job_jvmspec_test.go b/api/v1/create_job_jvmspec_test.go index d81af7122..474e821b1 100644 --- a/api/v1/create_job_jvmspec_test.go +++ b/api/v1/create_job_jvmspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -56,7 +56,7 @@ func TestCreateJobWithJvmSpecWithArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -91,7 +91,7 @@ func TestCreateJobWithJvmSpecWithClasspath(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -109,7 +109,7 @@ func TestCreateJobWithJvmSpecWithUseContainerLimitsTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -127,7 +127,7 @@ func TestCreateJobWithJvmSpecWithUseContainerLimitsFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -172,10 +172,10 @@ func TestCreateJobWithJvmSpecWithDebugEnabledTrueSuspendTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPortsForJob(jobExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -203,9 +203,9 @@ func TestCreateJobWithJvmSpecWithDebugEnabledTrueSuspendFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPortsForJob(jobExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -230,7 +230,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollector(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -251,7 +251,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollectorArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -271,7 +271,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollectorLoggingFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -291,7 +291,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollectorLoggingTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -341,11 +341,11 @@ func TestCreateJobWithJvmSpecWithMemorySettings(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -368,7 +368,7 @@ func TestCreateJobWithJvmSpecWithExitOnOomTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -391,7 +391,7 @@ func TestCreateJobWithJvmSpecWithExitOnOomFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -413,7 +413,7 @@ func TestCreateJobWithJvmSpecWithHeapDumpOnOomTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -435,7 +435,7 @@ func TestCreateJobWithJvmSpecWithHeapDumpOnOomFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index b4fcfdf72..7189216da 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -25,7 +25,7 @@ func TestCreateStatefulSetWithApplicationType(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -45,7 +45,7 @@ func TestCreateStatefulSetWithApplicationMain(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -64,7 +64,7 @@ func TestCreateStatefulSetWithApplicationMainArgs(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -100,7 +100,7 @@ func TestCreateStatefulSetWithWorkingDirectory(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_coherencespec_management_test.go b/api/v1/create_statefulset_coherencespec_management_test.go index ec15b2867..79bc170d6 100644 --- a/api/v1/create_statefulset_coherencespec_management_test.go +++ b/api/v1/create_statefulset_coherencespec_management_test.go @@ -80,8 +80,8 @@ func TestCreateStatefulSetWithCoherenceManagementEnabledTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -102,8 +102,8 @@ func TestCreateStatefulSetWithCoherenceManagementEnabledWithPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -138,7 +138,7 @@ func TestCreateStatefulSetWithCoherenceManagementWithSSLEnabledWithoutSecret(t * deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, @@ -191,7 +191,7 @@ func TestCreateStatefulSetWithCoherenceManagementWithSSLEnabledWithSecret(t *tes deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, diff --git a/api/v1/create_statefulset_coherencespec_metrics_test.go b/api/v1/create_statefulset_coherencespec_metrics_test.go index 38a698f46..858c0838c 100644 --- a/api/v1/create_statefulset_coherencespec_metrics_test.go +++ b/api/v1/create_statefulset_coherencespec_metrics_test.go @@ -80,8 +80,8 @@ func TestCreateStatefulSetWithCoherenceMetricsEnabledTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -102,8 +102,8 @@ func TestCreateStatefulSetWithCoherenceMetricsEnabledWithPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -138,7 +138,7 @@ func TestCreateStatefulSetWithCoherenceMetricsWithSSLEnabledWithoutSecret(t *tes deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, @@ -191,7 +191,7 @@ func TestCreateStatefulSetWithCoherenceMetricsWithSSLEnabledWithSecret(t *testin deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, diff --git a/api/v1/create_statefulset_coherencespec_persistence_test.go b/api/v1/create_statefulset_coherencespec_persistence_test.go index 77c8b011e..e34a47ad9 100644 --- a/api/v1/create_statefulset_coherencespec_persistence_test.go +++ b/api/v1/create_statefulset_coherencespec_persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,7 +44,7 @@ func TestCreateStatefulSetWithPersistenceModeOnDemand(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -64,7 +64,7 @@ func TestCreateStatefulSetWithPersistenceModeActive(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -83,7 +83,7 @@ func TestCreateStatefulSetWithPersistenceModeActiveAsync(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -210,8 +210,7 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolume(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -219,6 +218,12 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolume(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -262,8 +267,7 @@ func TestCreateStatefulSetWithPersistenceSnapshotPVC(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -271,6 +275,12 @@ func TestCreateStatefulSetWithPersistenceSnapshotPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -324,8 +334,7 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -333,6 +342,12 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -374,16 +389,19 @@ func TestCreateStatefulSetWithPersistenceAndSnapshotVolume(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -439,16 +457,19 @@ func TestCreateStatefulSetWithPersistenceAndSnapshotPVC(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -484,8 +505,7 @@ func createResources(spec coh.CoherenceResourceSpec) (*appsv1.StatefulSet, *coh. stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -493,6 +513,12 @@ func createResources(spec coh.CoherenceResourceSpec) (*appsv1.StatefulSet, *coh. MountPath: coh.VolumeMountPathPersistence, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNamePersistence, + MountPath: coh.VolumeMountPathPersistence, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNamePersistence, diff --git a/api/v1/create_statefulset_coherencespec_test.go b/api/v1/create_statefulset_coherencespec_test.go index 0c1e07573..46009ddbe 100644 --- a/api/v1/create_statefulset_coherencespec_test.go +++ b/api/v1/create_statefulset_coherencespec_test.go @@ -40,6 +40,7 @@ func TestCreateStatefulSetWithImage(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.InitContainers[1].Image = "coherence:1.0" stsExpected.Spec.Template.Spec.Containers[0].Image = "coherence:1.0" // assert that the StatefulSet is as expected @@ -74,7 +75,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithStorageEnabledTrue(t *testing.T) deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -92,7 +93,7 @@ func TestCreateStatefulSetWithCoherenceLocalPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -110,7 +111,7 @@ func TestCreateStatefulSetWithCoherenceLocalPortAdjustTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -128,7 +129,7 @@ func TestCreateStatefulSetWithCoherenceLocalPortAdjustFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -146,7 +147,7 @@ func TestCreateStatefulSetWithCoherenceLocalPortAdjust(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -164,7 +165,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithStorageEnabledFalse(t *testing.T) deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -182,7 +183,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithCacheConfig(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -200,7 +201,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithOverrideConfig(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -218,7 +219,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithLogLevel(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -275,7 +276,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithTracingRatio(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -327,8 +328,8 @@ func TestCreateStatefulSetWithCoherenceSpecWithIpMonitorEnabled(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) - removeEnvVars(stsExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + removeEnvVarsFromAll(stsExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -349,7 +350,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithWkaSameNamespace(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -373,7 +374,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithWkaDifferentNamespace(t *testing. // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) expectedWka := deployment.GetWKA() - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -399,7 +400,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithWkaAddress(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) expectedWka := "storage.foo.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -425,7 +426,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithMultipleWkaAddresses(t *testing.T stsExpected := createMinimalExpectedStatefulSet(deployment) expectedWka := "storage.one.bar.local,storage.two.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -442,7 +443,7 @@ func TestCreateStatefulSetWithResumeServicesOnStartupTrue(t *testing.T) { deployment := createTestCoherenceDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -458,7 +459,7 @@ func TestCreateStatefulSetWithResumeServicesOnStartupFalse(t *testing.T) { deployment := createTestCoherenceDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_coherenceutils_test.go b/api/v1/create_statefulset_coherenceutils_test.go index da4d241c6..9f942a6f5 100644 --- a/api/v1/create_statefulset_coherenceutils_test.go +++ b/api/v1/create_statefulset_coherenceutils_test.go @@ -41,6 +41,7 @@ func TestCreateStatefulSetWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Set the expected Operator image pull policy stsExpected.Spec.Template.Spec.InitContainers[0].ImagePullPolicy = policy + stsExpected.Spec.Template.Spec.InitContainers[1].ImagePullPolicy = policy // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_jvmspec_test.go b/api/v1/create_statefulset_jvmspec_test.go index 3fa19cd96..05628c1c0 100644 --- a/api/v1/create_statefulset_jvmspec_test.go +++ b/api/v1/create_statefulset_jvmspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -56,7 +56,7 @@ func TestCreateStatefulSetWithJvmSpecWithArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -91,7 +91,7 @@ func TestCreateStatefulSetWithJvmSpecWithClasspath(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -109,7 +109,7 @@ func TestCreateStatefulSetWithJvmSpecWithUseContainerLimitsTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -127,7 +127,7 @@ func TestCreateStatefulSetWithJvmSpecWithUseContainerLimitsFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -172,10 +172,10 @@ func TestCreateStatefulSetWithJvmSpecWithDebugEnabledTrueSuspendTrue(t *testing. deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPorts(stsExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -203,9 +203,9 @@ func TestCreateStatefulSetWithJvmSpecWithDebugEnabledTrueSuspendFalse(t *testing deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPorts(stsExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -230,7 +230,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollector(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -251,7 +251,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollectorArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -271,7 +271,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollectorLoggingFalse(t *testing deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -291,7 +291,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollectorLoggingTrue(t *testing. deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -341,11 +341,11 @@ func TestCreateStatefulSetWithJvmSpecWithMemorySettings(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -368,7 +368,7 @@ func TestCreateStatefulSetWithJvmSpecWithExitOnOomTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -391,7 +391,7 @@ func TestCreateStatefulSetWithJvmSpecWithExitOnOomFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -413,7 +413,7 @@ func TestCreateStatefulSetWithJvmSpecWithHeapDumpOnOomTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -435,7 +435,7 @@ func TestCreateStatefulSetWithJvmSpecWithHeapDumpOnOomFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_test.go b/api/v1/create_statefulset_test.go index d5740618c..0a171eeec 100644 --- a/api/v1/create_statefulset_test.go +++ b/api/v1/create_statefulset_test.go @@ -71,7 +71,7 @@ func TestCreateStatefulSetWithRackLabel(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) url := fmt.Sprintf("%s?nodeLabel=%s", coh.OperatorRackURL, "coherence.oracle.com/test") - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohRack, Value: url}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohRack, Value: url}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -87,7 +87,7 @@ func TestCreateStatefulSetWithSiteLabel(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) url := fmt.Sprintf("%s?nodeLabel=%s", coh.OperatorSiteURL, "coherence.oracle.com/test") - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSite, Value: url}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSite, Value: url}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -107,7 +107,7 @@ func TestCreateStatefulSetWithEnvVars(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, ev...) + addEnvVarsToAll(stsExpected, ev...) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -300,6 +300,7 @@ func TestCreateStatefulSetWithInitContainerResources(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.InitContainers[0].Resources = res + stsExpected.Spec.Template.Spec.InitContainers[1].Resources = res // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -441,6 +442,7 @@ func TestCreateStatefulSetWithContainerSecurityContext(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected security context to both the init-container and the Coherence container stsExpected.Spec.Template.Spec.InitContainers[0].SecurityContext = &ctx + stsExpected.Spec.Template.Spec.InitContainers[1].SecurityContext = &ctx stsExpected.Spec.Template.Spec.Containers[0].SecurityContext = &ctx // assert that the StatefulSet is as expected diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go new file mode 100644 index 000000000..23a7a0db6 --- /dev/null +++ b/pkg/runner/cmd_config.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v 1.0 as shown at + * http://oss.oracle.com/licenses/upl. + */ + +package runner + +import ( + "fmt" + v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "os" +) + +// configCommand creates the corba "config" sub-command +func configCommand(env map[string]string) *cobra.Command { + cmd := &cobra.Command{ + Use: v1.RunnerConfig, + Short: "Create the Operator JVM args files a Coherence server", + Long: "Create the Operator JVM args files a Coherence server", + RunE: func(cmd *cobra.Command, args []string) error { + return maybeRun(cmd, createArgsFile) + }, + } + + utilDir, found := env[v1.EnvVarCohUtilDir] + if !found || utilDir == "" { + utilDir = v1.VolumeMountPathUtils + } + + flagSet := cmd.Flags() + flagSet.String(ArgUtilsDir, utilDir, "The utils files root directory") + + return cmd +} + +// config will create the JVM args files for a Coherence Pod - typically this is run from an init-container +func createArgsFile(details *RunDetails, _ *cobra.Command) (bool, error) { + var err error + + populateServerDetails(details) + err = configureCommand(details) + if err != nil { + return false, errors.Wrap(err, "failed to configure server command") + } + + cpFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + classpath := details.getClasspath() + err = os.WriteFile(cpFile, []byte(classpath), os.ModePerm) + fmt.Printf("Created class path file %s\n", cpFile) + fmt.Println("--------------------") + fmt.Println(classpath) + fmt.Println("--------------------") + if err != nil { + return false, errors.Wrap(err, "failed to write coherence classpath file") + } + + args := details.Args + + argFileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + argFile, err := os.Create(argFileName) + if err != nil { + return false, errors.Wrap(err, "failed to create coherence jvm args file") + } + defer argFile.Close() + for _, arg := range args { + _, err = argFile.WriteString(arg + "\n") + if err != nil { + return false, errors.Wrap(err, "failed to write coherence jvm args file") + } + } + + err = os.Chmod(argFileName, os.ModePerm) + if err != nil { + return false, errors.Wrap(err, "failed to set file-mode on coherence jvm args file") + } + fmt.Printf("Created JVM args file %s\n", argFileName) + fmt.Println("--------------------") + for _, arg := range args { + fmt.Println(arg) + } + fmt.Println("--------------------") + + return false, err +} diff --git a/pkg/runner/cmd_server.go b/pkg/runner/cmd_server.go index b4fb196f8..de0fa7b1f 100644 --- a/pkg/runner/cmd_server.go +++ b/pkg/runner/cmd_server.go @@ -38,6 +38,32 @@ func serverCommand() *cobra.Command { // Configure the runner to run a Coherence Server func server(details *RunDetails, _ *cobra.Command) { + var err error + + if details.ClassPathFile != "" { + fmt.Printf("**** INFO found class path file %s\n", details.ClassPathFile) + data, err := os.ReadFile(details.ClassPathFile) + if err != nil { + fmt.Printf("**** ERROR error reading %s %v\n", details.ClassPathFile, err) + } else { + fmt.Printf("**** INFO contents of %s\n------\n%s\n------\n", details.ClassPathFile, string(data)) + } + } else { + fmt.Println("**** ERROR class path file does not exist") + } + + if details.JvmArgsFile != "" { + fmt.Printf("**** INFO found %s\n", details.JvmArgsFile) + data, err := os.ReadFile(details.JvmArgsFile) + if err != nil { + fmt.Printf("**** ERROR error reading %s %v\n", details.JvmArgsFile, err) + } else { + fmt.Printf("**** INFO contents of %s\n------\n%s\n------\n", details.JvmArgsFile, string(data)) + } + } else { + fmt.Println("**** ERROR JVM args does not exist") + } + details.Command = CommandServer details.MainClass = ServerMain @@ -99,6 +125,11 @@ func server(details *RunDetails, _ *cobra.Command) { } } + populateServerDetails(details) +} + +// Configure the runner to run a Coherence Server +func populateServerDetails(details *RunDetails) { // Configure the Coherence member's role details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") // Configure whether this member is storage enabled @@ -126,6 +157,7 @@ func server(details *RunDetails, _ *cobra.Command) { if details.CoherenceHome != "" { // If management is enabled and the COHERENCE_HOME environment variable is set // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath + // This is for legacy 14.1.1.0 and 12.2.1.4 images details.addClasspath(details.CoherenceHome + "/lib/coherence-management.jar") } } @@ -139,6 +171,7 @@ func server(details *RunDetails, _ *cobra.Command) { if details.CoherenceHome != "" { // If metrics is enabled and the COHERENCE_HOME environment variable is set // then $COHERENCE_HOME/lib/coherence-metrics.jar will be added to the classpath + // This is for legacy 14.1.1.0 and 12.2.1.4 images details.addClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") } } diff --git a/pkg/runner/run_details.go b/pkg/runner/run_details.go index e46fc06bb..c5bfd2051 100644 --- a/pkg/runner/run_details.go +++ b/pkg/runner/run_details.go @@ -17,6 +17,8 @@ import ( ) func NewRunDetails(v *viper.Viper) *RunDetails { + var err error + skipSiteVar := v.GetString(v1.EnvVarCohSkipSite) skipSite := strings.ToLower(skipSiteVar) != "true" @@ -35,6 +37,16 @@ func NewRunDetails(v *viper.Viper) *RunDetails { details.addClasspath(v.GetString(v1.EnvVarJvmExtraClasspath)) details.addClasspath(v.GetString(v1.EnvVarJavaClasspath)) + cpFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + if _, err = os.Stat(cpFile); err == nil { + details.ClassPathFile = cpFile + } + + argFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + if _, err = os.Stat(argFile); err == nil { + details.JvmArgsFile = argFile + } + return details } @@ -54,6 +66,8 @@ type RunDetails struct { MainArgs []string BuildPacks *bool ExtraEnv []string + ClassPathFile string + JvmArgsFile string env *viper.Viper } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index e0c98c9c2..2d8ffc2ad 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -26,6 +26,7 @@ import ( "os/exec" "path/filepath" ctrl "sigs.k8s.io/controller-runtime" + "sort" "strconv" "strings" "time" @@ -129,6 +130,7 @@ func NewRootCommand(env map[string]string, v *viper.Viper) *cobra.Command { rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") rootCmd.AddCommand(initCommand(env)) + rootCmd.AddCommand(configCommand(env)) rootCmd.AddCommand(serverCommand()) rootCmd.AddCommand(consoleCommand(v)) rootCmd.AddCommand(queryPlusCommand(v)) @@ -311,8 +313,8 @@ func fromContext(ctx context.Context) *Execution { return &Execution{} } -// create the process to execute. -func createCommand(details *RunDetails) (string, *exec.Cmd, error) { +// configure the command details. +func configureCommand(details *RunDetails) error { var err error // Set standard system properties @@ -350,8 +352,8 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { } // Add the Operator Utils jar to the classpath - details.addClasspath(details.UtilsDir + "/lib/coherence-operator.jar") - details.addClasspathIfExists(details.UtilsDir + "/config") + details.addClasspath(details.UtilsDir + v1.OperatorJarFileSuffix) + details.addClasspathIfExists(details.UtilsDir + v1.OperatorConfigDirSuffix) // Configure Coherence persistence mode := details.getenvOrDefault(v1.EnvVarCohPersistenceMode, "on-demand") @@ -427,13 +429,13 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { jvmDir := v1.VolumeMountPathJVM + "/" + member + "/" + podUID if _, err = os.Stat(v1.VolumeMountPathJVM); err == nil { if err = os.MkdirAll(jvmDir, os.ModePerm); err != nil { - return "", nil, err + return err } if err = os.MkdirAll(jvmDir+"/jfr", os.ModePerm); err != nil { - return "", nil, err + return err } if err = os.MkdirAll(jvmDir+"/heap-dumps", os.ModePerm); err != nil { - return "", nil, err + return err } } @@ -601,6 +603,12 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { details.addArgs(strings.Split(gcArgs, " ")...) } + // sort the args added up to this point, + // anything following are customer added args and must come last + sort.SliceStable(details.Args, func(i, j int) bool { + return details.Args[i] < details.Args[j] + }) + jvmArgs := details.Getenv(v1.EnvVarJvmArgs) if jvmArgs != "" { details.addArgs(strings.Split(jvmArgs, " ")...) @@ -611,8 +619,20 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { details.addArgs(extraJvmArgs...) } + return nil +} + +// create the process to execute. +func createCommand(details *RunDetails) (string, *exec.Cmd, error) { + var err error var cmd *exec.Cmd var app string + + err = configureCommand(details) + if err != nil { + return "", nil, err + } + switch { case details.AppType == AppTypeNone || details.AppType == AppTypeJava: app = "Java" From 65a9063617cd3bbf6c0ce4e7125cf76409e34475 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 11 Mar 2025 19:36:01 +0300 Subject: [PATCH 08/33] Add init container to create class path and JVM args files --- .../coherence/k8s/CoherenceVersion.java | 6 ++--- pkg/runner/run_details.go | 2 -- pkg/runner/runner.go | 26 +++++++------------ 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java index 8a3ad34d6..71be0f414 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -29,10 +29,10 @@ private CoherenceVersion() { public static void main(String[] args) { int exitCode = 0; - String version = System.getenv().getOrDefault("COH_VERSION_CHECK", CacheFactory.VERSION); + String version = System.getenv().getOrDefault("COHERENCE_OPERATOR_VERSION_CHECK", CacheFactory.VERSION); if (args != null && args.length > 0) { - exitCode = versionCheck(version, args) ? 0 : 1; + exitCode = versionCheck(version, args) ? 0 : 99; } else { System.out.println(version); diff --git a/pkg/runner/run_details.go b/pkg/runner/run_details.go index c5bfd2051..448243bfe 100644 --- a/pkg/runner/run_details.go +++ b/pkg/runner/run_details.go @@ -12,7 +12,6 @@ import ( "github.com/spf13/viper" "os" "path/filepath" - "sort" "strings" ) @@ -326,7 +325,6 @@ func (in *RunDetails) addJarsToClasspath(dir string) { return nil }) - sort.Strings(jars) for _, jar := range jars { in.addClasspath(jar) } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 2d8ffc2ad..0eeda12a1 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -26,7 +26,6 @@ import ( "os/exec" "path/filepath" ctrl "sigs.k8s.io/controller-runtime" - "sort" "strconv" "strings" "time" @@ -318,6 +317,7 @@ func configureCommand(details *RunDetails) error { var err error // Set standard system properties + details.addArg("-Dcoherence.ttl=0") details.addArgFromEnvVar(v1.EnvVarCohWka, "-Dcoherence.wka") details.addArgFromEnvVar(v1.EnvVarCohMachineName, "-Dcoherence.machine") details.addArgFromEnvVar(v1.EnvVarCohMemberName, "-Dcoherence.member") @@ -579,8 +579,6 @@ func configureCommand(details *RunDetails) error { } } - details.addArg("-Dcoherence.ttl=0") - details.addArg(fmt.Sprintf("-XX:ErrorFile=%s/hs-err-%s-%s.log", jvmDir, member, podUID)) if details.isEnvTrueOrBlank(v1.EnvVarJvmOomHeapDump) { @@ -603,12 +601,6 @@ func configureCommand(details *RunDetails) error { details.addArgs(strings.Split(gcArgs, " ")...) } - // sort the args added up to this point, - // anything following are customer added args and must come last - sort.SliceStable(details.Args, func(i, j int) bool { - return details.Args[i] < details.Args[j] - }) - jvmArgs := details.Getenv(v1.EnvVarJvmArgs) if jvmArgs != "" { details.addArgs(strings.Split(jvmArgs, " ")...) @@ -1055,14 +1047,16 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { log.Info("Executed Coherence version check, version is greater than or equal to expected", "version", v) return true } - if _, ok := err.(*exec.ExitError); ok { - // The program has exited with an exit code != 0 - log.Info("Executed Coherence version check, version is lower than expected", "version", v) - return false + if exitError, ok := err.(*exec.ExitError); ok { + // The program has exited with an exit code == 99 which means the version is lower than requested + if exitError.ExitCode() == 99 { + log.Info("Executed Coherence version check, version is lower than expected", "version", v) + return false + } } - // command exited with some other error - log.Error(err, "Coherence version check failed") - return false + // command exited with some other error, assume the version is good + log.Error(err, "Coherence version check failed, assuming version is valid", "version", v) + return true } func cohPre12214(details *RunDetails) { From 1044114d51c828179ababd9db999194591df0b27 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 11 Mar 2025 20:49:02 +0300 Subject: [PATCH 09/33] fix runner unit tests --- pkg/runner/runner_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 7d0c7c247..83d89f892 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -61,9 +61,7 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { expectedCommand := GetJavaCommand() expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.override="), - "-Dcoherence.override=k8s-coherence-override.xml", - "-Dcoherence.operator.health.enabled=false", - "-Dcoherence.health.http.port=6676") + "-Dcoherence.override=k8s-coherence-override.xml") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -159,10 +157,12 @@ func AppendCommonExpectedNonServerArgs(args []string, role string) []string { "-Dcoherence.wka=test-wka..svc", "-Dcoherence.cluster=test", "-Dcoherence.operator.health.port=6676", + "-Dcoherence.health.http.port=6676", + "-Dcoherence.operator.health.enabled=false", "-Dcoherence.management.http.port=30000", "-Dcoherence.metrics.http.port=9612", "-Dcoherence.distributed.persistence-mode=on-demand", - "-Dcoherence.override=k8s-coherence-nossl-override.xml", + "-Dcoherence.override=k8s-coherence-override.xml", "-Dcoherence.ipmonitor.pingtimeout=0", "-Dcoherence.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown", "-XX:HeapDumpPath=/coherence-operator/jvm/unknown/unknown/heap-dumps/unknown-unknown.hprof", From e1386b7eb2c05021caf6e8ae1d2165910967efbb Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 11 Mar 2025 22:41:35 +0300 Subject: [PATCH 10/33] Create CLI config in init container --- api/v1/coherenceresourcespec_types.go | 1 + api/v1/common_test.go | 4 + api/v1/constants.go | 3 + pkg/runner/cmd_config.go | 108 ++++++++++++++++++++------ 4 files changed, 91 insertions(+), 25 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index ea58080c8..8eb6029ec 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -968,6 +968,7 @@ func (in *CoherenceResourceSpec) CreateDefaultEnv(deployment CoherenceResource) corev1.EnvVar{Name: EnvVarOperatorTimeout, Value: Int32PtrToStringWithDefault(in.OperatorRequestTimeout, 120)}, corev1.EnvVar{Name: EnvVarCohHealthPort, Value: Int32ToString(in.GetHealthPort())}, corev1.EnvVar{Name: EnvVarCoherenceTTL, Value: "0"}, + corev1.EnvVar{Name: EnvVarCohCtlHome, Value: VolumeMountPathUtils}, ) ann := deployment.GetAnnotations() diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 08cf6f83a..1d4847639 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -361,6 +361,10 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Name: "COHERENCE_TTL", Value: "0", }, + { + Name: "COHCTL_HOME", + Value: coh.VolumeMountPathUtils, + }, { Name: "COHERENCE_IPMONITOR_PINGTIMEOUT", Value: "0", diff --git a/api/v1/constants.go b/api/v1/constants.go index bf246e84b..57467aa81 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -215,6 +215,7 @@ const ( EnvVarCnbpEnabled = "COHERENCE_OPERATOR_CNBP_ENABLED" EnvVarCnbpLauncher = "COHERENCE_OPERATOR_CNBP_LAUNCHER" EnvVarCohForceExit = "COHERENCE_OPERATOR_FORCE_EXIT" + EnvVarCohCliProtocol = "COHERENCE_OPERATOR_CLI_PROTOCOL" EnvVarCoherenceHome = "COHERENCE_HOME" EnvVarCohClusterName = "COHERENCE_CLUSTER" @@ -241,6 +242,8 @@ const ( EnvVarEnableIPMonitor = "COHERENCE_ENABLE_IPMONITOR" EnvVarIPMonitorPingTimeout = "COHERENCE_IPMONITOR_PINGTIMEOUT" + EnvVarCohCtlHome = "COHCTL_HOME" + EnvVarCohEnabledSuffix = "_ENABLED" EnvVarCohPortSuffix = "_PORT" EnvVarSuffixSSLEnabled = "_SSL_ENABLED" diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 23a7a0db6..a4f246908 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -7,6 +7,7 @@ package runner import ( + "bytes" "fmt" v1 "github.com/oracle/coherence-operator/api/v1" "github.com/pkg/errors" @@ -21,7 +22,7 @@ func configCommand(env map[string]string) *cobra.Command { Short: "Create the Operator JVM args files a Coherence server", Long: "Create the Operator JVM args files a Coherence server", RunE: func(cmd *cobra.Command, args []string) error { - return maybeRun(cmd, createArgsFile) + return maybeRun(cmd, createsFiles) }, } @@ -36,14 +37,26 @@ func configCommand(env map[string]string) *cobra.Command { return cmd } -// config will create the JVM args files for a Coherence Pod - typically this is run from an init-container -func createArgsFile(details *RunDetails, _ *cobra.Command) (bool, error) { - var err error - +// createsFiles will create the various config files +func createsFiles(details *RunDetails, _ *cobra.Command) (bool, error) { populateServerDetails(details) - err = configureCommand(details) + if err := createClassPathFile(details); err != nil { + return false, err + } + if err := createArgsFile(details); err != nil { + return false, err + } + if err := createCliConfig(details); err != nil { + return false, err + } + return false, nil +} + +// createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container +func createClassPathFile(details *RunDetails) error { + err := configureCommand(details) if err != nil { - return false, errors.Wrap(err, "failed to configure server command") + return errors.Wrap(err, "failed to configure server command") } cpFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) @@ -54,34 +67,79 @@ func createArgsFile(details *RunDetails, _ *cobra.Command) (bool, error) { fmt.Println(classpath) fmt.Println("--------------------") if err != nil { - return false, errors.Wrap(err, "failed to write coherence classpath file") + return errors.Wrap(err, "failed to write coherence classpath file") } + return nil +} - args := details.Args +// createArgsFile will create the JVM args files for a Coherence Pod - typically this is run from an init-container +func createArgsFile(details *RunDetails) error { + var err error + args := details.Args argFileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) - argFile, err := os.Create(argFileName) - if err != nil { - return false, errors.Wrap(err, "failed to create coherence jvm args file") - } - defer argFile.Close() + + var buffer bytes.Buffer for _, arg := range args { - _, err = argFile.WriteString(arg + "\n") - if err != nil { - return false, errors.Wrap(err, "failed to write coherence jvm args file") - } + buffer.WriteString(arg + "\n") } - - err = os.Chmod(argFileName, os.ModePerm) - if err != nil { - return false, errors.Wrap(err, "failed to set file-mode on coherence jvm args file") + if err := os.WriteFile(argFileName, buffer.Bytes(), os.ModePerm); err != nil { + return errors.Wrap(err, "failed to write JVM args file "+argFileName) } + fmt.Printf("Created JVM args file %s\n", argFileName) fmt.Println("--------------------") - for _, arg := range args { - fmt.Println(arg) + fmt.Println(buffer.String()) + fmt.Println("--------------------") + + return err +} + +func createCliConfig(details *RunDetails) error { + fileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, "cohctl.yaml") + + cluster := details.Getenv(v1.EnvVarCohClusterName) + port := details.Getenv(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohPortSuffix) + if port == "" { + port = string(v1.DefaultManagementPort) } + protocol := details.Getenv(v1.EnvVarCohCliProtocol) + if protocol == "" { + protocol = "http" + } + + var buffer bytes.Buffer + buffer.WriteString("clusters:\n") + buffer.WriteString(" - name: default\n") + buffer.WriteString(" discoverytype: manual\n") + buffer.WriteString(" connectiontype: " + protocol) + buffer.WriteString(" connectionurl: " + protocol + "://127.0.0.1:" + port + "/management/coherence/cluster\n") + buffer.WriteString(" nameservicediscovery: \"\"\n") + buffer.WriteString(" clusterversion: \"\"\n") + buffer.WriteString(" clustername: \"" + cluster + "\"\n") + buffer.WriteString(" clustertype: Standalone\n") + buffer.WriteString(" manuallycreated: true\n") + buffer.WriteString(" baseclasspath: \"\"\n") + buffer.WriteString(" additionalclasspath: \"\"\n") + buffer.WriteString(" arguments: \"\"\n") + buffer.WriteString(" managementport: " + port + "\n") + buffer.WriteString(" persistencemode: \"\"\n") + buffer.WriteString(" loggingdestination: \"\"\n") + buffer.WriteString(" managementavailable: false\n") + buffer.WriteString("color: \"on\"\n") + buffer.WriteString("currentcontext: default\n") + buffer.WriteString("debug: false\n") + buffer.WriteString("defaultbytesformat: m\n") + buffer.WriteString("ignoreinvalidcerts: false\n") + buffer.WriteString("requesttimeout: 30\n") + if err := os.WriteFile(fileName, buffer.Bytes(), os.ModePerm); err != nil { + return errors.Wrap(err, "failed to write coherence CLI config file "+fileName) + } + + fmt.Printf("Created CLI config file %s\n", fileName) + fmt.Println("--------------------") + fmt.Println(buffer.String()) fmt.Println("--------------------") - return false, err + return nil } From 948e172c53c479ba7fb1c23fc21ba223b54eca74 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Wed, 12 Mar 2025 07:18:58 +0300 Subject: [PATCH 11/33] Create CLI config in init container --- .../CoherenceOperatorLifecycleListener.java | 139 ------------------ pkg/runner/cmd_config.go | 7 +- pkg/runner/cmd_server.go | 13 ++ 3 files changed, 17 insertions(+), 142 deletions(-) diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java index 2cee9f1e1..6543e1283 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java @@ -6,8 +6,6 @@ package com.oracle.coherence.k8s; -import java.io.File; -import java.io.PrintWriter; import java.util.Base64; import java.util.Collections; import java.util.HashMap; @@ -17,11 +15,7 @@ import com.tangosol.application.Context; import com.tangosol.application.LifecycleListener; import com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache; -import com.tangosol.coherence.config.Config; -import com.tangosol.net.CacheFactory; -import com.tangosol.net.Cluster; import com.tangosol.net.DistributedCacheService; -import com.tangosol.net.Member; import com.tangosol.net.PartitionedService; import com.tangosol.net.events.Event; import com.tangosol.net.events.EventDispatcher; @@ -163,7 +157,6 @@ public void preStart(Context context) { @Override public void postStart(Context context) { - initCohCtl(); } @Override @@ -271,136 +264,4 @@ static Map getResumeMap(String services) { return null; } } - - void initCohCtl() { - try { - Cluster cluster = CacheFactory.getCluster(); - Member member = cluster.getLocalMember(); - String clusterName = member.getClusterName(); - String port = Config.getProperty("coherence.management.http.port", "30000"); - String provider = Config.getProperty("coherence.management.http.provider"); - String defaultProtocol = provider == null || provider.isEmpty() ? "http" : "https"; - String protocol = Config.getProperty("coherence.operator.cli.protocol", defaultProtocol); - String connectionType = "http"; - - - // If COHCTL_HOME is set use that for the config location - String cohCtlHome = System.getenv("COHCTL_HOME"); - if (cohCtlHome == null || !cohCtlHome.isEmpty()) { - // Try corresponding system property - cohCtlHome = Config.getProperty("cohctl.home"); - } - - // If we have a COHCTL_HOME env var or property try to create the config there - if (cohCtlHome != null && !cohCtlHome.isEmpty() - && tryCreateConfig(new File(cohCtlHome), connectionType, protocol, port, clusterName)) { - return; - } - - // Either COHCTL_HOME was not set or we failed to create a config there, try ${user.home} - String userHome = System.getProperty("user.home"); - File fileUserHome = new File(userHome); - File fileCohCtlHome = null; - - if (fileUserHome.exists() && fileUserHome.isDirectory()) { - // use ${user.home}/.cohctl - fileCohCtlHome = new File(fileUserHome, ".cohctl"); - if (!fileCohCtlHome.exists()) { - try { - if (!fileCohCtlHome.mkdirs()) { - fileCohCtlHome = null; - } - } - catch (Exception e) { - LOGGER.error("CoherenceOperator: Failed to create cohctl home directory at " + fileCohCtlHome, e); - fileCohCtlHome = null; - } - } - } - - boolean success = false; - if (fileCohCtlHome != null) { - if (fileCohCtlHome.exists() && fileCohCtlHome.isDirectory()) { - success = tryCreateConfig(fileCohCtlHome, connectionType, protocol, port, clusterName); - } - else { - if (!fileCohCtlHome.exists()) { - LOGGER.error("CoherenceOperator: Cannot create cohctl config, directory " - + fileCohCtlHome + " does not exist"); - } - else { - LOGGER.error("CoherenceOperator: Cannot create cohctl config, location " - + fileCohCtlHome + " is not a directory"); - } - } - } - - if (!success) { - if (fileCohCtlHome != null) { - LOGGER.info("CoherenceOperator: unable to create cohctl config in \"" + fileCohCtlHome - + "\" creating cohctl config at /coherence-operator/utils"); - } - tryCreateConfig(new File("/coherence-operator/utils"), connectionType, protocol, port, clusterName); - } - } - catch (Exception e) { - LOGGER.error("Coherence Operator: Failed to create default cohctl config. " + e.getMessage()); - } - } - - /** - * Try to create the Coherence CLI configuration. - * - * @param home the location of the CLI home directory - * @param connectionType the type of the connection http or https - * @param protocol the protocol for the connection http or https - * @param port the management over REST port - * @param clusterName the cluster name - * - * @return {@code true} of the configuration was created - */ - protected boolean tryCreateConfig(File home, String connectionType, String protocol, String port, String clusterName) { - File configFile = new File(home, "cohctl.yaml"); - - if (configFile.exists()) { - return true; - } - - try { - LOGGER.info("CoherenceOperator: creating default cohctl config at " + configFile.getAbsolutePath()); - if (!home.exists()) { - home.mkdirs(); - } - try (PrintWriter out = new PrintWriter(configFile)) { - out.println("clusters:"); - out.println(" - name: default"); - out.println(" discoverytype: manual"); - out.println(" connectiontype: " + connectionType); - out.println(" connectionurl: " + protocol + "://127.0.0.1:" + port + "/management/coherence/cluster"); - out.println(" nameservicediscovery: \"\""); - out.println(" clusterversion: \"" + CacheFactory.VERSION + "\""); - out.println(" clustername: \"" + clusterName + "\""); - out.println(" clustertype: Standalone"); - out.println(" manuallycreated: false"); - out.println(" baseclasspath: \"\""); - out.println(" additionalclasspath: \"\""); - out.println(" arguments: \"\""); - out.println(" managementport: 0"); - out.println(" persistencemode: \"\""); - out.println(" loggingdestination: \"\""); - out.println(" managementavailable: false"); - out.println("color: \"on\""); - out.println("currentcontext: default"); - out.println("debug: false"); - out.println("defaultbytesformat: m"); - out.println("ignoreinvalidcerts: false"); - out.println("requesttimeout: 30"); - } - return true; - } - catch (Exception e) { - LOGGER.error("Coherence Operator: Failed to create default cohctl config. " + e.getMessage()); - return false; - } - } } diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index a4f246908..2679ff0ab 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -96,12 +96,13 @@ func createArgsFile(details *RunDetails) error { } func createCliConfig(details *RunDetails) error { - fileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, "cohctl.yaml") + home := details.getenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) + fileName := fmt.Sprintf("%s%c%s", home, os.PathSeparator, "cohctl.yaml") cluster := details.Getenv(v1.EnvVarCohClusterName) port := details.Getenv(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohPortSuffix) if port == "" { - port = string(v1.DefaultManagementPort) + port = fmt.Sprintf("%d", v1.DefaultManagementPort) } protocol := details.Getenv(v1.EnvVarCohCliProtocol) if protocol == "" { @@ -112,7 +113,7 @@ func createCliConfig(details *RunDetails) error { buffer.WriteString("clusters:\n") buffer.WriteString(" - name: default\n") buffer.WriteString(" discoverytype: manual\n") - buffer.WriteString(" connectiontype: " + protocol) + buffer.WriteString(" connectiontype: " + protocol + "\n") buffer.WriteString(" connectionurl: " + protocol + "://127.0.0.1:" + port + "/management/coherence/cluster\n") buffer.WriteString(" nameservicediscovery: \"\"\n") buffer.WriteString(" clusterversion: \"\"\n") diff --git a/pkg/runner/cmd_server.go b/pkg/runner/cmd_server.go index de0fa7b1f..032d63414 100644 --- a/pkg/runner/cmd_server.go +++ b/pkg/runner/cmd_server.go @@ -64,6 +64,19 @@ func server(details *RunDetails, _ *cobra.Command) { fmt.Println("**** ERROR JVM args does not exist") } + home := details.getenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) + cliCfg := fmt.Sprintf("%s%c%s", home, os.PathSeparator, "cohctl.yaml") + if _, err = os.Stat(cliCfg); err != nil { + fmt.Printf("**** ERROR error CLI config does not exist %s %v\n", cliCfg, err) + } else { + data, err := os.ReadFile(cliCfg) + if err != nil { + fmt.Printf("**** ERROR error reading CLI config %s %v\n", cliCfg, err) + } else { + fmt.Printf("**** INFO contents of CLI config %s\n------\n%s\n------\n", cliCfg, string(data)) + } + } + details.Command = CommandServer details.MainClass = ServerMain From f7fd621ce2e3d825f5d66a378bf19a4420e34cd1 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Wed, 12 Mar 2025 09:31:28 +0300 Subject: [PATCH 12/33] Create CLI config in init container --- api/v1/coherenceresourcespec_types.go | 16 +++++++++------- api/v1/common_test.go | 10 +++++----- api/v1/constants.go | 4 ++-- .../create_job_coherencespec_persistence_test.go | 2 +- pkg/runner/cmd_config.go | 3 ++- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 8eb6029ec..e2ff81ca7 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -685,11 +685,13 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou cohContainer.Ports = append(cohContainer.Ports, p.CreatePort(deployment)) } + initContainer := in.CreateOperatorInitContainer(deployment) + configInitContainer := in.CreateOperatorConfigInitContainer(deployment) + // append any additional VolumeMounts cohContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) - - initContainer := in.CreateOperatorInitContainer(deployment) - jvmArgsInitContainer := in.CreateOperatorJvmArgsInitContainer(deployment) + initContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) + configInitContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) podTemplate := corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ @@ -721,7 +723,7 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou } // The order of this append is very important, the jvmArgs must come second - podTemplate.Spec.InitContainers = append(podTemplate.Spec.InitContainers, initContainer, jvmArgsInitContainer) + podTemplate.Spec.InitContainers = append(podTemplate.Spec.InitContainers, initContainer, configInitContainer) podTemplate.Spec.Containers = append(podTemplate.Spec.Containers, cohContainer) // Add any network settings @@ -1043,8 +1045,8 @@ func (in *CoherenceResourceSpec) CreateOperatorInitContainer(deployment Coherenc return in.createInitContainer(deployment, ContainerNameOperatorInit, image, []string{RunnerInitCommand, RunnerInit}) } -// CreateOperatorJvmArgsInitContainer creates the JVM args file init-container spec. -func (in *CoherenceResourceSpec) CreateOperatorJvmArgsInitContainer(deployment CoherenceResource) corev1.Container { +// CreateOperatorConfigInitContainer creates the JVM args file init-container spec. +func (in *CoherenceResourceSpec) CreateOperatorConfigInitContainer(deployment CoherenceResource) corev1.Container { var image string if in.Image == nil { @@ -1052,7 +1054,7 @@ func (in *CoherenceResourceSpec) CreateOperatorJvmArgsInitContainer(deployment C } else { image = *in.Image } - return in.createInitContainer(deployment, ContainerNameOperatorArgs, image, []string{RunnerCommand, RunnerConfig}) + return in.createInitContainer(deployment, ContainerNameOperatorConfig, image, []string{RunnerCommand, RunnerConfig}) } // CreateOperatorInitContainer creates the Operator init-container spec. diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 1d4847639..e8f169b6c 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -448,7 +448,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe // The Operator JVM Args Init-Container argsContainer := corev1.Container{ - Name: coh.ContainerNameOperatorArgs, + Name: coh.ContainerNameOperatorConfig, Image: testCoherenceImage, Command: []string{coh.RunnerCommand, coh.RunnerConfig}, VolumeMounts: []corev1.VolumeMount{ @@ -594,7 +594,7 @@ func sortPortsForPodTemplate(template *corev1.PodTemplateSpec) { func addEnvVarsToAll(sts *appsv1.StatefulSet, envVars ...corev1.EnvVar) { addEnvVars(sts, coh.ContainerNameCoherence, envVars...) addEnvVars(sts, coh.ContainerNameOperatorInit, envVars...) - addEnvVars(sts, coh.ContainerNameOperatorArgs, envVars...) + addEnvVars(sts, coh.ContainerNameOperatorConfig, envVars...) } func addEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...corev1.EnvVar) { @@ -606,7 +606,7 @@ func addEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...corev1 func addEnvVarsToAllJobContainers(job *batchv1.Job, envVars ...corev1.EnvVar) { addEnvVarsToJob(job, coh.ContainerNameCoherence, envVars...) addEnvVarsToJob(job, coh.ContainerNameOperatorInit, envVars...) - addEnvVarsToJob(job, coh.ContainerNameOperatorArgs, envVars...) + addEnvVarsToJob(job, coh.ContainerNameOperatorConfig, envVars...) } func addEnvVarsToJob(job *batchv1.Job, containerName string, envVars ...corev1.EnvVar) { @@ -651,7 +651,7 @@ func addEnvVarsToContainer(c *corev1.Container, envVars ...corev1.EnvVar) { func removeEnvVarsFromAll(sts *appsv1.StatefulSet, envVars ...string) { removeEnvVars(sts, coh.ContainerNameCoherence, envVars...) removeEnvVars(sts, coh.ContainerNameOperatorInit, envVars...) - removeEnvVars(sts, coh.ContainerNameOperatorArgs, envVars...) + removeEnvVars(sts, coh.ContainerNameOperatorConfig, envVars...) } func removeEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...string) { @@ -663,7 +663,7 @@ func removeEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...str func removeEnvVarsFromAllJobContainers(job *batchv1.Job, envVars ...string) { removeEnvVarsFromJob(job, coh.ContainerNameCoherence, envVars...) removeEnvVarsFromJob(job, coh.ContainerNameOperatorInit, envVars...) - removeEnvVarsFromJob(job, coh.ContainerNameOperatorArgs, envVars...) + removeEnvVarsFromJob(job, coh.ContainerNameOperatorConfig, envVars...) } func removeEnvVarsFromJob(job *batchv1.Job, containerName string, envVars ...string) { diff --git a/api/v1/constants.go b/api/v1/constants.go index 57467aa81..e7d9d4ea8 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -78,8 +78,8 @@ const ( ContainerNameCoherence = "coherence" // ContainerNameOperatorInit is the Operator init-container name ContainerNameOperatorInit = "coherence-k8s-utils" - // ContainerNameOperatorArgs is the Operator JVM args init-container name - ContainerNameOperatorArgs = "coherence-k8s-jvm-args" + // ContainerNameOperatorConfig is the Operator config files init-container name + ContainerNameOperatorConfig = "coherence-k8s-config" // VolumeNamePersistence is the name of the persistence volume VolumeNamePersistence = "persistence-volume" diff --git a/api/v1/create_job_coherencespec_persistence_test.go b/api/v1/create_job_coherencespec_persistence_test.go index ea70e49a9..1c7118e99 100644 --- a/api/v1/create_job_coherencespec_persistence_test.go +++ b/api/v1/create_job_coherencespec_persistence_test.go @@ -466,7 +466,7 @@ func createResourcesForJob(spec coh.CoherenceResourceSpec) (*batchv1.Job, *coh.C // Add the expected environment variables addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorArgs, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorConfig, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 2679ff0ab..535dccc30 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -134,7 +134,8 @@ func createCliConfig(details *RunDetails) error { buffer.WriteString("ignoreinvalidcerts: false\n") buffer.WriteString("requesttimeout: 30\n") if err := os.WriteFile(fileName, buffer.Bytes(), os.ModePerm); err != nil { - return errors.Wrap(err, "failed to write coherence CLI config file "+fileName) + fmt.Printf("Failed to write coherence CLI config file at %s cause: %v", fileName, err) + return nil } fmt.Printf("Created CLI config file %s\n", fileName) From 669f3c1b2f4d1e226491effebd0c8a9455f63394 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Thu, 13 Mar 2025 23:04:43 +0300 Subject: [PATCH 13/33] Create JVM argument files --- api/v1/coherence_types.go | 6 +- api/v1/coherenceresourcespec_types.go | 63 ++++- api/v1/common_test.go | 12 +- api/v1/constants.go | 29 ++ api/v1/create_job_add_containers_test.go | 4 +- api/v1/create_job_applicationspec_test.go | 2 + api/v1/create_job_volumemounts_test.go | 6 +- .../create_statefulset_add_containers_test.go | 4 +- ...create_statefulset_applicationspec_test.go | 2 + .../create_statefulset_volumemounts_test.go | 6 +- docs/about/04_coherence_spec.adoc | 2 +- pkg/runner/cmd_config.go | 229 +++++++++++++-- pkg/runner/cmd_console.go | 17 +- pkg/runner/cmd_jshell.go | 9 +- pkg/runner/cmd_operator_test.go | 12 +- pkg/runner/cmd_query_plus.go | 17 +- pkg/runner/cmd_server.go | 228 +++++---------- pkg/runner/run_details.go | 50 +--- pkg/runner/runner.go | 43 ++- pkg/runner/runner_application_test.go | 47 ++-- pkg/runner/runner_application_type_test.go | 62 +++-- pkg/runner/runner_coherence_test.go | 261 ++++++++++-------- pkg/runner/runner_initialise_test.go | 6 +- pkg/runner/runner_jvm_jibclasspath_test.go | 73 ++--- pkg/runner/runner_jvm_memory_test.go | 191 ++++++------- pkg/runner/runner_jvm_test.go | 142 +++++----- pkg/runner/runner_persistence_test.go | 67 +++-- pkg/runner/runner_spring_test.go | 225 ++++++++------- pkg/runner/runner_test.go | 205 ++++++++++++-- pkg/runner/suite_test.go | 5 +- 30 files changed, 1191 insertions(+), 834 deletions(-) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 1488bcb28..999b939d5 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -210,10 +210,7 @@ type ApplicationSpec struct { // +listType=atomic // +optional Args []string `json:"args,omitempty"` - // The application folder in the custom artifacts Docker image containing - // application artifacts. - // This will effectively become the working directory of the Coherence container. - // If not set the application directory default value is "/app". + // WorkingDir sets the working directory of the Coherence container. // +optional WorkingDir *string `json:"workingDir,omitempty"` // Optional settings that may be configured if using a Cloud Native Buildpack Image. @@ -243,6 +240,7 @@ func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { } if in.WorkingDir != nil { c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohAppDir, Value: *in.WorkingDir}) + c.WorkingDir = *in.WorkingDir } if len(in.Args) > 0 { args := strings.Join(in.Args, " ") diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index e2ff81ca7..bdbabb071 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -16,6 +16,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" + "os" "strconv" "strings" ) @@ -685,13 +686,16 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou cohContainer.Ports = append(cohContainer.Ports, p.CreatePort(deployment)) } + // Create the Operator init-container initContainer := in.CreateOperatorInitContainer(deployment) + + // Create the Operator config files init-container configInitContainer := in.CreateOperatorConfigInitContainer(deployment) // append any additional VolumeMounts cohContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) - initContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) - configInitContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) + initContainer.VolumeMounts = append(initContainer.VolumeMounts, in.VolumeMounts...) + configInitContainer.VolumeMounts = append(configInitContainer.VolumeMounts, in.VolumeMounts...) podTemplate := corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ @@ -760,6 +764,26 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou return podTemplate } +func (in *CoherenceResourceSpec) GetApplicationType() string { + if in != nil && in.Application != nil && in.Application.Type != nil { + return strings.ToLower(*in.Application.Type) + } + return AppTypeNone +} + +// IsSpringBoot returns true if this is a Spring Boot application +func (in *CoherenceResourceSpec) IsSpringBoot() bool { + app := in.GetApplicationType() + return app == AppTypeSpring2 || app == AppTypeSpring3 +} + +func (in *CoherenceResourceSpec) GetApplicationMainClass() string { + if in != nil && in.Application != nil && in.Application.Main != nil { + return *in.Application.Main + } + return DefaultMain +} + func (in *CoherenceResourceSpec) GetImagePullSecrets() []corev1.LocalObjectReference { var secrets []corev1.LocalObjectReference @@ -794,17 +818,9 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe vm := in.CreateCommonVolumeMounts() lp, _ := in.Coherence.GetLocalPorts() - cmd := []string{RunnerCommand} - if in.Application != nil && in.Application.Type != nil && *in.Application.Type == "operator" { - cmd = append(cmd, in.Application.Args...) - } else { - cmd = append(cmd, "server") - } - c := corev1.Container{ - Name: ContainerNameCoherence, - Image: cohImage, - Command: cmd, + Name: ContainerNameCoherence, + Image: cohImage, Ports: []corev1.ContainerPort{ { Name: PortNameCoherence, @@ -868,6 +884,25 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe c.Lifecycle = in.Lifecycle + cmd := []string{"java"} + + if in.IsSpringBoot() { + cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) + cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) + } else { + cmd = append(cmd, "--class-path", fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorClasspathFile)) + cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) + } + + cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) + + if in.Application != nil { + cmd = append(cmd, in.Application.Args...) + } + + // set the command line into the container + c.Command = cmd + return c } @@ -1054,7 +1089,9 @@ func (in *CoherenceResourceSpec) CreateOperatorConfigInitContainer(deployment Co } else { image = *in.Image } - return in.createInitContainer(deployment, ContainerNameOperatorConfig, image, []string{RunnerCommand, RunnerConfig}) + + c := in.createInitContainer(deployment, ContainerNameOperatorConfig, image, []string{RunnerCommand, RunnerConfig}) + return c } // CreateOperatorInitContainer creates the Operator init-container spec. diff --git a/api/v1/common_test.go b/api/v1/common_test.go index e8f169b6c..744c72219 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -382,9 +382,15 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe // The Coherence Container cohContainer := corev1.Container{ - Name: coh.ContainerNameCoherence, - Image: testCoherenceImage, - Command: []string{coh.RunnerCommand, "server"}, + Name: coh.ContainerNameCoherence, + Image: testCoherenceImage, + Command: []string{ + "java", + "--class-path", + fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorClasspathFile), + fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorJvmArgsFile), + fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorMainClassFile), + }, Ports: []corev1.ContainerPort{ { Name: coh.PortNameCoherence, diff --git a/api/v1/constants.go b/api/v1/constants.go index e7d9d4ea8..a2b45b3cb 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -179,6 +179,10 @@ const ( OperatorJvmArgsFile = "coherence-jvm-args.txt" // OperatorClasspathFile is the name of the file in the utils directory containing the JVM class path OperatorClasspathFile = "coherence-class-path.txt" + // OperatorMainClassFile is the name of the file in the utils directory containing the main class name + OperatorMainClassFile = "coherence-main-class.txt" + // OperatorSpringBootArgsFile is the name of the file in the utils directory containing the SpringBoot JVM args + OperatorSpringBootArgsFile = "coherence-spring-args.txt" // OperatorJarFileSuffix is the suffix to append to the utils directory to locate the Operator jar file. OperatorJarFileSuffix = "/lib/coherence-operator.jar" // OperatorConfigDirSuffix is the suffix to append to the utils directory to locate the Operator config directory. @@ -262,6 +266,7 @@ const ( EnvVarSuffixSSLRequireClientCert = "_SSL_REQUIRE_CLIENT_CERT" EnvVarJavaHome = "JAVA_HOME" + EnvVarJdkOptions = "JDK_JAVA_OPTIONS" EnvVarJavaClasspath = "CLASSPATH" EnvVarJvmClasspathJib = "JVM_USE_JIB_CLASSPATH" EnvVarJvmExtraClasspath = "JVM_EXTRA_CLASSPATH" @@ -289,6 +294,30 @@ const ( EnvVarJvmMemoryNativeTracking = "JVM_NATIVE_MEMORY_TRACKING" EnvVarJvmOomExit = "JVM_OOM_EXIT" EnvVarJvmOomHeapDump = "JVM_OOM_HEAP_DUMP" + + // AppTypeNone is the argument to specify no application type. + AppTypeNone = "" + // AppTypeJava is the argument to specify a Java application. + AppTypeJava = "java" + // AppTypeCoherence is the argument to specify a Coherence application. + AppTypeCoherence = "coherence" + // AppTypeHelidon is the argument to specify a Helidon application. + AppTypeHelidon = "helidon" + // AppTypeSpring2 is the argument to specify an exploded Spring Boot 2.x application. + AppTypeSpring2 = "spring" + // AppTypeSpring3 is the argument to specify an exploded Spring Boot 3.x application. + AppTypeSpring3 = "spring3" + + // DefaultMain is an indicator to run the default main class. + DefaultMain = "$DEFAULT$" + // HelidonMain is the default Helidon main class name. + HelidonMain = "io.helidon.microprofile.cdi.Main" + // ServerMain is the default server main class name. + ServerMain = "com.oracle.coherence.k8s.Main" + // SpringBootMain2 is the default Spring Boot 2.x main class name. + SpringBootMain2 = "org.springframework.boot.loader.PropertiesLauncher" + // SpringBootMain3 is the default Spring Boot 3.x main class name. + SpringBootMain3 = "org.springframework.boot.loader.launch.PropertiesLauncher" ) var ( diff --git a/api/v1/create_job_add_containers_test.go b/api/v1/create_job_add_containers_test.go index 0c64c1ca6..862ce8055 100644 --- a/api/v1/create_job_add_containers_test.go +++ b/api/v1/create_job_add_containers_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -245,6 +245,8 @@ func TestCreateJobWithExtraContainerAndVolume(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) jobExpected.Spec.Template.Spec.Volumes = append(jobExpected.Spec.Template.Spec.Volumes, vol) jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mount) + jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mount) + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mount) // Create expected container conExpected := corev1.Container{ diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index b9b8189b6..777857b99 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -63,6 +63,7 @@ func TestCreateJobWithApplicationMainArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = append(jobExpected.Spec.Template.Spec.Containers[0].Command, "arg1", "arg2") // Add the expected environment variables addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) @@ -100,6 +101,7 @@ func TestCreateJobWithWorkingDirectory(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].WorkingDir = dir addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) // assert that the Job is as expected diff --git a/api/v1/create_job_volumemounts_test.go b/api/v1/create_job_volumemounts_test.go index 9551ffeeb..26db8170e 100644 --- a/api/v1/create_job_volumemounts_test.go +++ b/api/v1/create_job_volumemounts_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,6 +44,8 @@ func TestCreateJobWithOneVolumeMount(t *testing.T) { // Create expected Job stsExpected := createMinimalExpectedJob(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne) // assert that the Job is as expected assertJobCreation(t, deployment, stsExpected) @@ -71,6 +73,8 @@ func TestCreateJobWithTwoVolumeMounts(t *testing.T) { // Create expected Job stsExpected := createMinimalExpectedJob(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne, mountTwo) // assert that the Job is as expected assertJobCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_add_containers_test.go b/api/v1/create_statefulset_add_containers_test.go index 5ee81f1dd..d3b903128 100644 --- a/api/v1/create_statefulset_add_containers_test.go +++ b/api/v1/create_statefulset_add_containers_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -245,6 +245,8 @@ func TestCreateStatefulSetWithExtraContainerAndVolume(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Volumes = append(stsExpected.Spec.Template.Spec.Volumes, vol) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mount) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mount) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mount) // Create expected container conExpected := corev1.Container{ diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index 7189216da..d518b2a52 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -63,6 +63,7 @@ func TestCreateStatefulSetWithApplicationMainArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = append(stsExpected.Spec.Template.Spec.Containers[0].Command, "arg1", "arg2") // Add the expected environment variables addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) @@ -100,6 +101,7 @@ func TestCreateStatefulSetWithWorkingDirectory(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].WorkingDir = dir addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) // assert that the StatefulSet is as expected diff --git a/api/v1/create_statefulset_volumemounts_test.go b/api/v1/create_statefulset_volumemounts_test.go index 32eea4e19..97e8fec8e 100644 --- a/api/v1/create_statefulset_volumemounts_test.go +++ b/api/v1/create_statefulset_volumemounts_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,6 +44,8 @@ func TestCreateStatefulSetWithOneVolumeMount(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -71,6 +73,8 @@ func TestCreateStatefulSetWithTwoVolumeMounts(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne, mountTwo) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index e6a4ca235..7561099ef 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -138,7 +138,7 @@ ApplicationSpec is the specification of the application deployed into the Cohere m| type | The application type to execute. This field would be set if using the Coherence Graal image and running a none-Java application. For example if the application was a Node application this field would be set to "node". The default is to run a plain Java application. m| *string | false m| main | Class is the Coherence container main class. The default value is com.tangosol.net.DefaultCacheServer. If the application type is non-Java this would be the name of the corresponding language specific runnable, for example if the application type is "node" the main may be a Javascript file. m| *string | false m| args | Args is the optional arguments to pass to the main class. m| []string | false -m| workingDir | The application folder in the custom artifacts Docker image containing application artifacts. This will effectively become the working directory of the Coherence container. If not set the application directory default value is "/app". m| *string | false +m| workingDir | WorkingDir sets the working directory of the Coherence container. m| *string | false m| cloudNativeBuildPack | Optional settings that may be configured if using a Cloud Native Buildpack Image. For example an image build with the Spring Boot Maven/Gradle plugin. See: https://github.com/paketo-buildpacks/spring-boot and https://buildpacks.io/ m| *<> | false m| springBootFatJar | SpringBootFatJar is the full path name to the Spring Boot fat jar if the application image has been built by just adding a Spring Boot fat jar to the image. If this field is set then the application will be run by executing this jar. For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" m| *string | false |=== diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 535dccc30..c99aa8470 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -12,9 +12,16 @@ import ( v1 "github.com/oracle/coherence-operator/api/v1" "github.com/pkg/errors" "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/api/resource" "os" + "path/filepath" + ctrl "sigs.k8s.io/controller-runtime" + "strconv" + "strings" ) +var configLog = ctrl.Log.WithName("config") + // configCommand creates the corba "config" sub-command func configCommand(env map[string]string) *cobra.Command { cmd := &cobra.Command{ @@ -39,13 +46,24 @@ func configCommand(env map[string]string) *cobra.Command { // createsFiles will create the various config files func createsFiles(details *RunDetails, _ *cobra.Command) (bool, error) { + populateMainClass(details) populateServerDetails(details) + err := configureCommand(details) + if err != nil { + return false, errors.Wrap(err, "failed to configure server command") + } if err := createClassPathFile(details); err != nil { return false, err } if err := createArgsFile(details); err != nil { return false, err } + if err := createMainClassFile(details); err != nil { + return false, err + } + if err := createSpringBootFile(details); err != nil { + return false, err + } if err := createCliConfig(details); err != nil { return false, err } @@ -54,29 +72,19 @@ func createsFiles(details *RunDetails, _ *cobra.Command) (bool, error) { // createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container func createClassPathFile(details *RunDetails) error { - err := configureCommand(details) - if err != nil { - return errors.Wrap(err, "failed to configure server command") - } - cpFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) classpath := details.getClasspath() - err = os.WriteFile(cpFile, []byte(classpath), os.ModePerm) - fmt.Printf("Created class path file %s\n", cpFile) - fmt.Println("--------------------") - fmt.Println(classpath) - fmt.Println("--------------------") + err := os.WriteFile(cpFile, []byte(classpath), os.ModePerm) if err != nil { return errors.Wrap(err, "failed to write coherence classpath file") } + configLog.Info("Created class path file", "FileName", cpFile, "ClassPath", classpath) return nil } // createArgsFile will create the JVM args files for a Coherence Pod - typically this is run from an init-container func createArgsFile(details *RunDetails) error { - var err error - - args := details.Args + args := details.GetArgs() argFileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) var buffer bytes.Buffer @@ -87,12 +95,46 @@ func createArgsFile(details *RunDetails) error { return errors.Wrap(err, "failed to write JVM args file "+argFileName) } - fmt.Printf("Created JVM args file %s\n", argFileName) - fmt.Println("--------------------") - fmt.Println(buffer.String()) - fmt.Println("--------------------") + configLog.Info("Created JVM args file", "FileName", argFileName, "Args", buffer.String()) + return nil +} + +// createSpringBootFile will create the SpringBoot JVM args files for a Coherence Pod - typically this is run from an init-container +func createSpringBootFile(details *RunDetails) error { + argsFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) + cp := strings.ReplaceAll(details.getClasspath(), ":", ",") + + var args string + if details.InnerMainClass == "" || details.InnerMainClass == v1.DefaultMain { + args = fmt.Sprintf("-Dloader.path=%s", cp) + } else { + args = fmt.Sprintf("-Dloader.path=%s\n-Dloader.main=%s", cp, details.InnerMainClass) + } - return err + err := os.WriteFile(argsFile, []byte(args), os.ModePerm) + if err != nil { + return errors.Wrap(err, "failed to write coherence classpath file") + } + configLog.Info("Created SpringBoot args file", "FileName", argsFile, "Args", args) + return nil +} + +// createMainClassFile will create the file containing the main class name for a Coherence Pod - typically this is run from an init-container +func createMainClassFile(details *RunDetails) error { + fileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorMainClassFile) + + var s string + if details.InnerMainClass == "" || details.IsSpringBoot() { + s = details.MainClass + } else { + s = fmt.Sprintf("%s\n%s", details.MainClass, details.InnerMainClass) + } + + if err := os.WriteFile(fileName, []byte(s), os.ModePerm); err != nil { + return errors.Wrap(err, "failed to write coherence classpath file") + } + configLog.Info("Created main class file", "FileName", fileName, "MainClass", details.InnerMainClass) + return nil } func createCliConfig(details *RunDetails) error { @@ -134,14 +176,153 @@ func createCliConfig(details *RunDetails) error { buffer.WriteString("ignoreinvalidcerts: false\n") buffer.WriteString("requesttimeout: 30\n") if err := os.WriteFile(fileName, buffer.Bytes(), os.ModePerm); err != nil { - fmt.Printf("Failed to write coherence CLI config file at %s cause: %v", fileName, err) + configLog.Error(err, "Failed to write coherence CLI config file", "FileName", fileName) return nil } - fmt.Printf("Created CLI config file %s\n", fileName) - fmt.Println("--------------------") - fmt.Println(buffer.String()) - fmt.Println("--------------------") - + configLog.Info("Created CLI config file", "FileName", fileName, "Config", buffer.String()) return nil } + +// Configure the main class +func populateMainClass(details *RunDetails) { + details.MainClass = ServerMain + + // If the main class environment variable is set then use that + // otherwise run Coherence DefaultMain. + mc, found := details.lookupEnv(v1.EnvVarAppMainClass) + + if !found || mc == "" { + // no custom mani set so check for a JIB main class file + appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") + jibMainClassFileName := filepath.Join(appDir, "jib-main-class-file") + fi, err := os.Stat(jibMainClassFileName) + if err != nil && appDir != "/app" { + // try /app dir + jibMainClassFileName = "/app/jib-main-class-file" + fi, err = os.Stat(jibMainClassFileName) + } + + if err == nil && (fi.Size() != 0) { + mainCls, _ := readFirstLineFromFile(jibMainClassFileName) + if len(mainCls) != 0 { + mc = mainCls + found = true + } + } + } + + isSpring := details.IsSpringBoot() + switch { + case found && !isSpring: + // we have a main class specified, and we're not a Spring Boot app + details.InnerMainClass = mc + case found && details.AppType == AppTypeSpring2: + // we have a main class and the app is Spring Boot 2.x + // the main is PropertiesLauncher, + details.MainClass = SpringBootMain2 + // the specified main class is set as a Spring loader property + details.InnerMainClass = mc + case found && details.AppType == AppTypeSpring3: + // we have a main class and the app is Spring Boot 3.x + // the main is PropertiesLauncher, + details.MainClass = SpringBootMain3 + // the specified main class is set as a Spring loader property + details.InnerMainClass = mc + case !found && details.AppType == AppTypeSpring2: + // the app type is Spring Boot 2.x so main is PropertiesLauncher + details.MainClass = SpringBootMain2 + case !found && details.AppType == AppTypeSpring3: + // the app type is Spring Boot 3.x so main is PropertiesLauncher + details.MainClass = SpringBootMain3 + case !found && details.AppType == AppTypeCoherence: + // the app type is Coherence so main is DefaultMain + details.InnerMainClass = DefaultMain + case !found && details.AppType == AppTypeHelidon: + // the app type is Helidon so main is the Helidon CDI starter + details.InnerMainClass = HelidonMain + default: + // no main or app type specified, use DefaultMain + details.InnerMainClass = DefaultMain + } +} + +// Configure the runner to run a Coherence Server +func populateServerDetails(details *RunDetails) { + // Configure the Coherence member's role + details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") + // Configure whether this member is storage enabled + details.addArgFromEnvVar(v1.EnvVarCohStorage, "-Dcoherence.distributed.localstorage") + + // Configure Coherence Tracing + ratio := details.Getenv(v1.EnvVarCohTracingRatio) + if ratio != "" { + q, err := resource.ParseQuantity(ratio) + if err == nil { + d := q.AsDec() + details.addArg("-Dcoherence.tracing.ratio=" + d.String()) + } else { + fmt.Printf("ERROR: Coherence tracing ratio \"%s\" is invalid - %s\n", ratio, err.Error()) + os.Exit(1) + } + } + + // Configure whether Coherence management is enabled + hasMgmt := details.isEnvTrue(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohEnabledSuffix) + log.Info("Coherence Management over REST", "enabled", strconv.FormatBool(hasMgmt), "envVar", v1.EnvVarCohMgmtPrefix+v1.EnvVarCohEnabledSuffix) + if hasMgmt { + fmt.Println("INFO: Configuring Coherence Management over REST") + details.addArg("-Dcoherence.management.http=all") + if details.CoherenceHome != "" { + // If management is enabled and the COHERENCE_HOME environment variable is set + // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath + // This is for legacy 14.1.1.0 and 12.2.1.4 images + details.addClasspath(details.CoherenceHome + "/lib/coherence-management.jar") + } + } + + // Configure whether Coherence metrics is enabled + hasMetrics := details.isEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) + log.Info("Coherence Metrics", "enabled", strconv.FormatBool(hasMetrics), "envVar", v1.EnvVarCohMetricsPrefix+v1.EnvVarCohEnabledSuffix) + if hasMetrics { + details.addArg("-Dcoherence.metrics.http.enabled=true") + fmt.Println("INFO: Configuring Coherence Metrics") + if details.CoherenceHome != "" { + // If metrics is enabled and the COHERENCE_HOME environment variable is set + // then $COHERENCE_HOME/lib/coherence-metrics.jar will be added to the classpath + // This is for legacy 14.1.1.0 and 12.2.1.4 images + details.addClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") + } + } + + // Configure whether to add third-party modules to the classpath if management over rest + // or metrics are enabled and the directory pointed to by the DEPENDENCY_MODULES environment + // variable exists. + if hasMgmt || hasMetrics { + dm := details.Getenv(v1.EnvVarCohDependencyModules) + if dm != "" { + stat, err := os.Stat(dm) + if err == nil && stat.IsDir() { + // dependency modules directory exists + details.addClasspath(dm + "/*") + } + } + } + + if details.isEnvTrueOrBlank(v1.EnvVarJvmShowSettings) { + details.addArg("-XshowSettings:all") + details.addArg("-XX:+PrintCommandLineFlags") + details.addArg("-XX:+PrintFlagsFinal") + } + + // Add GC logging parameters if required + if details.isEnvTrue(v1.EnvVarJvmGcLogging) { + details.addArg("-verbose:gc") + details.addArg("-XX:+PrintGCDetails") + details.addArg("-XX:+PrintGCTimeStamps") + details.addArg("-XX:+PrintHeapAtGC") + details.addArg("-XX:+PrintTenuringDistribution") + details.addArg("-XX:+PrintGCApplicationStoppedTime") + details.addArg("-XX:+PrintGCApplicationConcurrentTime") + } +} diff --git a/pkg/runner/cmd_console.go b/pkg/runner/cmd_console.go index 78427899a..c3809512b 100644 --- a/pkg/runner/cmd_console.go +++ b/pkg/runner/cmd_console.go @@ -7,10 +7,8 @@ package runner import ( - v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/cobra" "github.com/spf13/viper" - "strings" ) const ( @@ -38,16 +36,17 @@ func consoleCommand(v *viper.Viper) *cobra.Command { // Configure the runner to run a Coherence CacheFactory console func console(details *RunDetails, args []string, v *viper.Viper) { - app := strings.ToLower(v.GetString(v1.EnvVarAppType)) - if app == AppTypeSpring2 { - details.AppType = AppTypeSpring2 - details.MainClass = SpringBootMain2 + details.Command = CommandConsole + loadConfigFiles(details) + + if details.IsSpringBoot() { details.addArg("-Dloader.main=" + ConsoleMain) } else { details.AppType = AppTypeJava details.MainClass = ConsoleMain } - details.Command = CommandConsole + + details.addArg("-Dcoherence.role=console") details.addArg("-Dcoherence.distributed.localstorage=false") details.addArg("-Dcoherence.localport.adjust=true") details.addArg("-Dcoherence.management.http=none") @@ -57,8 +56,6 @@ func console(details *RunDetails, args []string, v *viper.Viper) { details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.health.http.port=0") details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarCohRole, "console") - details.setenv(v1.EnvVarCohHealthPort, "0") + details.addArg("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_jshell.go b/pkg/runner/cmd_jshell.go index 0db18d4cf..30420e7f4 100644 --- a/pkg/runner/cmd_jshell.go +++ b/pkg/runner/cmd_jshell.go @@ -7,7 +7,6 @@ package runner import ( - v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -40,18 +39,18 @@ func jShellCommand(v *viper.Viper) *cobra.Command { func jShell(details *RunDetails, args []string, v *viper.Viper) { details.AppType = AppTypeJShell details.Command = CommandJShell + loadConfigFiles(details) + + details.addArg("-Dcoherence.role=jshell") details.addArg("-Dcoherence.distributed.localstorage=false") details.addArg("-Dcoherence.localport.adjust=true") details.addArg("-Dcoherence.management.http=none") details.addArg("-Dcoherence.management.http.port=0") details.addArg("-Dcoherence.metrics.http.enabled=false") details.addArg("-Dcoherence.metrics.http.port=0") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarJvmUseContainerLimits, "false") details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.health.http.port=0") details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarCohRole, "jshell") - details.setenv(v1.EnvVarCohHealthPort, "0") + details.addArg("-XX:NativeMemoryTracking=summary") details.MainArgs = args } diff --git a/pkg/runner/cmd_operator_test.go b/pkg/runner/cmd_operator_test.go index 4ead725e8..bad967317 100644 --- a/pkg/runner/cmd_operator_test.go +++ b/pkg/runner/cmd_operator_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -22,7 +22,7 @@ func TestBasicOperator(t *testing.T) { } args := []string{"operator", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -45,7 +45,7 @@ func TestOperatorWithSingleGlobalLabel(t *testing.T) { } args := []string{"operator", "--dry-run", "--global-label", "one=value-one"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -69,7 +69,7 @@ func TestOperatorWithMultipleGlobalLabels(t *testing.T) { "--global-label", "two=value-two", "--global-label", "three=value-three", } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -91,7 +91,7 @@ func TestOperatorWithSingleGlobalAnnotation(t *testing.T) { } args := []string{"operator", "--dry-run", "--global-annotation", "one=value-one"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -115,7 +115,7 @@ func TestOperatorWithMultipleGlobalAnnotations(t *testing.T) { "--global-annotation", "two=value-two", "--global-annotation", "three=value-three", } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/runner/cmd_query_plus.go b/pkg/runner/cmd_query_plus.go index 35659f3a9..a542a3084 100644 --- a/pkg/runner/cmd_query_plus.go +++ b/pkg/runner/cmd_query_plus.go @@ -7,10 +7,8 @@ package runner import ( - v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/cobra" "github.com/spf13/viper" - "strings" ) const ( @@ -39,16 +37,17 @@ func queryPlusCommand(v *viper.Viper) *cobra.Command { // Configure the runner to run a Coherence Query Plus console func queryPlus(details *RunDetails, args []string, v *viper.Viper) { - app := strings.ToLower(v.GetString(v1.EnvVarAppType)) - if app == AppTypeSpring2 { - details.AppType = AppTypeSpring2 - details.MainClass = SpringBootMain2 + details.Command = CommandQueryPlus + loadConfigFiles(details) + + if details.IsSpringBoot() { details.addArg("-Dloader.main=" + QueryPlusMain) } else { details.AppType = AppTypeJava details.MainClass = QueryPlusMain } - details.Command = CommandQueryPlus + + details.addArg("-Dcoherence.role=console") details.addArg("-Dcoherence.distributed.localstorage=false") details.addArg("-Dcoherence.localport.adjust=true") details.addArg("-Dcoherence.management.http=none") @@ -58,8 +57,6 @@ func queryPlus(details *RunDetails, args []string, v *viper.Viper) { details.addArg("-Dcoherence.operator.health.enabled=false") details.addArg("-Dcoherence.health.http.port=0") details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarCohRole, "queryPlus") - details.setenv(v1.EnvVarCohHealthPort, "0") + details.addArg("-XX:NativeMemoryTracking=summary") details.MainArgs = args } diff --git a/pkg/runner/cmd_server.go b/pkg/runner/cmd_server.go index 032d63414..edf963aec 100644 --- a/pkg/runner/cmd_server.go +++ b/pkg/runner/cmd_server.go @@ -7,13 +7,12 @@ package runner import ( + "bufio" "fmt" v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/pkg/errors" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/api/resource" "os" - "path/filepath" - "strconv" "strings" ) @@ -38,185 +37,98 @@ func serverCommand() *cobra.Command { // Configure the runner to run a Coherence Server func server(details *RunDetails, _ *cobra.Command) { - var err error + details.Command = CommandServer + loadConfigFiles(details) - if details.ClassPathFile != "" { - fmt.Printf("**** INFO found class path file %s\n", details.ClassPathFile) - data, err := os.ReadFile(details.ClassPathFile) - if err != nil { - fmt.Printf("**** ERROR error reading %s %v\n", details.ClassPathFile, err) - } else { - fmt.Printf("**** INFO contents of %s\n------\n%s\n------\n", details.ClassPathFile, string(data)) + ma, found := details.lookupEnv(v1.EnvVarAppMainArgs) + if found { + if ma != "" { + for _, arg := range strings.Split(ma, " ") { + details.MainArgs = append(details.MainArgs, details.ExpandEnv(arg)) + } } - } else { - fmt.Println("**** ERROR class path file does not exist") } +} - if details.JvmArgsFile != "" { - fmt.Printf("**** INFO found %s\n", details.JvmArgsFile) - data, err := os.ReadFile(details.JvmArgsFile) - if err != nil { - fmt.Printf("**** ERROR error reading %s %v\n", details.JvmArgsFile, err) - } else { - fmt.Printf("**** INFO contents of %s\n------\n%s\n------\n", details.JvmArgsFile, string(data)) - } - } else { - fmt.Println("**** ERROR JVM args does not exist") - } +func loadConfigFiles(details *RunDetails) { + var err error - home := details.getenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) - cliCfg := fmt.Sprintf("%s%c%s", home, os.PathSeparator, "cohctl.yaml") - if _, err = os.Stat(cliCfg); err != nil { - fmt.Printf("**** ERROR error CLI config does not exist %s %v\n", cliCfg, err) - } else { - data, err := os.ReadFile(cliCfg) - if err != nil { - fmt.Printf("**** ERROR error reading CLI config %s %v\n", cliCfg, err) - } else { - fmt.Printf("**** INFO contents of CLI config %s\n------\n%s\n------\n", cliCfg, string(data)) - } + if err = loadClassPathFile(details); err != nil { + fmt.Printf("Error loading class path file %v\n", err) } - details.Command = CommandServer - details.MainClass = ServerMain - - // If the main class environment variable is set then use that - // otherwise run Coherence DefaultMain. - mc, found := details.lookupEnv(v1.EnvVarAppMainClass) - appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") - jibMainClassFileName := filepath.Join(appDir, "jib-main-class-file") - fi, err := os.Stat(jibMainClassFileName) - mainCls := "" - if err == nil && (fi.Size() != 0) { - mainCls, _ = readFirstLineFromFile(jibMainClassFileName) - } - if !found && (len(mainCls) != 0) { - mc = mainCls - found = true - } - isSpring := details.IsSpringBoot() - switch { - case found && !isSpring: - // we have a main class specified, and we're not a Spring Boot app - details.MainArgs = []string{mc} - case found && details.AppType == AppTypeSpring2: - // we have a main class and the app is Spring Boot 2.x - // the main is PropertiesLauncher, - details.MainClass = SpringBootMain2 - // the specified main class is set as a Spring loader property - details.addArg("-Dloader.main=" + mc) - case found && details.AppType == AppTypeSpring3: - // we have a main class and the app is Spring Boot 3.x - // the main is PropertiesLauncher, - details.MainClass = SpringBootMain3 - // the specified main class is set as a Spring loader property - details.addArg("-Dloader.main=" + mc) - case !found && details.AppType == AppTypeSpring2: - // the app type is Spring Boot 2.x so main is PropertiesLauncher - details.MainClass = SpringBootMain2 - case !found && details.AppType == AppTypeSpring3: - // the app type is Spring Boot 3.x so main is PropertiesLauncher - details.MainClass = SpringBootMain3 - case !found && details.AppType == AppTypeCoherence: - // the app type is Coherence so main is DefaultMain - details.MainArgs = []string{DefaultMain} - case !found && details.AppType == AppTypeHelidon: - // the app type is Helidon so main is the Helidon CDI starter - details.MainArgs = []string{HelidonMain} - default: - // no main or app type specified, use DefaultMain - details.MainArgs = []string{DefaultMain} + if err = loadJvmArgsFile(details); err != nil { + fmt.Printf("Error loading class path file %v\n", err) } - // Check for any main class arguments - ma, found := details.lookupEnv(v1.EnvVarAppMainArgs) - if found { - if ma != "" { - for _, arg := range strings.Split(ma, " ") { - details.MainArgs = append(details.MainArgs, details.ExpandEnv(arg)) - } + if details.IsSpringBoot() { + if err = loadSpringBootArgsFile(details); err != nil { + fmt.Printf("Error loading main class file %v\n", err) } } - populateServerDetails(details) + if err = loadMainClassFile(details); err != nil { + fmt.Printf("Error loading main class file %v\n", err) + } } -// Configure the runner to run a Coherence Server -func populateServerDetails(details *RunDetails) { - // Configure the Coherence member's role - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") - // Configure whether this member is storage enabled - details.addArgFromEnvVar(v1.EnvVarCohStorage, "-Dcoherence.distributed.localstorage") - - // Configure Coherence Tracing - ratio := details.Getenv(v1.EnvVarCohTracingRatio) - if ratio != "" { - q, err := resource.ParseQuantity(ratio) - if err == nil { - d := q.AsDec() - details.addArg("-Dcoherence.tracing.ratio=" + d.String()) - } else { - fmt.Printf("ERROR: Coherence tracing ratio \"%s\" is invalid - %s\n", ratio, err.Error()) - os.Exit(1) - } +func loadClassPathFile(details *RunDetails) error { + file := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + data, err := os.ReadFile(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) } + details.Classpath = string(data) + return nil +} - // Configure whether Coherence management is enabled - hasMgmt := details.isEnvTrue(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohEnabledSuffix) - log.Info("Coherence Management over REST", "enabled", strconv.FormatBool(hasMgmt), "envVar", v1.EnvVarCohMgmtPrefix+v1.EnvVarCohEnabledSuffix) - if hasMgmt { - fmt.Println("INFO: Configuring Coherence Management over REST") - details.addArg("-Dcoherence.management.http=all") - if details.CoherenceHome != "" { - // If management is enabled and the COHERENCE_HOME environment variable is set - // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath - // This is for legacy 14.1.1.0 and 12.2.1.4 images - details.addClasspath(details.CoherenceHome + "/lib/coherence-management.jar") - } +func loadJvmArgsFile(details *RunDetails) error { + file := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + lines, err := readLines(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) } + details.addArgs(lines...) + return nil +} - // Configure whether Coherence metrics is enabled - hasMetrics := details.isEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) - log.Info("Coherence Metrics", "enabled", strconv.FormatBool(hasMetrics), "envVar", v1.EnvVarCohMetricsPrefix+v1.EnvVarCohEnabledSuffix) - if hasMetrics { - details.addArg("-Dcoherence.metrics.http.enabled=true") - fmt.Println("INFO: Configuring Coherence Metrics") - if details.CoherenceHome != "" { - // If metrics is enabled and the COHERENCE_HOME environment variable is set - // then $COHERENCE_HOME/lib/coherence-metrics.jar will be added to the classpath - // This is for legacy 14.1.1.0 and 12.2.1.4 images - details.addClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") +func loadMainClassFile(details *RunDetails) error { + dir := details.getenvOrDefault(v1.EnvVarCohUtilDir, details.UtilsDir) + file := fmt.Sprintf("%s%c%s", dir, os.PathSeparator, v1.OperatorMainClassFile) + lines, err := readLines(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) + } + if len(lines) > 0 { + details.MainClass = lines[0] + if len(lines) > 1 { + details.MainArgs = append(details.MainArgs, lines[1:]...) } } + return nil +} - // Configure whether to add third-party modules to the classpath if management over rest - // or metrics are enabled and the directory pointed to by the DEPENDENCY_MODULES environment - // variable exists. - if hasMgmt || hasMetrics { - dm := details.Getenv(v1.EnvVarCohDependencyModules) - if dm != "" { - stat, err := os.Stat(dm) - if err == nil && stat.IsDir() { - // dependency modules directory exists - details.addClasspath(dm + "/*") - } - } +func loadSpringBootArgsFile(details *RunDetails) error { + file := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) + lines, err := readLines(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) } + details.addArgs(lines...) + return nil +} - if details.isEnvTrueOrBlank(v1.EnvVarJvmShowSettings) { - details.addArg("-XshowSettings:all") - details.addArg("-XX:+PrintCommandLineFlags") - details.addArg("-XX:+PrintFlagsFinal") +func readLines(path string) ([]string, error) { + file, err := os.Open(path) + if err != nil { + return nil, err } + defer file.Close() - // Add GC logging parameters if required - if details.isEnvTrue(v1.EnvVarJvmGcLogging) { - details.addArg("-verbose:gc") - details.addArg("-XX:+PrintGCDetails") - details.addArg("-XX:+PrintGCTimeStamps") - details.addArg("-XX:+PrintHeapAtGC") - details.addArg("-XX:+PrintTenuringDistribution") - details.addArg("-XX:+PrintGCApplicationStoppedTime") - details.addArg("-XX:+PrintGCApplicationConcurrentTime") + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) } + return lines, scanner.Err() } diff --git a/pkg/runner/run_details.go b/pkg/runner/run_details.go index 448243bfe..6fb3a6730 100644 --- a/pkg/runner/run_details.go +++ b/pkg/runner/run_details.go @@ -60,16 +60,21 @@ type RunDetails struct { UseOperatorHealth bool AppType string Classpath string - Args []string MainClass string + InnerMainClass string MainArgs []string BuildPacks *bool ExtraEnv []string ClassPathFile string JvmArgsFile string + args []string env *viper.Viper } +func (in *RunDetails) GetArgs() []string { + return in.args +} + // IsSpringBoot returns true if this is a Spring Boot application func (in *RunDetails) IsSpringBoot() bool { if in.env == nil { @@ -233,9 +238,9 @@ func (in *RunDetails) getCommandWithPrefix(propPrefix, jvmPrefix string) []strin cmd = append(cmd, "--class-path", cp) } if propPrefix == "" && jvmPrefix == "" { - cmd = append(cmd, in.Args...) + cmd = append(cmd, in.args...) } else { - for _, arg := range in.Args { + for _, arg := range in.args { if strings.HasPrefix(arg, "-D") && propPrefix != "" { cmd = append(cmd, propPrefix+arg) } else if jvmPrefix != "" { @@ -252,43 +257,12 @@ func (in *RunDetails) getSpringBootCommand() []string { func (in *RunDetails) getSpringBootArgs() []string { var cmd []string - cp := strings.ReplaceAll(in.getClasspath(), ":", ",") - if cp != "" { - cmd = append(cmd, "-Dloader.path="+cp) - } - // Are we using a Spring Boot fat jar if jar, _ := in.lookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { cmd = append(cmd, "--class-path", jar) } - cmd = append(cmd, in.Args...) - - return cmd -} - -/* -func (in *RunDetails) getGraalCommand() []string { - cmd := in.getCommand() - for i, c := range cmd { - switch { - case c == "-cp": - cmd[i] = "--vm.cp" - case strings.HasPrefix(c, "-D"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-XX"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-Xms"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-Xmx"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-Xss"): - cmd[i] = "--vm." + c[1:] - } - } - - return cmd + return append(cmd, in.args...) } -*/ func (in *RunDetails) addArgs(args ...string) { for _, a := range args { @@ -298,7 +272,7 @@ func (in *RunDetails) addArgs(args ...string) { func (in *RunDetails) addArg(arg string) { if arg != "" { - in.Args = append(in.Args, in.ExpandEnv(arg)) + in.args = append(in.args, in.ExpandEnv(arg)) } } @@ -367,7 +341,7 @@ func (in *RunDetails) addArgFromEnvVar(name, property string) { value := in.Getenv(name) if value != "" { s := fmt.Sprintf("%s=%s", property, value) - in.Args = append(in.Args, s) + in.args = append(in.args, s) } } @@ -379,7 +353,7 @@ func (in *RunDetails) setSystemPropertyFromEnvVarOrDefault(name, property, dflt } else { s = fmt.Sprintf("%s=%s", property, dflt) } - in.Args = append(in.Args, s) + in.args = append(in.args, s) } func (in *RunDetails) getJavaExecutable() string { diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 0eeda12a1..f6969a30f 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -221,7 +221,11 @@ func Execute() (Execution, error) { // ExecuteWithArgsAndNewViper runs the runner with a given environment and argument overrides. func ExecuteWithArgsAndNewViper(env map[string]string, args []string) (Execution, error) { - return ExecuteWithArgsAndViper(env, args, viper.New()) + v := viper.New() + for key, value := range env { + v.SetDefault(key, value) + } + return ExecuteWithArgsAndViper(env, args, v) } // ExecuteWithArgsAndViper runs the runner with a given environment and argument overrides. @@ -338,6 +342,12 @@ func configureCommand(details *RunDetails) error { appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") cpFile := filepath.Join(appDir, "jib-classpath-file") fi, e := os.Stat(cpFile) + if e != nil && appDir != "/app" { + // try in /app + cpFile = "/app/jib-classpath-file" + fi, e = os.Stat(cpFile) + } + if e == nil && (fi.Size() != 0) { clsPath, _ := readFirstLineFromFile(cpFile) if len(clsPath) != 0 { @@ -381,14 +391,8 @@ func configureCommand(details *RunDetails) error { details.addArg("-Dcoherence.ipmonitor.pingtimeout=0") } - // Do the Coherence version specific configuration - if ok := checkCoherenceVersion("12.2.1.4.0", details); ok { - // is at least 12.2.1.4 - cohPost12214(details) - } else { - // is at pre-12.2.1.4 - cohPre12214(details) - } + details.addArg("-Dcoherence.override=k8s-coherence-override.xml") + details.addArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") post2206 := checkCoherenceVersion("14.1.1.2206.0", details) if post2206 { @@ -620,11 +624,6 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { var cmd *exec.Cmd var app string - err = configureCommand(details) - if err != nil { - return "", nil, err - } - switch { case details.AppType == AppTypeNone || details.AppType == AppTypeJava: app = "Java" @@ -833,7 +832,7 @@ func configureSiteAndRack(details *RunDetails) { details.addArg("-Dcoherence.site=" + site) } } else { - log.Info("Coherence site property not set as "+v1.EnvVarCoherenceSite+" environment variable is set", "Site", site) + details.addArg("-Dcoherence.site=" + site) } } @@ -878,7 +877,7 @@ func configureSiteAndRack(details *RunDetails) { details.addArg("-Dcoherence.rack=" + rack) } } else { - log.Info("Coherence rack property not set as "+v1.EnvVarCoherenceRack+" environment variable is set", "Rack", rack) + details.addArg("-Dcoherence.rack=" + rack) } } } @@ -1055,20 +1054,10 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { } } // command exited with some other error, assume the version is good - log.Error(err, "Coherence version check failed, assuming version is valid", "version", v) + log.Info("Coherence version check failed, assuming version is valid", "version", v, "error", err.Error()) return true } -func cohPre12214(details *RunDetails) { - details.addArg("-Dcoherence.override=k8s-coherence-nossl-override.xml") - details.addArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") -} - -func cohPost12214(details *RunDetails) { - details.addArg("-Dcoherence.override=k8s-coherence-override.xml") - details.addArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") -} - func cohPost2206(details *RunDetails) { if details.UseOperatorHealth { details.addArg("-Dcoherence.operator.health.enabled=true") diff --git a/pkg/runner/runner_application_test.go b/pkg/runner/runner_application_test.go index bb8a035f8..ed0374d5f 100644 --- a/pkg/runner/runner_application_test.go +++ b/pkg/runner/runner_application_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -30,11 +30,12 @@ func TestApplicationArgsEmpty(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,7 +44,7 @@ func TestApplicationArgsEmpty(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationArgs(t *testing.T) { @@ -60,11 +61,12 @@ func TestApplicationArgs(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "Foo", "Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -73,7 +75,7 @@ func TestApplicationArgs(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "Foo", "Bar"))) } func TestApplicationArgsWithEnvVarExpansion(t *testing.T) { @@ -94,11 +96,12 @@ func TestApplicationArgsWithEnvVarExpansion(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "foo-value", "bar-value") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -107,7 +110,7 @@ func TestApplicationArgsWithEnvVarExpansion(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "foo-value", "bar-value"))) } func TestApplicationMain(t *testing.T) { @@ -124,11 +127,12 @@ func TestApplicationMain(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), "$DEFAULT$", "com.oracle.test.Main") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -137,13 +141,15 @@ func TestApplicationMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.oracle.test.Main"))) } func TestApplicationWorkingDirectory(t *testing.T) { g := NewGomegaWithT(t) - wd, err := os.Getwd() + utils := ensureTestUtilsDir(t) + wd := utils + "/foo" + err := os.MkdirAll(wd, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) d := &coh.Coherence{ @@ -157,11 +163,12 @@ func TestApplicationWorkingDirectory(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedCP := GetOperatorClasspathWithUtilsDir(utils) + expectedArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutAppClasspath() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -169,6 +176,6 @@ func TestApplicationWorkingDirectory(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(wd)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithWorkingDir(t, wd))) } diff --git a/pkg/runner/runner_application_type_test.go b/pkg/runner/runner_application_type_test.go index 20f4831b0..6c734c05a 100644 --- a/pkg/runner/runner_application_type_test.go +++ b/pkg/runner/runner_application_type_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -28,11 +28,13 @@ func TestApplicationTypeNone(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + //expectedArgs := GetMinimalExpectedArgs(t) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -41,7 +43,7 @@ func TestApplicationTypeNone(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationTypeNoneWithMain(t *testing.T) { @@ -59,11 +61,13 @@ func TestApplicationTypeNoneWithMain(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") + //expectedArgs := ReplaceArg(GetMinimalExpectedArgs(t), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -72,7 +76,7 @@ func TestApplicationTypeNoneWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } func TestApplicationTypeCoherence(t *testing.T) { @@ -89,11 +93,13 @@ func TestApplicationTypeCoherence(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + //expectedArgs := GetMinimalExpectedArgs(t) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -102,7 +108,7 @@ func TestApplicationTypeCoherence(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationTypeCoherenceWithMain(t *testing.T) { @@ -120,11 +126,12 @@ func TestApplicationTypeCoherenceWithMain(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -133,7 +140,7 @@ func TestApplicationTypeCoherenceWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } func TestApplicationTypeJava(t *testing.T) { @@ -150,11 +157,13 @@ func TestApplicationTypeJava(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + //expectedArgs := GetMinimalExpectedArgs(t) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -163,7 +172,7 @@ func TestApplicationTypeJava(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationTypeJavaWithMain(t *testing.T) { @@ -181,11 +190,12 @@ func TestApplicationTypeJavaWithMain(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -194,7 +204,7 @@ func TestApplicationTypeJavaWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } func TestApplicationTypeHelidon(t *testing.T) { @@ -211,11 +221,12 @@ func TestApplicationTypeHelidon(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, HelidonMain) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -224,7 +235,7 @@ func TestApplicationTypeHelidon(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "io.helidon.microprofile.cdi.Main"))) } func TestApplicationTypeHelidonWithMain(t *testing.T) { @@ -242,11 +253,12 @@ func TestApplicationTypeHelidonWithMain(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(e).NotTo(BeNil()) @@ -255,5 +267,5 @@ func TestApplicationTypeHelidonWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } diff --git a/pkg/runner/runner_coherence_test.go b/pkg/runner/runner_coherence_test.go index aa3f6b471..9106f0c30 100644 --- a/pkg/runner/runner_coherence_test.go +++ b/pkg/runner/runner_coherence_test.go @@ -26,20 +26,23 @@ func TestCoherenceClusterName(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.cluster="), + expectedArgsFile := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.cluster="), "-Dcoherence.cluster=test-cluster") + verifyConfigFilesWithArgs(t, d, expectedArgsFile) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.cluster="), + "-Dcoherence.cluster=test-cluster") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -57,20 +60,23 @@ func TestCoherenceCacheConfig(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.cacheconfig="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.cacheconfig="), "-Dcoherence.cacheconfig=test-config.xml") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.cacheconfig="), + "-Dcoherence.cacheconfig=test-config.xml") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -88,20 +94,23 @@ func TestCoherenceOperationalConfig(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.k8s.override="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.k8s.override="), "-Dcoherence.k8s.override=test-override.xml") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.k8s.override="), + "-Dcoherence.k8s.override=test-override.xml") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -119,20 +128,23 @@ func TestCoherenceStorageEnabledTrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.distributed.localstorage="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.distributed.localstorage="), "-Dcoherence.distributed.localstorage=true") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.distributed.localstorage="), + "-Dcoherence.distributed.localstorage=true") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -150,20 +162,23 @@ func TestCoherenceStorageEnabledFalse(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.distributed.localstorage="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.distributed.localstorage="), "-Dcoherence.distributed.localstorage=false") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.distributed.localstorage="), + "-Dcoherence.distributed.localstorage=false") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -181,11 +196,10 @@ func TestCoherenceExcludeFromWKATrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -193,8 +207,8 @@ func TestCoherenceExcludeFromWKATrue(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceLogLevel(t *testing.T) { @@ -211,20 +225,23 @@ func TestCoherenceLogLevel(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.log.level="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.log.level="), "-Dcoherence.log.level=9") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.log.level="), + "-Dcoherence.log.level=9") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -243,11 +260,10 @@ func TestCoherenceTracingRatio(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.tracing.ratio=0.012340")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.tracing.ratio=0.012340") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -255,7 +271,8 @@ func TestCoherenceTracingRatio(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.tracing.ratio=0.012340") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -273,11 +290,10 @@ func TestCoherenceAllowEndangeredEmptyList(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -285,8 +301,8 @@ func TestCoherenceAllowEndangeredEmptyList(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceAllowEndangered(t *testing.T) { @@ -303,11 +319,10 @@ func TestCoherenceAllowEndangered(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.operator.statusha.allowendangered=foo,bar")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.operator.statusha.allowendangered=foo,bar") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -315,7 +330,8 @@ func TestCoherenceAllowEndangered(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.operator.statusha.allowendangered=foo,bar") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -336,12 +352,13 @@ func TestCoherenceExistingWKADeploymentSameNamespace(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedFileArgs := GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.wka") + expectedFileArgs = append(expectedFileArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".foo.svc") - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.wka") - expectedArgs = append(expectedArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".foo.svc") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -349,7 +366,9 @@ func TestCoherenceExistingWKADeploymentSameNamespace(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.wka"), + "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".foo.svc") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -370,12 +389,13 @@ func TestCoherenceExistingWKADeploymentDifferentNamespace(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedFileArgs := GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.wka") + expectedFileArgs = append(expectedFileArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".back-end.svc") - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.wka") - expectedArgs = append(expectedArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".back-end.svc") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -383,7 +403,9 @@ func TestCoherenceExistingWKADeploymentDifferentNamespace(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.wka"), + "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".back-end.svc") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -401,11 +423,12 @@ func TestCoherenceEnableIpMonitor(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.ipmonitor.pingtimeout") - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.ipmonitor.pingtimeout") + verifyConfigFilesWithArgs(t, d, expectedArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -413,8 +436,8 @@ func TestCoherenceEnableIpMonitor(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.ipmonitor.pingtimeout"))) } func TestCoherenceDisableIpMonitor(t *testing.T) { @@ -431,11 +454,10 @@ func TestCoherenceDisableIpMonitor(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -443,8 +465,8 @@ func TestCoherenceDisableIpMonitor(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceDefaultIpMonitor(t *testing.T) { @@ -461,11 +483,10 @@ func TestCoherenceDefaultIpMonitor(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -473,8 +494,8 @@ func TestCoherenceDefaultIpMonitor(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceSiteEAndRackEnvVarSet(t *testing.T) { @@ -487,24 +508,22 @@ func TestCoherenceSiteEAndRackEnvVarSet(t *testing.T) { Env: []corev1.EnvVar{ { Name: coh.EnvVarCoherenceSite, - Value: "test-site", + Value: "site-foo", }, { Name: coh.EnvVarCoherenceRack, - Value: "test-rack", + Value: "rack-bar", }, }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) + verifyConfigFilesWithArgsWithSkipSite(t, d, GetExpectedArgsFileContentWith("-Dcoherence.site=site-foo", + "-Dcoherence.rack=rack-bar"), false) - expectedCommand := GetJavaCommand() - // site and rack system properties should not be set - expectedArgs := RemoveArg(GetMinimalExpectedArgs(), "-Dcoherence.site") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.rack") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -512,7 +531,8 @@ func TestCoherenceSiteEAndRackEnvVarSet(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=site-foo", "-Dcoherence.rack=rack-bar") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -530,7 +550,7 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVar(t *testing.T) { }, { Name: "TEST_SITE_VAR", - Value: "test-site", + Value: "x-site", }, { Name: coh.EnvVarCoherenceRack, @@ -538,19 +558,18 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVar(t *testing.T) { }, { Name: "TEST_RACK_VAR", - Value: "test-rack", + Value: "x-rack", }, }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) + verifyConfigFilesWithArgsWithSkipSite(t, d, GetExpectedArgsFileContentWith("-Dcoherence.site=x-site", + "-Dcoherence.rack=x-rack"), false) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.site=test-site") - expectedArgs = append(expectedArgs, "-Dcoherence.rack=test-rack") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -558,7 +577,8 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVar(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=x-site", "-Dcoherence.rack=x-rack") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -587,13 +607,13 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVarWhenRackIsMissing(t *testin }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.site=test-site") // rack should be set to site - expectedArgs = append(expectedArgs, "-Dcoherence.rack=test-site") + expectedFileArgs := append(GetExpectedArgsFileContent(), "-Dcoherence.site=test-site", "-Dcoherence.rack=test-site") + + verifyConfigFilesWithArgsWithSkipSite(t, d, expectedFileArgs, false) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -601,7 +621,9 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVarWhenRackIsMissing(t *testin g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=test-site", + "-Dcoherence.rack=test-site") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -626,12 +648,13 @@ func TestCoherenceSiteAndRackFromFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) + expectedFileArgs := append(GetExpectedArgsFileContent(), "-Dcoherence.site=site-from-file", + "-Dcoherence.rack=rack-from-file") - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.site=site-from-file") - expectedArgs = append(expectedArgs, "-Dcoherence.rack=rack-from-file") + verifyConfigFilesWithArgsWithSkipSite(t, d, expectedFileArgs, false) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -639,6 +662,8 @@ func TestCoherenceSiteAndRackFromFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=site-from-file", + "-Dcoherence.rack=rack-from-file") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } diff --git a/pkg/runner/runner_initialise_test.go b/pkg/runner/runner_initialise_test.go index 0d44baaee..b472e00e9 100644 --- a/pkg/runner/runner_initialise_test.go +++ b/pkg/runner/runner_initialise_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -31,7 +31,7 @@ func TestInitialise(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test"}, } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) args, err := createArgs() g.Expect(err).NotTo(HaveOccurred()) @@ -49,7 +49,7 @@ func TestInitialiseWithCommand(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test"}, } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) args, err := createArgs() g.Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/runner/runner_jvm_jibclasspath_test.go b/pkg/runner/runner_jvm_jibclasspath_test.go index 32e524298..e939723bd 100644 --- a/pkg/runner/runner_jvm_jibclasspath_test.go +++ b/pkg/runner/runner_jvm_jibclasspath_test.go @@ -17,7 +17,12 @@ import ( "testing" ) -func TestJibClasspath(t *testing.T) { +const ( + JibClassPath = "jib/classpath/*:jib/libs/*" + JibMainClass = "com.test.JibMainClass" +) + +func TestJibClasspathWhenNoJibFilePresent(t *testing.T) { g := NewGomegaWithT(t) d := &coh.Coherence{ @@ -31,11 +36,10 @@ func TestJibClasspath(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,11 +47,11 @@ func TestJibClasspath(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } -func TestJibClasspathFile(t *testing.T) { +func TestJibClasspathFileWhenJibFilePresent(t *testing.T) { g := NewGomegaWithT(t) d := &coh.Coherence{ @@ -61,13 +65,14 @@ func TestJibClasspathFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() f := createJibClasspathFile() defer os.Remove(f.Name()) - expectedArgs := GetMinimalExpectedArgsWithAppClasspathFile() + + expectedCp := JibClassPath + ":" + GetOperatorClasspathWithUtilsDir(ensureTestUtilsDir(t)) + verifyConfigFilesWithArgsAndClasspath(t, d, GetExpectedArgsFileContent(), expectedCp) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -75,8 +80,10 @@ func TestJibClasspathFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + + expected := append(GetMinimalExpectedArgsWithoutCP(), "--class-path", expectedCp) + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJibMainClassFile(t *testing.T) { @@ -93,13 +100,13 @@ func TestJibMainClassFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() f := createJibMainClassFile() defer os.Remove(f.Name()) - expectedArgs := GetMinimalExpectedArgsWithAppMainClassFile() + + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -107,8 +114,8 @@ func TestJibMainClassFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, JibMainClass))) } func TestJibClasspathFileAndMainClassFile(t *testing.T) { @@ -125,15 +132,16 @@ func TestJibClasspathFileAndMainClassFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() f1 := createJibClasspathFile() defer os.Remove(f1.Name()) f2 := createJibMainClassFile() defer os.Remove(f2.Name()) - expectedArgs := GetMinimalExpectedArgsWithAppClasspathFileAndMainClassFile() + + expectedCp := JibClassPath + ":" + GetOperatorClasspathWithUtilsDir(ensureTestUtilsDir(t)) + verifyConfigFilesWithArgsAndClasspath(t, d, GetExpectedArgsFileContent(), expectedCp) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -141,8 +149,11 @@ func TestJibClasspathFileAndMainClassFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(GetMinimalExpectedArgsWithoutCP(), "--class-path", expectedCp) + expected = ReplaceArg(expected, coh.DefaultMain, JibMainClass) + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) + // g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.tangosol.net.DefaultCacheServer"))) } func createJibClasspathFile() *os.File { @@ -152,7 +163,7 @@ func createJibClasspathFile() *os.File { os.Exit(1) } - _, err = f.WriteString(fmt.Sprintf("%s/classpath/*:%s/libs/*", TestAppDir, TestAppDir)) + _, err = f.WriteString(JibClassPath) if err != nil { fmt.Print(err) os.Exit(1) @@ -173,7 +184,7 @@ func createJibMainClassFile() *os.File { os.Exit(1) } - _, err = f.WriteString("com.tangosol.net.DefaultCacheServer") + _, err = f.WriteString(JibMainClass) if err != nil { fmt.Print(err) os.Exit(1) diff --git a/pkg/runner/runner_jvm_memory_test.go b/pkg/runner/runner_jvm_memory_test.go index 44974b559..485c14bd0 100644 --- a/pkg/runner/runner_jvm_memory_test.go +++ b/pkg/runner/runner_jvm_memory_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -31,11 +31,10 @@ func TestJvmHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialHeapSize=10g", "-XX:MaxHeapSize=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialHeapSize=10g", "-XX:MaxHeapSize=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,8 +42,8 @@ func TestJvmHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialHeapSize=10g", "-XX:MaxHeapSize=10g"))) } func TestJvmInitialHeapSize(t *testing.T) { @@ -63,11 +62,10 @@ func TestJvmInitialHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialHeapSize=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialHeapSize=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -75,8 +73,8 @@ func TestJvmInitialHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialHeapSize=10g"))) } func TestJvmMaxHeapSize(t *testing.T) { @@ -95,11 +93,10 @@ func TestJvmMaxHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxHeapSize=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxHeapSize=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -107,8 +104,8 @@ func TestJvmMaxHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxHeapSize=10g"))) } func TestJvmHeapSizeOverridesInitialAndMaxHeapSize(t *testing.T) { @@ -129,11 +126,10 @@ func TestJvmHeapSizeOverridesInitialAndMaxHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialHeapSize=5g", "-XX:MaxHeapSize=5g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialHeapSize=5g", "-XX:MaxHeapSize=5g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -141,8 +137,8 @@ func TestJvmHeapSizeOverridesInitialAndMaxHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialHeapSize=5g", "-XX:MaxHeapSize=5g"))) } func TestJvmMaxRam(t *testing.T) { @@ -161,11 +157,10 @@ func TestJvmMaxRam(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxRAM=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxRAM=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -173,8 +168,8 @@ func TestJvmMaxRam(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxRAM=10g"))) } func TestJvmRamPercent(t *testing.T) { @@ -194,12 +189,11 @@ func TestJvmRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialRAMPercentage=5.500", - "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -207,8 +201,9 @@ func TestJvmRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500"))) } func TestJvmInitialRamPercent(t *testing.T) { @@ -228,11 +223,10 @@ func TestJvmInitialRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -240,8 +234,8 @@ func TestJvmInitialRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialRAMPercentage=5.500"))) } func TestJvmMaxRamPercent(t *testing.T) { @@ -261,11 +255,10 @@ func TestJvmMaxRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -273,8 +266,8 @@ func TestJvmMaxRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxRAMPercentage=5.500"))) } func TestJvmMinRamPercent(t *testing.T) { @@ -294,11 +287,10 @@ func TestJvmMinRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MinRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MinRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -306,8 +298,8 @@ func TestJvmMinRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MinRAMPercentage=5.500"))) } func TestJvmRamPercentOverridesInitialMaxAndMin(t *testing.T) { @@ -333,12 +325,11 @@ func TestJvmRamPercentOverridesInitialMaxAndMin(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialRAMPercentage=5.500", - "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -346,8 +337,9 @@ func TestJvmRamPercentOverridesInitialMaxAndMin(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500"))) } func TestJvmStackSize(t *testing.T) { @@ -366,11 +358,10 @@ func TestJvmStackSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Xss500k")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Xss500k") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -378,8 +369,8 @@ func TestJvmStackSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Xss500k"))) } func TestJvmMetaspaceSize(t *testing.T) { @@ -398,11 +389,10 @@ func TestJvmMetaspaceSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MetaspaceSize=5g", "-XX:MaxMetaspaceSize=5g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MetaspaceSize=5g", "-XX:MaxMetaspaceSize=5g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -410,8 +400,9 @@ func TestJvmMetaspaceSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, + "-XX:MetaspaceSize=5g", "-XX:MaxMetaspaceSize=5g"))) } func TestJvmDirectMemorySize(t *testing.T) { @@ -430,11 +421,10 @@ func TestJvmDirectMemorySize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxDirectMemorySize=5g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxDirectMemorySize=5g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -442,8 +432,8 @@ func TestJvmDirectMemorySize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxDirectMemorySize=5g"))) } func TestJvmNativeMemoryTracking(t *testing.T) { @@ -462,11 +452,11 @@ func TestJvmNativeMemoryTracking(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:NativeMemoryTracking="), "-XX:NativeMemoryTracking=detail") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:NativeMemoryTracking="), "-XX:NativeMemoryTracking=detail") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -474,8 +464,9 @@ func TestJvmNativeMemoryTracking(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:NativeMemoryTracking="), "-XX:NativeMemoryTracking=detail") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmOOMHeapDumpOff(t *testing.T) { @@ -496,11 +487,11 @@ func TestJvmOOMHeapDumpOff(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-XX:+HeapDumpOnOutOfMemoryError") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-XX:+HeapDumpOnOutOfMemoryError") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -508,8 +499,9 @@ func TestJvmOOMHeapDumpOff(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+HeapDumpOnOutOfMemoryError") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmOOMExitOff(t *testing.T) { @@ -530,11 +522,11 @@ func TestJvmOOMExitOff(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-XX:+ExitOnOutOfMemoryError") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-XX:+ExitOnOutOfMemoryError") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -542,6 +534,7 @@ func TestJvmOOMExitOff(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+ExitOnOutOfMemoryError") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } diff --git a/pkg/runner/runner_jvm_test.go b/pkg/runner/runner_jvm_test.go index 5ff5a888b..8f94b16eb 100644 --- a/pkg/runner/runner_jvm_test.go +++ b/pkg/runner/runner_jvm_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -29,11 +29,10 @@ func TestJvmArgsEmpty(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -41,8 +40,8 @@ func TestJvmArgsEmpty(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestJvmArgs(t *testing.T) { @@ -59,11 +58,10 @@ func TestJvmArgs(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dfoo=foo-value", "-Dbar=bar-value")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dfoo=foo-value", "-Dbar=bar-value") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -71,8 +69,8 @@ func TestJvmArgs(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dfoo=foo-value", "-Dbar=bar-value"))) } func TestJvmArgsWithEnvExpansion(t *testing.T) { @@ -93,11 +91,10 @@ func TestJvmArgsWithEnvExpansion(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dfoo=foo-value", "-Dbar=bar-value")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dfoo=foo-value", "-Dbar=bar-value") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -105,8 +102,8 @@ func TestJvmArgsWithEnvExpansion(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dfoo=foo-value", "-Dbar=bar-value"))) } func TestJvmUseContainerLimitsFalse(t *testing.T) { @@ -123,11 +120,11 @@ func TestJvmUseContainerLimitsFalse(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-XX:+UseContainerSupport") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-XX:+UseContainerSupport") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -135,8 +132,9 @@ func TestJvmUseContainerLimitsFalse(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgsWith(t), "-XX:+UseContainerSupport") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmUseContainerLimitsTrue(t *testing.T) { @@ -153,11 +151,10 @@ func TestJvmUseContainerLimitsTrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -165,8 +162,8 @@ func TestJvmUseContainerLimitsTrue(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestJvmGarbageCollectorG1(t *testing.T) { @@ -185,11 +182,11 @@ func TestJvmGarbageCollectorG1(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseG1GC") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseG1GC") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -197,8 +194,9 @@ func TestJvmGarbageCollectorG1(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseG1GC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmGarbageCollectorCMS(t *testing.T) { @@ -217,11 +215,11 @@ func TestJvmGarbageCollectorCMS(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseConcMarkSweepGC") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseConcMarkSweepGC") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -229,8 +227,9 @@ func TestJvmGarbageCollectorCMS(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseConcMarkSweepGC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmGarbageCollectorParallel(t *testing.T) { @@ -249,11 +248,11 @@ func TestJvmGarbageCollectorParallel(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseParallelGC") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseParallelGC") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -261,8 +260,9 @@ func TestJvmGarbageCollectorParallel(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseParallelGC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { @@ -281,11 +281,7 @@ func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), + expectedArgs := append(GetExpectedArgsFileContent(), "-verbose:gc", "-XX:+PrintGCDetails", "-XX:+PrintGCTimeStamps", @@ -294,14 +290,26 @@ func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { "-XX:+PrintGCApplicationStoppedTime", "-XX:+PrintGCApplicationConcurrentTime") + verifyConfigFilesWithArgs(t, d, expectedArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, + "-verbose:gc", + "-XX:+PrintGCDetails", + "-XX:+PrintGCTimeStamps", + "-XX:+PrintHeapAtGC", + "-XX:+PrintTenuringDistribution", + "-XX:+PrintGCApplicationStoppedTime", + "-XX:+PrintGCApplicationConcurrentTime"))) } func TestJvmGarbageCollectorArgsEmpty(t *testing.T) { @@ -320,11 +328,10 @@ func TestJvmGarbageCollectorArgsEmpty(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -332,8 +339,8 @@ func TestJvmGarbageCollectorArgsEmpty(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestJvmGarbageCollectorArgs(t *testing.T) { @@ -352,11 +359,10 @@ func TestJvmGarbageCollectorArgs(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:Arg1", "-XX:Arg2")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:Arg1", "-XX:Arg2") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -364,6 +370,6 @@ func TestJvmGarbageCollectorArgs(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:Arg1", "-XX:Arg2"))) } diff --git a/pkg/runner/runner_persistence_test.go b/pkg/runner/runner_persistence_test.go index cbbb30e0a..70880e05d 100644 --- a/pkg/runner/runner_persistence_test.go +++ b/pkg/runner/runner_persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package runner import ( . "github.com/onsi/gomega" coh "github.com/oracle/coherence-operator/api/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" "testing" @@ -30,12 +31,12 @@ func TestServerWithPersistenceMode(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.distributed.persistence-mode="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.distributed.persistence-mode="), "-Dcoherence.distributed.persistence-mode=active") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,46 +44,72 @@ func TestServerWithPersistenceMode(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-Dcoherence.distributed.persistence-mode=") + expected = append(expected, "-Dcoherence.distributed.persistence-mode=active") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestServerWithPersistenceDirectory(t *testing.T) { g := NewGomegaWithT(t) - args := []string{"server", "--dry-run"} - env := map[string]string{ - coh.EnvVarCohPersistenceDir: coh.VolumeMountPathPersistence, + d := &coh.Coherence{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: coh.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: coh.CoherenceResourceSpec{ + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarCohPersistenceDir, + Value: coh.VolumeMountPathPersistence, + }, + }, + }, + }, } - expectedCommand := GetJavaCommand() + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.distributed.persistence.base.dir="+coh.VolumeMountPathPersistence)) + env := EnvVarsFromDeployment(t, d) + + args := []string{"server", "--dry-run"} e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ContainElement("-Dcoherence.distributed.persistence.base.dir=" + coh.VolumeMountPathPersistence)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dcoherence.distributed.persistence.base.dir="+coh.VolumeMountPathPersistence))) } func TestServerWithSnapshotDirectory(t *testing.T) { g := NewGomegaWithT(t) - args := []string{"server", "--dry-run"} - env := map[string]string{ - coh.EnvVarCohSnapshotDir: coh.VolumeMountPathSnapshots, + d := &coh.Coherence{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: coh.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: coh.CoherenceResourceSpec{ + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarCohSnapshotDir, + Value: coh.VolumeMountPathSnapshots, + }, + }, + }, + }, } - expectedCommand := GetJavaCommand() + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.distributed.persistence.snapshot.dir="+coh.VolumeMountPathSnapshots)) + + env := EnvVarsFromDeployment(t, d) + args := []string{"server", "--dry-run"} e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ContainElement("-Dcoherence.distributed.persistence.snapshot.dir=" + coh.VolumeMountPathSnapshots)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dcoherence.distributed.persistence.snapshot.dir="+coh.VolumeMountPathSnapshots))) } diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index 7dcb8b05c..8195ac430 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -12,7 +12,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" "os" - "strings" "testing" ) @@ -30,11 +29,13 @@ func TestSpringBootApplication(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootArgs(SpringBootMain2) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -42,8 +43,8 @@ func TestSpringBootApplication(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2))) } func TestSpringBoot3Application(t *testing.T) { @@ -60,11 +61,13 @@ func TestSpringBoot3Application(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootArgs(SpringBootMain3) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -72,8 +75,8 @@ func TestSpringBoot3Application(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, SpringBootMain3))) } func TestSpringBootFatJarApplication(t *testing.T) { @@ -92,11 +95,13 @@ func TestSpringBootFatJarApplication(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgs(jar, SpringBootMain2) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -104,8 +109,9 @@ func TestSpringBootFatJarApplication(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), "--class-path", "/apps/lib/foo.jar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestSpringBoot3FatJarApplication(t *testing.T) { @@ -124,11 +130,13 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgs(jar, SpringBootMain3) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -136,8 +144,9 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain3), "--class-path", "/apps/lib/foo.jar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestSpringBootFatJarConsole(t *testing.T) { @@ -156,23 +165,13 @@ func TestSpringBootFatJarConsole(t *testing.T) { }, } + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) + args := []string{"console", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgsForRole(jar, ConsoleMain, "") - expectedArgs = ReplaceArg(expectedArgs, "-XX:NativeMemoryTracking=summary", "-XX:NativeMemoryTracking=off") - expectedArgs = ReplaceArg(expectedArgs, "-Dcoherence.health.http.port=6676", "-Dcoherence.health.http.port=0") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.operator.health.port=6676") - expectedArgs = append(expectedArgs, "-Dcoherence.localport.adjust=true", - "-Dcoherence.metrics.http.enabled=false", - "-Dcoherence.management.http=none", - "-Dcoherence.management.http.port=0", - "-Dcoherence.metrics.http.port=0", - "-Dcoherence.operator.health.enabled=false", - "-Dcoherence.health.http.port=0", - "-Dcoherence.grpc.enabled=false", - "-Dcoherence.operator.health.port=0") + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -180,7 +179,22 @@ func TestSpringBootFatJarConsole(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), "--class-path", jar) + expectedArgs = append(expectedArgs, "-Dcoherence.role=console", + "-Dloader.main=com.tangosol.net.CacheFactory", + "-Dcoherence.distributed.localstorage=false", + "-Dcoherence.localport.adjust=true", + "-Dcoherence.management.http=none", + "-Dcoherence.management.http.port=0", + "-Dcoherence.metrics.http.enabled=false", + "-Dcoherence.metrics.http.port=0", + "-Dcoherence.operator.health.enabled=false", + "-Dcoherence.health.http.port=0", + "-Dcoherence.grpc.enabled=false", + "-XX:NativeMemoryTracking=off") + g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -200,24 +214,13 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { }, } + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) + args := []string{"console", "--dry-run", "--", "foo", "bar"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgsForRole(jar, ConsoleMain, "") - expectedArgs = ReplaceArg(expectedArgs, "-XX:NativeMemoryTracking=summary", "-XX:NativeMemoryTracking=off") - expectedArgs = ReplaceArg(expectedArgs, "-Dcoherence.health.http.port=6676", "-Dcoherence.health.http.port=0") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.operator.health.port=6676") - expectedArgs = append(expectedArgs, "-Dcoherence.localport.adjust=true", - "-Dcoherence.metrics.http.enabled=false", - "-Dcoherence.management.http=none", - "-Dcoherence.management.http.port=0", - "-Dcoherence.metrics.http.port=0", - "-Dcoherence.operator.health.enabled=false", - "-Dcoherence.grpc.enabled=false", - "-Dcoherence.operator.health.port=0", - "-Dcoherence.health.http.port=0", - "foo", "bar") + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -225,7 +228,23 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), "--class-path", jar) + expectedArgs = append(expectedArgs, "-Dcoherence.role=console", + "-Dloader.main=com.tangosol.net.CacheFactory", + "-Dcoherence.distributed.localstorage=false", + "-Dcoherence.localport.adjust=true", + "-Dcoherence.management.http=none", + "-Dcoherence.management.http.port=0", + "-Dcoherence.metrics.http.enabled=false", + "-Dcoherence.metrics.http.port=0", + "-Dcoherence.operator.health.enabled=false", + "-Dcoherence.health.http.port=0", + "-Dcoherence.grpc.enabled=false", + "-XX:NativeMemoryTracking=off", + "foo", "bar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -246,11 +265,13 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedSpringBootFatJarArgs(jar, SpringBootMain2), "-Dloader.main=foo.Bar") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -258,7 +279,11 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), + "--class-path", jar, "-Dloader.main=foo.Bar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -279,10 +304,13 @@ func TestSpringBootBuildpacks(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd := ensureTestUtilsDir(t) + expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := getBuildpackLauncher() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -290,39 +318,27 @@ func TestSpringBootBuildpacks(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal("")) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(getBuildpackLauncher())) g.Expect(len(e.OsCmd.Args)).To(Equal(4)) g.Expect(e.OsCmd.Args[0]).To(Equal(coh.DefaultCnbpLauncher)) g.Expect(e.OsCmd.Args[1]).To(Equal("java")) g.Expect(e.OsCmd.Args[3]).To(Equal(SpringBootMain2)) - - g.Expect(e.OsCmd.Args[2]).To(HavePrefix("@")) - fileName := e.OsCmd.Args[2][1:] - data, err := os.ReadFile(fileName) - g.Expect(err).NotTo(HaveOccurred()) - - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" - } - - actualOpts := strings.Split(string(data), "\n") - expectedOpts := AppendCommonExpectedArgs([]string{"-Dloader.path=" + cp}) - g.Expect(actualOpts).To(ConsistOf(expectedOpts)) } -func GetMinimalExpectedSpringBootArgs(main string) []string { - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ",/coherence-operator/utils/config" +func GetMinimalExpectedSpringBootArgs(t *testing.T, main string) []string { + utils := ensureTestUtilsDir(t) + + cp := utils + "/lib/coherence-operator.jar" + cfg := utils + "config" + if _, err := os.Stat(cfg); err == nil { + cp = cp + "," + cfg } args := []string{ GetJavaArg(), "-Dloader.path=" + cp, } - args = append(AppendCommonExpectedArgs(args), main) - return args + return append(AppendCommonExpectedArgs(args), main) } func GetMinimalExpectedSpringBootFatJarArgs(jar, main string) []string { @@ -330,40 +346,15 @@ func GetMinimalExpectedSpringBootFatJarArgs(jar, main string) []string { } func GetMinimalExpectedSpringBootFatJarArgsWithMain(jar, springMain, main string) []string { - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ",/coherence-operator/utils/config" - } args := []string{ GetJavaArg(), "--class-path", jar, - "-Dloader.path=" + cp, } - - if main != "" { - args = append(args, "-Dloader.main="+main) - } - - return append(AppendCommonExpectedArgs(args), springMain) + return append(args, springMain) } -func GetMinimalExpectedSpringBootFatJarArgsForRole(jar, main, role string) []string { - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ",/coherence-operator/utils/config" - } - args := []string{ - GetJavaArg(), - "--class-path", - jar, - "-Dloader.path=" + cp, - "-Dcoherence.distributed.localstorage=false", - } - - if main != "" { - args = append(args, "-Dloader.main="+main) - } - +func GetMinimalExpectedSpringBootFatJarArgsForRole(t *testing.T, jar, main, role string) []string { + args := GetMinimalExpectedSpringBootArgs(t, main) return append(AppendCommonExpectedNonServerArgs(args, role), SpringBootMain2) } diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 83d89f892..2cd2d093b 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -10,6 +10,7 @@ import ( "fmt" . "github.com/onsi/gomega" coh "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/test/e2e/helper" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" @@ -26,11 +27,10 @@ func TestMinimalDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test"}, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -38,8 +38,8 @@ func TestMinimalDeployment(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { @@ -56,12 +56,13 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.override="), - "-Dcoherence.override=k8s-coherence-override.xml") + //expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.override="), "-Dcoherence.override=k8s-coherence-override.xml") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -70,11 +71,7 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) -} - -func GetMinimalExpectedArgsWithoutPrefix(prefix string) []string { - return RemoveArgWithPrefix(GetMinimalExpectedArgs(), prefix) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func ReplaceArg(args []string, toReplace, replaceWith string) []string { @@ -105,25 +102,49 @@ func GetJavaArg() string { return javaCmd } -func GetMinimalExpectedArgs() []string { - cp := fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar", - TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) +func GetMinimalExpectedArgs(t *testing.T) []string { + return GetMinimalExpectedArgsWithWorkingDir(t, TestAppDir) +} - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" +func GetMinimalExpectedArgsWithWorkingDir(t *testing.T, wd string) []string { + cp := "" + if wd == TestAppDir { + cp = fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar:", + TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) } - args := []string{GetJavaArg(), "--class-path", cp} + utils := ensureTestUtilsDir(t) + jar := fmt.Sprintf("%s/lib/coherence-operator.jar", utils) + cfg := fmt.Sprintf(":%s/config", utils) + cp = cp + jar + if _, err := os.Stat(cfg); err == nil { + cp = cp + ":" + cfg + } + args := []string{GetJavaArg(), "--class-path", cp} return append(AppendCommonExpectedArgs(args), "com.oracle.coherence.k8s.Main", "$DEFAULT$") } +func GetExpectedArgsWithoutPrefix(t *testing.T, prefix ...string) []string { + args := GetMinimalExpectedArgs(t) + for _, p := range prefix { + args = RemoveArgWithPrefix(args, p) + } + return args +} + +func GetMinimalExpectedArgsWith(t *testing.T, args ...string) []string { + return append(GetMinimalExpectedArgs(t), args...) +} + +func GetMinimalExpectedArgsWithMainClass(t *testing.T, clz string) []string { + return append(RemoveArg(GetMinimalExpectedArgs(t), coh.DefaultMain), clz) +} + func GetMinimalExpectedArgsWithoutCP() []string { - args := make([]string, 0) - args = append(args, GetJavaArg()) + args := []string{GetJavaArg()} return append(AppendCommonExpectedArgs(args), "com.oracle.coherence.k8s.Main", "$DEFAULT$") @@ -141,6 +162,36 @@ func GetMinimalExpectedArgsWithoutAppClasspath() []string { "$DEFAULT$") } +func GetExpectedClasspathWithUtilsDir(utils string) string { + cp := fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar", + TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) + return cp + ":" + GetOperatorClasspathWithUtilsDir(utils) +} + +func GetOperatorClasspathWithUtilsDir(utils string) string { + cp := utils + "/lib/coherence-operator.jar" + cfg := utils + "/config" + if _, err := os.Stat(cfg); err == nil { + cp = cp + ":" + cfg + } + return cp +} + +func GetExpectedArgsFileContent() []string { + return GetExpectedArgsFileContentWith() +} + +func GetExpectedArgsFileContentWith(args ...string) []string { + var expected []string + expected = AppendCommonExpectedArgs(expected) + expected = append(expected, args...) + return expected +} + +func GetExpectedArgsFileContentWithoutPrefix(prefix string) []string { + return RemoveArgWithPrefix(GetExpectedArgsFileContent(), prefix) +} + func AppendCommonExpectedArgs(args []string) []string { return append(AppendCommonExpectedNonServerArgs(args, "test"), "-XshowSettings:all", @@ -210,14 +261,20 @@ func GetJavaCommand() string { return "java" } -func EnvVarsFromDeployment(d *coh.Coherence) map[string]string { - return EnvVarsFromDeploymentWithSkipSite(d, true) +func EnvVarsFromDeployment(t *testing.T, d *coh.Coherence) map[string]string { + return EnvVarsForContainerWithSkipSite(t, d, coh.ContainerNameCoherence, true) +} + +func EnvVarsFromDeploymentWithSkipSite(t *testing.T, d *coh.Coherence, skipSite bool) map[string]string { + return EnvVarsForContainerWithSkipSite(t, d, coh.ContainerNameCoherence, skipSite) +} + +func EnvVarsForConfigContainerWithSkipSite(t *testing.T, d *coh.Coherence, skipSite bool) map[string]string { + return EnvVarsForContainerWithSkipSite(t, d, coh.ContainerNameOperatorConfig, skipSite) } -func EnvVarsFromDeploymentWithSkipSite(d *coh.Coherence, skipSite bool) map[string]string { +func EnvVarsForContainerWithSkipSite(t *testing.T, d *coh.Coherence, containerName string, skipSite bool) map[string]string { envVars := make(map[string]string) - envVars[coh.EnvVarCohAppDir] = TestAppDir - envVars[coh.EnvVarCohSkipSite] = fmt.Sprintf("%t", skipSite) if d.Spec.JVM == nil { d.Spec.JVM = &coh.JVMSpec{} @@ -225,12 +282,102 @@ func EnvVarsFromDeploymentWithSkipSite(d *coh.Coherence, skipSite bool) map[stri res := d.Spec.CreateStatefulSetResource(d) sts := res.Spec.(*appsv1.StatefulSet) - c := coh.FindContainer(coh.ContainerNameCoherence, sts) + c := coh.FindContainer(containerName, sts) + if c == nil { + c = coh.FindInitContainer(containerName, sts) + } + if c == nil { + return nil + } + for _, ev := range c.Env { if ev.ValueFrom == nil { envVars[ev.Name] = ev.Value } } + if d.Spec.Application != nil && d.Spec.Application.WorkingDir != nil && *d.Spec.Application.WorkingDir != "" { + envVars[coh.EnvVarCohAppDir] = *d.Spec.Application.WorkingDir + } else { + envVars[coh.EnvVarCohAppDir] = TestAppDir + } + + dir := ensureTestUtilsDir(t) + envVars[coh.EnvVarCohUtilDir] = dir + envVars[coh.EnvVarCohCtlHome] = dir + envVars[coh.EnvVarCohSkipSite] = fmt.Sprintf("%t", skipSite) + return envVars } + +func ensureTestUtilsDir(t *testing.T) string { + g := NewGomegaWithT(t) + dir, err := helper.EnsureLogsDir(t.Name()) + g.Expect(err).NotTo(HaveOccurred()) + return dir +} + +func verifyConfigFilesWithArgs(t *testing.T, d *coh.Coherence, expectedArgs []string) { + verifyConfigFilesWithArgsWithSkipSite(t, d, expectedArgs, true) +} + +func verifyConfigFilesWithArgsWithSkipSite(t *testing.T, d *coh.Coherence, expectedArgs []string, skipSite bool) { + dir := ensureTestUtilsDir(t) + expectedCP := GetExpectedClasspathWithUtilsDir(dir) + verifyConfigFilesWithArgsAndClasspathWithSkipSite(t, d, expectedArgs, expectedCP, skipSite) +} + +func verifyConfigFilesWithArgsAndClasspath(t *testing.T, d *coh.Coherence, expectedArgs []string, expectedCP string) { + verifyConfigFilesWithArgsAndClasspathWithSkipSite(t, d, expectedArgs, expectedCP, true) +} + +func verifyConfigFilesWithArgsAndClasspathWithSkipSite(t *testing.T, d *coh.Coherence, expectedArgs []string, expectedCP string, skipSite bool) { + cfgEnv := EnvVarsForConfigContainerWithSkipSite(t, d, skipSite) + verifyConfigFilesWithArgsAndClasspathUsingEnv(t, cfgEnv, expectedArgs, expectedCP) +} + +func verifyConfigFilesWithArgsAndClasspathUsingEnv(t *testing.T, cfgEnv map[string]string, expectedArgs []string, expectedCP string) { + var err error + + g := NewGomegaWithT(t) + dir := ensureTestUtilsDir(t) + cfgEnv[coh.EnvVarCohUtilDir] = dir + cfgEnv[coh.EnvVarCohCtlHome] = dir + + _, err = ExecuteWithArgsAndNewViper(cfgEnv, []string{coh.RunnerConfig}) + g.Expect(err).NotTo(HaveOccurred()) + + cpName := fmt.Sprintf("%s/%s", dir, coh.OperatorClasspathFile) + _, err = os.Stat(cpName) + g.Expect(err).NotTo(HaveOccurred()) + dataCP, err := os.ReadFile(cpName) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(dataCP).NotTo(BeNil()) + cp := string(dataCP) + g.Expect(cp).To(Equal(expectedCP)) + + argsName := fmt.Sprintf("%s/%s", dir, coh.OperatorJvmArgsFile) + _, err = os.Stat(argsName) + g.Expect(err).NotTo(HaveOccurred()) + dataArgs, err := os.ReadFile(argsName) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(dataArgs).NotTo(BeNil()) + + args := filterNonEmptyStringArray(strings.Split(string(dataArgs), "\n")) + + g.Expect(args).To(ConsistOf(expectedArgs)) +} + +func filterNonEmptyStringArray(ss []string) (ret []string) { + test := func(s string) bool { return s != "" } + return filterStringArray(ss, test) +} + +func filterStringArray(ss []string, test func(string) bool) (ret []string) { + for _, s := range ss { + if test(s) { + ret = append(ret, s) + } + } + return +} diff --git a/pkg/runner/suite_test.go b/pkg/runner/suite_test.go index 61bd05100..7d5ae3087 100644 --- a/pkg/runner/suite_test.go +++ b/pkg/runner/suite_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -10,6 +10,7 @@ import ( "fmt" v1 "github.com/oracle/coherence-operator/api/v1" "os" + ctrl "sigs.k8s.io/controller-runtime" "testing" ) @@ -84,6 +85,8 @@ func TestMain(m *testing.M) { os.Exit(1) } + log = ctrl.Log.WithName("runner") + exitCode := m.Run() _ = os.RemoveAll(TestAppDir) From a502f1f72462f6ae455710b4e323e3c702de82fe Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 06:59:12 +0300 Subject: [PATCH 14/33] Capture all container logs for tests --- test/e2e/helper/e2e-helpers.go | 48 ++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/test/e2e/helper/e2e-helpers.go b/test/e2e/helper/e2e-helpers.go index db1d7cdae..40bc52119 100644 --- a/test/e2e/helper/e2e-helpers.go +++ b/test/e2e/helper/e2e-helpers.go @@ -903,30 +903,38 @@ func DumpPodLog(ctx TestContext, pod *corev1.Pod, directory string) { } ctx.Logger.Info("Capturing Pod logs for " + pod.Name) + pathSep := string(os.PathSeparator) + name := logs + pathSep + directory + err = os.MkdirAll(name, os.ModePerm) + for _, container := range pod.Spec.InitContainers { + DumpContainerLogs(ctx, container, pod, name) + } for _, container := range pod.Spec.Containers { - var err error - res := ctx.KubeClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Container: container.Name}) - s, err := res.Stream(ctx.Context) + DumpContainerLogs(ctx, container, pod, name) + } +} + +// DumpContainerLogs dumps the logs for a container +func DumpContainerLogs(ctx TestContext, container corev1.Container, pod *corev1.Pod, name string) { + var err error + pathSep := string(os.PathSeparator) + res := ctx.KubeClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Container: container.Name}) + s, err := res.Stream(ctx.Context) + if err == nil { if err == nil { - name := logs + pathSep + directory - err = os.MkdirAll(name, os.ModePerm) - if err == nil { - suffix := 0 - logName := fmt.Sprintf("%s%s%s(%s).log", name, pathSep, pod.Name, container.Name) + suffix := 0 + logName := fmt.Sprintf("%s%s%s(%s).log", name, pathSep, pod.Name, container.Name) + _, err = os.Stat(logName) + for err == nil { + suffix++ + logName = fmt.Sprintf("%s%s%s(%s)-%d.log", name, pathSep, pod.Name, container.Name, suffix) _, err = os.Stat(logName) - for err == nil { - suffix++ - logName = fmt.Sprintf("%s%s%s(%s)-%d.log", name, pathSep, pod.Name, container.Name, suffix) - _, err = os.Stat(logName) - } - out, err := os.Create(logName) - if err == nil { - if _, err = io.Copy(out, s); err != nil { - ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) - } - } else { + } + out, err := os.Create(logName) + if err == nil { + if _, err = io.Copy(out, s); err != nil { ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } } else { @@ -935,6 +943,8 @@ func DumpPodLog(ctx TestContext, pod *corev1.Pod, directory string) { } else { ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } + } else { + ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } } From c4559cd747355986b0c471c83c98e5d2e5950821 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 07:33:24 +0300 Subject: [PATCH 15/33] move constants --- api/v1/coherenceresourcespec_types.go | 10 ++-- api/v1/common_test.go | 16 ++++--- api/v1/constants.go | 13 +++++ pkg/runner/cmd_config.go | 38 +++++++-------- pkg/runner/cmd_console.go | 7 +-- pkg/runner/cmd_jshell.go | 3 +- pkg/runner/cmd_node_labels.go | 5 +- pkg/runner/cmd_query_plus.go | 7 +-- pkg/runner/cmd_server.go | 8 ++-- pkg/runner/cmd_sleep.go | 8 ++-- pkg/runner/run_details.go | 8 ++-- pkg/runner/runner.go | 56 +++++----------------- pkg/runner/runner_application_type_test.go | 16 +++---- pkg/runner/runner_spring_test.go | 50 +++++++------------ test/e2e/helper/e2e-helpers.go | 29 ++++++----- 15 files changed, 121 insertions(+), 153 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index bdbabb071..aba76db6b 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -887,14 +887,14 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe cmd := []string{"java"} if in.IsSpringBoot() { - cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) - cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) + cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) + cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) } else { - cmd = append(cmd, "--class-path", fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorClasspathFile)) - cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) + cmd = append(cmd, "--class-path", fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorClasspathFile)) + cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) } - cmd = append(cmd, fmt.Sprintf("@%s%c%s", VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) + cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) if in.Application != nil { cmd = append(cmd, in.Application.Args...) diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 744c72219..d2b2e4b78 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -29,6 +29,10 @@ import ( const ( testCoherenceImage = "oracle/coherence-ce:1.2.3" testOperatorImage = "oracle/operator:1.2.3" + + actualFilePattern = coh.FileNamePattern + "-Actual.json" + expectedFilePattern = coh.FileNamePattern + "-Expected.json" + diffFilePattern = coh.FileNamePattern + "-Diff.txt" ) // Returns a pointer to an int32 @@ -118,13 +122,13 @@ func assertStatefulSet(t *testing.T, res coh.Resource, stsExpected *appsv1.State // Dump the json for the actual StatefulSet for debugging failures jsonActual, err := json.MarshalIndent(stsActual, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Actual.json", dir, os.PathSeparator, stsActual.Name), jsonActual, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(actualFilePattern, dir, os.PathSeparator, stsActual.Name), jsonActual, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) // Dump the json for the expected StatefulSet for debugging failures jsonExpected, err := json.MarshalIndent(stsExpected, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Expected.json", dir, os.PathSeparator, stsActual.Name), jsonExpected, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(expectedFilePattern, dir, os.PathSeparator, stsActual.Name), jsonExpected, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) assertEnvironmentVariables(t, stsActual, stsExpected) @@ -134,7 +138,7 @@ func assertStatefulSet(t *testing.T, res coh.Resource, stsExpected *appsv1.State msg := "StatefulSets not equal:" if len(diffs) > 0 { // Dump the diffs - err = os.WriteFile(fmt.Sprintf("%s%c%s-Diff.txt", dir, os.PathSeparator, stsActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) + err = os.WriteFile(fmt.Sprintf(diffFilePattern, dir, os.PathSeparator, stsActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) for _, diff := range diffs { msg = msg + "\n" + diff @@ -173,13 +177,13 @@ func assertJob(t *testing.T, res coh.Resource, expected *batchv1.Job) { // Dump the json for the actual StatefulSet for debugging failures jsonActual, err := json.MarshalIndent(jobActual, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Actual.json", dir, os.PathSeparator, jobActual.Name), jsonActual, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(actualFilePattern, dir, os.PathSeparator, jobActual.Name), jsonActual, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) // Dump the json for the expected StatefulSet for debugging failures jsonExpected, err := json.MarshalIndent(expected, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Expected.json", dir, os.PathSeparator, jobActual.Name), jsonExpected, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(expectedFilePattern, dir, os.PathSeparator, jobActual.Name), jsonExpected, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) assertEnvironmentVariablesForJob(t, jobActual, expected) @@ -188,7 +192,7 @@ func assertJob(t *testing.T, res coh.Resource, expected *batchv1.Job) { msg := "Jobs not equal:" if len(diffs) > 0 { // Dump the diffs - err = os.WriteFile(fmt.Sprintf("%s%c%s-Diff.txt", dir, os.PathSeparator, jobActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) + err = os.WriteFile(fmt.Sprintf(diffFilePattern, dir, os.PathSeparator, jobActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) for _, diff := range diffs { msg = msg + "\n" + diff diff --git a/api/v1/constants.go b/api/v1/constants.go index a2b45b3cb..799c69bd8 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -188,6 +188,11 @@ const ( // OperatorConfigDirSuffix is the suffix to append to the utils directory to locate the Operator config directory. OperatorConfigDirSuffix = "/config" + // FileNamePattern is a formatting pattern for a directory separator and file name + FileNamePattern = "%s%c%s" + // ArgumentFileNamePattern is a formatting pattern for a JDK argument fle name: directory separator and file name + ArgumentFileNamePattern = "@" + FileNamePattern + // DefaultReadinessPath is the default readiness endpoint path DefaultReadinessPath = "/ready" // DefaultLivenessPath is the default liveness endpoint path @@ -307,6 +312,10 @@ const ( AppTypeSpring2 = "spring" // AppTypeSpring3 is the argument to specify an exploded Spring Boot 3.x application. AppTypeSpring3 = "spring3" + // AppTypeOperator is the argument to specify running an Operator command. + AppTypeOperator = "operator" + // AppTypeJShell is the argument to specify a JShell application. + AppTypeJShell = "jshell" // DefaultMain is an indicator to run the default main class. DefaultMain = "$DEFAULT$" @@ -318,6 +327,10 @@ const ( SpringBootMain2 = "org.springframework.boot.loader.PropertiesLauncher" // SpringBootMain3 is the default Spring Boot 3.x main class name. SpringBootMain3 = "org.springframework.boot.loader.launch.PropertiesLauncher" + // ConsoleMain is the Coherence console main class + ConsoleMain = "com.tangosol.net.CacheFactory" + // QueryPlusMain is the main class to run Coherence Query Plus + QueryPlusMain = "com.tangosol.coherence.dslquery.QueryPlus" ) var ( diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index c99aa8470..8556a5254 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -72,7 +72,7 @@ func createsFiles(details *RunDetails, _ *cobra.Command) (bool, error) { // createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container func createClassPathFile(details *RunDetails) error { - cpFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) classpath := details.getClasspath() err := os.WriteFile(cpFile, []byte(classpath), os.ModePerm) if err != nil { @@ -85,7 +85,7 @@ func createClassPathFile(details *RunDetails) error { // createArgsFile will create the JVM args files for a Coherence Pod - typically this is run from an init-container func createArgsFile(details *RunDetails) error { args := details.GetArgs() - argFileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + argFileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) var buffer bytes.Buffer for _, arg := range args { @@ -101,7 +101,7 @@ func createArgsFile(details *RunDetails) error { // createSpringBootFile will create the SpringBoot JVM args files for a Coherence Pod - typically this is run from an init-container func createSpringBootFile(details *RunDetails) error { - argsFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) + argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) cp := strings.ReplaceAll(details.getClasspath(), ":", ",") var args string @@ -121,7 +121,7 @@ func createSpringBootFile(details *RunDetails) error { // createMainClassFile will create the file containing the main class name for a Coherence Pod - typically this is run from an init-container func createMainClassFile(details *RunDetails) error { - fileName := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorMainClassFile) + fileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorMainClassFile) var s string if details.InnerMainClass == "" || details.IsSpringBoot() { @@ -139,7 +139,7 @@ func createMainClassFile(details *RunDetails) error { func createCliConfig(details *RunDetails) error { home := details.getenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) - fileName := fmt.Sprintf("%s%c%s", home, os.PathSeparator, "cohctl.yaml") + fileName := fmt.Sprintf(v1.FileNamePattern, home, os.PathSeparator, "cohctl.yaml") cluster := details.Getenv(v1.EnvVarCohClusterName) port := details.Getenv(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohPortSuffix) @@ -186,7 +186,7 @@ func createCliConfig(details *RunDetails) error { // Configure the main class func populateMainClass(details *RunDetails) { - details.MainClass = ServerMain + details.MainClass = v1.ServerMain // If the main class environment variable is set then use that // otherwise run Coherence DefaultMain. @@ -217,33 +217,33 @@ func populateMainClass(details *RunDetails) { case found && !isSpring: // we have a main class specified, and we're not a Spring Boot app details.InnerMainClass = mc - case found && details.AppType == AppTypeSpring2: + case found && details.AppType == v1.AppTypeSpring2: // we have a main class and the app is Spring Boot 2.x // the main is PropertiesLauncher, - details.MainClass = SpringBootMain2 + details.MainClass = v1.SpringBootMain2 // the specified main class is set as a Spring loader property details.InnerMainClass = mc - case found && details.AppType == AppTypeSpring3: + case found && details.AppType == v1.AppTypeSpring3: // we have a main class and the app is Spring Boot 3.x // the main is PropertiesLauncher, - details.MainClass = SpringBootMain3 + details.MainClass = v1.SpringBootMain3 // the specified main class is set as a Spring loader property details.InnerMainClass = mc - case !found && details.AppType == AppTypeSpring2: + case !found && details.AppType == v1.AppTypeSpring2: // the app type is Spring Boot 2.x so main is PropertiesLauncher - details.MainClass = SpringBootMain2 - case !found && details.AppType == AppTypeSpring3: + details.MainClass = v1.SpringBootMain2 + case !found && details.AppType == v1.AppTypeSpring3: // the app type is Spring Boot 3.x so main is PropertiesLauncher - details.MainClass = SpringBootMain3 - case !found && details.AppType == AppTypeCoherence: + details.MainClass = v1.SpringBootMain3 + case !found && details.AppType == v1.AppTypeCoherence: // the app type is Coherence so main is DefaultMain - details.InnerMainClass = DefaultMain - case !found && details.AppType == AppTypeHelidon: + details.InnerMainClass = v1.DefaultMain + case !found && details.AppType == v1.AppTypeHelidon: // the app type is Helidon so main is the Helidon CDI starter - details.InnerMainClass = HelidonMain + details.InnerMainClass = v1.HelidonMain default: // no main or app type specified, use DefaultMain - details.InnerMainClass = DefaultMain + details.InnerMainClass = v1.DefaultMain } } diff --git a/pkg/runner/cmd_console.go b/pkg/runner/cmd_console.go index c3809512b..8f4299498 100644 --- a/pkg/runner/cmd_console.go +++ b/pkg/runner/cmd_console.go @@ -7,6 +7,7 @@ package runner import ( + v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -40,10 +41,10 @@ func console(details *RunDetails, args []string, v *viper.Viper) { loadConfigFiles(details) if details.IsSpringBoot() { - details.addArg("-Dloader.main=" + ConsoleMain) + details.addArg("-Dloader.main=" + v1.ConsoleMain) } else { - details.AppType = AppTypeJava - details.MainClass = ConsoleMain + details.AppType = v1.AppTypeJava + details.MainClass = v1.ConsoleMain } details.addArg("-Dcoherence.role=console") diff --git a/pkg/runner/cmd_jshell.go b/pkg/runner/cmd_jshell.go index 30420e7f4..95c92808b 100644 --- a/pkg/runner/cmd_jshell.go +++ b/pkg/runner/cmd_jshell.go @@ -7,6 +7,7 @@ package runner import ( + v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -37,7 +38,7 @@ func jShellCommand(v *viper.Viper) *cobra.Command { // Configure the runner to run a Coherence JShell console func jShell(details *RunDetails, args []string, v *viper.Viper) { - details.AppType = AppTypeJShell + details.AppType = v1.AppTypeJShell details.Command = CommandJShell loadConfigFiles(details) diff --git a/pkg/runner/cmd_node_labels.go b/pkg/runner/cmd_node_labels.go index 99e3a1f17..532017ab8 100644 --- a/pkg/runner/cmd_node_labels.go +++ b/pkg/runner/cmd_node_labels.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package runner import ( "context" "fmt" + v1 "github.com/oracle/coherence-operator/api/v1" "github.com/pkg/errors" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -100,7 +101,7 @@ func executeNodeQuery(cmd *cobra.Command) error { } for label, value := range node.Labels { - fileName := fmt.Sprintf("%s%c%s", dir, sep, label) + fileName := fmt.Sprintf(v1.FileNamePattern, dir, sep, label) fileDir := filepath.Dir(fileName) err = os.MkdirAll(fileDir, 0755) diff --git a/pkg/runner/cmd_query_plus.go b/pkg/runner/cmd_query_plus.go index a542a3084..845947765 100644 --- a/pkg/runner/cmd_query_plus.go +++ b/pkg/runner/cmd_query_plus.go @@ -7,6 +7,7 @@ package runner import ( + v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -41,10 +42,10 @@ func queryPlus(details *RunDetails, args []string, v *viper.Viper) { loadConfigFiles(details) if details.IsSpringBoot() { - details.addArg("-Dloader.main=" + QueryPlusMain) + details.addArg("-Dloader.main=" + v1.QueryPlusMain) } else { - details.AppType = AppTypeJava - details.MainClass = QueryPlusMain + details.AppType = v1.AppTypeJava + details.MainClass = v1.QueryPlusMain } details.addArg("-Dcoherence.role=console") diff --git a/pkg/runner/cmd_server.go b/pkg/runner/cmd_server.go index edf963aec..d1fcdab23 100644 --- a/pkg/runner/cmd_server.go +++ b/pkg/runner/cmd_server.go @@ -73,7 +73,7 @@ func loadConfigFiles(details *RunDetails) { } func loadClassPathFile(details *RunDetails) error { - file := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) data, err := os.ReadFile(file) if err != nil { return errors.Wrapf(err, "error reading %s", file) @@ -83,7 +83,7 @@ func loadClassPathFile(details *RunDetails) error { } func loadJvmArgsFile(details *RunDetails) error { - file := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) lines, err := readLines(file) if err != nil { return errors.Wrapf(err, "error reading %s", file) @@ -94,7 +94,7 @@ func loadJvmArgsFile(details *RunDetails) error { func loadMainClassFile(details *RunDetails) error { dir := details.getenvOrDefault(v1.EnvVarCohUtilDir, details.UtilsDir) - file := fmt.Sprintf("%s%c%s", dir, os.PathSeparator, v1.OperatorMainClassFile) + file := fmt.Sprintf(v1.FileNamePattern, dir, os.PathSeparator, v1.OperatorMainClassFile) lines, err := readLines(file) if err != nil { return errors.Wrapf(err, "error reading %s", file) @@ -109,7 +109,7 @@ func loadMainClassFile(details *RunDetails) error { } func loadSpringBootArgsFile(details *RunDetails) error { - file := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) + file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) lines, err := readLines(file) if err != nil { return errors.Wrapf(err, "error reading %s", file) diff --git a/pkg/runner/cmd_sleep.go b/pkg/runner/cmd_sleep.go index af4c2d6dd..ac3efe1da 100644 --- a/pkg/runner/cmd_sleep.go +++ b/pkg/runner/cmd_sleep.go @@ -39,12 +39,12 @@ func sleepCommand(v *viper.Viper) *cobra.Command { func sleep(details *RunDetails, args []string, v *viper.Viper) { app := strings.ToLower(v.GetString(v1.EnvVarAppType)) - if app == AppTypeSpring2 { - details.AppType = AppTypeSpring2 - details.MainClass = SpringBootMain2 + if app == v1.AppTypeSpring2 { + details.AppType = v1.AppTypeSpring2 + details.MainClass = v1.SpringBootMain2 details.addArg("-Dloader.main=com.oracle.coherence.k8s.Sleep") } else { - details.AppType = AppTypeJava + details.AppType = v1.AppTypeJava details.MainClass = "com.oracle.coherence.k8s.Sleep" } details.Command = CommandSleep diff --git a/pkg/runner/run_details.go b/pkg/runner/run_details.go index 6fb3a6730..8c4cc414a 100644 --- a/pkg/runner/run_details.go +++ b/pkg/runner/run_details.go @@ -28,7 +28,7 @@ func NewRunDetails(v *viper.Viper) *RunDetails { JavaHome: v.GetString(v1.EnvVarJavaHome), AppType: strings.ToLower(v.GetString(v1.EnvVarAppType)), Dir: v.GetString(v1.EnvVarCohAppDir), - MainClass: DefaultMain, + MainClass: v1.DefaultMain, GetSite: skipSite, } @@ -36,12 +36,12 @@ func NewRunDetails(v *viper.Viper) *RunDetails { details.addClasspath(v.GetString(v1.EnvVarJvmExtraClasspath)) details.addClasspath(v.GetString(v1.EnvVarJavaClasspath)) - cpFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) if _, err = os.Stat(cpFile); err == nil { details.ClassPathFile = cpFile } - argFile := fmt.Sprintf("%s%c%s", details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + argFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) if _, err = os.Stat(argFile); err == nil { details.JvmArgsFile = argFile } @@ -80,7 +80,7 @@ func (in *RunDetails) IsSpringBoot() bool { if in.env == nil { return false } - return in.AppType == AppTypeSpring2 || in.AppType == AppTypeSpring3 + return in.AppType == v1.AppTypeSpring2 || in.AppType == v1.AppTypeSpring3 } // Getenv returns the value for the specified environment variable, or empty string if not set. diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index f6969a30f..1d229298f 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -34,40 +34,6 @@ import ( // The code that actually starts the process in the Coherence container. const ( - // DefaultMain is an indicator to run the default main class. - DefaultMain = "$DEFAULT$" - // HelidonMain is the default Helidon main class name. - HelidonMain = "io.helidon.microprofile.cdi.Main" - // ServerMain is the default server main class name. - ServerMain = "com.oracle.coherence.k8s.Main" - // SpringBootMain2 is the default Spring Boot 2.x main class name. - SpringBootMain2 = "org.springframework.boot.loader.PropertiesLauncher" - // SpringBootMain3 is the default Spring Boot 3.x main class name. - SpringBootMain3 = "org.springframework.boot.loader.launch.PropertiesLauncher" - // ConsoleMain is the Coherence console main class - ConsoleMain = "com.tangosol.net.CacheFactory" - // QueryPlusMain is the main class to run Coherence Query Plus - QueryPlusMain = "com.tangosol.coherence.dslquery.QueryPlus" - // JShellMain is the main class to run a JShell console - JShellMain = "jdk.internal.jshell.tool.JShellToolProvider" - - // AppTypeNone is the argument to specify no application type. - AppTypeNone = "" - // AppTypeJava is the argument to specify a Java application. - AppTypeJava = "java" - // AppTypeCoherence is the argument to specify a Coherence application. - AppTypeCoherence = "coherence" - // AppTypeHelidon is the argument to specify a Helidon application. - AppTypeHelidon = "helidon" - // AppTypeSpring2 is the argument to specify an exploded Spring Boot 2.x application. - AppTypeSpring2 = "spring" - // AppTypeSpring3 is the argument to specify an exploded Spring Boot 3.x application. - AppTypeSpring3 = "spring3" - // AppTypeOperator is the argument to specify running an Operator command. - AppTypeOperator = "operator" - // AppTypeJShell is the argument to specify a JShell application. - AppTypeJShell = "jshell" - // defaultConfig is the root name of the default configuration file defaultConfig = ".coherence-runner" ) @@ -625,22 +591,22 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { var app string switch { - case details.AppType == AppTypeNone || details.AppType == AppTypeJava: + case details.AppType == v1.AppTypeNone || details.AppType == v1.AppTypeJava: app = "Java" cmd, err = createJavaCommand(details.getJavaExecutable(), details) case details.IsSpringBoot(): app = "SpringBoot" cmd, err = createSpringBootCommand(details.getJavaExecutable(), details) - case details.AppType == AppTypeHelidon: + case details.AppType == v1.AppTypeHelidon: app = "Java" cmd, err = createJavaCommand(details.getJavaExecutable(), details) - case details.AppType == AppTypeCoherence: + case details.AppType == v1.AppTypeCoherence: app = "Java" cmd, err = createJavaCommand(details.getJavaExecutable(), details) - case details.AppType == AppTypeJShell: + case details.AppType == v1.AppTypeJShell: app = "JShell" cmd, err = createJShellCommand(details.getJShellExecutable(), details) - case details.AppType == AppTypeOperator: + case details.AppType == v1.AppTypeOperator: app = "Operator" cmd, err = createOperatorCommand(details) default: @@ -688,10 +654,10 @@ func readFirstLineFromFile(path string) (string, error) { func createSpringBootCommand(javaCmd string, details *RunDetails) (*exec.Cmd, error) { if details.isBuildPacks() { - if details.AppType == AppTypeSpring2 { - return _createBuildPackCommand(details, SpringBootMain2, details.getSpringBootArgs()) + if details.AppType == v1.AppTypeSpring2 { + return _createBuildPackCommand(details, v1.SpringBootMain2, details.getSpringBootArgs()) } - return _createBuildPackCommand(details, SpringBootMain3, details.getSpringBootArgs()) + return _createBuildPackCommand(details, v1.SpringBootMain3, details.getSpringBootArgs()) } args := details.getSpringBootCommand() return _createJavaCommand(javaCmd, details, args) @@ -1020,12 +986,12 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { args = append(args, "--class-path", jar) } - if details.AppType == AppTypeSpring2 { + if details.AppType == v1.AppTypeSpring2 { // we are running SpringBoot 2.x - args = append(args, SpringBootMain2, v) + args = append(args, v1.SpringBootMain2, v) } else { // we are running SpringBoot 3.x - args = append(args, SpringBootMain3, v) + args = append(args, v1.SpringBootMain3, v) } } else { // We can use normal Java diff --git a/pkg/runner/runner_application_type_test.go b/pkg/runner/runner_application_type_test.go index 6c734c05a..ec5fad632 100644 --- a/pkg/runner/runner_application_type_test.go +++ b/pkg/runner/runner_application_type_test.go @@ -22,7 +22,7 @@ func TestApplicationTypeNone(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeNone), + Type: ptr.To(coh.AppTypeNone), }, }, }, @@ -54,7 +54,7 @@ func TestApplicationTypeNoneWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeNone), + Type: ptr.To(coh.AppTypeNone), Main: ptr.To("com.foo.Bar"), }, }, @@ -87,7 +87,7 @@ func TestApplicationTypeCoherence(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeCoherence), + Type: ptr.To(coh.AppTypeCoherence), }, }, }, @@ -119,7 +119,7 @@ func TestApplicationTypeCoherenceWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeCoherence), + Type: ptr.To(coh.AppTypeCoherence), Main: ptr.To("com.foo.Bar"), }, }, @@ -151,7 +151,7 @@ func TestApplicationTypeJava(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeJava), + Type: ptr.To(v1.AppTypeJava), }, }, }, @@ -183,7 +183,7 @@ func TestApplicationTypeJavaWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeJava), + Type: ptr.To(coh.AppTypeJava), Main: ptr.To("com.foo.Bar"), }, }, @@ -215,7 +215,7 @@ func TestApplicationTypeHelidon(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeHelidon), + Type: ptr.To(coh.AppTypeHelidon), }, }, }, @@ -246,7 +246,7 @@ func TestApplicationTypeHelidonWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeHelidon), + Type: ptr.To(coh.AppTypeHelidon), Main: ptr.To("com.foo.Bar"), }, }, diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index 8195ac430..a01a00031 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -23,7 +23,7 @@ func TestSpringBootApplication(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), }, }, }, @@ -44,7 +44,7 @@ func TestSpringBootApplication(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2))) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2))) } func TestSpringBoot3Application(t *testing.T) { @@ -55,7 +55,7 @@ func TestSpringBoot3Application(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring3), + Type: ptr.To(coh.AppTypeSpring3), }, }, }, @@ -76,7 +76,7 @@ func TestSpringBoot3Application(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, SpringBootMain3))) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain3))) } func TestSpringBootFatJarApplication(t *testing.T) { @@ -88,7 +88,7 @@ func TestSpringBootFatJarApplication(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, }, }, @@ -110,7 +110,7 @@ func TestSpringBootFatJarApplication(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expected := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), "--class-path", "/apps/lib/foo.jar") + expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", "/apps/lib/foo.jar") g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } @@ -123,7 +123,7 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring3), + Type: ptr.To(coh.AppTypeSpring3), SpringBootFatJar: &jar, }, }, @@ -145,7 +145,7 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expected := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain3), "--class-path", "/apps/lib/foo.jar") + expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain3), "--class-path", "/apps/lib/foo.jar") g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } @@ -158,7 +158,7 @@ func TestSpringBootFatJarConsole(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, }, }, @@ -181,7 +181,7 @@ func TestSpringBootFatJarConsole(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), "--class-path", jar) + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", jar) expectedArgs = append(expectedArgs, "-Dcoherence.role=console", "-Dloader.main=com.tangosol.net.CacheFactory", "-Dcoherence.distributed.localstorage=false", @@ -207,7 +207,7 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, }, }, @@ -230,7 +230,7 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), "--class-path", jar) + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", jar) expectedArgs = append(expectedArgs, "-Dcoherence.role=console", "-Dloader.main=com.tangosol.net.CacheFactory", "-Dcoherence.distributed.localstorage=false", @@ -257,7 +257,7 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, Main: ptr.To("foo.Bar"), }, @@ -281,7 +281,7 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, SpringBootMain2), + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", jar, "-Dloader.main=foo.Bar") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) @@ -295,7 +295,7 @@ func TestSpringBootBuildpacks(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), CloudNativeBuildPack: &coh.CloudNativeBuildPackSpec{ Enabled: ptr.To(true), }, @@ -323,7 +323,7 @@ func TestSpringBootBuildpacks(t *testing.T) { g.Expect(len(e.OsCmd.Args)).To(Equal(4)) g.Expect(e.OsCmd.Args[0]).To(Equal(coh.DefaultCnbpLauncher)) g.Expect(e.OsCmd.Args[1]).To(Equal("java")) - g.Expect(e.OsCmd.Args[3]).To(Equal(SpringBootMain2)) + g.Expect(e.OsCmd.Args[3]).To(Equal(coh.SpringBootMain2)) } func GetMinimalExpectedSpringBootArgs(t *testing.T, main string) []string { @@ -340,21 +340,3 @@ func GetMinimalExpectedSpringBootArgs(t *testing.T, main string) []string { } return append(AppendCommonExpectedArgs(args), main) } - -func GetMinimalExpectedSpringBootFatJarArgs(jar, main string) []string { - return GetMinimalExpectedSpringBootFatJarArgsWithMain(jar, main, "") -} - -func GetMinimalExpectedSpringBootFatJarArgsWithMain(jar, springMain, main string) []string { - args := []string{ - GetJavaArg(), - "--class-path", - jar, - } - return append(args, springMain) -} - -func GetMinimalExpectedSpringBootFatJarArgsForRole(t *testing.T, jar, main, role string) []string { - args := GetMinimalExpectedSpringBootArgs(t, main) - return append(AppendCommonExpectedNonServerArgs(args, role), SpringBootMain2) -} diff --git a/test/e2e/helper/e2e-helpers.go b/test/e2e/helper/e2e-helpers.go index 40bc52119..e169b5180 100644 --- a/test/e2e/helper/e2e-helpers.go +++ b/test/e2e/helper/e2e-helpers.go @@ -907,6 +907,9 @@ func DumpPodLog(ctx TestContext, pod *corev1.Pod, directory string) { pathSep := string(os.PathSeparator) name := logs + pathSep + directory err = os.MkdirAll(name, os.ModePerm) + if err != nil { + ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " due to " + err.Error()) + } for _, container := range pod.Spec.InitContainers { DumpContainerLogs(ctx, container, pod, name) @@ -917,27 +920,23 @@ func DumpPodLog(ctx TestContext, pod *corev1.Pod, directory string) { } // DumpContainerLogs dumps the logs for a container -func DumpContainerLogs(ctx TestContext, container corev1.Container, pod *corev1.Pod, name string) { +func DumpContainerLogs(ctx TestContext, container corev1.Container, pod *corev1.Pod, directory string) { var err error pathSep := string(os.PathSeparator) res := ctx.KubeClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Container: container.Name}) s, err := res.Stream(ctx.Context) if err == nil { - if err == nil { - suffix := 0 - logName := fmt.Sprintf("%s%s%s(%s).log", name, pathSep, pod.Name, container.Name) + suffix := 0 + logName := fmt.Sprintf("%s%s%s(%s).log", directory, pathSep, pod.Name, container.Name) + _, err = os.Stat(logName) + for err == nil { + suffix++ + logName = fmt.Sprintf("%s%s%s(%s)-%d.log", directory, pathSep, pod.Name, container.Name, suffix) _, err = os.Stat(logName) - for err == nil { - suffix++ - logName = fmt.Sprintf("%s%s%s(%s)-%d.log", name, pathSep, pod.Name, container.Name, suffix) - _, err = os.Stat(logName) - } - out, err := os.Create(logName) - if err == nil { - if _, err = io.Copy(out, s); err != nil { - ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) - } - } else { + } + out, err := os.Create(logName) + if err == nil { + if _, err = io.Copy(out, s); err != nil { ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } } else { From 7d12ce6a1c5f9084812f420a2dfbf6d2a380b63f Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 07:43:02 +0300 Subject: [PATCH 16/33] fix code review --- pkg/runner/runner_application_type_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/runner/runner_application_type_test.go b/pkg/runner/runner_application_type_test.go index ec5fad632..3bc66a65f 100644 --- a/pkg/runner/runner_application_type_test.go +++ b/pkg/runner/runner_application_type_test.go @@ -151,7 +151,7 @@ func TestApplicationTypeJava(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(v1.AppTypeJava), + Type: ptr.To(coh.AppTypeJava), }, }, }, From 335f8d4aa1988e037dd9b704f4800720e70e24ac Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 14:23:08 +0300 Subject: [PATCH 17/33] Fix using entry point --- api/v1/coherence_types.go | 161 +++++++-- api/v1/coherenceresourcespec_types.go | 93 +++--- api/v1/common_test.go | 8 +- api/v1/create_job_applicationspec_test.go | 90 +++++- ...create_statefulset_applicationspec_test.go | 90 +++++- api/v1/zz_generated.deepcopy.go | 17 +- docs/about/04_coherence_spec.adoc | 2 + pkg/runner/cmd_config.go | 91 +++--- pkg/runner/cmd_console.go | 29 +- pkg/runner/cmd_initialise.go | 5 +- pkg/runner/cmd_jshell.go | 27 +- pkg/runner/cmd_query_plus.go | 29 +- pkg/runner/cmd_server.go | 21 +- pkg/runner/cmd_sleep.go | 29 +- pkg/runner/{ => run_details}/run_details.go | 150 ++++++--- .../{ => run_details}/rundetails_test.go | 73 +++-- pkg/runner/runner.go | 306 +++++++++--------- pkg/runner/runner_spring_test.go | 64 +--- .../e2e/local/spring-buildpack-cluster-2.yaml | 1 + test/e2e/local/spring-buildpack-cluster.yaml | 1 + test/e2e/local/spring_test.go | 10 +- 21 files changed, 813 insertions(+), 484 deletions(-) rename pkg/runner/{ => run_details}/run_details.go (68%) rename pkg/runner/{ => run_details}/rundetails_test.go (63%) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 999b939d5..1f79195d0 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" + "os" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -206,7 +207,18 @@ type ApplicationSpec struct { // runnable, for example if the application type is "node" the main may be a Javascript file. // +optional Main *string `json:"main,omitempty"` - // Args is the optional arguments to pass to the main class. + // Entrypoint array that will override the "java" entry point configured by the Operator or + // and any container entry point. This is an advanced use case, specifying an incorrect value here can + // cause the container not to start. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. Cannot be updated. + // +optional + // +listType=atomic + EntryPoint []string `json:"entryPoint,omitempty"` + // Args is the optional arguments to pass to the main class or the container entry point. // +listType=atomic // +optional Args []string `json:"args,omitempty"` @@ -224,43 +236,138 @@ type ApplicationSpec struct { // For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" // +optional SpringBootFatJar *string `json:"springBootFatJar,omitempty"` + // UseImageEntryPoint is a flag to indicate that the Coherence container in the Pods + // should just execute the image entry point and not configure a custom command line. + // If this flag is set to true any arguments in the Args field are passed as container arguments + // to the entry point. + // +optional + UseImageEntryPoint *bool `json:"useImageEntryPoint,omitempty"` + // UseJdkJavaOptions is a flag to indicate that the JDK_JAVA_OPTIONS environment variable + // should be set in the Coherence container to contain the JVM arguments configured by + // the Operator. + // Setting JDK_JAVA_OPTIONS defaults to true and only applies if UseImageEntryPoint is set to true. + // +optional + UseJdkJavaOptions *bool `json:"useJdkJavaOptions,omitempty"` } // UpdateCoherenceContainer updates the Coherence container with the relevant settings. func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { - if in == nil { - return - } + useImageEntryPoint := false + useJdkJavaOptions := true - if in.Type != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppType, Value: *in.Type}) - } - if in.Main != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainClass, Value: *in.Main}) - } - if in.WorkingDir != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohAppDir, Value: *in.WorkingDir}) - c.WorkingDir = *in.WorkingDir - } - if len(in.Args) > 0 { - args := strings.Join(in.Args, " ") - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainArgs, Value: args}) - } - if in.CloudNativeBuildPack != nil { - if in.CloudNativeBuildPack.Enabled != nil { - if *in.CloudNativeBuildPack.Enabled { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "true"}) + if in != nil { + if len(in.EntryPoint) > 0 { + c.Command = in.EntryPoint + } + + if in.Type != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppType, Value: *in.Type}) + } + if in.Main != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainClass, Value: *in.Main}) + } + if in.WorkingDir != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohAppDir, Value: *in.WorkingDir}) + c.WorkingDir = *in.WorkingDir + } + if len(in.Args) > 0 { + args := strings.Join(in.Args, " ") + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainArgs, Value: args}) + } + if in.CloudNativeBuildPack != nil { + if in.CloudNativeBuildPack.Enabled != nil { + if *in.CloudNativeBuildPack.Enabled { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "true"}) + useImageEntryPoint = true + } else { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "false"}) + } + } + if in.CloudNativeBuildPack.Launcher != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpLauncher, Value: *in.CloudNativeBuildPack.Launcher}) + } + } + if in.SpringBootFatJar != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarSpringBootFatJar, Value: *in.SpringBootFatJar}) + } + useImageEntryPoint = useImageEntryPoint || (in.UseImageEntryPoint != nil && *in.UseImageEntryPoint) + useJdkJavaOptions = useImageEntryPoint && (in.UseJdkJavaOptions == nil || *in.UseJdkJavaOptions) + } + + if useImageEntryPoint { + // we are configured to use the image's entry point + // in cannot be nil if we get here + if useJdkJavaOptions { + // find any existing JDK_JAVA_OPTION env var so we do not loose its value + jdkOpts := "" + jdkOptsIdx := -1 + for i, ev := range c.Env { + if ev.Name == EnvVarJdkOptions { + jdkOpts = ev.Value + jdkOptsIdx = i + break + } + } + + if in.IsSpringBoot() { + jdkOpts = jdkOpts + " " + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile) + jdkOpts = jdkOpts + " " + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile) + } else { + jdkOpts = jdkOpts + " " + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile) + } + + jdkOptsEV := corev1.EnvVar{ + Name: EnvVarJdkOptions, + Value: strings.TrimSpace(jdkOpts), + } + if jdkOptsIdx >= 0 { + c.Env[jdkOptsIdx] = jdkOptsEV } else { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "false"}) + c.Env = append(c.Env, jdkOptsEV) } } - if in.CloudNativeBuildPack.Launcher != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpLauncher, Value: *in.CloudNativeBuildPack.Launcher}) + + // Use the application args as container args + c.Args = in.Args + } else { + args := []string{"--class-path", + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorClasspathFile)} + + if in.IsSpringBoot() { + args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) + args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) + } else { + args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) + args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) } + + if in != nil { + args = append(args, in.Args...) + } + + if c.Command == nil { + // if not already set, use "java" as the container entry point + c.Command = []string{"java"} + } + c.Args = args } - if in.SpringBootFatJar != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarSpringBootFatJar, Value: *in.SpringBootFatJar}) +} + +// IsSpringBoot returns true if this is a Spring Boot application +func (in *ApplicationSpec) IsSpringBoot() bool { + if in == nil { + return false + } + app := in.GetApplicationType() + return app == AppTypeSpring2 || app == AppTypeSpring3 +} + +// GetApplicationType returns the configured application type +func (in *ApplicationSpec) GetApplicationType() string { + if in != nil && in.Type != nil { + return strings.ToLower(*in.Type) } + return AppTypeNone } // ----- CloudNativeBuildPackSpec struct ------------------------------------ diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index aba76db6b..0e8c3cc03 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -16,7 +16,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" - "os" "strconv" "strings" ) @@ -680,6 +679,17 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou } cohContainer := in.CreateCoherenceContainer(deployment) + // Save any existing JDK_JAVA_OPTIONS env var from the Coherence container + // before the Application spec has a chance to change it + var jdkOptEnv *corev1.EnvVar + for _, ev := range cohContainer.Env { + if ev.Name == EnvVarJdkOptions { + jdkOptEnv = &ev + break + } + } + // Update the Coherence container with the application settings + in.Application.UpdateCoherenceContainer(&cohContainer) // Add additional ports for _, p := range in.Ports { @@ -758,30 +768,31 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou sv.AddVolumes(&podTemplate) } - // FINALLY - Set the init-container environment variables to match the Coherence container + // Set the init-container environment variables to match the Coherence container podTemplate.Spec.InitContainers[0].Env = append(podTemplate.Spec.InitContainers[0].Env, podTemplate.Spec.Containers[0].Env...) podTemplate.Spec.InitContainers[1].Env = append(podTemplate.Spec.InitContainers[1].Env, podTemplate.Spec.Containers[0].Env...) - return podTemplate -} - -func (in *CoherenceResourceSpec) GetApplicationType() string { - if in != nil && in.Application != nil && in.Application.Type != nil { - return strings.ToLower(*in.Application.Type) - } - return AppTypeNone -} + // The Application spec may have applied the JDK_JAVA_OPTIONS env var to the Coherence container + // so we need to remove it from the init-containers + in.replaceEnvVar(&podTemplate.Spec.InitContainers[0], EnvVarJdkOptions, jdkOptEnv) + in.replaceEnvVar(&podTemplate.Spec.InitContainers[1], EnvVarJdkOptions, jdkOptEnv) -// IsSpringBoot returns true if this is a Spring Boot application -func (in *CoherenceResourceSpec) IsSpringBoot() bool { - app := in.GetApplicationType() - return app == AppTypeSpring2 || app == AppTypeSpring3 + return podTemplate } -func (in *CoherenceResourceSpec) GetApplicationMainClass() string { - if in != nil && in.Application != nil && in.Application.Main != nil { - return *in.Application.Main +func (in *CoherenceResourceSpec) replaceEnvVar(c *corev1.Container, name string, ev *corev1.EnvVar) { + env := c.Env + for i, e := range env { + if e.Name == name { + if ev == nil { + c.Env = env[:i] + c.Env = append(c.Env, env[i+1:]...) + } else { + c.Env[i] = *ev + c.Env[i].Name = name + } + break + } } - return DefaultMain } func (in *CoherenceResourceSpec) GetImagePullSecrets() []corev1.LocalObjectReference { @@ -864,8 +875,6 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe }) } - in.Application.UpdateCoherenceContainer(&c) - if in.Resources != nil { // set the container resources if specified c.Resources = *in.Resources @@ -884,25 +893,6 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe c.Lifecycle = in.Lifecycle - cmd := []string{"java"} - - if in.IsSpringBoot() { - cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) - cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) - } else { - cmd = append(cmd, "--class-path", fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorClasspathFile)) - cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) - } - - cmd = append(cmd, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) - - if in.Application != nil { - cmd = append(cmd, in.Application.Args...) - } - - // set the command line into the container - c.Command = cmd - return c } @@ -919,25 +909,25 @@ func (in *CoherenceResourceSpec) CreateCommonEnv(deployment CoherenceResource) [ env := []corev1.EnvVar{ { Name: EnvVarCohMachineName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "spec.nodeName", }, }, + }, { Name: EnvVarCohMemberName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.name", - }, + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", }, }, + }, { Name: EnvVarCohPodUID, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.uid", - }, + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.uid", }, }, + }, {Name: EnvVarCohRole, Value: deployment.GetRoleName()}, } @@ -1091,6 +1081,11 @@ func (in *CoherenceResourceSpec) CreateOperatorConfigInitContainer(deployment Co } c := in.createInitContainer(deployment, ContainerNameOperatorConfig, image, []string{RunnerCommand, RunnerConfig}) + + if in.Application != nil && in.Application.WorkingDir != nil { + c.WorkingDir = *in.Application.WorkingDir + } + return c } diff --git a/api/v1/common_test.go b/api/v1/common_test.go index d2b2e4b78..fc9603461 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -386,10 +386,10 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe // The Coherence Container cohContainer := corev1.Container{ - Name: coh.ContainerNameCoherence, - Image: testCoherenceImage, - Command: []string{ - "java", + Name: coh.ContainerNameCoherence, + Image: testCoherenceImage, + Command: []string{"java"}, + Args: []string{ "--class-path", fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorClasspathFile), fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorJvmArgsFile), diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index 777857b99..d3590c2f2 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -9,6 +9,7 @@ package v1_test import ( coh "github.com/oracle/coherence-operator/api/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "testing" ) @@ -63,7 +64,7 @@ func TestCreateJobWithApplicationMainArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - jobExpected.Spec.Template.Spec.Containers[0].Command = append(jobExpected.Spec.Template.Spec.Containers[0].Command, "arg1", "arg2") + jobExpected.Spec.Template.Spec.Containers[0].Args = append(jobExpected.Spec.Template.Spec.Containers[0].Args, "arg1", "arg2") // Add the expected environment variables addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) @@ -102,8 +103,95 @@ func TestCreateJobWithWorkingDirectory(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) jobExpected.Spec.Template.Spec.Containers[0].WorkingDir = dir + jobExpected.Spec.Template.Spec.InitContainers[1].WorkingDir = dir addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) } + +func TestCreateJobUseImageEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + stsExpected := createMinimalExpectedJob(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-jvm-args.txt"}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, stsExpected) +} + +func TestCreateJobUseImageEntryPointAndUseJdkOptsFalse(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + stsExpected := createMinimalExpectedJob(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + + // assert that the Job is as expected + assertJobCreation(t, deployment, stsExpected) +} + +func TestCreateJobUseImageEntryPointWithExistingJdkOpts(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarJdkOptions, + Value: "-Dfoo=bar", + }, + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + stsExpected := createMinimalExpectedJob(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-jvm-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, stsExpected) +} + +func TestCreateJobWithApplicationEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + EntryPoint: []string{"foo", "bar"}, + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + stsExpected := createMinimalExpectedJob(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = []string{"foo", "bar"} + + // assert that the Job is as expected + assertJobCreation(t, deployment, stsExpected) +} diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index d518b2a52..7d5ffbbdb 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -9,6 +9,7 @@ package v1_test import ( coh "github.com/oracle/coherence-operator/api/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "testing" ) @@ -63,7 +64,7 @@ func TestCreateStatefulSetWithApplicationMainArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - stsExpected.Spec.Template.Spec.Containers[0].Command = append(stsExpected.Spec.Template.Spec.Containers[0].Command, "arg1", "arg2") + stsExpected.Spec.Template.Spec.Containers[0].Args = append(stsExpected.Spec.Template.Spec.Containers[0].Args, "arg1", "arg2") // Add the expected environment variables addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) @@ -102,8 +103,95 @@ func TestCreateStatefulSetWithWorkingDirectory(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Containers[0].WorkingDir = dir + stsExpected.Spec.Template.Spec.InitContainers[1].WorkingDir = dir addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) } + +func TestCreateStatefulSetUseImageEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-jvm-args.txt"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointAndUseJdkOptsFalse(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointWithExistingJdkOpts(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarJdkOptions, + Value: "-Dfoo=bar", + }, + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-jvm-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetWithApplicationEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + EntryPoint: []string{"foo", "bar"}, + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = []string{"foo", "bar"} + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 7d95a990a..e77191749 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* - * Copyright (c) 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -86,6 +86,11 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { *out = new(string) **out = **in } + if in.EntryPoint != nil { + in, out := &in.EntryPoint, &out.EntryPoint + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Args != nil { in, out := &in.Args, &out.Args *out = make([]string, len(*in)) @@ -106,6 +111,16 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { *out = new(string) **out = **in } + if in.UseImageEntryPoint != nil { + in, out := &in.UseImageEntryPoint, &out.UseImageEntryPoint + *out = new(bool) + **out = **in + } + if in.UseJdkJavaOptions != nil { + in, out := &in.UseJdkJavaOptions, &out.UseJdkJavaOptions + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSpec. diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index 7561099ef..53e3a7476 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -141,6 +141,8 @@ m| args | Args is the optional arguments to pass to the main class. m| []string m| workingDir | WorkingDir sets the working directory of the Coherence container. m| *string | false m| cloudNativeBuildPack | Optional settings that may be configured if using a Cloud Native Buildpack Image. For example an image build with the Spring Boot Maven/Gradle plugin. See: https://github.com/paketo-buildpacks/spring-boot and https://buildpacks.io/ m| *<> | false m| springBootFatJar | SpringBootFatJar is the full path name to the Spring Boot fat jar if the application image has been built by just adding a Spring Boot fat jar to the image. If this field is set then the application will be run by executing this jar. For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" m| *string | false +m| useImageEntryPoint | UseImageEntryPoint is a flag to indicate that the Coherence container in the Pods should just execute the image entry point and not configure a custom command line. If this flag is set to true any arguments in the Args field are passed as container arguments to the entry point. m| *bool | false +m| useJdkJavaOptions | UseJdkJavaOptions is a flag to indicate that the JDK_JAVA_OPTIONS environment variable should be set in the Coherence container to contain the JVM arguments configured by the Operator. Setting JDK_JAVA_OPTIONS defaults to true and only applies if UseImageEntryPoint is set to true. m| *bool | false |=== <
> diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 8556a5254..81803fdc5 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -10,6 +10,7 @@ import ( "bytes" "fmt" v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/pkg/errors" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/api/resource" @@ -45,7 +46,7 @@ func configCommand(env map[string]string) *cobra.Command { } // createsFiles will create the various config files -func createsFiles(details *RunDetails, _ *cobra.Command) (bool, error) { +func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, error) { populateMainClass(details) populateServerDetails(details) err := configureCommand(details) @@ -71,10 +72,26 @@ func createsFiles(details *RunDetails, _ *cobra.Command) (bool, error) { } // createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container -func createClassPathFile(details *RunDetails) error { +func createClassPathFile(details *run_details.RunDetails) error { + var classpath string + var err error + if details.IsSpringBoot() { + if jar, _ := details.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { + classpath = jar + } else { + // no fat jar, so use the current directory + wd, err := os.Getwd() + if err != nil { + return errors.Wrap(err, "failed to get the current working directory") + } + classpath = fmt.Sprintf(v1.FileNamePattern, wd, os.PathSeparator, "*") + classpath = classpath + ":" + wd + } + } else { + classpath = details.GetClasspath() + } cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) - classpath := details.getClasspath() - err := os.WriteFile(cpFile, []byte(classpath), os.ModePerm) + err = os.WriteFile(cpFile, []byte(classpath), os.ModePerm) if err != nil { return errors.Wrap(err, "failed to write coherence classpath file") } @@ -83,8 +100,8 @@ func createClassPathFile(details *RunDetails) error { } // createArgsFile will create the JVM args files for a Coherence Pod - typically this is run from an init-container -func createArgsFile(details *RunDetails) error { - args := details.GetArgs() +func createArgsFile(details *run_details.RunDetails) error { + args := details.GetAllArgs() argFileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) var buffer bytes.Buffer @@ -100,9 +117,9 @@ func createArgsFile(details *RunDetails) error { } // createSpringBootFile will create the SpringBoot JVM args files for a Coherence Pod - typically this is run from an init-container -func createSpringBootFile(details *RunDetails) error { +func createSpringBootFile(details *run_details.RunDetails) error { argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) - cp := strings.ReplaceAll(details.getClasspath(), ":", ",") + cp := strings.ReplaceAll(details.GetClasspath(), ":", ",") var args string if details.InnerMainClass == "" || details.InnerMainClass == v1.DefaultMain { @@ -120,7 +137,7 @@ func createSpringBootFile(details *RunDetails) error { } // createMainClassFile will create the file containing the main class name for a Coherence Pod - typically this is run from an init-container -func createMainClassFile(details *RunDetails) error { +func createMainClassFile(details *run_details.RunDetails) error { fileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorMainClassFile) var s string @@ -137,8 +154,8 @@ func createMainClassFile(details *RunDetails) error { return nil } -func createCliConfig(details *RunDetails) error { - home := details.getenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) +func createCliConfig(details *run_details.RunDetails) error { + home := details.GetenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) fileName := fmt.Sprintf(v1.FileNamePattern, home, os.PathSeparator, "cohctl.yaml") cluster := details.Getenv(v1.EnvVarCohClusterName) @@ -185,16 +202,16 @@ func createCliConfig(details *RunDetails) error { } // Configure the main class -func populateMainClass(details *RunDetails) { +func populateMainClass(details *run_details.RunDetails) { details.MainClass = v1.ServerMain // If the main class environment variable is set then use that // otherwise run Coherence DefaultMain. - mc, found := details.lookupEnv(v1.EnvVarAppMainClass) + mc, found := details.LookupEnv(v1.EnvVarAppMainClass) if !found || mc == "" { // no custom mani set so check for a JIB main class file - appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") + appDir := details.GetenvOrDefault(v1.EnvVarCohAppDir, "/app") jibMainClassFileName := filepath.Join(appDir, "jib-main-class-file") fi, err := os.Stat(jibMainClassFileName) if err != nil && appDir != "/app" { @@ -248,11 +265,11 @@ func populateMainClass(details *RunDetails) { } // Configure the runner to run a Coherence Server -func populateServerDetails(details *RunDetails) { +func populateServerDetails(details *run_details.RunDetails) { // Configure the Coherence member's role - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") // Configure whether this member is storage enabled - details.addArgFromEnvVar(v1.EnvVarCohStorage, "-Dcoherence.distributed.localstorage") + details.AddArgFromEnvVar(v1.EnvVarCohStorage, "-Dcoherence.distributed.localstorage") // Configure Coherence Tracing ratio := details.Getenv(v1.EnvVarCohTracingRatio) @@ -260,7 +277,7 @@ func populateServerDetails(details *RunDetails) { q, err := resource.ParseQuantity(ratio) if err == nil { d := q.AsDec() - details.addArg("-Dcoherence.tracing.ratio=" + d.String()) + details.AddArg("-Dcoherence.tracing.ratio=" + d.String()) } else { fmt.Printf("ERROR: Coherence tracing ratio \"%s\" is invalid - %s\n", ratio, err.Error()) os.Exit(1) @@ -268,30 +285,30 @@ func populateServerDetails(details *RunDetails) { } // Configure whether Coherence management is enabled - hasMgmt := details.isEnvTrue(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohEnabledSuffix) + hasMgmt := details.IsEnvTrue(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohEnabledSuffix) log.Info("Coherence Management over REST", "enabled", strconv.FormatBool(hasMgmt), "envVar", v1.EnvVarCohMgmtPrefix+v1.EnvVarCohEnabledSuffix) if hasMgmt { fmt.Println("INFO: Configuring Coherence Management over REST") - details.addArg("-Dcoherence.management.http=all") + details.AddArg("-Dcoherence.management.http=all") if details.CoherenceHome != "" { // If management is enabled and the COHERENCE_HOME environment variable is set // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath // This is for legacy 14.1.1.0 and 12.2.1.4 images - details.addClasspath(details.CoherenceHome + "/lib/coherence-management.jar") + details.AddClasspath(details.CoherenceHome + "/lib/coherence-management.jar") } } // Configure whether Coherence metrics is enabled - hasMetrics := details.isEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) + hasMetrics := details.IsEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) log.Info("Coherence Metrics", "enabled", strconv.FormatBool(hasMetrics), "envVar", v1.EnvVarCohMetricsPrefix+v1.EnvVarCohEnabledSuffix) if hasMetrics { - details.addArg("-Dcoherence.metrics.http.enabled=true") + details.AddArg("-Dcoherence.metrics.http.enabled=true") fmt.Println("INFO: Configuring Coherence Metrics") if details.CoherenceHome != "" { // If metrics is enabled and the COHERENCE_HOME environment variable is set // then $COHERENCE_HOME/lib/coherence-metrics.jar will be added to the classpath // This is for legacy 14.1.1.0 and 12.2.1.4 images - details.addClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") + details.AddClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") } } @@ -304,25 +321,25 @@ func populateServerDetails(details *RunDetails) { stat, err := os.Stat(dm) if err == nil && stat.IsDir() { // dependency modules directory exists - details.addClasspath(dm + "/*") + details.AddClasspath(dm + "/*") } } } - if details.isEnvTrueOrBlank(v1.EnvVarJvmShowSettings) { - details.addArg("-XshowSettings:all") - details.addArg("-XX:+PrintCommandLineFlags") - details.addArg("-XX:+PrintFlagsFinal") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmShowSettings) { + details.AddDiagnosticOption("-XshowSettings:all") + details.AddDiagnosticOption("-XX:+PrintCommandLineFlags") + details.AddDiagnosticOption("-XX:+PrintFlagsFinal") } // Add GC logging parameters if required - if details.isEnvTrue(v1.EnvVarJvmGcLogging) { - details.addArg("-verbose:gc") - details.addArg("-XX:+PrintGCDetails") - details.addArg("-XX:+PrintGCTimeStamps") - details.addArg("-XX:+PrintHeapAtGC") - details.addArg("-XX:+PrintTenuringDistribution") - details.addArg("-XX:+PrintGCApplicationStoppedTime") - details.addArg("-XX:+PrintGCApplicationConcurrentTime") + if details.IsEnvTrue(v1.EnvVarJvmGcLogging) { + details.AddMemoryOption("-verbose:gc") + details.AddMemoryOption("-XX:+PrintGCDetails") + details.AddMemoryOption("-XX:+PrintGCTimeStamps") + details.AddMemoryOption("-XX:+PrintHeapAtGC") + details.AddMemoryOption("-XX:+PrintTenuringDistribution") + details.AddMemoryOption("-XX:+PrintGCApplicationStoppedTime") + details.AddMemoryOption("-XX:+PrintGCApplicationConcurrentTime") } } diff --git a/pkg/runner/cmd_console.go b/pkg/runner/cmd_console.go index 8f4299498..d92a153a5 100644 --- a/pkg/runner/cmd_console.go +++ b/pkg/runner/cmd_console.go @@ -8,6 +8,7 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -24,7 +25,7 @@ func consoleCommand(v *viper.Viper) *cobra.Command { Short: "Start a Coherence interactive console", Long: "Starts a Coherence interactive console", RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { console(details, args, v) }) }, @@ -36,27 +37,27 @@ func consoleCommand(v *viper.Viper) *cobra.Command { } // Configure the runner to run a Coherence CacheFactory console -func console(details *RunDetails, args []string, v *viper.Viper) { +func console(details *run_details.RunDetails, args []string, v *viper.Viper) { details.Command = CommandConsole loadConfigFiles(details) if details.IsSpringBoot() { - details.addArg("-Dloader.main=" + v1.ConsoleMain) + details.AddArg("-Dloader.main=" + v1.ConsoleMain) } else { details.AppType = v1.AppTypeJava details.MainClass = v1.ConsoleMain } - details.addArg("-Dcoherence.role=console") - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.operator.health.enabled=false") - details.addArg("-Dcoherence.health.http.port=0") - details.addArg("-Dcoherence.grpc.enabled=false") - details.addArg("-XX:NativeMemoryTracking=off") + details.AddArg("-Dcoherence.role=console") + details.AddArg("-Dcoherence.distributed.localstorage=false") + details.AddArg("-Dcoherence.localport.adjust=true") + details.AddArg("-Dcoherence.management.http=none") + details.AddArg("-Dcoherence.management.http.port=0") + details.AddArg("-Dcoherence.metrics.http.enabled=false") + details.AddArg("-Dcoherence.metrics.http.port=0") + details.AddArg("-Dcoherence.operator.health.enabled=false") + details.AddArg("-Dcoherence.health.http.port=0") + details.AddArg("-Dcoherence.grpc.enabled=false") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_initialise.go b/pkg/runner/cmd_initialise.go index 639bc6fb6..d5aa78f85 100644 --- a/pkg/runner/cmd_initialise.go +++ b/pkg/runner/cmd_initialise.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package runner import ( "fmt" v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/oracle/coherence-operator/pkg/utils" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -61,7 +62,7 @@ func initCommand(env map[string]string) *cobra.Command { } // initialise will initialise a Coherence Pod - typically this is run from an init-container -func initialise(details *RunDetails, cmd *cobra.Command) (bool, error) { +func initialise(details *run_details.RunDetails, cmd *cobra.Command) (bool, error) { return initialiseWithEnv(cmd, details.Getenv) } diff --git a/pkg/runner/cmd_jshell.go b/pkg/runner/cmd_jshell.go index 95c92808b..37fe4bc83 100644 --- a/pkg/runner/cmd_jshell.go +++ b/pkg/runner/cmd_jshell.go @@ -8,6 +8,7 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -25,7 +26,7 @@ func jShellCommand(v *viper.Viper) *cobra.Command { Long: "Starts a Coherence interactive JShell console", Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { jShell(details, args, v) }) }, @@ -37,21 +38,21 @@ func jShellCommand(v *viper.Viper) *cobra.Command { } // Configure the runner to run a Coherence JShell console -func jShell(details *RunDetails, args []string, v *viper.Viper) { +func jShell(details *run_details.RunDetails, args []string, v *viper.Viper) { details.AppType = v1.AppTypeJShell details.Command = CommandJShell loadConfigFiles(details) - details.addArg("-Dcoherence.role=jshell") - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.operator.health.enabled=false") - details.addArg("-Dcoherence.health.http.port=0") - details.addArg("-Dcoherence.grpc.enabled=false") - details.addArg("-XX:NativeMemoryTracking=summary") + details.AddArg("-Dcoherence.role=jshell") + details.AddArg("-Dcoherence.distributed.localstorage=false") + details.AddArg("-Dcoherence.localport.adjust=true") + details.AddArg("-Dcoherence.management.http=none") + details.AddArg("-Dcoherence.management.http.port=0") + details.AddArg("-Dcoherence.metrics.http.enabled=false") + details.AddArg("-Dcoherence.metrics.http.port=0") + details.AddArg("-Dcoherence.operator.health.enabled=false") + details.AddArg("-Dcoherence.health.http.port=0") + details.AddArg("-Dcoherence.grpc.enabled=false") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_query_plus.go b/pkg/runner/cmd_query_plus.go index 845947765..512c35f71 100644 --- a/pkg/runner/cmd_query_plus.go +++ b/pkg/runner/cmd_query_plus.go @@ -8,6 +8,7 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -25,7 +26,7 @@ func queryPlusCommand(v *viper.Viper) *cobra.Command { Long: "Starts a Coherence interactive QueryPlus console", Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { queryPlus(details, args, v) }) }, @@ -37,27 +38,27 @@ func queryPlusCommand(v *viper.Viper) *cobra.Command { } // Configure the runner to run a Coherence Query Plus console -func queryPlus(details *RunDetails, args []string, v *viper.Viper) { +func queryPlus(details *run_details.RunDetails, args []string, v *viper.Viper) { details.Command = CommandQueryPlus loadConfigFiles(details) if details.IsSpringBoot() { - details.addArg("-Dloader.main=" + v1.QueryPlusMain) + details.AddArg("-Dloader.main=" + v1.QueryPlusMain) } else { details.AppType = v1.AppTypeJava details.MainClass = v1.QueryPlusMain } - details.addArg("-Dcoherence.role=console") - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.operator.health.enabled=false") - details.addArg("-Dcoherence.health.http.port=0") - details.addArg("-Dcoherence.grpc.enabled=false") - details.addArg("-XX:NativeMemoryTracking=summary") + details.AddArg("-Dcoherence.role=console") + details.AddArg("-Dcoherence.distributed.localstorage=false") + details.AddArg("-Dcoherence.localport.adjust=true") + details.AddArg("-Dcoherence.management.http=none") + details.AddArg("-Dcoherence.management.http.port=0") + details.AddArg("-Dcoherence.metrics.http.enabled=false") + details.AddArg("-Dcoherence.metrics.http.port=0") + details.AddArg("-Dcoherence.operator.health.enabled=false") + details.AddArg("-Dcoherence.health.http.port=0") + details.AddArg("-Dcoherence.grpc.enabled=false") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_server.go b/pkg/runner/cmd_server.go index d1fcdab23..a2b82c39c 100644 --- a/pkg/runner/cmd_server.go +++ b/pkg/runner/cmd_server.go @@ -10,6 +10,7 @@ import ( "bufio" "fmt" v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/pkg/errors" "github.com/spf13/cobra" "os" @@ -36,11 +37,11 @@ func serverCommand() *cobra.Command { } // Configure the runner to run a Coherence Server -func server(details *RunDetails, _ *cobra.Command) { +func server(details *run_details.RunDetails, _ *cobra.Command) { details.Command = CommandServer loadConfigFiles(details) - ma, found := details.lookupEnv(v1.EnvVarAppMainArgs) + ma, found := details.LookupEnv(v1.EnvVarAppMainArgs) if found { if ma != "" { for _, arg := range strings.Split(ma, " ") { @@ -50,7 +51,7 @@ func server(details *RunDetails, _ *cobra.Command) { } } -func loadConfigFiles(details *RunDetails) { +func loadConfigFiles(details *run_details.RunDetails) { var err error if err = loadClassPathFile(details); err != nil { @@ -72,7 +73,7 @@ func loadConfigFiles(details *RunDetails) { } } -func loadClassPathFile(details *RunDetails) error { +func loadClassPathFile(details *run_details.RunDetails) error { file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) data, err := os.ReadFile(file) if err != nil { @@ -82,18 +83,18 @@ func loadClassPathFile(details *RunDetails) error { return nil } -func loadJvmArgsFile(details *RunDetails) error { +func loadJvmArgsFile(details *run_details.RunDetails) error { file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) lines, err := readLines(file) if err != nil { return errors.Wrapf(err, "error reading %s", file) } - details.addArgs(lines...) + details.AddArgs(lines...) return nil } -func loadMainClassFile(details *RunDetails) error { - dir := details.getenvOrDefault(v1.EnvVarCohUtilDir, details.UtilsDir) +func loadMainClassFile(details *run_details.RunDetails) error { + dir := details.GetenvOrDefault(v1.EnvVarCohUtilDir, details.UtilsDir) file := fmt.Sprintf(v1.FileNamePattern, dir, os.PathSeparator, v1.OperatorMainClassFile) lines, err := readLines(file) if err != nil { @@ -108,13 +109,13 @@ func loadMainClassFile(details *RunDetails) error { return nil } -func loadSpringBootArgsFile(details *RunDetails) error { +func loadSpringBootArgsFile(details *run_details.RunDetails) error { file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) lines, err := readLines(file) if err != nil { return errors.Wrapf(err, "error reading %s", file) } - details.addArgs(lines...) + details.AddArgs(lines...) return nil } diff --git a/pkg/runner/cmd_sleep.go b/pkg/runner/cmd_sleep.go index ac3efe1da..ec9515f23 100644 --- a/pkg/runner/cmd_sleep.go +++ b/pkg/runner/cmd_sleep.go @@ -8,6 +8,7 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" "strings" @@ -26,7 +27,7 @@ func sleepCommand(v *viper.Viper) *cobra.Command { Long: "Sleep for a number of seconds", Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { sleep(details, args, v) }) }, @@ -37,12 +38,12 @@ func sleepCommand(v *viper.Viper) *cobra.Command { return cmd } -func sleep(details *RunDetails, args []string, v *viper.Viper) { +func sleep(details *run_details.RunDetails, args []string, v *viper.Viper) { app := strings.ToLower(v.GetString(v1.EnvVarAppType)) if app == v1.AppTypeSpring2 { details.AppType = v1.AppTypeSpring2 details.MainClass = v1.SpringBootMain2 - details.addArg("-Dloader.main=com.oracle.coherence.k8s.Sleep") + details.AddArg("-Dloader.main=com.oracle.coherence.k8s.Sleep") } else { details.AppType = v1.AppTypeJava details.MainClass = "com.oracle.coherence.k8s.Sleep" @@ -50,16 +51,16 @@ func sleep(details *RunDetails, args []string, v *viper.Viper) { details.Command = CommandSleep details.MainArgs = args details.UseOperatorHealth = true - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.operator.health.enabled=false") - details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarCohRole, "sleep") - details.setenv(v1.EnvVarCohHealthPort, "0") + details.AddArg("-Dcoherence.distributed.localstorage=false") + details.AddArg("-Dcoherence.localport.adjust=true") + details.AddArg("-Dcoherence.management.http=none") + details.AddArg("-Dcoherence.management.http.port=0") + details.AddArg("-Dcoherence.metrics.http.enabled=false") + details.AddArg("-Dcoherence.metrics.http.port=0") + details.AddArg("-Dcoherence.operator.health.enabled=false") + details.AddArg("-Dcoherence.grpc.enabled=false") + details.Setenv(v1.EnvVarJvmMemoryNativeTracking, "off") + details.Setenv(v1.EnvVarCohRole, "sleep") + details.Setenv(v1.EnvVarCohHealthPort, "0") details.MainArgs = args } diff --git a/pkg/runner/run_details.go b/pkg/runner/run_details/run_details.go similarity index 68% rename from pkg/runner/run_details.go rename to pkg/runner/run_details/run_details.go index 8c4cc414a..8211f67b0 100644 --- a/pkg/runner/run_details.go +++ b/pkg/runner/run_details/run_details.go @@ -4,10 +4,11 @@ * http://oss.oracle.com/licenses/upl. */ -package runner +package run_details import ( "fmt" + "github.com/go-logr/logr" v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/viper" "os" @@ -15,7 +16,7 @@ import ( "strings" ) -func NewRunDetails(v *viper.Viper) *RunDetails { +func NewRunDetails(v *viper.Viper, log logr.Logger) *RunDetails { var err error skipSiteVar := v.GetString(v1.EnvVarCohSkipSite) @@ -30,11 +31,12 @@ func NewRunDetails(v *viper.Viper) *RunDetails { Dir: v.GetString(v1.EnvVarCohAppDir), MainClass: v1.DefaultMain, GetSite: skipSite, + log: log, } // add any Classpath items - details.addClasspath(v.GetString(v1.EnvVarJvmExtraClasspath)) - details.addClasspath(v.GetString(v1.EnvVarJavaClasspath)) + details.AddClasspath(v.GetString(v1.EnvVarJvmExtraClasspath)) + details.AddClasspath(v.GetString(v1.EnvVarJavaClasspath)) cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) if _, err = os.Stat(cpFile); err == nil { @@ -68,13 +70,38 @@ type RunDetails struct { ClassPathFile string JvmArgsFile string args []string + vmOptions []string + memoryArgs []string + diagnosticArgs []string env *viper.Viper + log logr.Logger } -func (in *RunDetails) GetArgs() []string { +func (in *RunDetails) GetAllArgs() []string { + var args []string + args = append(args, in.vmOptions...) + args = append(args, in.memoryArgs...) + args = append(args, in.diagnosticArgs...) + args = append(args, in.args...) + return args +} + +func (in *RunDetails) GetArguments() []string { return in.args } +func (in *RunDetails) GetMemoryOptions() []string { + return in.memoryArgs +} + +func (in *RunDetails) GetDiagnosticOptions() []string { + return in.diagnosticArgs +} + +func (in *RunDetails) GetVMOptions() []string { + return in.vmOptions +} + // IsSpringBoot returns true if this is a Spring Boot application func (in *RunDetails) IsSpringBoot() bool { if in.env == nil { @@ -110,7 +137,7 @@ func (in *RunDetails) Expand(s string, mapping func(string) string) string { buf = make([]byte, 0, 2*len(s)) } buf = append(buf, s[i:j]...) - name, w := in.getShellName(s[j+1:]) + name, w := in.GetShellName(s[j+1:]) switch { case name == "" && w > 0: // Encountered invalid syntax; eat the @@ -133,10 +160,10 @@ func (in *RunDetails) Expand(s string, mapping func(string) string) string { return string(buf) + s[i:] } -// getShellName returns the name that begins the string and the number of bytes +// GetShellName returns the name that begins the string and the number of bytes // consumed to extract it. If the name is enclosed in {}, it's part of a ${} // expansion and two more bytes are needed than the length of the name. -func (in *RunDetails) getShellName(s string) (string, int) { +func (in *RunDetails) GetShellName(s string) (string, int) { switch { case s[0] == '{': if len(s) > 2 && in.isShellSpecialVar(s[1]) && s[2] == '}' { @@ -192,55 +219,55 @@ func (in *RunDetails) isAlphaNum(c uint8) bool { return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' } -func (in *RunDetails) getenvOrDefault(name string, defaultValue string) string { +func (in *RunDetails) GetenvOrDefault(name string, defaultValue string) string { if in.env != nil && in.env.IsSet(name) { return in.env.GetString(name) } return defaultValue } -func (in *RunDetails) lookupEnv(name string) (string, bool) { +func (in *RunDetails) LookupEnv(name string) (string, bool) { if in.env != nil && in.env.IsSet(name) { return in.env.GetString(name), true } return "", false } -func (in *RunDetails) getenvWithPrefix(prefix, name string) string { +func (in *RunDetails) GetenvWithPrefix(prefix, name string) string { return in.Getenv(prefix + name) } -func (in *RunDetails) setenv(key, value string) { +func (in *RunDetails) Setenv(key, value string) { if in.env == nil { in.env = viper.New() } in.env.Set(key, value) } -func (in *RunDetails) isEnvTrue(name string) bool { +func (in *RunDetails) IsEnvTrue(name string) bool { value := in.Getenv(name) return strings.ToLower(value) == "true" } -func (in *RunDetails) isEnvTrueOrBlank(name string) bool { +func (in *RunDetails) IsEnvTrueOrBlank(name string) bool { value := in.Getenv(name) return value == "" || strings.ToLower(value) == "true" } -func (in *RunDetails) getCommand() []string { - return in.getCommandWithPrefix("", "") +func (in *RunDetails) GetCommand() []string { + return in.GetCommandWithPrefix("", "") } -func (in *RunDetails) getCommandWithPrefix(propPrefix, jvmPrefix string) []string { +func (in *RunDetails) GetCommandWithPrefix(propPrefix, jvmPrefix string) []string { var cmd []string - cp := in.getClasspath() + cp := in.GetClasspath() if cp != "" { cmd = append(cmd, "--class-path", cp) } if propPrefix == "" && jvmPrefix == "" { - cmd = append(cmd, in.args...) + cmd = append(cmd, in.GetAllArgs()...) } else { - for _, arg := range in.args { + for _, arg := range in.GetAllArgs() { if strings.HasPrefix(arg, "-D") && propPrefix != "" { cmd = append(cmd, propPrefix+arg) } else if jvmPrefix != "" { @@ -251,32 +278,50 @@ func (in *RunDetails) getCommandWithPrefix(propPrefix, jvmPrefix string) []strin return cmd } -func (in *RunDetails) getSpringBootCommand() []string { - return append(in.getSpringBootArgs(), in.MainClass) +func (in *RunDetails) GetSpringBootCommand() []string { + return append(in.GetSpringBootArgs(), in.MainClass) } -func (in *RunDetails) getSpringBootArgs() []string { +func (in *RunDetails) GetSpringBootArgs() []string { var cmd []string // Are we using a Spring Boot fat jar - if jar, _ := in.lookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { + if jar, _ := in.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { cmd = append(cmd, "--class-path", jar) } - return append(cmd, in.args...) + return append(cmd, in.GetAllArgs()...) } -func (in *RunDetails) addArgs(args ...string) { +func (in *RunDetails) AddArgs(args ...string) { for _, a := range args { - in.addArg(a) + in.AddArg(a) } } -func (in *RunDetails) addArg(arg string) { +func (in *RunDetails) AddArg(arg string) { if arg != "" { in.args = append(in.args, in.ExpandEnv(arg)) } } -func (in *RunDetails) addToFrontOfClasspath(path string) { +func (in *RunDetails) AddVMOption(arg string) { + if arg != "" { + in.vmOptions = append(in.vmOptions, in.ExpandEnv(arg)) + } +} + +func (in *RunDetails) AddMemoryOption(arg string) { + if arg != "" { + in.memoryArgs = append(in.memoryArgs, in.ExpandEnv(arg)) + } +} + +func (in *RunDetails) AddDiagnosticOption(arg string) { + if arg != "" { + in.diagnosticArgs = append(in.diagnosticArgs, in.ExpandEnv(arg)) + } +} + +func (in *RunDetails) AddToFrontOfClasspath(path string) { if path != "" { if in.Classpath == "" { in.Classpath = in.ExpandEnv(path) @@ -287,7 +332,7 @@ func (in *RunDetails) addToFrontOfClasspath(path string) { } // addJarsToClasspath adds all jars in the specified directory to the classpath -func (in *RunDetails) addJarsToClasspath(dir string) { +func (in *RunDetails) AddJarsToClasspath(dir string) { path := in.ExpandEnv(dir) if _, err := os.Stat(path); err == nil { var jars []string @@ -300,18 +345,18 @@ func (in *RunDetails) addJarsToClasspath(dir string) { }) for _, jar := range jars { - in.addClasspath(jar) + in.AddClasspath(jar) } } } -func (in *RunDetails) addClasspathIfExists(path string) { +func (in *RunDetails) AddClasspathIfExists(path string) { if _, err := os.Stat(path); err == nil { - in.addClasspath(path) + in.AddClasspath(path) } } -func (in *RunDetails) addClasspath(path string) { +func (in *RunDetails) AddClasspath(path string) { if path != "" { if in.Classpath == "" { in.Classpath = in.ExpandEnv(path) @@ -321,7 +366,7 @@ func (in *RunDetails) addClasspath(path string) { } } -func (in *RunDetails) getClasspath() string { +func (in *RunDetails) GetClasspath() string { cp := in.Classpath // if ${COHERENCE_HOME} exists add coherence.jar to the classpath if in.CoherenceHome != "" { @@ -337,15 +382,15 @@ func (in *RunDetails) getClasspath() string { return cp } -func (in *RunDetails) addArgFromEnvVar(name, property string) { +func (in *RunDetails) AddArgFromEnvVar(name, property string) { value := in.Getenv(name) if value != "" { s := fmt.Sprintf("%s=%s", property, value) - in.args = append(in.args, s) + in.AddArg(s) } } -func (in *RunDetails) setSystemPropertyFromEnvVarOrDefault(name, property, dflt string) { +func (in *RunDetails) SetSystemPropertyFromEnvVarOrDefault(name, property, dflt string) { value := in.Getenv(name) var s string if value != "" { @@ -353,48 +398,55 @@ func (in *RunDetails) setSystemPropertyFromEnvVarOrDefault(name, property, dflt } else { s = fmt.Sprintf("%s=%s", property, dflt) } - in.args = append(in.args, s) + in.AddArg(s) } -func (in *RunDetails) getJavaExecutable() string { +func (in *RunDetails) GetJavaExecutable() string { if in.JavaHome != "" { return in.JavaHome + "/bin/java" } return "java" } -func (in *RunDetails) getJShellExecutable() string { +func (in *RunDetails) GetJShellExecutable() string { if in.JavaHome != "" { return in.JavaHome + "/bin/jshell" } return "jshell" } -// isBuildPacks determines whether to run the application with the Cloud Native Buildpack launcher -func (in *RunDetails) isBuildPacks() bool { +// IsBuildPacks determines whether to run the application with the Cloud Native Buildpack launcher +func (in *RunDetails) IsBuildPacks() bool { if in.BuildPacks == nil { var bp bool detect := strings.ToLower(in.env.GetString(v1.EnvVarCnbpEnabled)) switch detect { case "true": - log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) + in.log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) bp = true case "false": - log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) + in.log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) bp = false default: - log.Info("Auto-detecting Cloud Native Buildpacks") + in.log.Info("Auto-detecting Cloud Native Buildpacks") // else auto detect // look for the CNB API environment variable _, ok := os.LookupEnv("CNB_PLATFORM_API") - log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB_PLATFORM_API found=%t", ok)) + in.log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB_PLATFORM_API found=%t", ok)) // look for the CNB launcher - launcher := getBuildpackLauncher() + launcher := GetBuildpackLauncher() _, err := os.Stat(launcher) - log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB Launcher '%s' found=%t\n", launcher, err == nil)) + in.log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB Launcher '%s' found=%t\n", launcher, err == nil)) bp = ok && err == nil } in.BuildPacks = &bp } return *in.BuildPacks } + +func GetBuildpackLauncher() string { + if launcher, ok := os.LookupEnv(v1.EnvVarCnbpLauncher); ok { + return launcher + } + return v1.DefaultCnbpLauncher +} diff --git a/pkg/runner/rundetails_test.go b/pkg/runner/run_details/rundetails_test.go similarity index 63% rename from pkg/runner/rundetails_test.go rename to pkg/runner/run_details/rundetails_test.go index 3681d9f86..342268892 100644 --- a/pkg/runner/rundetails_test.go +++ b/pkg/runner/run_details/rundetails_test.go @@ -1,17 +1,22 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -package runner +package run_details import ( . "github.com/onsi/gomega" "github.com/spf13/viper" + ctrl "sigs.k8s.io/controller-runtime" "testing" ) +var ( + testLog = ctrl.Log.WithName("test") +) + func TestRunDetailsGetenvWhenMissing(t *testing.T) { g := NewGomegaWithT(t) @@ -25,15 +30,15 @@ func TestRunDetailsGetenvWhenPresent(t *testing.T) { v := viper.New() v.Set("foo", "bar") - r := NewRunDetails(v) + r := NewRunDetails(v, testLog) g.Expect(r.Getenv("foo")).To(Equal("bar")) } func TestRunDetailsGetenvWithPrefixWhenMissing(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - g.Expect(r.getenvWithPrefix("foo", "_test")).To(Equal("")) + r := NewRunDetails(viper.New(), testLog) + g.Expect(r.GetenvWithPrefix("foo", "_test")).To(Equal("")) } func TestRunDetailsGetenvWithPrefixWhenPresent(t *testing.T) { @@ -42,15 +47,15 @@ func TestRunDetailsGetenvWithPrefixWhenPresent(t *testing.T) { v := viper.New() v.Set("foo_test", "bar") - r := NewRunDetails(v) - g.Expect(r.getenvWithPrefix("foo", "_test")).To(Equal("bar")) + r := NewRunDetails(v, testLog) + g.Expect(r.GetenvWithPrefix("foo", "_test")).To(Equal("bar")) } func TestRunDetailsAddClasspath(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") g.Expect(r.Classpath).To(Equal("foo")) } @@ -60,88 +65,88 @@ func TestRunDetailsAddClasspathWithExpansion(t *testing.T) { v := viper.New() v.Set("FOO", "foo-value") - r := NewRunDetails(v) + r := NewRunDetails(v, testLog) - r.addClasspath("${FOO}") + r.AddClasspath("${FOO}") g.Expect(r.Classpath).To(Equal("foo-value")) } func TestRunDetailsAddClasspathMultipleTimes(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") - r.addClasspath("bar") + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") + r.AddClasspath("bar") g.Expect(r.Classpath).To(Equal("foo:bar")) } func TestRunDetailsAddClasspathEmptyString(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") - r.addClasspath("") + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") + r.AddClasspath("") g.Expect(r.Classpath).To(Equal("foo")) } func TestRunDetailsAddToFrontClasspath(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.Classpath = "foo" - r.addToFrontOfClasspath("bar") + r.AddToFrontOfClasspath("bar") g.Expect(r.Classpath).To(Equal("bar:foo")) } func TestRunDetailsAddToFrontClasspathMultipleTimes(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.Classpath = "foo" - r.addToFrontOfClasspath("bar1") - r.addToFrontOfClasspath("bar2") + r.AddToFrontOfClasspath("bar1") + r.AddToFrontOfClasspath("bar2") g.Expect(r.Classpath).To(Equal("bar2:bar1:foo")) } func TestRunDetailsAddToFrontOfClasspathEmptyString(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.Classpath = "foo" - r.addToFrontOfClasspath("") + r.AddToFrontOfClasspath("") g.Expect(r.Classpath).To(Equal("foo")) } func TestRunDetailsGetClasspath(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") - g.Expect(r.getClasspath()).To(Equal("foo")) + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") + g.Expect(r.GetClasspath()).To(Equal("foo")) } func TestRunDetailsGetJavaEmpty(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - g.Expect(r.getJavaExecutable()).To(Equal("java")) + r := NewRunDetails(viper.New(), testLog) + g.Expect(r.GetJavaExecutable()).To(Equal("java")) } func TestRunDetailsGetJavaWhenJavaHomeSet(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.JavaHome = "/local/bin/jdk11" - g.Expect(r.getJavaExecutable()).To(Equal("/local/bin/jdk11/bin/java")) + g.Expect(r.GetJavaExecutable()).To(Equal("/local/bin/jdk11/bin/java")) } func TestRunDetailsGetCommandWhenEmpty(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) var expected []string - g.Expect(r.getCommand()).To(Equal(expected)) + g.Expect(r.GetCommand()).To(Equal(expected)) } func TestExpandEnv(t *testing.T) { @@ -152,7 +157,7 @@ func TestExpandEnv(t *testing.T) { env["B"] = "value-b" env["C"] = "value-c" - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) result := r.Expand("$(A) ${B} $C", func(s string) string { return env[s] }) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 1d229298f..67fe70156 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -14,6 +14,7 @@ import ( "github.com/go-logr/logr" v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/pkg/operator" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -213,10 +214,10 @@ func ExecuteWithArgsAndViper(env map[string]string, args []string, v *viper.Vipe } // RunFunction is a function to run a command -type RunFunction func(*RunDetails, *cobra.Command) +type RunFunction func(*run_details.RunDetails, *cobra.Command) // MaybeRunFunction is a function to maybe run a command depending on the return bool -type MaybeRunFunction func(*RunDetails, *cobra.Command) (bool, error) +type MaybeRunFunction func(*run_details.RunDetails, *cobra.Command) (bool, error) // always is a wrapper around a RunFunction to turn it into a MaybeFunction that always runs type always struct { @@ -224,7 +225,7 @@ type always struct { } // run will wrap a RunFunction and always return true -func (in always) run(details *RunDetails, cmd *cobra.Command) (bool, error) { +func (in always) run(details *run_details.RunDetails, cmd *cobra.Command) (bool, error) { in.Fn(details, cmd) return true, nil } @@ -240,7 +241,7 @@ func maybeRun(cmd *cobra.Command, fn MaybeRunFunction) error { var err error e := fromContext(cmd.Context()) - details := NewRunDetails(e.V) + details := run_details.NewRunDetails(e.V, log) runCommand, err := fn(details, cmd) if err != nil { return err @@ -283,29 +284,29 @@ func fromContext(ctx context.Context) *Execution { } // configure the command details. -func configureCommand(details *RunDetails) error { +func configureCommand(details *run_details.RunDetails) error { var err error // Set standard system properties - details.addArg("-Dcoherence.ttl=0") - details.addArgFromEnvVar(v1.EnvVarCohWka, "-Dcoherence.wka") - details.addArgFromEnvVar(v1.EnvVarCohMachineName, "-Dcoherence.machine") - details.addArgFromEnvVar(v1.EnvVarCohMemberName, "-Dcoherence.member") - details.addArgFromEnvVar(v1.EnvVarCohClusterName, "-Dcoherence.cluster") - details.addArgFromEnvVar(v1.EnvVarCohCacheConfig, "-Dcoherence.cacheconfig") - details.addArgFromEnvVar(v1.EnvVarCohIdentity, "-Dcoherence.operator.identity") - details.addArgFromEnvVar(v1.EnvVarCohForceExit, "-Dcoherence.operator.force.exit") - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.operator.health.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.management.http.port", fmt.Sprintf("%d", v1.DefaultManagementPort)) - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.metrics.http.port", fmt.Sprintf("%d", v1.DefaultMetricsPort)) - - details.addArg("-XX:+UnlockDiagnosticVMOptions") + details.AddArg("-Dcoherence.ttl=0") + details.AddArgFromEnvVar(v1.EnvVarCohWka, "-Dcoherence.wka") + details.AddArgFromEnvVar(v1.EnvVarCohMachineName, "-Dcoherence.machine") + details.AddArgFromEnvVar(v1.EnvVarCohMemberName, "-Dcoherence.member") + details.AddArgFromEnvVar(v1.EnvVarCohClusterName, "-Dcoherence.cluster") + details.AddArgFromEnvVar(v1.EnvVarCohCacheConfig, "-Dcoherence.cacheconfig") + details.AddArgFromEnvVar(v1.EnvVarCohIdentity, "-Dcoherence.operator.identity") + details.AddArgFromEnvVar(v1.EnvVarCohForceExit, "-Dcoherence.operator.force.exit") + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.operator.health.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.management.http.port", fmt.Sprintf("%d", v1.DefaultManagementPort)) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.metrics.http.port", fmt.Sprintf("%d", v1.DefaultMetricsPort)) + + details.AddVMOption("-XX:+UnlockDiagnosticVMOptions") // Configure the classpath to support images created with the JIB Maven plugin // This is enabled by default unless the image is a buildpacks image, or we // are running a Spring Boot application. - if !details.isBuildPacks() && !details.IsSpringBoot() && details.isEnvTrueOrBlank(v1.EnvVarJvmClasspathJib) { - appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") + if !details.IsBuildPacks() && !details.IsSpringBoot() && details.IsEnvTrueOrBlank(v1.EnvVarJvmClasspathJib) { + appDir := details.GetenvOrDefault(v1.EnvVarCohAppDir, "/app") cpFile := filepath.Join(appDir, "jib-classpath-file") fi, e := os.Stat(cpFile) if e != nil && appDir != "/app" { @@ -317,48 +318,48 @@ func configureCommand(details *RunDetails) error { if e == nil && (fi.Size() != 0) { clsPath, _ := readFirstLineFromFile(cpFile) if len(clsPath) != 0 { - details.addClasspath(clsPath) + details.AddClasspath(clsPath) } } else { - details.addClasspathIfExists(appDir + "/resources") - details.addClasspathIfExists(appDir + "/classes") - details.addJarsToClasspath(appDir + "/classpath") - details.addJarsToClasspath(appDir + "/libs") + details.AddClasspathIfExists(appDir + "/resources") + details.AddClasspathIfExists(appDir + "/classes") + details.AddJarsToClasspath(appDir + "/classpath") + details.AddJarsToClasspath(appDir + "/libs") } } // Add the Operator Utils jar to the classpath - details.addClasspath(details.UtilsDir + v1.OperatorJarFileSuffix) - details.addClasspathIfExists(details.UtilsDir + v1.OperatorConfigDirSuffix) + details.AddClasspath(details.UtilsDir + v1.OperatorJarFileSuffix) + details.AddClasspathIfExists(details.UtilsDir + v1.OperatorConfigDirSuffix) // Configure Coherence persistence - mode := details.getenvOrDefault(v1.EnvVarCohPersistenceMode, "on-demand") - details.addArg("-Dcoherence.distributed.persistence-mode=" + mode) + mode := details.GetenvOrDefault(v1.EnvVarCohPersistenceMode, "on-demand") + details.AddArg("-Dcoherence.distributed.persistence-mode=" + mode) persistence := details.Getenv(v1.EnvVarCohPersistenceDir) if persistence != "" { - details.addArg("-Dcoherence.distributed.persistence.base.dir=" + persistence) + details.AddArg("-Dcoherence.distributed.persistence.base.dir=" + persistence) } snapshots := details.Getenv(v1.EnvVarCohSnapshotDir) if snapshots != "" { - details.addArg("-Dcoherence.distributed.persistence.snapshot.dir=" + snapshots) + details.AddArg("-Dcoherence.distributed.persistence.snapshot.dir=" + snapshots) } // Set the Coherence site and rack values configureSiteAndRack(details) // Set the Coherence log level - details.addArgFromEnvVar(v1.EnvVarCohLogLevel, "-Dcoherence.log.level") + details.AddArgFromEnvVar(v1.EnvVarCohLogLevel, "-Dcoherence.log.level") // Disable IPMonitor ipMon := details.Getenv(v1.EnvVarEnableIPMonitor) if ipMon != "TRUE" { - details.addArg("-Dcoherence.ipmonitor.pingtimeout=0") + details.AddArg("-Dcoherence.ipmonitor.pingtimeout=0") } - details.addArg("-Dcoherence.override=k8s-coherence-override.xml") - details.addArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") + details.AddArg("-Dcoherence.override=k8s-coherence-override.xml") + details.AddArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") post2206 := checkCoherenceVersion("14.1.1.2206.0", details) if post2206 { @@ -386,7 +387,7 @@ func configureCommand(details *RunDetails) error { allowEndangered := details.Getenv(v1.EnvVarCohAllowEndangered) if allowEndangered != "" { - details.addArg("-Dcoherence.operator.statusha.allowendangered=" + allowEndangered) + details.AddArg("-Dcoherence.operator.statusha.allowendangered=" + allowEndangered) } // Get the K8s Pod UID @@ -409,49 +410,49 @@ func configureCommand(details *RunDetails) error { } } - details.addArg(fmt.Sprintf("-Dcoherence.operator.diagnostics.dir=%s", jvmDir)) - details.addArg(fmt.Sprintf("-XX:HeapDumpPath=%s/heap-dumps/%s-%s.hprof", jvmDir, member, podUID)) + details.AddArg(fmt.Sprintf("-Dcoherence.operator.diagnostics.dir=%s", jvmDir)) + details.AddVMOption(fmt.Sprintf("-XX:HeapDumpPath=%s/heap-dumps/%s-%s.hprof", jvmDir, member, podUID)) // set the flag that allows the operator to resume suspended services on start-up - if !details.isEnvTrueOrBlank(v1.EnvVarOperatorAllowResume) { - details.addArg("-Dcoherence.operator.can.resume.services=false") + if !details.IsEnvTrueOrBlank(v1.EnvVarOperatorAllowResume) { + details.AddArg("-Dcoherence.operator.can.resume.services=false") } else { - details.addArg("-Dcoherence.operator.can.resume.services=true") + details.AddArg("-Dcoherence.operator.can.resume.services=true") } if svc := details.Getenv(v1.EnvVarOperatorResumeServices); svc != "" { - details.addArg("-Dcoherence.operator.resume.services=base64:" + svc) + details.AddArg("-Dcoherence.operator.resume.services=base64:" + svc) } gc := strings.ToLower(details.Getenv(v1.EnvVarJvmGcCollector)) switch { case gc == "" || gc == "g1": - details.addArg("-XX:+UseG1GC") + details.AddMemoryOption("-XX:+UseG1GC") case gc == "cms": - details.addArg("-XX:+UseConcMarkSweepGC") + details.AddMemoryOption("-XX:+UseConcMarkSweepGC") case gc == "parallel": - details.addArg("-XX:+UseParallelGC") + details.AddMemoryOption("-XX:+UseParallelGC") } maxRAM := details.Getenv(v1.EnvVarJvmMaxRAM) if maxRAM != "" { - details.addArg("-XX:MaxRAM=" + maxRAM) + details.AddMemoryOption("-XX:MaxRAM=" + maxRAM) } heap := details.Getenv(v1.EnvVarJvmMemoryHeap) if heap != "" { // if heap is set use it - details.addArg("-XX:InitialHeapSize=" + heap) - details.addArg("-XX:MaxHeapSize=" + heap) + details.AddMemoryOption("-XX:InitialHeapSize=" + heap) + details.AddMemoryOption("-XX:MaxHeapSize=" + heap) } else { // if heap is not set check whether the individual heap values are set initialHeap := details.Getenv(v1.EnvVarJvmMemoryInitialHeap) if initialHeap != "" { - details.addArg("-XX:InitialHeapSize=" + initialHeap) + details.AddMemoryOption("-XX:InitialHeapSize=" + initialHeap) } maxHeap := details.Getenv(v1.EnvVarJvmMemoryMaxHeap) if maxHeap != "" { - details.addArg("-XX:MaxHeapSize=" + maxHeap) + details.AddMemoryOption("-XX:MaxHeapSize=" + maxHeap) } } @@ -461,9 +462,9 @@ func configureCommand(details *RunDetails) error { q, err := resource.ParseQuantity(percentageHeap) if err == nil { d := q.AsDec() - details.addArg("-XX:InitialRAMPercentage=" + d.String()) - details.addArg("-XX:MinRAMPercentage=" + d.String()) - details.addArg("-XX:MaxRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:InitialRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MinRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MaxRAMPercentage=" + d.String()) } else { log.Info("ERROR: Heap Percentage is not a valid resource.Quantity", "Value", percentageHeap, "Error", err.Error()) os.Exit(1) @@ -475,7 +476,7 @@ func configureCommand(details *RunDetails) error { q, err := resource.ParseQuantity(initial) if err == nil { d := q.AsDec() - details.addArg("-XX:InitialRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:InitialRAMPercentage=" + d.String()) } else { log.Info("ERROR: InitialRAMPercentage is not a valid resource.Quantity", "Value", initial, "Error", err.Error()) os.Exit(1) @@ -487,7 +488,7 @@ func configureCommand(details *RunDetails) error { q, err := resource.ParseQuantity(maxRam) if err == nil { d := q.AsDec() - details.addArg("-XX:MaxRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MaxRAMPercentage=" + d.String()) } else { log.Info("ERROR: MaxRAMPercentage is not a valid resource.Quantity", "Value", maxRam, "Error", err.Error()) os.Exit(1) @@ -499,7 +500,7 @@ func configureCommand(details *RunDetails) error { q, err := resource.ParseQuantity(minRam) if err == nil { d := q.AsDec() - details.addArg("-XX:MinRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MinRAMPercentage=" + d.String()) } else { log.Info("ERROR: MinRAMPercentage is not a valid resource.Quantity", "Value", minRam, "Error", err.Error()) os.Exit(1) @@ -509,28 +510,28 @@ func configureCommand(details *RunDetails) error { direct := details.Getenv(v1.EnvVarJvmMemoryDirect) if direct != "" { - details.addArg("-XX:MaxDirectMemorySize=" + direct) + details.AddMemoryOption("-XX:MaxDirectMemorySize=" + direct) } stack := details.Getenv(v1.EnvVarJvmMemoryStack) if stack != "" { - details.addArg("-Xss" + stack) + details.AddMemoryOption("-Xss" + stack) } meta := details.Getenv(v1.EnvVarJvmMemoryMeta) if meta != "" { - details.addArg("-XX:MetaspaceSize=" + meta) - details.addArg("-XX:MaxMetaspaceSize=" + meta) + details.AddMemoryOption("-XX:MetaspaceSize=" + meta) + details.AddMemoryOption("-XX:MaxMetaspaceSize=" + meta) } - track := details.getenvOrDefault(v1.EnvVarJvmMemoryNativeTracking, "summary") + track := details.GetenvOrDefault(v1.EnvVarJvmMemoryNativeTracking, "summary") if track != "" { - details.addArg("-XX:NativeMemoryTracking=" + track) - details.addArg("-XX:+PrintNMTStatistics") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=" + track) + details.AddDiagnosticOption("-XX:+PrintNMTStatistics") } // Configure debugging debugArgs := "" - if details.isEnvTrue(v1.EnvVarJvmDebugEnabled) { + if details.IsEnvTrue(v1.EnvVarJvmDebugEnabled) { var suspend string - if details.isEnvTrue(v1.EnvVarJvmDebugSuspended) { + if details.IsEnvTrue(v1.EnvVarJvmDebugSuspended) { suspend = "y" } else { suspend = "n" @@ -549,43 +550,43 @@ func configureCommand(details *RunDetails) error { } } - details.addArg(fmt.Sprintf("-XX:ErrorFile=%s/hs-err-%s-%s.log", jvmDir, member, podUID)) + details.AddVMOption(fmt.Sprintf("-XX:ErrorFile=%s/hs-err-%s-%s.log", jvmDir, member, podUID)) - if details.isEnvTrueOrBlank(v1.EnvVarJvmOomHeapDump) { - details.addArg("-XX:+HeapDumpOnOutOfMemoryError") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmOomHeapDump) { + details.AddVMOption("-XX:+HeapDumpOnOutOfMemoryError") } - if details.isEnvTrueOrBlank(v1.EnvVarJvmOomExit) { - details.addArg("-XX:+ExitOnOutOfMemoryError") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmOomExit) { + details.AddVMOption("-XX:+ExitOnOutOfMemoryError") } // Use JVM container support - if details.isEnvTrueOrBlank(v1.EnvVarJvmUseContainerLimits) { - details.addArg("-XX:+UseContainerSupport") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmUseContainerLimits) { + details.AddVMOption("-XX:+UseContainerSupport") } - details.addArgs(debugArgs) + details.AddArgs(debugArgs) gcArgs := details.Getenv(v1.EnvVarJvmGcArgs) if gcArgs != "" { - details.addArgs(strings.Split(gcArgs, " ")...) + details.AddArgs(strings.Split(gcArgs, " ")...) } jvmArgs := details.Getenv(v1.EnvVarJvmArgs) if jvmArgs != "" { - details.addArgs(strings.Split(jvmArgs, " ")...) + details.AddArgs(strings.Split(jvmArgs, " ")...) } extraJvmArgs := operator.GetExtraJvmArgs() if extraJvmArgs != nil { - details.addArgs(extraJvmArgs...) + details.AddArgs(extraJvmArgs...) } return nil } // create the process to execute. -func createCommand(details *RunDetails) (string, *exec.Cmd, error) { +func createCommand(details *run_details.RunDetails) (string, *exec.Cmd, error) { var err error var cmd *exec.Cmd var app string @@ -593,19 +594,19 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { switch { case details.AppType == v1.AppTypeNone || details.AppType == v1.AppTypeJava: app = "Java" - cmd, err = createJavaCommand(details.getJavaExecutable(), details) + cmd, err = createJavaCommand(details.GetJavaExecutable(), details) case details.IsSpringBoot(): app = "SpringBoot" - cmd, err = createSpringBootCommand(details.getJavaExecutable(), details) + cmd, err = createSpringBootCommand(details.GetJavaExecutable(), details) case details.AppType == v1.AppTypeHelidon: app = "Java" - cmd, err = createJavaCommand(details.getJavaExecutable(), details) + cmd, err = createJavaCommand(details.GetJavaExecutable(), details) case details.AppType == v1.AppTypeCoherence: app = "Java" - cmd, err = createJavaCommand(details.getJavaExecutable(), details) + cmd, err = createJavaCommand(details.GetJavaExecutable(), details) case details.AppType == v1.AppTypeJShell: app = "JShell" - cmd, err = createJShellCommand(details.getJShellExecutable(), details) + cmd, err = createJShellCommand(details.GetJShellExecutable(), details) case details.AppType == v1.AppTypeOperator: app = "Operator" cmd, err = createOperatorCommand(details) @@ -622,14 +623,14 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { return app, cmd, err } -func createJavaCommand(javaCmd string, details *RunDetails) (*exec.Cmd, error) { - args := details.getCommand() +func createJavaCommand(javaCmd string, details *run_details.RunDetails) (*exec.Cmd, error) { + args := details.GetCommand() args = append(args, details.MainClass) return _createJavaCommand(javaCmd, details, args) } -func createJShellCommand(jshellCmd string, details *RunDetails) (*exec.Cmd, error) { - args := details.getCommandWithPrefix("-R", "-J") +func createJShellCommand(jshellCmd string, details *run_details.RunDetails) (*exec.Cmd, error) { + args := details.GetCommandWithPrefix("-R", "-J") return _createJavaCommand(jshellCmd, details, args) } @@ -652,18 +653,18 @@ func readFirstLineFromFile(path string) (string, error) { return text[0], nil } -func createSpringBootCommand(javaCmd string, details *RunDetails) (*exec.Cmd, error) { - if details.isBuildPacks() { +func createSpringBootCommand(javaCmd string, details *run_details.RunDetails) (*exec.Cmd, error) { + if details.IsBuildPacks() { if details.AppType == v1.AppTypeSpring2 { - return _createBuildPackCommand(details, v1.SpringBootMain2, details.getSpringBootArgs()) + return _createBuildPackCommand(details, v1.SpringBootMain2, details.GetSpringBootArgs()) } - return _createBuildPackCommand(details, v1.SpringBootMain3, details.getSpringBootArgs()) + return _createBuildPackCommand(details, v1.SpringBootMain3, details.GetSpringBootArgs()) } - args := details.getSpringBootCommand() + args := details.GetSpringBootCommand() return _createJavaCommand(javaCmd, details, args) } -func _createJavaCommand(javaCmd string, details *RunDetails, args []string) (*exec.Cmd, error) { +func _createJavaCommand(javaCmd string, details *run_details.RunDetails, args []string) (*exec.Cmd, error) { args = append(args, details.MainArgs...) cmd := exec.Command(javaCmd, args...) cmd.Stdout = os.Stdout @@ -681,7 +682,7 @@ func _createJavaCommand(javaCmd string, details *RunDetails, args []string) (*ex return cmd, nil } -func createOperatorCommand(details *RunDetails) (*exec.Cmd, error) { +func createOperatorCommand(details *run_details.RunDetails) (*exec.Cmd, error) { executable := os.Args[0] args := details.MainArgs[1:] cmd := exec.Command(executable, args...) @@ -700,8 +701,8 @@ func createOperatorCommand(details *RunDetails) (*exec.Cmd, error) { return cmd, nil } -func _createBuildPackCommand(_ *RunDetails, className string, args []string) (*exec.Cmd, error) { - launcher := getBuildpackLauncher() +func _createBuildPackCommand(_ *run_details.RunDetails, className string, args []string) (*exec.Cmd, error) { + launcher := run_details.GetBuildpackLauncher() // Create the JVM arguments file argsFile, err := os.CreateTemp("", "jvm-args") @@ -725,17 +726,10 @@ func _createBuildPackCommand(_ *RunDetails, className string, args []string) (*e return cmd, nil } -func getBuildpackLauncher() string { - if launcher, ok := os.LookupEnv(v1.EnvVarCnbpLauncher); ok { - return launcher - } - return v1.DefaultCnbpLauncher -} - -func createGraalCommand(details *RunDetails) (*exec.Cmd, error) { +func createGraalCommand(details *run_details.RunDetails) (*exec.Cmd, error) { ex := details.AppType args := []string{"--polyglot", "--jvm"} - args = append(args, details.getCommand()...) + args = append(args, details.GetCommand()...) args = append(args, details.MainClass) args = append(args, details.MainArgs...) @@ -756,7 +750,7 @@ func createGraalCommand(details *RunDetails) (*exec.Cmd, error) { } // Set the Coherence site and rack values -func configureSiteAndRack(details *RunDetails) { +func configureSiteAndRack(details *run_details.RunDetails) { var err error if !details.GetSite { return @@ -787,7 +781,7 @@ func configureSiteAndRack(details *RunDetails) { } if site != "" { - details.addArg("-Dcoherence.site=" + site) + details.AddArg("-Dcoherence.site=" + site) } } else { expanded := details.ExpandEnv(site) @@ -795,10 +789,10 @@ func configureSiteAndRack(details *RunDetails) { log.Info("Coherence site property set from expanded "+v1.EnvVarCoherenceSite+" environment variable", v1.EnvVarCoherenceSite, site, "Site", expanded) site = expanded if strings.TrimSpace(site) != "" { - details.addArg("-Dcoherence.site=" + site) + details.AddArg("-Dcoherence.site=" + site) } } else { - details.addArg("-Dcoherence.site=" + site) + details.AddArg("-Dcoherence.site=" + site) } } @@ -825,9 +819,9 @@ func configureSiteAndRack(details *RunDetails) { } if rack != "" { - details.addArg("-Dcoherence.rack=" + rack) + details.AddArg("-Dcoherence.rack=" + rack) } else if site != "" { - details.addArg("-Dcoherence.rack=" + site) + details.AddArg("-Dcoherence.rack=" + site) } } else { expanded := details.ExpandEnv(rack) @@ -840,10 +834,10 @@ func configureSiteAndRack(details *RunDetails) { rack = site } if strings.TrimSpace(rack) != "" { - details.addArg("-Dcoherence.rack=" + rack) + details.AddArg("-Dcoherence.rack=" + rack) } } else { - details.addArg("-Dcoherence.rack=" + rack) + details.AddArg("-Dcoherence.rack=" + rack) } } } @@ -856,7 +850,7 @@ func maybeStripFileScheme(uri string) string { } // httpGetWithBackoff does a http get for the specified url with retry back-off for errors. -func httpGetWithBackoff(url string, details *RunDetails) string { +func httpGetWithBackoff(url string, details *run_details.RunDetails) string { var backoff time.Duration timeout := 120 @@ -950,28 +944,28 @@ func httpGet(urlString string, client http.Client) (string, int, error) { return s, resp.StatusCode, nil } -func checkCoherenceVersion(v string, details *RunDetails) bool { +func checkCoherenceVersion(v string, details *run_details.RunDetails) bool { log.Info("Performing Coherence version check", "version", v) - if details.isEnvTrue(v1.EnvVarCohSkipVersionCheck) { + if details.IsEnvTrue(v1.EnvVarCohSkipVersionCheck) { log.Info("Skipping Coherence version check", "envVar", v1.EnvVarCohSkipVersionCheck, "value", details.Getenv(v1.EnvVarCohSkipVersionCheck)) return true } // Get the classpath to use (we need Coherence jar) - cp := details.getClasspath() + cp := details.GetClasspath() var exe string var cmd *exec.Cmd var args []string - if details.isBuildPacks() { + if details.IsBuildPacks() { // This is a build-packs image so use the Build-packs launcher to run Java - exe = getBuildpackLauncher() + exe = run_details.GetBuildpackLauncher() args = []string{exe} } else { // this should be a normal image with Java available - exe = details.getJavaExecutable() + exe = details.GetJavaExecutable() } if details.IsSpringBoot() { @@ -981,7 +975,7 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { "-Dcoherence.operator.springboot.listener=false", "-Dloader.main=com.oracle.coherence.k8s.CoherenceVersion") - if jar, _ := details.lookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { + if jar, _ := details.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { // This is a fat jar Spring boot app so put the fat jar on the classpath args = append(args, "--class-path", jar) } @@ -1024,32 +1018,32 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { return true } -func cohPost2206(details *RunDetails) { +func cohPost2206(details *run_details.RunDetails) { if details.UseOperatorHealth { - details.addArg("-Dcoherence.operator.health.enabled=true") + details.AddArg("-Dcoherence.operator.health.enabled=true") } else { - useOperator := details.getenvOrDefault(v1.EnvVarUseOperatorHealthCheck, "false") + useOperator := details.GetenvOrDefault(v1.EnvVarUseOperatorHealthCheck, "false") if strings.EqualFold("true", useOperator) { - details.addArg("-Dcoherence.operator.health.enabled=true") + details.AddArg("-Dcoherence.operator.health.enabled=true") } else { - details.addArg("-Dcoherence.operator.health.enabled=false") - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.health.http.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.AddArg("-Dcoherence.operator.health.enabled=false") + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.health.http.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) } } } -func addManagementSSL(details *RunDetails) { +func addManagementSSL(details *run_details.RunDetails) { addSSL(v1.EnvVarCohMgmtPrefix, v1.PortNameManagement, details) } -func addMetricsSSL(details *RunDetails) { +func addMetricsSSL(details *run_details.RunDetails) { addSSL(v1.EnvVarCohMetricsPrefix, v1.PortNameMetrics, details) } -func addSSL(prefix, prop string, details *RunDetails) { +func addSSL(prefix, prop string, details *run_details.RunDetails) { var urlPrefix string - sslCerts := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLCerts) + sslCerts := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLCerts) if sslCerts != "" { if !strings.HasSuffix(sslCerts, "/") { sslCerts += "/" @@ -1063,58 +1057,58 @@ func addSSL(prefix, prop string, details *RunDetails) { urlPrefix = "file:" } - if details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLEnabled) != "" { - details.addArg("-Dcoherence." + prop + ".http.provider=ManagementSSLProvider") + if details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLEnabled) != "" { + details.AddArg("-Dcoherence." + prop + ".http.provider=ManagementSSLProvider") } - ks := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStore) + ks := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStore) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore=" + urlPrefix + ks) + details.AddArg("-Dcoherence." + prop + ".security.keystore=" + urlPrefix + ks) } - kspw := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreCredFile) + kspw := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreCredFile) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.password=" + urlPrefix + kspw) + details.AddArg("-Dcoherence." + prop + ".security.keystore.password=" + urlPrefix + kspw) } - kpw := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyCredFile) + kpw := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyCredFile) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.key.password=" + urlPrefix + kpw) + details.AddArg("-Dcoherence." + prop + ".security.key.password=" + urlPrefix + kpw) } - kalg := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreAlgo) + kalg := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreAlgo) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.algorithm=" + urlPrefix + kalg) + details.AddArg("-Dcoherence." + prop + ".security.keystore.algorithm=" + urlPrefix + kalg) } - kprov := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreProvider) + kprov := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreProvider) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.provider=" + urlPrefix + kprov) + details.AddArg("-Dcoherence." + prop + ".security.keystore.provider=" + urlPrefix + kprov) } - ktyp := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreType) + ktyp := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreType) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.type=" + urlPrefix + ktyp) + details.AddArg("-Dcoherence." + prop + ".security.keystore.type=" + urlPrefix + ktyp) } - ts := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStore) + ts := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStore) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore=" + urlPrefix + ts) + details.AddArg("-Dcoherence." + prop + ".security.truststore=" + urlPrefix + ts) } - tspw := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreCredFile) + tspw := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreCredFile) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.password=" + urlPrefix + tspw) + details.AddArg("-Dcoherence." + prop + ".security.truststore.password=" + urlPrefix + tspw) } - talg := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreAlgo) + talg := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreAlgo) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.algorithm=" + urlPrefix + talg) + details.AddArg("-Dcoherence." + prop + ".security.truststore.algorithm=" + urlPrefix + talg) } - tprov := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreProvider) + tprov := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreProvider) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.provider=" + urlPrefix + tprov) + details.AddArg("-Dcoherence." + prop + ".security.truststore.provider=" + urlPrefix + tprov) } - ttyp := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreType) + ttyp := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreType) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.type=" + urlPrefix + ttyp) + details.AddArg("-Dcoherence." + prop + ".security.truststore.type=" + urlPrefix + ttyp) } - if details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLRequireClientCert) != "" { - details.addArg("-Dcoherence." + prop + ".http.auth=cert") + if details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLRequireClientCert) != "" { + details.AddArg("-Dcoherence." + prop + ".http.auth=cert") } } diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index a01a00031..91d71d8ce 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -29,8 +29,9 @@ func TestSpringBootApplication(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + wd, err := os.Getwd() + g.Expect(err).To(BeNil()) + expectedCP := wd + "/*:" + wd expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -61,8 +62,9 @@ func TestSpringBoot3Application(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + wd, err := os.Getwd() + g.Expect(err).To(BeNil()) + expectedCP := wd + "/*:" + wd expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -95,8 +97,7 @@ func TestSpringBootFatJarApplication(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedCP := jar expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -130,8 +131,7 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedCP := jar expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -165,8 +165,7 @@ func TestSpringBootFatJarConsole(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedCP := jar expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -214,8 +213,7 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedCP := jar expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -265,8 +263,7 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { }, } - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) + expectedCP := jar expectedFileArgs := GetExpectedArgsFileContent() verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) @@ -287,45 +284,6 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } -func TestSpringBootBuildpacks(t *testing.T) { - g := NewGomegaWithT(t) - - d := &coh.Coherence{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - Application: &coh.ApplicationSpec{ - Type: ptr.To(coh.AppTypeSpring2), - CloudNativeBuildPack: &coh.CloudNativeBuildPackSpec{ - Enabled: ptr.To(true), - }, - }, - }, - }, - } - - wd := ensureTestUtilsDir(t) - expectedCP := GetOperatorClasspathWithUtilsDir(wd) - expectedFileArgs := GetExpectedArgsFileContent() - verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(t, d) - - e, err := ExecuteWithArgsAndNewViper(env, args) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(e).NotTo(BeNil()) - g.Expect(e.OsCmd).NotTo(BeNil()) - - g.Expect(e.OsCmd.Dir).To(Equal("")) - g.Expect(e.OsCmd.Path).To(Equal(getBuildpackLauncher())) - - g.Expect(len(e.OsCmd.Args)).To(Equal(4)) - g.Expect(e.OsCmd.Args[0]).To(Equal(coh.DefaultCnbpLauncher)) - g.Expect(e.OsCmd.Args[1]).To(Equal("java")) - g.Expect(e.OsCmd.Args[3]).To(Equal(coh.SpringBootMain2)) -} - func GetMinimalExpectedSpringBootArgs(t *testing.T, main string) []string { utils := ensureTestUtilsDir(t) diff --git a/test/e2e/local/spring-buildpack-cluster-2.yaml b/test/e2e/local/spring-buildpack-cluster-2.yaml index e549f8c61..94eb72e6a 100644 --- a/test/e2e/local/spring-buildpack-cluster-2.yaml +++ b/test/e2e/local/spring-buildpack-cluster-2.yaml @@ -7,6 +7,7 @@ spec: image: ${TEST_APPLICATION_IMAGE_SPRING_CNBP_2} application: type: spring + useImageEntryPoint: true jvm: args: - -Dcoherence.log=jdk diff --git a/test/e2e/local/spring-buildpack-cluster.yaml b/test/e2e/local/spring-buildpack-cluster.yaml index b7f04a9f3..fe91e7c07 100644 --- a/test/e2e/local/spring-buildpack-cluster.yaml +++ b/test/e2e/local/spring-buildpack-cluster.yaml @@ -7,6 +7,7 @@ spec: image: ${TEST_APPLICATION_IMAGE_SPRING_CNBP} application: type: spring3 + useImageEntryPoint: true jvm: args: - -Dcoherence.log=jdk diff --git a/test/e2e/local/spring_test.go b/test/e2e/local/spring_test.go index cca95fe64..3c8b18b17 100644 --- a/test/e2e/local/spring_test.go +++ b/test/e2e/local/spring_test.go @@ -27,11 +27,11 @@ func TestStartSpringFatJarCluster(t *testing.T) { AssertSpringEndpoint(t, pods) } -//func TestStartSpringBuildpacksCluster(t *testing.T) { -// testContext.CleanupAfterTest(t) -// _, pods := helper.AssertDeployments(testContext, t, "spring-buildpack-cluster.yaml") -// AssertSpringEndpoint(t, pods) -//} +func TestStartSpringBuildpacksCluster(t *testing.T) { + testContext.CleanupAfterTest(t) + _, pods := helper.AssertDeployments(testContext, t, "spring-buildpack-cluster.yaml") + AssertSpringEndpoint(t, pods) +} func TestStartSpringTwoCluster(t *testing.T) { testContext.CleanupAfterTest(t) From 19928d77433f38256b3e8601cb2e52812c0d043d Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 14:23:59 +0300 Subject: [PATCH 18/33] Fix using entry point --- api/v1/coherenceresourcespec_types.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 0e8c3cc03..ffd7d645a 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -909,25 +909,25 @@ func (in *CoherenceResourceSpec) CreateCommonEnv(deployment CoherenceResource) [ env := []corev1.EnvVar{ { Name: EnvVarCohMachineName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "spec.nodeName", + }, }, }, - }, { Name: EnvVarCohMemberName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.name", + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, }, }, - }, { Name: EnvVarCohPodUID, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.uid", + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.uid", + }, }, }, - }, {Name: EnvVarCohRole, Value: deployment.GetRoleName()}, } From 1c1812209d98498d35634fa1e52eda543566900d Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 16:34:01 +0300 Subject: [PATCH 19/33] Fix Spring tests --- api/v1/coherence_types.go | 1 + controllers/statefulset/statefulset_controller.go | 9 +++++++++ docs/about/04_coherence_spec.adoc | 3 ++- hack/boilerplate.go.txt | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 1f79195d0..a471ea40a 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -336,6 +336,7 @@ func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { if in.IsSpringBoot() { args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) + args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) } else { args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) diff --git a/controllers/statefulset/statefulset_controller.go b/controllers/statefulset/statefulset_controller.go index 75b846ebe..5f9cfabb0 100644 --- a/controllers/statefulset/statefulset_controller.go +++ b/controllers/statefulset/statefulset_controller.go @@ -433,6 +433,15 @@ func (in *ReconcileStatefulSet) patchStatefulSet(ctx context.Context, deployment current.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{} original.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{} + // K8s does not allow the entry point (command) and arguments cannot be patched + // So we ignore these even if they have been changed + desired.Spec.Template.Spec.Containers[0].Command = []string{} + current.Spec.Template.Spec.Containers[0].Command = []string{} + original.Spec.Template.Spec.Containers[0].Command = []string{} + desired.Spec.Template.Spec.Containers[0].Args = []string{} + current.Spec.Template.Spec.Containers[0].Args = []string{} + original.Spec.Template.Spec.Containers[0].Args = []string{} + desiredPodSpec := desired.Spec.Template currentPodSpec := current.Spec.Template originalPodSpec := original.Spec.Template diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index 53e3a7476..613a07c29 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -137,7 +137,8 @@ ApplicationSpec is the specification of the application deployed into the Cohere | Field | Description | Type | Required m| type | The application type to execute. This field would be set if using the Coherence Graal image and running a none-Java application. For example if the application was a Node application this field would be set to "node". The default is to run a plain Java application. m| *string | false m| main | Class is the Coherence container main class. The default value is com.tangosol.net.DefaultCacheServer. If the application type is non-Java this would be the name of the corresponding language specific runnable, for example if the application type is "node" the main may be a Javascript file. m| *string | false -m| args | Args is the optional arguments to pass to the main class. m| []string | false +m| entryPoint | Entrypoint array that will override the "java" entry point configured by the Operator or and any container entry point. This is an advanced use case, specifying an incorrect value here can cause the container not to start. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. m| []string | false +m| args | Args is the optional arguments to pass to the main class or the container entry point. m| []string | false m| workingDir | WorkingDir sets the working directory of the Coherence container. m| *string | false m| cloudNativeBuildPack | Optional settings that may be configured if using a Cloud Native Buildpack Image. For example an image build with the Spring Boot Maven/Gradle plugin. See: https://github.com/paketo-buildpacks/spring-boot and https://buildpacks.io/ m| *<> | false m| springBootFatJar | SpringBootFatJar is the full path name to the Spring Boot fat jar if the application image has been built by just adding a Spring Boot fat jar to the image. If this field is set then the application will be run by executing this jar. For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" m| *string | false diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index b4db25815..009165e12 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. + * Copyright (c) 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ From 5386d40615fa88046ea616030e0d6e588993adcf Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 18:58:15 +0300 Subject: [PATCH 20/33] use more constants --- api/v1/constants.go | 41 ++++++++++++++++++ pkg/runner/cmd_config.go | 15 +++---- pkg/runner/cmd_console.go | 22 +++++----- pkg/runner/cmd_jshell.go | 20 ++++----- pkg/runner/cmd_query_plus.go | 22 +++++----- pkg/runner/cmd_sleep.go | 26 ++++++------ pkg/runner/run_details/run_details.go | 20 +++++++-- pkg/runner/runner.go | 60 +++++++++++++-------------- 8 files changed, 141 insertions(+), 85 deletions(-) diff --git a/api/v1/constants.go b/api/v1/constants.go index 799c69bd8..1ca8c4b8e 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -300,6 +300,45 @@ const ( EnvVarJvmOomExit = "JVM_OOM_EXIT" EnvVarJvmOomHeapDump = "JVM_OOM_HEAP_DUMP" + SystemPropertyPattern = "-D%s=%s" + + SysPropCoherenceCacheConfig = "coherence.cacheconfig" + SysPropCoherenceCluster = "coherence.cluster" + SysPropCoherenceDistributedLocalStorage = "coherence.distributed.localstorage" + SysPropCoherenceGrpcEnabled = "coherence.grpc.enabled" + SysPropCoherenceHealthHttpPort = "coherence.health.http.port" + SysPropCoherenceIpMonitor = "coherence.ipmonitor.pingtimeout" + SysPropCoherenceLocalPortAdjust = "coherence.localport.adjust" + SysPropCoherenceLogLevel = "coherence.log.level" + SysPropCoherenceMachine = "coherence.machine" + SysPropCoherenceManagementHttp = "coherence.management.http" + SysPropCoherenceManagementHttpPort = "coherence.management.http.port" + SysPropCoherenceMember = "coherence.member" + SysPropCoherenceMetricsHttpEnabled = "coherence.metrics.http.enabled" + SysPropCoherenceMetricsHttpPort = "coherence.metrics.http.port" + SysPropCoherenceOverride = "coherence.override" + SysPropCoherencePersistenceBaseDir = "coherence.distributed.persistence.base.dir" + SysPropCoherencePersistenceMode = "coherence.distributed.persistence-mode" + SysPropCoherencePersistenceSnapshotDir = "coherence.distributed.persistence.snapshot.dir" + SysPropCoherenceRole = "coherence.role" + SysPropCoherenceRack = "coherence.rack" + SysPropCoherenceSite = "coherence.site" + SysPropCoherenceTracingRatio = "coherence.tracing.ratio" + SysPropCoherenceTTL = "coherence.ttl" + SysPropCoherenceWKA = "coherence.wka" + + SysPropOperatorForceExit = "coherence.operator.force.exit" + SysPropOperatorHealthEnabled = "coherence.operator.health.enabled" + SysPropOperatorHealthPort = "coherence.operator.health.port" + SysPropOperatorIdentity = "coherence.operator.identity" + SysPropOperatorOverride = "coherence.k8s.override" + + SysPropSpringLoaderMain = "loader.main" + SysPropSpringLoaderPath = "loader.path" + + JvmOptUnlockDiagnosticVMOptions = "-XX:+UnlockDiagnosticVMOptions" + JvmOptNativeMemoryTracking = "-XX:NativeMemoryTracking" + // AppTypeNone is the argument to specify no application type. AppTypeNone = "" // AppTypeJava is the argument to specify a Java application. @@ -331,6 +370,8 @@ const ( ConsoleMain = "com.tangosol.net.CacheFactory" // QueryPlusMain is the main class to run Coherence Query Plus QueryPlusMain = "com.tangosol.coherence.dslquery.QueryPlus" + // SleepMain is the main class to run Operator sleep command + SleepMain = "com.oracle.coherence.k8s.Sleep" ) var ( diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 81803fdc5..1d9cdc5c3 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -123,9 +123,10 @@ func createSpringBootFile(details *run_details.RunDetails) error { var args string if details.InnerMainClass == "" || details.InnerMainClass == v1.DefaultMain { - args = fmt.Sprintf("-Dloader.path=%s", cp) + args = fmt.Sprintf(v1.SystemPropertyPattern, v1.SysPropSpringLoaderPath, cp) } else { - args = fmt.Sprintf("-Dloader.path=%s\n-Dloader.main=%s", cp, details.InnerMainClass) + args = fmt.Sprintf(v1.SystemPropertyPattern, v1.SysPropSpringLoaderPath, cp) + args = args + "\n" + fmt.Sprintf(v1.SystemPropertyPattern, v1.SysPropSpringLoaderMain, details.InnerMainClass) } err := os.WriteFile(argsFile, []byte(args), os.ModePerm) @@ -267,9 +268,9 @@ func populateMainClass(details *run_details.RunDetails) { // Configure the runner to run a Coherence Server func populateServerDetails(details *run_details.RunDetails) { // Configure the Coherence member's role - details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, v1.SysPropCoherenceRole, "storage") // Configure whether this member is storage enabled - details.AddArgFromEnvVar(v1.EnvVarCohStorage, "-Dcoherence.distributed.localstorage") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohStorage, v1.SysPropCoherenceDistributedLocalStorage) // Configure Coherence Tracing ratio := details.Getenv(v1.EnvVarCohTracingRatio) @@ -277,7 +278,7 @@ func populateServerDetails(details *run_details.RunDetails) { q, err := resource.ParseQuantity(ratio) if err == nil { d := q.AsDec() - details.AddArg("-Dcoherence.tracing.ratio=" + d.String()) + details.AddSystemPropertyArg(v1.SysPropCoherenceTracingRatio, d.String()) } else { fmt.Printf("ERROR: Coherence tracing ratio \"%s\" is invalid - %s\n", ratio, err.Error()) os.Exit(1) @@ -289,7 +290,7 @@ func populateServerDetails(details *run_details.RunDetails) { log.Info("Coherence Management over REST", "enabled", strconv.FormatBool(hasMgmt), "envVar", v1.EnvVarCohMgmtPrefix+v1.EnvVarCohEnabledSuffix) if hasMgmt { fmt.Println("INFO: Configuring Coherence Management over REST") - details.AddArg("-Dcoherence.management.http=all") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "all") if details.CoherenceHome != "" { // If management is enabled and the COHERENCE_HOME environment variable is set // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath @@ -302,7 +303,7 @@ func populateServerDetails(details *run_details.RunDetails) { hasMetrics := details.IsEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) log.Info("Coherence Metrics", "enabled", strconv.FormatBool(hasMetrics), "envVar", v1.EnvVarCohMetricsPrefix+v1.EnvVarCohEnabledSuffix) if hasMetrics { - details.AddArg("-Dcoherence.metrics.http.enabled=true") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "true") fmt.Println("INFO: Configuring Coherence Metrics") if details.CoherenceHome != "" { // If metrics is enabled and the COHERENCE_HOME environment variable is set diff --git a/pkg/runner/cmd_console.go b/pkg/runner/cmd_console.go index d92a153a5..f945fe809 100644 --- a/pkg/runner/cmd_console.go +++ b/pkg/runner/cmd_console.go @@ -42,22 +42,22 @@ func console(details *run_details.RunDetails, args []string, v *viper.Viper) { loadConfigFiles(details) if details.IsSpringBoot() { - details.AddArg("-Dloader.main=" + v1.ConsoleMain) + details.AddSystemPropertyArg(v1.SysPropSpringLoaderMain, v1.ConsoleMain) } else { details.AppType = v1.AppTypeJava details.MainClass = v1.ConsoleMain } - details.AddArg("-Dcoherence.role=console") - details.AddArg("-Dcoherence.distributed.localstorage=false") - details.AddArg("-Dcoherence.localport.adjust=true") - details.AddArg("-Dcoherence.management.http=none") - details.AddArg("-Dcoherence.management.http.port=0") - details.AddArg("-Dcoherence.metrics.http.enabled=false") - details.AddArg("-Dcoherence.metrics.http.port=0") - details.AddArg("-Dcoherence.operator.health.enabled=false") - details.AddArg("-Dcoherence.health.http.port=0") - details.AddArg("-Dcoherence.grpc.enabled=false") + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandConsole) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_jshell.go b/pkg/runner/cmd_jshell.go index 37fe4bc83..182b2a15a 100644 --- a/pkg/runner/cmd_jshell.go +++ b/pkg/runner/cmd_jshell.go @@ -43,16 +43,16 @@ func jShell(details *run_details.RunDetails, args []string, v *viper.Viper) { details.Command = CommandJShell loadConfigFiles(details) - details.AddArg("-Dcoherence.role=jshell") - details.AddArg("-Dcoherence.distributed.localstorage=false") - details.AddArg("-Dcoherence.localport.adjust=true") - details.AddArg("-Dcoherence.management.http=none") - details.AddArg("-Dcoherence.management.http.port=0") - details.AddArg("-Dcoherence.metrics.http.enabled=false") - details.AddArg("-Dcoherence.metrics.http.port=0") - details.AddArg("-Dcoherence.operator.health.enabled=false") - details.AddArg("-Dcoherence.health.http.port=0") - details.AddArg("-Dcoherence.grpc.enabled=false") + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandJShell) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_query_plus.go b/pkg/runner/cmd_query_plus.go index 512c35f71..68da88ac2 100644 --- a/pkg/runner/cmd_query_plus.go +++ b/pkg/runner/cmd_query_plus.go @@ -43,22 +43,22 @@ func queryPlus(details *run_details.RunDetails, args []string, v *viper.Viper) { loadConfigFiles(details) if details.IsSpringBoot() { - details.AddArg("-Dloader.main=" + v1.QueryPlusMain) + details.AddSystemPropertyArg(v1.SysPropSpringLoaderMain, v1.QueryPlusMain) } else { details.AppType = v1.AppTypeJava details.MainClass = v1.QueryPlusMain } - details.AddArg("-Dcoherence.role=console") - details.AddArg("-Dcoherence.distributed.localstorage=false") - details.AddArg("-Dcoherence.localport.adjust=true") - details.AddArg("-Dcoherence.management.http=none") - details.AddArg("-Dcoherence.management.http.port=0") - details.AddArg("-Dcoherence.metrics.http.enabled=false") - details.AddArg("-Dcoherence.metrics.http.port=0") - details.AddArg("-Dcoherence.operator.health.enabled=false") - details.AddArg("-Dcoherence.health.http.port=0") - details.AddArg("-Dcoherence.grpc.enabled=false") + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandQueryPlus) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_sleep.go b/pkg/runner/cmd_sleep.go index ec9515f23..2d2b2e849 100644 --- a/pkg/runner/cmd_sleep.go +++ b/pkg/runner/cmd_sleep.go @@ -43,24 +43,26 @@ func sleep(details *run_details.RunDetails, args []string, v *viper.Viper) { if app == v1.AppTypeSpring2 { details.AppType = v1.AppTypeSpring2 details.MainClass = v1.SpringBootMain2 - details.AddArg("-Dloader.main=com.oracle.coherence.k8s.Sleep") + details.AddSystemPropertyArg(v1.SysPropSpringLoaderMain, v1.SleepMain) } else { details.AppType = v1.AppTypeJava - details.MainClass = "com.oracle.coherence.k8s.Sleep" + details.MainClass = v1.SleepMain } details.Command = CommandSleep details.MainArgs = args details.UseOperatorHealth = true - details.AddArg("-Dcoherence.distributed.localstorage=false") - details.AddArg("-Dcoherence.localport.adjust=true") - details.AddArg("-Dcoherence.management.http=none") - details.AddArg("-Dcoherence.management.http.port=0") - details.AddArg("-Dcoherence.metrics.http.enabled=false") - details.AddArg("-Dcoherence.metrics.http.port=0") - details.AddArg("-Dcoherence.operator.health.enabled=false") - details.AddArg("-Dcoherence.grpc.enabled=false") + + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandSleep) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") + details.Setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.Setenv(v1.EnvVarCohRole, "sleep") - details.Setenv(v1.EnvVarCohHealthPort, "0") details.MainArgs = args } diff --git a/pkg/runner/run_details/run_details.go b/pkg/runner/run_details/run_details.go index 8211f67b0..b74832e52 100644 --- a/pkg/runner/run_details/run_details.go +++ b/pkg/runner/run_details/run_details.go @@ -303,6 +303,13 @@ func (in *RunDetails) AddArg(arg string) { } } +func (in *RunDetails) AddSystemPropertyArg(propName, value string) { + if propName != "" { + arg := fmt.Sprintf(v1.SystemPropertyPattern, propName, value) + in.args = append(in.args, in.ExpandEnv(arg)) + } +} + func (in *RunDetails) AddVMOption(arg string) { if arg != "" { in.vmOptions = append(in.vmOptions, in.ExpandEnv(arg)) @@ -390,15 +397,20 @@ func (in *RunDetails) AddArgFromEnvVar(name, property string) { } } +func (in *RunDetails) AddSystemPropertyFromEnvVar(name, property string) { + value := in.Getenv(name) + if value != "" { + in.AddSystemPropertyArg(property, value) + } +} + func (in *RunDetails) SetSystemPropertyFromEnvVarOrDefault(name, property, dflt string) { value := in.Getenv(name) - var s string if value != "" { - s = fmt.Sprintf("%s=%s", property, value) + in.AddSystemPropertyArg(property, value) } else { - s = fmt.Sprintf("%s=%s", property, dflt) + in.AddSystemPropertyArg(property, dflt) } - in.AddArg(s) } func (in *RunDetails) GetJavaExecutable() string { diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 67fe70156..e1d3d4ff1 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -288,19 +288,19 @@ func configureCommand(details *run_details.RunDetails) error { var err error // Set standard system properties - details.AddArg("-Dcoherence.ttl=0") - details.AddArgFromEnvVar(v1.EnvVarCohWka, "-Dcoherence.wka") - details.AddArgFromEnvVar(v1.EnvVarCohMachineName, "-Dcoherence.machine") - details.AddArgFromEnvVar(v1.EnvVarCohMemberName, "-Dcoherence.member") - details.AddArgFromEnvVar(v1.EnvVarCohClusterName, "-Dcoherence.cluster") - details.AddArgFromEnvVar(v1.EnvVarCohCacheConfig, "-Dcoherence.cacheconfig") - details.AddArgFromEnvVar(v1.EnvVarCohIdentity, "-Dcoherence.operator.identity") - details.AddArgFromEnvVar(v1.EnvVarCohForceExit, "-Dcoherence.operator.force.exit") - details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.operator.health.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) - details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.management.http.port", fmt.Sprintf("%d", v1.DefaultManagementPort)) - details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.metrics.http.port", fmt.Sprintf("%d", v1.DefaultMetricsPort)) - - details.AddVMOption("-XX:+UnlockDiagnosticVMOptions") + details.AddSystemPropertyArg(v1.SysPropCoherenceTTL, "0") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohWka, v1.SysPropCoherenceWKA) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohMachineName, v1.SysPropCoherenceMachine) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohMemberName, v1.SysPropCoherenceMember) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohClusterName, v1.SysPropCoherenceCluster) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohCacheConfig, v1.SysPropCoherenceCacheConfig) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohIdentity, v1.SysPropOperatorIdentity) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohForceExit, v1.SysPropOperatorForceExit) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, v1.SysPropOperatorHealthPort, fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, v1.SysPropCoherenceManagementHttpPort, fmt.Sprintf("%d", v1.DefaultManagementPort)) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, v1.SysPropCoherenceMetricsHttpPort, fmt.Sprintf("%d", v1.DefaultMetricsPort)) + + details.AddVMOption(v1.JvmOptUnlockDiagnosticVMOptions) // Configure the classpath to support images created with the JIB Maven plugin // This is enabled by default unless the image is a buildpacks image, or we @@ -334,32 +334,32 @@ func configureCommand(details *run_details.RunDetails) error { // Configure Coherence persistence mode := details.GetenvOrDefault(v1.EnvVarCohPersistenceMode, "on-demand") - details.AddArg("-Dcoherence.distributed.persistence-mode=" + mode) + details.AddSystemPropertyArg(v1.SysPropCoherencePersistenceMode, mode) persistence := details.Getenv(v1.EnvVarCohPersistenceDir) if persistence != "" { - details.AddArg("-Dcoherence.distributed.persistence.base.dir=" + persistence) + details.AddSystemPropertyArg(v1.SysPropCoherencePersistenceBaseDir, persistence) } snapshots := details.Getenv(v1.EnvVarCohSnapshotDir) if snapshots != "" { - details.AddArg("-Dcoherence.distributed.persistence.snapshot.dir=" + snapshots) + details.AddSystemPropertyArg(v1.SysPropCoherencePersistenceSnapshotDir, snapshots) } // Set the Coherence site and rack values configureSiteAndRack(details) // Set the Coherence log level - details.AddArgFromEnvVar(v1.EnvVarCohLogLevel, "-Dcoherence.log.level") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohLogLevel, v1.SysPropCoherenceLogLevel) // Disable IPMonitor ipMon := details.Getenv(v1.EnvVarEnableIPMonitor) if ipMon != "TRUE" { - details.AddArg("-Dcoherence.ipmonitor.pingtimeout=0") + details.AddSystemPropertyArg(v1.SysPropCoherenceIpMonitor, "0") } - details.AddArg("-Dcoherence.override=k8s-coherence-override.xml") - details.AddArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") + details.AddSystemPropertyArg(v1.SysPropCoherenceOverride, "k8s-coherence-override.xml") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohOverride, v1.SysPropOperatorOverride) post2206 := checkCoherenceVersion("14.1.1.2206.0", details) if post2206 { @@ -781,7 +781,7 @@ func configureSiteAndRack(details *run_details.RunDetails) { } if site != "" { - details.AddArg("-Dcoherence.site=" + site) + details.AddSystemPropertyArg(v1.EnvVarCoherenceSite, site) } } else { expanded := details.ExpandEnv(site) @@ -789,10 +789,10 @@ func configureSiteAndRack(details *run_details.RunDetails) { log.Info("Coherence site property set from expanded "+v1.EnvVarCoherenceSite+" environment variable", v1.EnvVarCoherenceSite, site, "Site", expanded) site = expanded if strings.TrimSpace(site) != "" { - details.AddArg("-Dcoherence.site=" + site) + details.AddSystemPropertyArg(v1.EnvVarCoherenceSite, site) } } else { - details.AddArg("-Dcoherence.site=" + site) + details.AddSystemPropertyArg(v1.EnvVarCoherenceSite, site) } } @@ -819,9 +819,9 @@ func configureSiteAndRack(details *run_details.RunDetails) { } if rack != "" { - details.AddArg("-Dcoherence.rack=" + rack) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, rack) } else if site != "" { - details.AddArg("-Dcoherence.rack=" + site) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, site) } } else { expanded := details.ExpandEnv(rack) @@ -834,10 +834,10 @@ func configureSiteAndRack(details *run_details.RunDetails) { rack = site } if strings.TrimSpace(rack) != "" { - details.AddArg("-Dcoherence.rack=" + rack) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, rack) } } else { - details.AddArg("-Dcoherence.rack=" + rack) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, rack) } } } @@ -1024,10 +1024,10 @@ func cohPost2206(details *run_details.RunDetails) { } else { useOperator := details.GetenvOrDefault(v1.EnvVarUseOperatorHealthCheck, "false") if strings.EqualFold("true", useOperator) { - details.AddArg("-Dcoherence.operator.health.enabled=true") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "true") } else { - details.AddArg("-Dcoherence.operator.health.enabled=false") - details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.health.http.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, v1.SysPropCoherenceHealthHttpPort, fmt.Sprintf("%d", v1.DefaultHealthPort)) } } } From 18d4f731187bf890c144bbd0df111c4a55a381e1 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 19:33:33 +0300 Subject: [PATCH 21/33] fix broken site --- pkg/runner/runner.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index e1d3d4ff1..ace37d78d 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -781,7 +781,7 @@ func configureSiteAndRack(details *run_details.RunDetails) { } if site != "" { - details.AddSystemPropertyArg(v1.EnvVarCoherenceSite, site) + details.AddSystemPropertyArg(v1.SysPropCoherenceSite, site) } } else { expanded := details.ExpandEnv(site) @@ -789,10 +789,10 @@ func configureSiteAndRack(details *run_details.RunDetails) { log.Info("Coherence site property set from expanded "+v1.EnvVarCoherenceSite+" environment variable", v1.EnvVarCoherenceSite, site, "Site", expanded) site = expanded if strings.TrimSpace(site) != "" { - details.AddSystemPropertyArg(v1.EnvVarCoherenceSite, site) + details.AddSystemPropertyArg(v1.SysPropCoherenceSite, site) } } else { - details.AddSystemPropertyArg(v1.EnvVarCoherenceSite, site) + details.AddSystemPropertyArg(v1.SysPropCoherenceSite, site) } } From b5cfce42412ade021104944f5cbfaa2b8c9f5909 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Fri, 14 Mar 2025 21:49:12 +0300 Subject: [PATCH 22/33] Java 8 --- api/v1/coherence_types.go | 13 +++ .../certifiy_deployment_test.go | 82 ++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index a471ea40a..9edccfa39 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -787,6 +787,14 @@ type JVMSpec struct { // The default value fif not specified is true. // +optional UseJibClasspath *bool `json:"useJibClasspath,omitempty"` + // Java8 is a flag to indicate that a Coherence container is + // running on Java 8 and must use the legacy Operator container + // entry point. This would only apply to applications using + // older Coherence 12.2.1-4-* or 14.1.1-0-* versions. + // The default value for this field is false, if this field is not set to + // true when Java 8 is used the container will fail to start. + // +optional + Java8 *bool `json:"java8,omitempty"` } // UpdatePodTemplate updates the StatefulSet with any JVM specific settings @@ -820,6 +828,11 @@ func (in *JVMSpec) UpdatePodTemplate(podTemplate *corev1.PodTemplateSpec) { if in.Gc != nil { gc = in.Gc } + + if in.Java8 != nil && *in.Java8 { + podTemplate.Spec.Containers[0].Command = []string{RunnerCommand, "server"} + podTemplate.Spec.Containers[0].Args = []string{} + } } //goland:noinspection GoNilness diff --git a/test/coherence_compatibility/certifiy_deployment_test.go b/test/coherence_compatibility/certifiy_deployment_test.go index a72cd2301..a89dfe90b 100644 --- a/test/coherence_compatibility/certifiy_deployment_test.go +++ b/test/coherence_compatibility/certifiy_deployment_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -12,6 +12,7 @@ import ( v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/test/e2e/helper" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" "testing" "time" ) @@ -47,3 +48,82 @@ func TestCoherenceCompatibilityMinimalSpec(t *testing.T) { _, err = helper.WaitForStatefulSetForDeployment(testContext, ns, d, time.Second*10, time.Minute*5) g.Expect(err).NotTo(HaveOccurred()) } + +func TestCoherenceCompatibilityScaling(t *testing.T) { + // Ensure that everything is cleaned up after the test! + testContext.CleanupAfterTest(t) + g := NewGomegaWithT(t) + + ns := helper.GetTestClusterNamespace() + d := &v1.Coherence{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: "certify-scale", + }, + Spec: v1.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: v1.CoherenceResourceSpec{ + Replicas: ptr.To(int32(1)), + ReadinessProbe: &v1.ReadinessProbeSpec{ + InitialDelaySeconds: ptr.To(int32(10)), + PeriodSeconds: ptr.To(int32(10)), + }, + }, + }, + } + + // Start with one replica + err := testContext.Client.Create(context.TODO(), d) + g.Expect(err).NotTo(HaveOccurred()) + _, err = helper.WaitForStatefulSetForDeployment(testContext, ns, d, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) + + // Scale Up to three + err = scale(t, ns, d.Name, 3) + g.Expect(err).NotTo(HaveOccurred()) + _, err = helper.WaitForStatefulSet(testContext, ns, d.Name, 3, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) + + // Scale down to one + err = scale(t, ns, d.Name, 1) + g.Expect(err).NotTo(HaveOccurred()) + _, err = helper.WaitForStatefulSet(testContext, ns, d.Name, 1, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) +} + +// This test is not really using Java8. +// It just sets the Java8 field to true to test running with +// the legacy container entry point. +func TestCoherenceCompatibilityJava8(t *testing.T) { + // Ensure that everything is cleaned up after the test! + testContext.CleanupAfterTest(t) + + g := NewGomegaWithT(t) + + imageName := helper.GetCoherenceCompatibilityImage() + + ns := helper.GetTestNamespace() + d := &v1.Coherence{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: "certify-coherence", + }, + Spec: v1.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: v1.CoherenceResourceSpec{ + Image: &imageName, + JVM: &v1.JVMSpec{ + Java8: ptr.To(true), + }, + }, + }, + } + + // ensure the imagePullSecrets are correctly injected + secrets := helper.GetImagePullSecrets() + d.Spec.ImagePullSecrets = append(d.Spec.ImagePullSecrets, secrets...) + + err := testContext.Client.Create(context.TODO(), d) + g.Expect(err).NotTo(HaveOccurred()) + + _, err = helper.WaitForStatefulSetForDeployment(testContext, ns, d, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) +} From 14eb6bd659d2c43fabcb21f1bd342b75c13733f8 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 15 Mar 2025 09:54:33 +0300 Subject: [PATCH 23/33] fix tests to work with Java 8 Coherence images --- .github/workflows/coherence-matrix.yaml | 20 ++++++++++++++++--- api/v1/constants.go | 1 + api/v1/zz_generated.deepcopy.go | 5 +++++ pkg/runner/run_details/run_details.go | 4 ++-- pkg/runner/runner.go | 4 ++-- pkg/runner/runner_jvm_jibclasspath_test.go | 4 ++-- pkg/runner/runner_spring_test.go | 10 +++++----- pkg/runner/runner_test.go | 2 +- .../certifiy_deployment_test.go | 13 +++++++----- .../certify_persistence_test.go | 10 ++++++++-- test/e2e/helper/proj_helpers.go | 8 ++++++++ 11 files changed, 59 insertions(+), 22 deletions(-) diff --git a/.github/workflows/coherence-matrix.yaml b/.github/workflows/coherence-matrix.yaml index d91b9d879..aeef3e190 100644 --- a/.github/workflows/coherence-matrix.yaml +++ b/.github/workflows/coherence-matrix.yaml @@ -51,35 +51,41 @@ jobs: coherenceVersion: "15.1.1-0-0-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:15.1.1-0-0-SNAPSHOT-java17" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "15.1.1-0-SNAPSHOT-Graal" coherenceVersion: "15.1.1-0-0-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:15.1.1-0-0-SNAPSHOT-graal" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "24.09" coherenceVersion: "24.09" coherenceImage: "ghcr.io/oracle/coherence-ce:24.09" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "24.09-Graal" coherenceVersion: "24.09" coherenceImage: "ghcr.io/oracle/coherence-ce:24.09-graal" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "14.1.2-0-SNAPSHOT" coherenceVersion: "14.1.2-0-1-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:14.1.2-0-1-SNAPSHOT" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "14.1.2-0" coherenceVersion: "14.1.2-0-0" - javaVersion: 8 + javaVersion: 17 + coherenceIsJava8: false coherenceImage: "ghcr.io/oracle/coherence-ce:14.1.2-0-0" baseImage: "gcr.io/distroless/java17-debian12" @@ -87,23 +93,27 @@ jobs: coherenceVersion: "22.06.10" coherenceImage: "ghcr.io/oracle/coherence-ce:22.06.10" javaVersion: 11 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "14.1.1-2206-SNAPSHOT" coherenceVersion: "14.1.1-2206-11-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:14.1.1-2206-11-SNAPSHOT" javaVersion: 11 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "14.1.1-0-SNAPSHOT" coherenceVersion: "14.1.1-0-20-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:14.1.1-0-20-SNAPSHOT" - javaVersion: 8 + javaVersion: 11 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "14.1.1-0" coherenceVersion: "14.1.1-0-19" - javaVersion: 8 + javaVersion: 11 + coherenceIsJava8: false coherenceImage: "ghcr.io/oracle/coherence-ce:14.1.1-0-19" baseImage: "gcr.io/distroless/java11-debian11" @@ -111,18 +121,21 @@ jobs: coherenceVersion: "14.1.1.0.0" coherenceImage: "container-registry.oracle.com/middleware/coherence:14.1.1.0.0" javaVersion: 8 + coherenceIsJava8: true baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "12.2.1.4.0" coherenceVersion: "12.2.1.4.0" coherenceImage: "container-registry.oracle.com/middleware/coherence:12.2.1.4.0" javaVersion: 8 + coherenceIsJava8: true baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "12.2.1-4-SNAPSHOT" coherenceVersion: "12.2.1-4-24-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:12.2.1-4-24-SNAPSHOT" javaVersion: 8 + coherenceIsJava8: true baseImage: "gcr.io/distroless/java11-debian11" steps: @@ -209,6 +222,7 @@ jobs: echo "BUILD_JAVA_VERSION=${BUILD_JAVA_VERSION}" export COHERENCE_TEST_BASE_IMAGE=${{ matrix.baseImage }} echo "COHERENCE_TEST_BASE_IMAGE=${COHERENCE_TEST_BASE_IMAGE}" + export OPERATOR_COHERENCE_JAVA_8=${{ matrix.coherenceIsJava8 }} make clean echo "Building Operator Image" make build-operator-images diff --git a/api/v1/constants.go b/api/v1/constants.go index 1ca8c4b8e..2e48ba36b 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -336,6 +336,7 @@ const ( SysPropSpringLoaderMain = "loader.main" SysPropSpringLoaderPath = "loader.path" + JvmOptClassPath = "-cp" JvmOptUnlockDiagnosticVMOptions = "-XX:+UnlockDiagnosticVMOptions" JvmOptNativeMemoryTracking = "-XX:NativeMemoryTracking" diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index e77191749..098939ca4 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1213,6 +1213,11 @@ func (in *JVMSpec) DeepCopyInto(out *JVMSpec) { *out = new(bool) **out = **in } + if in.Java8 != nil { + in, out := &in.Java8, &out.Java8 + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMSpec. diff --git a/pkg/runner/run_details/run_details.go b/pkg/runner/run_details/run_details.go index b74832e52..3fb99c377 100644 --- a/pkg/runner/run_details/run_details.go +++ b/pkg/runner/run_details/run_details.go @@ -262,7 +262,7 @@ func (in *RunDetails) GetCommandWithPrefix(propPrefix, jvmPrefix string) []strin var cmd []string cp := in.GetClasspath() if cp != "" { - cmd = append(cmd, "--class-path", cp) + cmd = append(cmd, v1.JvmOptClassPath, cp) } if propPrefix == "" && jvmPrefix == "" { cmd = append(cmd, in.GetAllArgs()...) @@ -286,7 +286,7 @@ func (in *RunDetails) GetSpringBootArgs() []string { var cmd []string // Are we using a Spring Boot fat jar if jar, _ := in.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { - cmd = append(cmd, "--class-path", jar) + cmd = append(cmd, v1.JvmOptClassPath, jar) } return append(cmd, in.GetAllArgs()...) } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index ace37d78d..4ad08cf58 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -977,7 +977,7 @@ func checkCoherenceVersion(v string, details *run_details.RunDetails) bool { if jar, _ := details.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { // This is a fat jar Spring boot app so put the fat jar on the classpath - args = append(args, "--class-path", jar) + args = append(args, v1.JvmOptClassPath, jar) } if details.AppType == v1.AppTypeSpring2 { @@ -989,7 +989,7 @@ func checkCoherenceVersion(v string, details *run_details.RunDetails) bool { } } else { // We can use normal Java - args = append(args, "--class-path", cp, + args = append(args, v1.JvmOptClassPath, cp, "-Dcoherence.operator.springboot.listener=false", "com.oracle.coherence.k8s.CoherenceVersion", v) } diff --git a/pkg/runner/runner_jvm_jibclasspath_test.go b/pkg/runner/runner_jvm_jibclasspath_test.go index e939723bd..f1dc78861 100644 --- a/pkg/runner/runner_jvm_jibclasspath_test.go +++ b/pkg/runner/runner_jvm_jibclasspath_test.go @@ -82,7 +82,7 @@ func TestJibClasspathFileWhenJibFilePresent(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expected := append(GetMinimalExpectedArgsWithoutCP(), "--class-path", expectedCp) + expected := append(GetMinimalExpectedArgsWithoutCP(), coh.JvmOptClassPath, expectedCp) g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } @@ -150,7 +150,7 @@ func TestJibClasspathFileAndMainClassFile(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expected := append(GetMinimalExpectedArgsWithoutCP(), "--class-path", expectedCp) + expected := append(GetMinimalExpectedArgsWithoutCP(), coh.JvmOptClassPath, expectedCp) expected = ReplaceArg(expected, coh.DefaultMain, JibMainClass) g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) // g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.tangosol.net.DefaultCacheServer"))) diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index 91d71d8ce..1bcb61abc 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -111,7 +111,7 @@ func TestSpringBootFatJarApplication(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", "/apps/lib/foo.jar") + expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), coh.JvmOptClassPath, "/apps/lib/foo.jar") g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } @@ -145,7 +145,7 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain3), "--class-path", "/apps/lib/foo.jar") + expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain3), coh.JvmOptClassPath, "/apps/lib/foo.jar") g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } @@ -180,7 +180,7 @@ func TestSpringBootFatJarConsole(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", jar) + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), coh.JvmOptClassPath, jar) expectedArgs = append(expectedArgs, "-Dcoherence.role=console", "-Dloader.main=com.tangosol.net.CacheFactory", "-Dcoherence.distributed.localstorage=false", @@ -228,7 +228,7 @@ func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), "--class-path", jar) + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), coh.JvmOptClassPath, jar) expectedArgs = append(expectedArgs, "-Dcoherence.role=console", "-Dloader.main=com.tangosol.net.CacheFactory", "-Dcoherence.distributed.localstorage=false", @@ -279,7 +279,7 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), - "--class-path", jar, "-Dloader.main=foo.Bar") + coh.JvmOptClassPath, jar, "-Dloader.main=foo.Bar") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 2cd2d093b..7131ac304 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -121,7 +121,7 @@ func GetMinimalExpectedArgsWithWorkingDir(t *testing.T, wd string) []string { cp = cp + ":" + cfg } - args := []string{GetJavaArg(), "--class-path", cp} + args := []string{GetJavaArg(), "-cp", cp} return append(AppendCommonExpectedArgs(args), "com.oracle.coherence.k8s.Main", "$DEFAULT$") diff --git a/test/coherence_compatibility/certifiy_deployment_test.go b/test/coherence_compatibility/certifiy_deployment_test.go index a89dfe90b..7e658d412 100644 --- a/test/coherence_compatibility/certifiy_deployment_test.go +++ b/test/coherence_compatibility/certifiy_deployment_test.go @@ -71,6 +71,12 @@ func TestCoherenceCompatibilityScaling(t *testing.T) { }, } + if helper.GetTestCoherenceIsJava8() { + d.Spec.JVM = &v1.JVMSpec{ + Java8: ptr.To(true), + } + } + // Start with one replica err := testContext.Client.Create(context.TODO(), d) g.Expect(err).NotTo(HaveOccurred()) @@ -90,8 +96,8 @@ func TestCoherenceCompatibilityScaling(t *testing.T) { g.Expect(err).NotTo(HaveOccurred()) } -// This test is not really using Java8. -// It just sets the Java8 field to true to test running with +// This test is not really using Java8 for images using Coherence 14.1.1-2206 +// and above. The test just sets the Java8 field to true to test running with // the legacy container entry point. func TestCoherenceCompatibilityJava8(t *testing.T) { // Ensure that everything is cleaned up after the test! @@ -99,8 +105,6 @@ func TestCoherenceCompatibilityJava8(t *testing.T) { g := NewGomegaWithT(t) - imageName := helper.GetCoherenceCompatibilityImage() - ns := helper.GetTestNamespace() d := &v1.Coherence{ ObjectMeta: metav1.ObjectMeta{ @@ -109,7 +113,6 @@ func TestCoherenceCompatibilityJava8(t *testing.T) { }, Spec: v1.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: v1.CoherenceResourceSpec{ - Image: &imageName, JVM: &v1.JVMSpec{ Java8: ptr.To(true), }, diff --git a/test/coherence_compatibility/certify_persistence_test.go b/test/coherence_compatibility/certify_persistence_test.go index 0bbe814f2..e51d53b89 100644 --- a/test/coherence_compatibility/certify_persistence_test.go +++ b/test/coherence_compatibility/certify_persistence_test.go @@ -1,8 +1,7 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. - * */ package compatibility @@ -15,6 +14,7 @@ import ( v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/test/e2e/helper" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "testing" "time" ) @@ -140,6 +140,12 @@ func ensurePods(g *GomegaWithT, yamlFile, ns string) (v1.Coherence, []corev1.Pod deployment, err := helper.NewSingleCoherenceFromYaml(ns, yamlFile) g.Expect(err).NotTo(HaveOccurred()) + if helper.GetTestCoherenceIsJava8() { + deployment.Spec.JVM = &v1.JVMSpec{ + Java8: ptr.To(true), + } + } + d, _ := json.Marshal(deployment) fmt.Printf("Persistence Test installing deployment:\n%s\n", string(d)) diff --git a/test/e2e/helper/proj_helpers.go b/test/e2e/helper/proj_helpers.go index 564f4288b..d2686e59b 100644 --- a/test/e2e/helper/proj_helpers.go +++ b/test/e2e/helper/proj_helpers.go @@ -34,6 +34,8 @@ const ( TestClusterNamespaceEnv = "CLUSTER_NAMESPACE" // TestClientNamespaceEnv is environment variable holding the name of the client test k8s namespace. TestClientNamespaceEnv = "OPERATOR_NAMESPACE_CLIENT" + // TestIsJava8Env is environment variable holding the flag to indicate the test Coherence image uses Java 8. + TestIsJava8Env = "OPERATOR_COHERENCE_JAVA_8" // PrometheusNamespaceEnv is environment variable holding the name of the Prometheus k8s namespace. PrometheusNamespaceEnv = "PROMETHEUS_NAMESPACE" // OperatorImageRegistryEnv is environment variable holding the registry of the Operator image. @@ -182,6 +184,12 @@ func GetTestClusterNamespace() string { return ns } +// GetTestCoherenceIsJava8 returns the name of the test cluster namespace. +func GetTestCoherenceIsJava8() bool { + s := os.Getenv(TestIsJava8Env) + return strings.ToLower(s) == "true" +} + // GetBuildOutputDirectory returns the build output directory func GetBuildOutputDirectory() (os.FileInfo, error) { name := os.Getenv(BuildOutputEnv) From 924803a0fbc7e3b3746a3039779251856e05a290 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 15 Mar 2025 10:57:40 +0300 Subject: [PATCH 24/33] Fix running Java 8 Coherence images --- Makefile | 2 +- api/v1/coherence_types.go | 4 ++-- api/v1/create_statefulset_test.go | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 55544519c..145c37db2 100644 --- a/Makefile +++ b/Makefile @@ -2749,7 +2749,7 @@ get-istio: $(BUILD_PROPS) $(BUILD_OUTPUT)/istio-config.yaml ## Download Istio to # ---------------------------------------------------------------------------------------------------------------------- $(TOOLS_BIN)/golangci-lint: @mkdir -p $(TOOLS_BIN) - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh --header $(GH_AUTH) | sh -s -- -b $(TOOLS_BIN) v1.63.1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh --header $(GH_AUTH) | sh -s -- -b $(TOOLS_BIN) v1.64.7 # ---------------------------------------------------------------------------------------------------------------------- # Display the full version string for the artifacts that would be built. diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 9edccfa39..f9c1d457c 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -830,8 +830,8 @@ func (in *JVMSpec) UpdatePodTemplate(podTemplate *corev1.PodTemplateSpec) { } if in.Java8 != nil && *in.Java8 { - podTemplate.Spec.Containers[0].Command = []string{RunnerCommand, "server"} - podTemplate.Spec.Containers[0].Args = []string{} + c.Command = []string{RunnerCommand, "server"} + c.Args = []string{} } } diff --git a/api/v1/create_statefulset_test.go b/api/v1/create_statefulset_test.go index 0a171eeec..d0298955e 100644 --- a/api/v1/create_statefulset_test.go +++ b/api/v1/create_statefulset_test.go @@ -780,3 +780,20 @@ func TestAddLifecycleToStatefulSetCoherenceContainer(t *testing.T) { // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) } + +func TestCreateStatefulUsingJava8(t *testing.T) { + // Create minimal spec spec + spec := coh.CoherenceResourceSpec{ + JVM: &coh.JVMSpec{ + Java8: ptr.To(true), + }, + } + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = []string{coh.RunnerCommand, "server"} + stsExpected.Spec.Template.Spec.Containers[0].Args = []string{} + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} From e84896d4e8ececc4edac15094d8f8a3070a59d09 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 15 Mar 2025 13:11:09 +0300 Subject: [PATCH 25/33] Adding more linters --- .golangci.yml | 24 +++++++++-------- Makefile | 2 +- api/v1/coherence_types.go | 12 ++++----- api/v1/common_test.go | 7 ++--- api/v1/hasher_test.go | 1 - controllers/coherencejob_controller.go | 1 - pkg/management/coherence_management.go | 15 +++++++---- pkg/management/pod_exec.go | 7 +++-- pkg/operator/operator.go | 26 ------------------- pkg/runner/run_details/run_details.go | 4 +-- pkg/runner/runner_application_type_test.go | 4 --- pkg/runner/runner_jvm_jibclasspath_test.go | 12 ++++----- pkg/runner/runner_spring_test.go | 2 +- pkg/runner/runner_test.go | 9 +++---- test/certification/certify_management_test.go | 8 +++++- test/certification/certify_metrics_test.go | 8 +++++- .../certification/certify_persistence_test.go | 13 ++++++++-- test/e2e/helper/e2e-helpers.go | 10 +------ test/e2e/helper/port_forward.go | 3 +-- test/e2e/helper/proj_helpers.go | 2 +- .../e2e/large-cluster/rolling_upgrade_test.go | 4 +-- test/e2e/local/helidon_test.go | 3 +++ test/e2e/local/management_test.go | 6 ++++- test/e2e/local/metrics_test.go | 6 ++++- test/e2e/local/rest_status_query_test.go | 11 +++++++- test/e2e/local/spring_test.go | 3 +++ test/e2e/prometheus/prometheus_test.go | 5 +++- test/e2e/remote/persistence_test.go | 8 +++++- 28 files changed, 117 insertions(+), 99 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f2e6cf90a..46dddb4fb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,22 +3,24 @@ run: # include test files or not, default is true tests: true - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # of this option's value: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs: -# - .*/fakes - linters: - -enable-all: true + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - gocritic + - gofmt issues: # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: + # Exclude some linters from running on data files. + - path: pkg/data + linters: + - gofmt # Exclude some linters from running on tests files. - - path: _test\.go + - path: test\.go linters: - gosec + - bodyclose diff --git a/Makefile b/Makefile index 145c37db2..74da346e9 100644 --- a/Makefile +++ b/Makefile @@ -801,7 +801,7 @@ code-review: $(BUILD_TARGETS)/generate golangci copyright ## Full code review a # ---------------------------------------------------------------------------------------------------------------------- .PHONY: golangci golangci: $(TOOLS_BIN)/golangci-lint ## Go code review - $(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G402:' --exclude='G101:' --exclude='G114:' --skip-dirs=.*/fakes --skip-files=zz_.*,generated/*,pkg/data/assets... ./api/... ./controllers/... ./pkg/... ./runner/... + $(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G402:' --exclude='G101:' --exclude='G114:' --exclude-dirs=.*/fakes --exclude-files=zz_.*,generated/*,pkg/data/assets... ./api/... ./controllers/... ./pkg/... ./runner/... $(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G107:' --exclude='G101:' --exclude='G112:' --exclude='SA4005:' --exclude='should not use dot imports' ./test/... ./pkg/fakes/... diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index f9c1d457c..5e3fa92d3 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -594,11 +594,9 @@ func (in *CoherenceSpec) UpdatePodTemplateSpec(podTemplate *corev1.PodTemplateSp if in.StorageEnabled != nil { c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohStorage, Value: BoolPtrToString(in.StorageEnabled)}) - } else { + } else if deployment.GetType() == CoherenceTypeJob { // StorageEnabled is nil, so if this is a CoherenceJob default to false - if deployment.GetType() == CoherenceTypeJob { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohStorage, Value: "false"}) - } + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohStorage, Value: "false"}) } if in.SkipVersionCheck != nil { @@ -2876,14 +2874,16 @@ func (in *Resource) IsPresent() bool { return in.Spec != nil } +var errCannotConvert = errors.New("cannot convert to runtime.Object") + // As converts the Spec to the specified value. // This is done by serializing the Spec to json and deserializing into the specified object. func (in *Resource) As(o runtime.Object) error { if in == nil { - return fmt.Errorf("cannot convert to runtime.Object - resource is nil") + return errors.Wrap(errCannotConvert, "resource is nil") } if in.Spec == nil { - return fmt.Errorf("cannot convert resource - spec is nil") + return errors.Wrap(errCannotConvert, "spec is nil") } data, err := json.Marshal(in.Spec) diff --git a/api/v1/common_test.go b/api/v1/common_test.go index fc9603461..b8eb03192 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -706,11 +706,12 @@ func removeEnvVarsFromContainer(c *corev1.Container, envVars ...string) { for _, name := range envVars { for e, ev := range c.Env { if ev.Name == name { - if e == 0 { + switch { + case e == 0: env = env[:1] - } else if (e + 1) == len(env) { + case (e + 1) == len(env): env = env[:e] - } else { + default: env = append(env[:e], env[e+1:]...) } break diff --git a/api/v1/hasher_test.go b/api/v1/hasher_test.go index 22e39b847..d6498213e 100644 --- a/api/v1/hasher_test.go +++ b/api/v1/hasher_test.go @@ -31,6 +31,5 @@ func TestHash(t *testing.T) { // If this test fails you have probably added a new field to CoherenceResourceSpec // This will break backwards compatibility. This field needs to be added to // both CoherenceStatefulSetResourceSpec and CoherenceJobResourceSpec instead - //g.Expect(deployment.GetLabels()["coherence-hash"]).To(Equal("5cb9fd9f96")) g.Expect(deployment.GetLabels()["coherence-hash"]).To(Equal("5859f96865")) } diff --git a/controllers/coherencejob_controller.go b/controllers/coherencejob_controller.go index b84f4d503..38e836854 100644 --- a/controllers/coherencejob_controller.go +++ b/controllers/coherencejob_controller.go @@ -132,7 +132,6 @@ func (in *CoherenceJobReconciler) ReconcileDeployment(ctx context.Context, reque // Check whether the deployment has a replica count specified // Ideally we'd do this with a validating/defaulting web-hook but maybe in a later version. - //spec = deployment.GetSpec() if spec.Replicas == nil { // No replica count, so we patch the deployment to have the default replicas value. // The reason we do this, is because the kubectl scale command will fail if the replicas diff --git a/pkg/management/coherence_management.go b/pkg/management/coherence_management.go index a1a8e9c0b..c5fa787d6 100644 --- a/pkg/management/coherence_management.go +++ b/pkg/management/coherence_management.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -147,6 +147,10 @@ func query(cl *http.Client, url string, v interface{}) (int, error) { time.Sleep(1 * time.Second) } + if response != nil { + defer response.Body.Close() + } + if err != nil { var status = http.StatusInternalServerError if response != nil { @@ -155,10 +159,11 @@ func query(cl *http.Client, url string, v interface{}) (int, error) { return status, err } - if response.StatusCode == http.StatusOK { - data, _ := io.ReadAll(response.Body) - - err = json.Unmarshal(data, v) + if response != nil { + if response.StatusCode == http.StatusOK { + data, _ := io.ReadAll(response.Body) + err = json.Unmarshal(data, v) + } } return response.StatusCode, err diff --git a/pkg/management/pod_exec.go b/pkg/management/pod_exec.go index c9c00922d..72f59f3e8 100644 --- a/pkg/management/pod_exec.go +++ b/pkg/management/pod_exec.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,10 +80,9 @@ func PodExec(ctx context.Context, req *ExecRequest, config *rest.Config) (int, s if err == nil { exitCode = 0 } else { - if exitErr, ok := err.(utilexec.ExitError); ok && exitErr.Exited() { + var exitErr utilexec.ExitError + if errors.As(err, &exitErr) && exitErr.Exited() { exitCode = exitErr.ExitStatus() - } else { - return 1, outStr, errStr, errors.New("failed to find exit code") } } diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index b6e045ba0..3b7e3e586 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -296,32 +296,6 @@ func SetupFlags(cmd *cobra.Command, v *viper.Viper) { v.AutomaticEnv() } -func ValidateFlags(v *viper.Viper) error { - var err error - certValidity := v.GetDuration(FlagCACertValidity) - certRotateBefore := v.GetDuration(FlagCACertRotateBefore) - if certRotateBefore > certValidity { - return fmt.Errorf("%s must be larger than %s", FlagCACertValidity, FlagCACertRotateBefore) - } - - certType := v.GetString(FlagCertType) - if certType != CertTypeSelfSigned && certType != CertTypeCertManager && certType != CertTypeManual { - return fmt.Errorf("%s parameter is invalid", FlagCertType) - } - - _, err = GetGlobalAnnotations(v) - if err != nil { - return err - } - - _, err = GetGlobalLabels(v) - if err != nil { - return err - } - - return err -} - func SetViper(v *viper.Viper) { currentViper = v } diff --git a/pkg/runner/run_details/run_details.go b/pkg/runner/run_details/run_details.go index 3fb99c377..c08618220 100644 --- a/pkg/runner/run_details/run_details.go +++ b/pkg/runner/run_details/run_details.go @@ -379,10 +379,10 @@ func (in *RunDetails) GetClasspath() string { if in.CoherenceHome != "" { if _, err := os.Stat(in.CoherenceHome); err == nil { if _, err := os.Stat(in.CoherenceHome + "/conf"); err == nil { - cp = cp + ":" + in.CoherenceHome + "/conf" + cp += ":" + in.CoherenceHome + "/conf" } if _, err := os.Stat(in.CoherenceHome + "/lib/coherence.jar"); err == nil { - cp = cp + ":" + in.CoherenceHome + "/lib/coherence.jar" + cp += ":" + in.CoherenceHome + "/lib/coherence.jar" } } } diff --git a/pkg/runner/runner_application_type_test.go b/pkg/runner/runner_application_type_test.go index 3bc66a65f..ab42dd9f7 100644 --- a/pkg/runner/runner_application_type_test.go +++ b/pkg/runner/runner_application_type_test.go @@ -34,7 +34,6 @@ func TestApplicationTypeNone(t *testing.T) { env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - //expectedArgs := GetMinimalExpectedArgs(t) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -67,7 +66,6 @@ func TestApplicationTypeNoneWithMain(t *testing.T) { env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - //expectedArgs := ReplaceArg(GetMinimalExpectedArgs(t), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -99,7 +97,6 @@ func TestApplicationTypeCoherence(t *testing.T) { env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - //expectedArgs := GetMinimalExpectedArgs(t) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -163,7 +160,6 @@ func TestApplicationTypeJava(t *testing.T) { env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - //expectedArgs := GetMinimalExpectedArgs(t) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/runner/runner_jvm_jibclasspath_test.go b/pkg/runner/runner_jvm_jibclasspath_test.go index f1dc78861..b7684f024 100644 --- a/pkg/runner/runner_jvm_jibclasspath_test.go +++ b/pkg/runner/runner_jvm_jibclasspath_test.go @@ -201,9 +201,9 @@ func createJibMainClassFile() *os.File { func GetMinimalExpectedArgsWithAppClasspathFile() []string { fileName := fmt.Sprintf("%s/jib-classpath-file", TestAppDir) cp := readFirstLine(fileName) - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" + cp += ":/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} @@ -217,9 +217,9 @@ func GetMinimalExpectedArgsWithAppMainClassFile() []string { cp := fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar", TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" + cp += ":/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} @@ -234,9 +234,9 @@ func GetMinimalExpectedArgsWithAppMainClassFile() []string { func GetMinimalExpectedArgsWithAppClasspathFileAndMainClassFile() []string { fileName := fmt.Sprintf("%s/jib-classpath-file", TestAppDir) cp := readFirstLine(fileName) - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" + cp += ":/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index 1bcb61abc..6237f696d 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -290,7 +290,7 @@ func GetMinimalExpectedSpringBootArgs(t *testing.T, main string) []string { cp := utils + "/lib/coherence-operator.jar" cfg := utils + "config" if _, err := os.Stat(cfg); err == nil { - cp = cp + "," + cfg + cp += "," + cfg } args := []string{ GetJavaArg(), diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 7131ac304..1a8604fdc 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -62,7 +62,6 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - //expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.override="), "-Dcoherence.override=k8s-coherence-override.xml") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -116,9 +115,9 @@ func GetMinimalExpectedArgsWithWorkingDir(t *testing.T, wd string) []string { utils := ensureTestUtilsDir(t) jar := fmt.Sprintf("%s/lib/coherence-operator.jar", utils) cfg := fmt.Sprintf(":%s/config", utils) - cp = cp + jar + cp += jar if _, err := os.Stat(cfg); err == nil { - cp = cp + ":" + cfg + cp += ":" + cfg } args := []string{GetJavaArg(), "-cp", cp} @@ -153,7 +152,7 @@ func GetMinimalExpectedArgsWithoutCP() []string { func GetMinimalExpectedArgsWithoutAppClasspath() []string { cp := "/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} @@ -172,7 +171,7 @@ func GetOperatorClasspathWithUtilsDir(utils string) string { cp := utils + "/lib/coherence-operator.jar" cfg := utils + "/config" if _, err := os.Stat(cfg); err == nil { - cp = cp + ":" + cfg + cp += ":" + cfg } return cp } diff --git a/test/certification/certify_management_test.go b/test/certification/certify_management_test.go index ef51b3c32..26618fdf3 100644 --- a/test/certification/certify_management_test.go +++ b/test/certification/certify_management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -81,6 +81,9 @@ func TestCertifyManagementDefaultPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) @@ -149,6 +152,9 @@ func TestCertifyManagementNonStandardPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) diff --git a/test/certification/certify_metrics_test.go b/test/certification/certify_metrics_test.go index d5c79c3d6..afb9b7b38 100644 --- a/test/certification/certify_metrics_test.go +++ b/test/certification/certify_metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -81,6 +81,9 @@ func TestCertifyMetricsDefaultPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) @@ -149,6 +152,9 @@ func TestCertifyMetricsNonStandardPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) diff --git a/test/certification/certify_persistence_test.go b/test/certification/certify_persistence_test.go index 40dbf11a3..2db46c24b 100644 --- a/test/certification/certify_persistence_test.go +++ b/test/certification/certify_persistence_test.go @@ -1,8 +1,7 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. - * */ package certification @@ -272,10 +271,17 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType, snaps if err == nil { break } + if resp != nil { + _ = resp.Body.Close() + } } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } + if err != nil { return err } @@ -294,6 +300,9 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType, snaps return false, err } resp, err = client.Do(req) + if resp != nil { + defer resp.Body.Close() + } if err != nil { fmt.Printf("Error in send idle check request: %v\n", url) return false, err diff --git a/test/e2e/helper/e2e-helpers.go b/test/e2e/helper/e2e-helpers.go index e169b5180..11da4fd47 100644 --- a/test/e2e/helper/e2e-helpers.go +++ b/test/e2e/helper/e2e-helpers.go @@ -174,7 +174,7 @@ func WaitForJob(ctx TestContext, namespace, stsName string, replicas int32, retr } else { ready = job.Status.Succeeded if job.Status.Ready != nil { - ready = ready + job.Status.Active + ready += job.Status.Active } } @@ -1720,20 +1720,12 @@ func AssertDeploymentsInNamespace(ctx TestContext, t *testing.T, yamlFile, names // Assert that a StatefulSet or Job of the correct number or replicas is created for each roleSpec in the cluster for _, d := range deployments { - //if d.IsRunAsJob() { - // ctx.Logf("Waiting for Job for deployment %s", d.Name) - // // Wait for the Job for the roleSpec to be ready - wait five minutes max - // _, err := WaitForJob(ctx, namespace, d.Name, d.GetReplicas(), time.Second*10, time.Minute*5) - // g.Expect(err).NotTo(HaveOccurred()) - // ctx.Logf("Have Job for deployment %s", d.Name) - //} else { ctx.Logf("Waiting for StatefulSet for deployment %s", d.Name) // Wait for the StatefulSet for the roleSpec to be ready - wait five minutes max sts, err := WaitForStatefulSet(ctx, namespace, d.Name, d.GetReplicas(), time.Second*10, time.Minute*5) g.Expect(err).NotTo(HaveOccurred()) g.Expect(sts.Status.ReadyReplicas).To(Equal(d.GetReplicas())) ctx.Logf("Have StatefulSet for deployment %s", d.Name) - //} } // Assert that the finalizer has been added to all the deployments that do not have AllowUnsafeDelete=false diff --git a/test/e2e/helper/port_forward.go b/test/e2e/helper/port_forward.go index 6eae956df..914f8691a 100644 --- a/test/e2e/helper/port_forward.go +++ b/test/e2e/helper/port_forward.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -166,7 +166,6 @@ func (f *PortForwarder) Start() error { if err = f.forwarder.ForwardPorts(); err != nil { // Locks until stopChan is closed. pfError = err fmt.Println(err) - //close(readyChan) } }() diff --git a/test/e2e/helper/proj_helpers.go b/test/e2e/helper/proj_helpers.go index d2686e59b..dcc5c7151 100644 --- a/test/e2e/helper/proj_helpers.go +++ b/test/e2e/helper/proj_helpers.go @@ -353,7 +353,7 @@ func NewCoherenceFromYamlWithSuffix(namespace, file, suffix string) ([]coh.Coher res, err := createCoherenceFromYaml(namespace, file) if err == nil && suffix != "" { for _, c := range res { - c.Name = c.Name + suffix + c.Name += suffix } } return res, err diff --git a/test/e2e/large-cluster/rolling_upgrade_test.go b/test/e2e/large-cluster/rolling_upgrade_test.go index f400a82d1..052294bf3 100644 --- a/test/e2e/large-cluster/rolling_upgrade_test.go +++ b/test/e2e/large-cluster/rolling_upgrade_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -226,7 +226,7 @@ func AssertPodRestartTimes(t *testing.T, before, after []corev1.Pod, idFunction // must not be equal g.Expect(i).NotTo(BeZero()) // ready must be the same comparison as scheduled, - //i.e. if scheduled is before then ready must be before + // i.e. if scheduled is before then ready must be before g.Expect(ready.Compare(readyOther)).To(Equal(i), fmt.Sprintf("node %s scheduled and ready overlap with node %s", name, otherName)) } } diff --git a/test/e2e/local/helidon_test.go b/test/e2e/local/helidon_test.go index dc9cf3276..eca244df3 100644 --- a/test/e2e/local/helidon_test.go +++ b/test/e2e/local/helidon_test.go @@ -46,6 +46,9 @@ func AssertHelidonEndpoint(t *testing.T, pods []corev1.Pod) { url := fmt.Sprintf("http://127.0.0.1:%d/ready", ports["web"]) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) } diff --git a/test/e2e/local/management_test.go b/test/e2e/local/management_test.go index c227decf0..cba4c5779 100644 --- a/test/e2e/local/management_test.go +++ b/test/e2e/local/management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -218,6 +218,10 @@ func assertManagementRequest(pod corev1.Pod, client *http.Client, protocol strin time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } + if err != nil { return err } diff --git a/test/e2e/local/metrics_test.go b/test/e2e/local/metrics_test.go index f6395d673..86c47aa7b 100644 --- a/test/e2e/local/metrics_test.go +++ b/test/e2e/local/metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -208,6 +208,10 @@ func assertMetricsRequest(pod corev1.Pod, client *http.Client, protocol string, time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } + if err != nil { return err } diff --git a/test/e2e/local/rest_status_query_test.go b/test/e2e/local/rest_status_query_test.go index 6c9c7e8b9..ceb6ccf2e 100644 --- a/test/e2e/local/rest_status_query_test.go +++ b/test/e2e/local/rest_status_query_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -26,6 +26,9 @@ func TestRestStatusQueryWithInvalidPath(t *testing.T) { println("Connecting with: ", url) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusBadRequest)) } @@ -41,6 +44,9 @@ func TestRestStatusQueryForUnknownDeployment(t *testing.T) { println("Connecting with: ", url) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) } @@ -65,6 +71,9 @@ func TestRestStatusQueryForDeployment(t *testing.T) { t.Logf("Testing status query URL is %s", url) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } t.Logf("Received status response: %v err %v", resp, err) g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) diff --git a/test/e2e/local/spring_test.go b/test/e2e/local/spring_test.go index 3c8b18b17..3feb52a5a 100644 --- a/test/e2e/local/spring_test.go +++ b/test/e2e/local/spring_test.go @@ -63,6 +63,9 @@ func AssertSpringEndpoint(t *testing.T, pods []corev1.Pod) { url := fmt.Sprintf("http://127.0.0.1:%d/", ports["web"]) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) } diff --git a/test/e2e/prometheus/prometheus_test.go b/test/e2e/prometheus/prometheus_test.go index 7f096a9d7..96039ff08 100644 --- a/test/e2e/prometheus/prometheus_test.go +++ b/test/e2e/prometheus/prometheus_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -219,6 +219,9 @@ func PrometheusAPIRequest(pod corev1.Pod, path string) (*PrometheusAPIResult, er url := fmt.Sprintf("http://127.0.0.1:%d%s%s", ports["web"], sep, path) resp, err := http.Get(url) + if resp != nil { + defer resp.Body.Close() + } if err != nil { return nil, err } diff --git a/test/e2e/remote/persistence_test.go b/test/e2e/remote/persistence_test.go index 71f6b68cd..a2b40545c 100644 --- a/test/e2e/remote/persistence_test.go +++ b/test/e2e/remote/persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -215,6 +215,9 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType) error req, err = http.NewRequest(httpMethod, url, nil) if err == nil { resp, err = client.Do(req) + if resp != nil { + _ = resp.Body.Close() + } if err == nil { break } @@ -240,6 +243,9 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType) error return false, err } resp, err = client.Do(req) + if resp != nil { + defer resp.Body.Close() + } if err != nil { fmt.Printf("Error in send idle check request: %v\n", url) return false, err From 44caa49a2dbd529c61229b7281c0a6e4b88b1f6d Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 15 Mar 2025 20:15:58 +0300 Subject: [PATCH 26/33] use a single combined Java args file --- api/v1/coherence_types.go | 66 +++---- api/v1/common_test.go | 8 +- api/v1/constants.go | 3 + api/v1/create_job_applicationspec_test.go | 95 +++++++--- ...create_statefulset_applicationspec_test.go | 57 +++++- api/v1/zz_generated.deepcopy.go | 5 + docs/applications/020_build_application.adoc | 33 +--- docs/applications/070_spring.adoc | 52 ++---- docs/applications/080_entrypoint.adoc | 174 ++++++++++++++++++ pkg/runner/cmd_config.go | 48 +++++ 10 files changed, 404 insertions(+), 137 deletions(-) create mode 100644 docs/applications/080_entrypoint.adoc diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 5e3fa92d3..11e9ea833 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -242,12 +242,22 @@ type ApplicationSpec struct { // to the entry point. // +optional UseImageEntryPoint *bool `json:"useImageEntryPoint,omitempty"` - // UseJdkJavaOptions is a flag to indicate that the JDK_JAVA_OPTIONS environment variable + // UseJdkJavaOptions is a flag to indicate that the `JDK_JAVA_OPTIONS` environment variable // should be set in the Coherence container to contain the JVM arguments configured by // the Operator. - // Setting JDK_JAVA_OPTIONS defaults to true and only applies if UseImageEntryPoint is set to true. + // Setting `JDK_JAVA_OPTIONS` defaults to true and only applies if UseImageEntryPoint is set to true. // +optional UseJdkJavaOptions *bool `json:"useJdkJavaOptions,omitempty"` + // AlternateJdkJavaOptions specifies an alternative environment variable name to use instead of + // `JDK_JAVA_OPTIONS` for the command line options. + // If an application does not want to use the `JDK_JAVA_OPTIONS` environment variable but still + // wants access to the options the operator would have configured, this field can be set to an + // environment variable that an application can then access in the container at runtime. + // The value of the environment variable specified here will be set even if `UseJdkJavaOptions` + // is set to false. + // Setting the alternate JVM options environment variable only applies if UseImageEntryPoint is set to true. + // +optional + AlternateJdkJavaOptions *string `json:"alternateJdkJavaOptions,omitempty"` } // UpdateCoherenceContainer updates the Coherence container with the relevant settings. @@ -294,32 +304,28 @@ func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { useJdkJavaOptions = useImageEntryPoint && (in.UseJdkJavaOptions == nil || *in.UseJdkJavaOptions) } + argsFile := fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorCoherenceArgsFile) + if useImageEntryPoint { // we are configured to use the image's entry point // in cannot be nil if we get here if useJdkJavaOptions { // find any existing JDK_JAVA_OPTION env var so we do not loose its value - jdkOpts := "" + existingJdkOpts := "" jdkOptsIdx := -1 for i, ev := range c.Env { if ev.Name == EnvVarJdkOptions { - jdkOpts = ev.Value + existingJdkOpts = ev.Value jdkOptsIdx = i break } } - if in.IsSpringBoot() { - jdkOpts = jdkOpts + " " + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile) - jdkOpts = jdkOpts + " " + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile) - } else { - jdkOpts = jdkOpts + " " + fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile) - } - jdkOptsEV := corev1.EnvVar{ Name: EnvVarJdkOptions, - Value: strings.TrimSpace(jdkOpts), + Value: strings.TrimSpace(existingJdkOpts + " " + argsFile), } + if jdkOptsIdx >= 0 { c.Env[jdkOptsIdx] = jdkOptsEV } else { @@ -327,30 +333,18 @@ func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { } } - // Use the application args as container args - c.Args = in.Args - } else { - args := []string{"--class-path", - fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorClasspathFile)} - - if in.IsSpringBoot() { - args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) - args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorSpringBootArgsFile)) - args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) - } else { - args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorJvmArgsFile)) - args = append(args, fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorMainClassFile)) - } - - if in != nil { - args = append(args, in.Args...) + if in.AlternateJdkJavaOptions != nil && *in.AlternateJdkJavaOptions != "" { + c.Env = append(c.Env, corev1.EnvVar{ + Name: *in.AlternateJdkJavaOptions, + Value: strings.TrimSpace(argsFile), + }) } - if c.Command == nil { - // if not already set, use "java" as the container entry point - c.Command = []string{"java"} - } - c.Args = args + // Use the application args as container args + c.Args = in.Args + } else if c.Command == nil { + // if not already set, use "java" as the container entry point + c.Command = []string{"java", argsFile} } } @@ -1649,11 +1643,11 @@ func (in *JvmDebugSpec) CreateEnvVars() []corev1.EnvVar { corev1.EnvVar{Name: EnvVarJvmDebugPort, Value: p}, ) - if in != nil && in.Suspend != nil && *in.Suspend { + if in.Suspend != nil && *in.Suspend { envVars = append(envVars, corev1.EnvVar{Name: EnvVarJvmDebugSuspended, Value: "true"}) } - if in != nil && in.Attach != nil { + if in.Attach != nil { envVars = append(envVars, corev1.EnvVar{Name: EnvVarJvmDebugAttach, Value: *in.Attach}) } diff --git a/api/v1/common_test.go b/api/v1/common_test.go index b8eb03192..8cbe5c9e1 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -388,13 +388,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe cohContainer := corev1.Container{ Name: coh.ContainerNameCoherence, Image: testCoherenceImage, - Command: []string{"java"}, - Args: []string{ - "--class-path", - fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorClasspathFile), - fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorJvmArgsFile), - fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorMainClassFile), - }, + Command: []string{"java", fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorCoherenceArgsFile)}, Ports: []corev1.ContainerPort{ { Name: coh.PortNameCoherence, diff --git a/api/v1/constants.go b/api/v1/constants.go index 2e48ba36b..3382ee74f 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -175,6 +175,9 @@ const ( // OperatorRackURL is the default Operator rack query URL OperatorRackURL = "http://$(COHERENCE_OPERATOR_HOST)/rack/$(COHERENCE_MACHINE)" + // OperatorCoherenceArgsFile is the name of the file in the utils directory containing the full set of + // JVM arguments to run the Coherence container + OperatorCoherenceArgsFile = "coherence-container-args.txt" // OperatorJvmArgsFile is the name of the file in the utils directory containing the JVM arguments OperatorJvmArgsFile = "coherence-jvm-args.txt" // OperatorClasspathFile is the name of the file in the utils directory containing the JVM class path diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index d3590c2f2..d77d7969c 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -64,7 +64,6 @@ func TestCreateJobWithApplicationMainArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - jobExpected.Spec.Template.Spec.Containers[0].Args = append(jobExpected.Spec.Template.Spec.Containers[0].Args, "arg1", "arg2") // Add the expected environment variables addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) @@ -120,14 +119,14 @@ func TestCreateJobUseImageEntryPoint(t *testing.T) { // Create the test deployment deployment := createTestCoherenceJob(spec) // Create expected Job - stsExpected := createMinimalExpectedJob(deployment) - stsExpected.Spec.Template.Spec.Containers[0].Command = nil - stsExpected.Spec.Template.Spec.Containers[0].Args = nil - stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-jvm-args.txt"}) + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}) // assert that the Job is as expected - assertJobCreation(t, deployment, stsExpected) + assertJobCreation(t, deployment, jobExpected) } func TestCreateJobUseImageEntryPointAndUseJdkOptsFalse(t *testing.T) { @@ -141,12 +140,12 @@ func TestCreateJobUseImageEntryPointAndUseJdkOptsFalse(t *testing.T) { // Create the test deployment deployment := createTestCoherenceJob(spec) // Create expected Job - stsExpected := createMinimalExpectedJob(deployment) - stsExpected.Spec.Template.Spec.Containers[0].Command = nil - stsExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil // assert that the Job is as expected - assertJobCreation(t, deployment, stsExpected) + assertJobCreation(t, deployment, jobExpected) } func TestCreateJobUseImageEntryPointWithExistingJdkOpts(t *testing.T) { @@ -165,18 +164,18 @@ func TestCreateJobUseImageEntryPointWithExistingJdkOpts(t *testing.T) { // Create the test deployment deployment := createTestCoherenceJob(spec) // Create expected Job - stsExpected := createMinimalExpectedJob(deployment) - stsExpected.Spec.Template.Spec.Containers[0].Command = nil - stsExpected.Spec.Template.Spec.Containers[0].Args = nil - stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-jvm-args.txt"}) - stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-container-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) - stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) // assert that the Job is as expected - assertJobCreation(t, deployment, stsExpected) + assertJobCreation(t, deployment, jobExpected) } func TestCreateJobWithApplicationEntryPoint(t *testing.T) { @@ -189,9 +188,61 @@ func TestCreateJobWithApplicationEntryPoint(t *testing.T) { // Create the test deployment deployment := createTestCoherenceJob(spec) // Create expected Job - stsExpected := createMinimalExpectedJob(deployment) - stsExpected.Spec.Template.Spec.Containers[0].Command = []string{"foo", "bar"} + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = []string{"foo", "bar"} + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPointWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPointAndUseJdkOptsFalseWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) // assert that the Job is as expected - assertJobCreation(t, deployment, stsExpected) + assertJobCreation(t, deployment, jobExpected) } diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index 7d5ffbbdb..1c2249922 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -64,7 +64,6 @@ func TestCreateStatefulSetWithApplicationMainArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - stsExpected.Spec.Template.Spec.Containers[0].Args = append(stsExpected.Spec.Template.Spec.Containers[0].Args, "arg1", "arg2") // Add the expected environment variables addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) @@ -124,7 +123,7 @@ func TestCreateStatefulSetUseImageEntryPoint(t *testing.T) { stsExpected.Spec.Template.Spec.Containers[0].Command = nil stsExpected.Spec.Template.Spec.Containers[0].Args = nil stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-jvm-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -169,7 +168,7 @@ func TestCreateStatefulSetUseImageEntryPointWithExistingJdkOpts(t *testing.T) { stsExpected.Spec.Template.Spec.Containers[0].Command = nil stsExpected.Spec.Template.Spec.Containers[0].Args = nil stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-jvm-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-container-args.txt"}) stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, @@ -195,3 +194,55 @@ func TestCreateStatefulSetWithApplicationEntryPoint(t *testing.T) { // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) } + +func TestCreateStatefulSetUseImageEntryPointWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointAndUseJdkOptsFalseWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 098939ca4..f136f37f7 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -121,6 +121,11 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { *out = new(bool) **out = **in } + if in.AlternateJdkJavaOptions != nil { + in, out := &in.AlternateJdkJavaOptions, &out.AlternateJdkJavaOptions + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSpec. diff --git a/docs/applications/020_build_application.adoc b/docs/applications/020_build_application.adoc index 8bbdd7844..faa20281b 100644 --- a/docs/applications/020_build_application.adoc +++ b/docs/applications/020_build_application.adoc @@ -46,30 +46,15 @@ Java executable location, in this example to `/usr/lib/jvm/java-11-openjdk/bin/j === Image `EntryPoint` - What Does the Operator Run? The image does not need to have an `EntryPoint` or command specified, it does not need to actually be executable. -If the image does have an `EntryPoint`, it will just be ignored. +The default behaviour of the Coherence operator it to configure its own entry point to execute the Coherence container, if the image does have an `EntryPoint`, it will just be ignored. -The Coherence Operator actually injects its own `runner` executable into the container which the container runs and which -in turn builds the Java command line to execute. The `runner` process looks at arguments and environment variables configured -for the Coherence container and from these constructs a Java command line that it then executes. - -The default command might look something like this: -[source,bash] ----- -java --class-path `/app/resources:/app/classes:/app/libs/*` \ - \ - \ - com.tangosol.net.Coherence ----- -The `runner` will work out the JVM's classpath, args and system properties to add to the command line -and execute the main class `com.tangosol.net.Coherence`. -All these are configurable in the `Coherence` resource spec. === Optional `CLASSPATH` Environment Variable If the `CLASSPATH` environment variable has been set in an image that classpath will be used when running the Coherence container. Other elements may also be added to the classpath depending on the configuration of the `Coherence` resource. -=== Setting the Classpath +==== Setting the Classpath An application image contains `.jar` files (at least `coherence.jar`), possibly Java class files, also possibly other ad-hoc files, all of which need to be on the application's classpath. @@ -127,20 +112,6 @@ The `JAVA_HOME` environment variable does not have to be set in the image. If it be used to run the application. If it is not set then the `java` executable *must* be on the `PATH` in the image. -=== Optional `COHERENCE_HOME` Environment Variable - -The `COHERENCE_HOME` environment variable does not have to be set in an image. -Typically, all the jar files, including `coherence.jar` would be packaged into a single directory which is then used as -the classpath. -It is possible to run official Coherence images published by Oracle, which have `COHERENCE_HOME` set, which is then used -by the Operator to set the classpath. - -If the `COHERENCE_HOME` environment variable is set in an image the following entries will be added to the end of the -classpath: - -* `$COHERENCE_HOME/lib/coherence.jar` -* `$COHERENCE_HOME/conf` - === Additional Data Volumes If the application requires access to external storage volumes in Kubernetes it is possible to add additional `Volumes` diff --git a/docs/applications/070_spring.adoc b/docs/applications/070_spring.adoc index 9719882dd..e9f083efb 100644 --- a/docs/applications/070_spring.adoc +++ b/docs/applications/070_spring.adoc @@ -174,36 +174,24 @@ class as opposed to the `org.springframework.boot.loader.JarLauncher` that `java === Using Could Native Buildpacks If the Spring Boot Maven or Gradle plugin has been used to produce an image using -https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1[Cloud Native Buildpacks] +https://docs.spring.io/spring-boot/reference/packaging/container-images/cloud-native-buildpacks.html[Cloud Native Buildpacks] these images can work with the Coherence Operator. +Images using Cloud Native Buildpacks contain a special launcher executable the runs the Java application. This makes it more complex than normal for the Operator to provide a custom Java command. For images built using Cloud Native Buildpacks to work the `Coherence` resource must be configured to execute the images entry point instead of the Operator injecting a command line. + [WARNING] ==== +Due to the way that the Coherence Operator configures JVM arguments +when configured to use an image entry point, the image must be running +Java 11 or higher. +==== + +Instead of building a custom command line, the Operator uses the `JDK_JAVA_OPTIONS` environment variable to pass and +configured JVM options and system properties to the Spring application. +This is a standard environment variable that the JVM will effectively use to pre-pend JVM arguments to its command line. + Due to limitation on the way that arguments can be passed to the JVM when using Buildpacks images the Coherence operator will only work with images containing a JVM greater than Java 11. -Although the Buildpacks launcher will honour the `JAVA_OPTS` or `JAVA_TOOL_OPTIONS` environment variables there appear -to be size limitations for the values of these variables that make it impractical for the Operator to use them. -The Operator therefore creates a JVM arguments file to pass the arguments to the JVM. -At the time of writing these docs, Java 8 (which is the default version of Java used by the Spring Boot plugin) does not -support the use of argument files for the JVM. - -It is simple to configure the version of the JVM used by the Spring Boot plugin, for example in Maven: -[source,xml] ----- - - org.springframework.boot - spring-boot-maven-plugin - 2.3.4.RELEASE - - - - 11.* - - - - ----- -==== When creating a `Coherence` deployment for a Spring Boot Buildpacks image The application type must be set to `spring`. @@ -220,25 +208,13 @@ spec: image: catalogue:1.0.0 application: type: spring # <1> + useImageEntryPoint: true <2> ---- <1> The application type has been set to `spring` (for Spring Boot 2.x) or `spring3` (for Spring Boot 3.x) so that the operator knows that this is a Spring Boot application, and the fact that the image is a Buildpacks image will be auto-discovered. +<2> The Operator will run the image's entry point -When the Operator starts the application it will then run the buildpacks launcher with a command equivalent -to this: - -*Spring Boot 2.x* -[source,bash] ----- -/cnb/lifecycle/launcher java @jvm-args-file org.springframework.boot.loader.PropertiesLauncher ----- - -*Spring Boot 3.x* -[source,bash] ----- -/cnb/lifecycle/launcher java @jvm-args-file org.springframework.boot.loader.launch.PropertiesLauncher ----- ==== Buildpacks Detection diff --git a/docs/applications/080_entrypoint.adoc b/docs/applications/080_entrypoint.adoc new file mode 100644 index 000000000..9dc14ea2d --- /dev/null +++ b/docs/applications/080_entrypoint.adoc @@ -0,0 +1,174 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2025, Oracle and/or its affiliates. + Licensed under the Universal Permissive License v 1.0 as shown at + http://oss.oracle.com/licenses/upl. + +/////////////////////////////////////////////////////////////////////////////// + += Run an Image Entry Point + +== Run an Image Entry Point + +The default behaviour of the Coherence operator is to configure the entry point and arguments to +use to run the Coherence container. This command line is created from the various configuration +elements in the `Coherence` resource yaml. Any entry point and arguments actually configured in +the image being used will be ignored. +The behaviour can be changed so that the images own entry point is used for the container. +This could be useful for example when an image contains a shell script that performs initialisation +before running the Java Coherence application. + +[NOTE] +==== +Using an image entry point is only supported in images that use Java 11 or higher. +==== + +To use an image's entry point set the `spec.application.useImageEntryPoint` field in the `Coherence` +resource to `true`. + +For example: + +[source] +.storage.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: storage +spec: + replicas: 3 + image: container-registry.oracle.com/middleware/coherence-ce:14.1.2-0-1 + application: + useImageEntryPoint: true +---- + +=== How are the JVM and Coherence Configured + +When the operator builds the container command line it can pass all the required JVM options +and system properties to configure the application on the command line. +But, when the image entry point it being used the operator needs to pass configuration another way. + +All the Coherence configuration system properties can also be passed as environment variables, so +the operator configures the container to have all the required environment variables to configure +Coherence. For example, the `coherence.role` system property is used to configure the role name +of a Coherence process, but Coherence will also use the `COHERENCE_ROLE` environment variable for this. +If `spec.role` value is set in the `Coherence` resource, this is be used to set `COHERENCE_ROLE` +environment variable in the Coherence container configuration in the Pod. + +The operator then uses a combination of Java arguments files and the `JDK_JAVA_OPTIONS` environment +variable to configure the JVM. This means that most of the features of the `Coherence` CRD can be +used, even when running an image entry point. + + +==== Java Argument Files + +Various other environment variables are set by the Coherence operator to configure the container. +When the Pod starts an init-container that the operator has configured uses these environment +variables to produce a number of Java command line argument files. +These files contain all the JVM command line options that the operator would have used in its +custom command line if it was running the container. +For more information on argument files see the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#java-command-line-argument-files[ +Java Arguments Files] documentation. + +The operator creates multiple arguments files for different purposes. +The Java argument files are always created by the init-container as these are used in the command line +that the operator normally configures for container. +There will be a file for the class path, a file for JVM options, a file for Spring Boot options +if the application is Spring Boot, etc. + +=== The `JDK_JAVA_OPTIONS` Environment Variable + +The `JDK_JAVA_OPTIONS` is a special environment variable recognised by the JVM. +Any values in the `JDK_JAVA_OPTIONS` environment variable are effectively prepended to the JVM +command line. +It is described fully in the +https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html#using-the-jdk_java_options-launcher-environment-variable +[Java Command] documentation. + +There are limitations on the size of the value for an environment variable, so the operator could +not specify all the options it needs in the `JDK_JAVA_OPTIONS` environment variable. +This is why the operator uses argument files instead, so all it needs to set into the `JDK_JAVA_OPTIONS` environment +variable are the names of the argument files to load. + +==== What If The Application Already Sets `JDK_JAVA_OPTIONS` + +If the `JDK_JAVA_OPTIONS` environment variable is set in the `Coherence` resource then the operator +will append its additional configuration onto the existing value. + +==== Disabling Use of `JDK_JAVA_OPTIONS` + +There may be occasions that the operator should not configure the `JDK_JAVA_OPTIONS` environment variable. +For example, an image may run a shell script that runs various other Java commands before starting the +main Coherence application. If the `JDK_JAVA_OPTIONS` environment variable was set it would be applied +to all these Java processes too. + +Setting the `spec.application.useJdkJavaOptions` field to `false` in the Coherence resource will +disable the use of the `JDK_JAVA_OPTIONS` environment variable and the operator will not set it. + +For example, + +[source] +.storage.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: storage +spec: + replicas: 3 + image: container-registry.oracle.com/middleware/coherence-ce:14.1.2-0-1 + application: + useImageEntryPoint: true + useJdkJavaOptions: false +---- + +[NOTE] +==== +When the `spec.application.useJdkJavaOptions` field is set to false the operator has no way to pass +a number of configuration options to the JVM. Coherence configurations that are passed as environment +variables will still work. Anything passed as JVM options, such as memory configurations, system +properties, etc cannot be configured. + +As long as the application that the image runs is a Coherence application correctly configured +to run in Kubernetes with the options required by the operator then it should still work. +==== + +==== Using An Alternative To `JDK_JAVA_OPTIONS` + +In use cases where the `JDK_JAVA_OPTIONS` environment variable cannot be used and is disabled as +described above, an alternative environment variable name can be specified that the operator will +configure instead. This allows an application to use this alternative environment variable at runtime +to obtain all the configurations that the Operator would have applied to the JVM. + +The name of the alternative environment variable is set in the `spec.application.alternateJdkJavaOptions` +field of the `Coherence` resource. + +For example, using the the yaml below will cause the operator to set the Java options values +into the `ALT_JAVA_OPTS` environment variable. + +[source] +.storage.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: storage +spec: + replicas: 3 + image: container-registry.oracle.com/middleware/coherence-ce:14.1.2-0-1 + application: + useImageEntryPoint: true + useJdkJavaOptions: false + alternateJdkJavaOptions: "ALT_JAVA_OPTS" +---- + +In the Coherence container the application code can then access the The `ALT_JAVA_OPTS` environment variable +to obtain the JVM options the Operator configured. + +==== Use Java Argument Files Directly + +In use cases where the `JDK_JAVA_OPTIONS` environment variable has been disabled application code +could also directly access the Java argument files the operator configured and use those to +configure the Coherence JVM. + diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 1d9cdc5c3..be5add682 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -47,6 +47,15 @@ func configCommand(env map[string]string) *cobra.Command { // createsFiles will create the various config files func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, error) { + ma, found := details.LookupEnv(v1.EnvVarAppMainArgs) + if found { + if ma != "" { + for _, arg := range strings.Split(ma, " ") { + details.MainArgs = append(details.MainArgs, details.ExpandEnv(arg)) + } + } + } + populateMainClass(details) populateServerDetails(details) err := configureCommand(details) @@ -68,9 +77,48 @@ func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, erro if err := createCliConfig(details); err != nil { return false, err } + + if err := createFinalArgsFile(details); err != nil { + return false, err + } return false, nil } +// createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container +func createFinalArgsFile(details *run_details.RunDetails) error { + var buffer bytes.Buffer + buffer.WriteString("--class-path") + buffer.WriteString("\n") + buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorClasspathFile)) + buffer.WriteString("\n") + + if details.IsSpringBoot() { + buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorJvmArgsFile)) + buffer.WriteString("\n") + buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorSpringBootArgsFile)) + buffer.WriteString("\n") + buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorMainClassFile)) + } else { + buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorJvmArgsFile)) + buffer.WriteString("\n") + buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorMainClassFile)) + } + + if len(details.MainArgs) > 0 { + for _, arg := range details.MainArgs { + buffer.WriteString("\n") + buffer.WriteString(arg) + } + } + argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorCoherenceArgsFile) + err := os.WriteFile(argsFile, buffer.Bytes(), os.ModePerm) + if err != nil { + return errors.Wrap(err, "failed to write coherence container args file") + } + configLog.Info("Created class path file", "FileName", argsFile, "Args", buffer.String()) + return nil +} + // createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container func createClassPathFile(details *run_details.RunDetails) error { var classpath string From ed3057039777fd8069c7ef383454bfccdd77beae Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 15 Mar 2025 21:27:52 +0300 Subject: [PATCH 27/33] fix container Java args file --- pkg/runner/cmd_config.go | 92 ++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index be5add682..5da44567d 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -47,6 +47,8 @@ func configCommand(env map[string]string) *cobra.Command { // createsFiles will create the various config files func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, error) { + var err error + ma, found := details.LookupEnv(v1.EnvVarAppMainArgs) if found { if ma != "" { @@ -56,71 +58,65 @@ func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, erro } } + var cp string + var args string + var main string + var sb string + populateMainClass(details) populateServerDetails(details) - err := configureCommand(details) + err = configureCommand(details) if err != nil { return false, errors.Wrap(err, "failed to configure server command") } - if err := createClassPathFile(details); err != nil { - return false, err - } - if err := createArgsFile(details); err != nil { + + if cp, err = createClassPathFile(details); err != nil { return false, err } - if err := createMainClassFile(details); err != nil { + if args, err = createArgsFile(details); err != nil { return false, err } - if err := createSpringBootFile(details); err != nil { + if main, err = createMainClassFile(details); err != nil { return false, err } - if err := createCliConfig(details); err != nil { + if sb, err = createSpringBootFile(details); err != nil { return false, err } - - if err := createFinalArgsFile(details); err != nil { + if err = createCliConfig(details); err != nil { return false, err } - return false, nil -} -// createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container -func createFinalArgsFile(details *run_details.RunDetails) error { var buffer bytes.Buffer buffer.WriteString("--class-path") buffer.WriteString("\n") - buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorClasspathFile)) + buffer.WriteString(cp) + buffer.WriteString("\n") + buffer.WriteString(args) buffer.WriteString("\n") - if details.IsSpringBoot() { - buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorJvmArgsFile)) - buffer.WriteString("\n") - buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorSpringBootArgsFile)) + buffer.WriteString(sb) buffer.WriteString("\n") - buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorMainClassFile)) - } else { - buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorJvmArgsFile)) - buffer.WriteString("\n") - buffer.WriteString(fmt.Sprintf(v1.ArgumentFileNamePattern, v1.VolumeMountPathUtils, os.PathSeparator, v1.OperatorMainClassFile)) } - + buffer.WriteString(main) if len(details.MainArgs) > 0 { for _, arg := range details.MainArgs { buffer.WriteString("\n") buffer.WriteString(arg) } } + argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorCoherenceArgsFile) - err := os.WriteFile(argsFile, buffer.Bytes(), os.ModePerm) + err = os.WriteFile(argsFile, buffer.Bytes(), os.ModePerm) if err != nil { - return errors.Wrap(err, "failed to write coherence container args file") + return false, errors.Wrap(err, "failed to write coherence container args file") } - configLog.Info("Created class path file", "FileName", argsFile, "Args", buffer.String()) - return nil + configLog.Info("Created Coherence container args file", "FileName", argsFile, "Args", buffer.String()) + + return false, nil } // createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container -func createClassPathFile(details *run_details.RunDetails) error { +func createClassPathFile(details *run_details.RunDetails) (string, error) { var classpath string var err error if details.IsSpringBoot() { @@ -130,7 +126,7 @@ func createClassPathFile(details *run_details.RunDetails) error { // no fat jar, so use the current directory wd, err := os.Getwd() if err != nil { - return errors.Wrap(err, "failed to get the current working directory") + return "", errors.Wrap(err, "failed to get the current working directory") } classpath = fmt.Sprintf(v1.FileNamePattern, wd, os.PathSeparator, "*") classpath = classpath + ":" + wd @@ -141,31 +137,27 @@ func createClassPathFile(details *run_details.RunDetails) error { cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) err = os.WriteFile(cpFile, []byte(classpath), os.ModePerm) if err != nil { - return errors.Wrap(err, "failed to write coherence classpath file") + return "", errors.Wrap(err, "failed to write coherence classpath file") } configLog.Info("Created class path file", "FileName", cpFile, "ClassPath", classpath) - return nil + return classpath, nil } // createArgsFile will create the JVM args files for a Coherence Pod - typically this is run from an init-container -func createArgsFile(details *run_details.RunDetails) error { +func createArgsFile(details *run_details.RunDetails) (string, error) { args := details.GetAllArgs() argFileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) - - var buffer bytes.Buffer - for _, arg := range args { - buffer.WriteString(arg + "\n") - } - if err := os.WriteFile(argFileName, buffer.Bytes(), os.ModePerm); err != nil { - return errors.Wrap(err, "failed to write JVM args file "+argFileName) + data := strings.Join(args, "\n") + if err := os.WriteFile(argFileName, []byte(data), os.ModePerm); err != nil { + return "", errors.Wrap(err, "failed to write JVM args file "+argFileName) } - configLog.Info("Created JVM args file", "FileName", argFileName, "Args", buffer.String()) - return nil + configLog.Info("Created JVM args file", "FileName", argFileName, "Args", data) + return data, nil } // createSpringBootFile will create the SpringBoot JVM args files for a Coherence Pod - typically this is run from an init-container -func createSpringBootFile(details *run_details.RunDetails) error { +func createSpringBootFile(details *run_details.RunDetails) (string, error) { argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) cp := strings.ReplaceAll(details.GetClasspath(), ":", ",") @@ -179,14 +171,14 @@ func createSpringBootFile(details *run_details.RunDetails) error { err := os.WriteFile(argsFile, []byte(args), os.ModePerm) if err != nil { - return errors.Wrap(err, "failed to write coherence classpath file") + return "", errors.Wrap(err, "failed to write coherence classpath file") } configLog.Info("Created SpringBoot args file", "FileName", argsFile, "Args", args) - return nil + return args, nil } // createMainClassFile will create the file containing the main class name for a Coherence Pod - typically this is run from an init-container -func createMainClassFile(details *run_details.RunDetails) error { +func createMainClassFile(details *run_details.RunDetails) (string, error) { fileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorMainClassFile) var s string @@ -197,10 +189,10 @@ func createMainClassFile(details *run_details.RunDetails) error { } if err := os.WriteFile(fileName, []byte(s), os.ModePerm); err != nil { - return errors.Wrap(err, "failed to write coherence classpath file") + return "", errors.Wrap(err, "failed to write coherence classpath file") } - configLog.Info("Created main class file", "FileName", fileName, "MainClass", details.InnerMainClass) - return nil + configLog.Info("Created main class file", "FileName", fileName, "Content", s) + return s, nil } func createCliConfig(details *run_details.RunDetails) error { From 15b2e8360489e4ddf8bbc0326ac30c43c3609b7a Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 16 Mar 2025 07:02:19 +0300 Subject: [PATCH 28/33] fix container Spring CNBP --- api/v1/zz_generated.deepcopy.go | 4 +++- docs/about/04_coherence_spec.adoc | 4 +++- pkg/runner/cmd_config.go | 13 +++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index f136f37f7..ec300fe05 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,10 +1,12 @@ //go:build !ignore_autogenerated +/* + * Copyright (c) 2020, 2 /* * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. - */ +//go:build !ignore_autogenerated // Code generated by controller-gen. DO NOT EDIT. diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index 613a07c29..aef2deb52 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -143,7 +143,8 @@ m| workingDir | WorkingDir sets the working directory of the Coherence container m| cloudNativeBuildPack | Optional settings that may be configured if using a Cloud Native Buildpack Image. For example an image build with the Spring Boot Maven/Gradle plugin. See: https://github.com/paketo-buildpacks/spring-boot and https://buildpacks.io/ m| *<> | false m| springBootFatJar | SpringBootFatJar is the full path name to the Spring Boot fat jar if the application image has been built by just adding a Spring Boot fat jar to the image. If this field is set then the application will be run by executing this jar. For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" m| *string | false m| useImageEntryPoint | UseImageEntryPoint is a flag to indicate that the Coherence container in the Pods should just execute the image entry point and not configure a custom command line. If this flag is set to true any arguments in the Args field are passed as container arguments to the entry point. m| *bool | false -m| useJdkJavaOptions | UseJdkJavaOptions is a flag to indicate that the JDK_JAVA_OPTIONS environment variable should be set in the Coherence container to contain the JVM arguments configured by the Operator. Setting JDK_JAVA_OPTIONS defaults to true and only applies if UseImageEntryPoint is set to true. m| *bool | false +m| useJdkJavaOptions | UseJdkJavaOptions is a flag to indicate that the `JDK_JAVA_OPTIONS` environment variable should be set in the Coherence container to contain the JVM arguments configured by the Operator. Setting `JDK_JAVA_OPTIONS` defaults to true and only applies if UseImageEntryPoint is set to true. m| *bool | false +m| alternateJdkJavaOptions | AlternateJdkJavaOptions specifies an alternative environment variable name to use instead of `JDK_JAVA_OPTIONS` for the command line options. If an application does not want to use the `JDK_JAVA_OPTIONS` environment variable but still wants access to the options the operator would have configured, this field can be set to an environment variable that an application can then access in the container at runtime. The value of the environment variable specified here will be set even if `UseJdkJavaOptions` is set to false. Setting the alternate JVM options environment variable only applies if UseImageEntryPoint is set to true. m| *string | false |=== <
> @@ -570,6 +571,7 @@ m| gc | Set JVM garbage collector options. m| *<> | false m| useJibClasspath | A flag indicating whether to automatically add the default classpath for images created by the JIB tool https://github.com/GoogleContainerTools/jib If true then the /app/lib/* /app/classes and /app/resources entries are added to the JVM classpath. The default value fif not specified is true. m| *bool | false +m| java8 | Java8 is a flag to indicate that a Coherence container is running on Java 8 and must use the legacy Operator container entry point. This would only apply to applications using older Coherence 12.2.1-4-* or 14.1.1-0-* versions. The default value for this field is false, if this field is not set to true when Java 8 is used the container will fail to start. m| *bool | false |=== <
> diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index 5da44567d..de1e84529 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -96,12 +96,13 @@ func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, erro if details.IsSpringBoot() { buffer.WriteString(sb) buffer.WriteString("\n") - } - buffer.WriteString(main) - if len(details.MainArgs) > 0 { - for _, arg := range details.MainArgs { - buffer.WriteString("\n") - buffer.WriteString(arg) + } else { + buffer.WriteString(main) + if len(details.MainArgs) > 0 { + for _, arg := range details.MainArgs { + buffer.WriteString("\n") + buffer.WriteString(arg) + } } } From 7cff3ecaa4f06476669e2d0512b366c12ff610f7 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 16 Mar 2025 07:08:22 +0300 Subject: [PATCH 29/33] fix container Spring CNBP --- hack/boilerplate.go.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index 009165e12..31b9ff299 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ From c82231928b3aaff5eeb05500ac02157b292dcc0b Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 16 Mar 2025 07:15:02 +0300 Subject: [PATCH 30/33] fix container Spring CNBP --- api/v1/zz_generated.deepcopy.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index ec300fe05..f136f37f7 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,12 +1,10 @@ //go:build !ignore_autogenerated -/* - * Copyright (c) 2020, 2 /* * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. -//go:build !ignore_autogenerated + */ // Code generated by controller-gen. DO NOT EDIT. From 07271e187e6c4e14d86c3fed0bfbedc47da5d33b Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 16 Mar 2025 09:54:43 +0300 Subject: [PATCH 31/33] fix Spring apps --- api/v1/coherence_types.go | 6 +-- api/v1/constants.go | 3 ++ docs/applications/070_spring.adoc | 71 ++++--------------------------- pkg/runner/cmd_config.go | 68 ++++++++++++++++++++++------- 4 files changed, 68 insertions(+), 80 deletions(-) diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 11e9ea833..a99bec183 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -304,11 +304,11 @@ func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { useJdkJavaOptions = useImageEntryPoint && (in.UseJdkJavaOptions == nil || *in.UseJdkJavaOptions) } - argsFile := fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorCoherenceArgsFile) - if useImageEntryPoint { // we are configured to use the image's entry point // in cannot be nil if we get here + argsFile := fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorEntryPointArgsFile) + if useJdkJavaOptions { // find any existing JDK_JAVA_OPTION env var so we do not loose its value existingJdkOpts := "" @@ -343,7 +343,7 @@ func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { // Use the application args as container args c.Args = in.Args } else if c.Command == nil { - // if not already set, use "java" as the container entry point + argsFile := fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorCoherenceArgsFile) c.Command = []string{"java", argsFile} } } diff --git a/api/v1/constants.go b/api/v1/constants.go index 3382ee74f..b22bbc6bb 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -178,6 +178,9 @@ const ( // OperatorCoherenceArgsFile is the name of the file in the utils directory containing the full set of // JVM arguments to run the Coherence container OperatorCoherenceArgsFile = "coherence-container-args.txt" + // OperatorEntryPointArgsFile is the arguments file to add to the JDK_JAVA_OPTIONS environment variable + // when running the image entry point + OperatorEntryPointArgsFile = "coherence-container-args.txt" // OperatorJvmArgsFile is the name of the file in the utils directory containing the JVM arguments OperatorJvmArgsFile = "coherence-jvm-args.txt" // OperatorClasspathFile is the name of the file in the utils directory containing the JVM class path diff --git a/docs/applications/070_spring.adoc b/docs/applications/070_spring.adoc index e9f083efb..206b0306f 100644 --- a/docs/applications/070_spring.adoc +++ b/docs/applications/070_spring.adoc @@ -177,9 +177,10 @@ If the Spring Boot Maven or Gradle plugin has been used to produce an image usin https://docs.spring.io/spring-boot/reference/packaging/container-images/cloud-native-buildpacks.html[Cloud Native Buildpacks] these images can work with the Coherence Operator. -Images using Cloud Native Buildpacks contain a special launcher executable the runs the Java application. This makes it more complex than normal for the Operator to provide a custom Java command. For images built using Cloud Native Buildpacks to work the `Coherence` resource must be configured to execute the images entry point instead of the Operator injecting a command line. +Images using Cloud Native Buildpacks contain a special launcher executable the runs the Java application. This makes it more complex than normal for the Operator to provide a custom Java command. +For images built using Cloud Native Buildpacks to work the `Coherence` resource must be configured to execute the images entry point instead of the Operator injecting a command line. -[WARNING] +[IMPORTANT] ==== Due to the way that the Coherence Operator configures JVM arguments when configured to use an image entry point, the image must be running @@ -190,10 +191,6 @@ Instead of building a custom command line, the Operator uses the `JDK_JAVA_OPTIO configured JVM options and system properties to the Spring application. This is a standard environment variable that the JVM will effectively use to pre-pend JVM arguments to its command line. -Due to limitation on the way that arguments can be passed to the JVM when using Buildpacks images the Coherence -operator will only work with images containing a JVM greater than Java 11. - - When creating a `Coherence` deployment for a Spring Boot Buildpacks image The application type must be set to `spring`. The Operator's launcher will automatically detect that the image is a Buildpacks image and launch the application using the Buildpacks launcher. @@ -208,68 +205,18 @@ spec: image: catalogue:1.0.0 application: type: spring # <1> - useImageEntryPoint: true <2> + useImageEntryPoint: true # <2> ---- <1> The application type has been set to `spring` (for Spring Boot 2.x) or `spring3` (for Spring Boot 3.x) so that the operator knows that this is a Spring Boot application, and the fact that the image is a Buildpacks image will be auto-discovered. -<2> The Operator will run the image's entry point - - -==== Buildpacks Detection - -If for some reason buildpacks auto-detection does not work properly the `Coherence` -CRD contains a filed to force buildpacks to be enabled or disabled. - -The `boolean` field `spec.application.cloudNativeBuildPack.enabled` can be set to `true` to enable buildpacks or false -to disable buildpack. - -[source,yaml] ----- -apiVersion: coherence.oracle.com/v1 -kind: Coherence -metadata: - name: test -spec: - image: catalogue:1.0.0 - application: - type: spring # <1> - cloudNativeBuildPack: - enabled: true # <2> ----- - -<1> The application type has been set to `spring` so that the operator knows that this is a Spring Boot application -<2> The `cloudNativeBuildPack.enabled` field has been set to `true` to force the Operator to use the Buildpacks launcher. - -==== Specify the Buildpacks Launcher - -A Cloud Native Buildpacks image uses a launcher mechanism to run the executable(s) in the image. The Coherence Operator -launcher will configure the application and then invoke the same buildpacks launcher. -The Coherence Operator assumes that the buildpacks launcher is in the image in the location `/cnb/lifecycle/launcher`. -If a buildpacks image has been built with the launcher in a different location then the `Coherence` CRD contains -a field to set the new location. - -The `spec.application.cloudNativeBuildPack.enabled` field. - -[source,yaml] ----- -apiVersion: coherence.oracle.com/v1 -kind: Coherence -metadata: - name: test -spec: - image: catalogue:1.0.0 - application: - type: spring # <1> - cloudNativeBuildPack: - launcher: /buildpack/launcher # <2> ----- - -<1> The application type has been set to `spring` so that the operator knows that this is a Spring Boot application -<2> The buildpacks launcher that the Operator will invoke is located at `/buildpack/launcher`. +<2> The Operator will run the image's entry point and set the `JDK_JAVA_OPTIONS` environment variable +to pass arguments to the JVM +For more information on using image entry points with the Coherence operator see the +<> documentation. -==== Buildpack JVM Arguments +==== Buildpacks JVM Arguments A typical Spring Boot buildpack launcher will attempt to configure options such as heap size based on the container resource limits configured, so this must be taken into account if using any of the memory options available in the diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go index de1e84529..159a02b60 100644 --- a/pkg/runner/cmd_config.go +++ b/pkg/runner/cmd_config.go @@ -70,33 +70,73 @@ func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, erro return false, errors.Wrap(err, "failed to configure server command") } + fileMap := make(map[string]string) if cp, err = createClassPathFile(details); err != nil { return false, err } + fileMap[v1.OperatorClasspathFile] = cp if args, err = createArgsFile(details); err != nil { return false, err } + fileMap[v1.OperatorJvmArgsFile] = args if main, err = createMainClassFile(details); err != nil { return false, err } + fileMap[v1.OperatorMainClassFile] = main if sb, err = createSpringBootFile(details); err != nil { return false, err } + fileMap[v1.OperatorSpringBootArgsFile] = sb if err = createCliConfig(details); err != nil { return false, err } + if err = createOperatorCoherenceArgsFile(details, fileMap); err != nil { + return false, err + } + if err = createOperatorEntryPointArgsFile(details, fileMap); err != nil { + return false, err + } + + return false, nil +} + +// createOperatorCoherenceArgsFile will create the full arguments file for the Coherence container. +// This file will contain the class path, all the JVM options, the main class and any main method arguments. +func createOperatorCoherenceArgsFile(details *run_details.RunDetails, files map[string]string) error { + return createFullArgsFile(details, files, v1.OperatorCoherenceArgsFile, true) +} + +// createOperatorCoherenceArgsFile will create the full arguments file for the Coherence container +// This file will contain the class path, all the JVM options, but not the main class or any main method arguments. +func createOperatorEntryPointArgsFile(details *run_details.RunDetails, files map[string]string) error { + return createFullArgsFile(details, files, v1.OperatorEntryPointArgsFile, false) +} + +// createOperatorCoherenceArgsFile will create the full arguments file of a specified name, +// optionally including the main class name and any main args +func createFullArgsFile(details *run_details.RunDetails, files map[string]string, fileName string, includeMain bool) error { var buffer bytes.Buffer buffer.WriteString("--class-path") - buffer.WriteString("\n") - buffer.WriteString(cp) - buffer.WriteString("\n") - buffer.WriteString(args) - buffer.WriteString("\n") + if cp, ok := files[v1.OperatorClasspathFile]; ok { + buffer.WriteString("\n") + buffer.WriteString(cp) + } + if args, ok := files[v1.OperatorJvmArgsFile]; ok { + buffer.WriteString("\n") + buffer.WriteString(args) + } + if details.IsSpringBoot() { - buffer.WriteString(sb) + if sb, ok := files[v1.OperatorSpringBootArgsFile]; ok { + buffer.WriteString("\n") + buffer.WriteString(sb) + } + } + + if includeMain { + main := files[v1.OperatorMainClassFile] buffer.WriteString("\n") - } else { buffer.WriteString(main) if len(details.MainArgs) > 0 { for _, arg := range details.MainArgs { @@ -106,17 +146,15 @@ func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, erro } } - argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorCoherenceArgsFile) - err = os.WriteFile(argsFile, buffer.Bytes(), os.ModePerm) - if err != nil { - return false, errors.Wrap(err, "failed to write coherence container args file") + path := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, fileName) + if err := os.WriteFile(path, buffer.Bytes(), os.ModePerm); err != nil { + return errors.Wrap(err, "failed to write coherence container args file") } - configLog.Info("Created Coherence container args file", "FileName", argsFile, "Args", buffer.String()) - - return false, nil + configLog.Info("Created args file", "FileName", path, "Args", buffer.String()) + return nil } -// createClassPathFile will create the class path files for a Coherence Pod - typically this is run from an init-container +// createClassPathFile will create the class path files for a Coherence Pod func createClassPathFile(details *run_details.RunDetails) (string, error) { var classpath string var err error From 2b606eb4fadf13e6dbf72b024da7a4bc87742f57 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 16 Mar 2025 11:59:47 +0300 Subject: [PATCH 32/33] fix entry point args file name --- api/v1/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/constants.go b/api/v1/constants.go index b22bbc6bb..462be4d59 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -180,7 +180,7 @@ const ( OperatorCoherenceArgsFile = "coherence-container-args.txt" // OperatorEntryPointArgsFile is the arguments file to add to the JDK_JAVA_OPTIONS environment variable // when running the image entry point - OperatorEntryPointArgsFile = "coherence-container-args.txt" + OperatorEntryPointArgsFile = "coherence-entrypoint-args.txt" // OperatorJvmArgsFile is the name of the file in the utils directory containing the JVM arguments OperatorJvmArgsFile = "coherence-jvm-args.txt" // OperatorClasspathFile is the name of the file in the utils directory containing the JVM class path From 264ecc9ff0755211e2c3463736c4344595b63a7d Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sun, 16 Mar 2025 17:21:22 +0300 Subject: [PATCH 33/33] fix tests --- api/v1/create_job_applicationspec_test.go | 18 +++++++++--------- .../create_statefulset_applicationspec_test.go | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index d77d7969c..7d346c64e 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -123,7 +123,7 @@ func TestCreateJobUseImageEntryPoint(t *testing.T) { jobExpected.Spec.Template.Spec.Containers[0].Command = nil jobExpected.Spec.Template.Spec.Containers[0].Args = nil jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -168,7 +168,7 @@ func TestCreateJobUseImageEntryPointWithExistingJdkOpts(t *testing.T) { jobExpected.Spec.Template.Spec.Containers[0].Command = nil jobExpected.Spec.Template.Spec.Containers[0].Args = nil jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-entrypoint-args.txt"}) jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, @@ -210,12 +210,12 @@ func TestCreateJobUseImageEntryPointWithAltJavaOptEnvVar(t *testing.T) { jobExpected.Spec.Template.Spec.Containers[0].Command = nil jobExpected.Spec.Template.Spec.Containers[0].Args = nil jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -237,11 +237,11 @@ func TestCreateJobUseImageEntryPointAndUseJdkOptsFalseWithAltJavaOptEnvVar(t *te jobExpected.Spec.Template.Spec.Containers[0].Command = nil jobExpected.Spec.Template.Spec.Containers[0].Args = nil jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index 1c2249922..30f02995d 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -123,7 +123,7 @@ func TestCreateStatefulSetUseImageEntryPoint(t *testing.T) { stsExpected.Spec.Template.Spec.Containers[0].Command = nil stsExpected.Spec.Template.Spec.Containers[0].Args = nil stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -168,7 +168,7 @@ func TestCreateStatefulSetUseImageEntryPointWithExistingJdkOpts(t *testing.T) { stsExpected.Spec.Template.Spec.Containers[0].Command = nil stsExpected.Spec.Template.Spec.Containers[0].Args = nil stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-entrypoint-args.txt"}) stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, @@ -210,12 +210,12 @@ func TestCreateStatefulSetUseImageEntryPointWithAltJavaOptEnvVar(t *testing.T) { stsExpected.Spec.Template.Spec.Containers[0].Command = nil stsExpected.Spec.Template.Spec.Containers[0].Args = nil stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-container-args.txt"}, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -237,11 +237,11 @@ func TestCreateStatefulSetUseImageEntryPointAndUseJdkOptsFalseWithAltJavaOptEnvV stsExpected.Spec.Template.Spec.Containers[0].Command = nil stsExpected.Spec.Template.Spec.Containers[0].Args = nil stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, - corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-container-args.txt"}) + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected)