diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go index 9499eef0d9..e78bd9f50d 100644 --- a/pkg/trait/jolokia.go +++ b/pkg/trait/jolokia.go @@ -127,6 +127,7 @@ func (t *jolokiaTrait) Apply(e *Environment) error { } } container.Args = append(container.Args, "-javaagent:"+jolokiaFilepath+"="+strings.Join(optionValues, ",")) + container.Args = append(container.Args, "-cp", jolokiaFilepath) containerPort := corev1.ContainerPort{ Name: "jolokia", diff --git a/pkg/trait/jolokia_test.go b/pkg/trait/jolokia_test.go index c5c685cc59..6668f38507 100644 --- a/pkg/trait/jolokia_test.go +++ b/pkg/trait/jolokia_test.go @@ -55,6 +55,7 @@ func TestApplyJolokiaTraitNominalShouldSucceed(t *testing.T) { assert.Equal(t, container.Args, []string{ "-javaagent:dependencies/lib/main/org.jolokia.jolokia-agent-jvm-1.7.1.jar=discoveryEnabled=false,host=*,port=8778", + "-cp", "dependencies/lib/main/org.jolokia.jolokia-agent-jvm-1.7.1.jar", }) assert.Len(t, container.Ports, 1) @@ -85,6 +86,7 @@ func TestApplyJolokiaTraitForOpenShiftProfileShouldSucceed(t *testing.T) { "clientPrincipal.1=cn=system:master-proxy,clientPrincipal.2=cn=hawtio-online.hawtio.svc," + "clientPrincipal.3=cn=fuse-console.fuse.svc,discoveryEnabled=false,extendedClientCheck=true," + "host=*,port=8778,protocol=https,useSslClientAuthentication=true", + "-cp", "dependencies/lib/main/org.jolokia.jolokia-agent-jvm-1.7.1.jar", }) assert.Len(t, container.Ports, 1) @@ -134,6 +136,7 @@ func TestApplyJolokiaTraitWithOptionShouldOverrideDefault(t *testing.T) { "-javaagent:dependencies/lib/main/org.jolokia.jolokia-agent-jvm-1.7.1.jar=caCert=.cacert,clientPrincipal=cn:any," + "discoveryEnabled=true,extendedClientCheck=false,host=explicit-host,port=8778,protocol=http," + "useSslClientAuthentication=false", + "-cp", "dependencies/lib/main/org.jolokia.jolokia-agent-jvm-1.7.1.jar", }) } diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go index 7ca44edd49..2a352f52b6 100644 --- a/pkg/trait/jvm.go +++ b/pkg/trait/jvm.go @@ -204,6 +204,7 @@ func (t *jvmTrait) enableDebug(e *Environment) string { } func (t *jvmTrait) prepareClasspathItems(container *corev1.Container) []string { + existingClasspaths := extractExistingClasspathItems(container) classpath := sets.NewSet() // Deprecated: replaced by /etc/camel/resources.d/[_configmaps/_secrets] (camel.ResourcesConfigmapsMountPath/camel.ResourcesSecretsMountPath). classpath.Add("./resources") @@ -223,9 +224,28 @@ func (t *jvmTrait) prepareClasspathItems(container *corev1.Container) []string { // Keep class path sorted so that it's consistent over reconciliation cycles sort.Strings(items) + if existingClasspaths != nil { + existingClasspaths = append(existingClasspaths, items...) + return existingClasspaths + } + return items } +// extractExistingClasspathItems returns any container classpath option (if exists). +func extractExistingClasspathItems(container *corev1.Container) []string { + for i, arg := range container.Args { + if arg == "-cp" || arg == "-classpath" { + if i < len(container.Args) { + // return the next argument + return strings.Split(container.Args[i+1], ":") + } + } + } + + return nil +} + // Translate HTTP proxy environment variables, that are set by the environment trait, // into corresponding JVM system properties. func (t *jvmTrait) prepareHTTPProxy(container *corev1.Container) ([]string, error) { diff --git a/pkg/trait/jvm_test.go b/pkg/trait/jvm_test.go index 13041de494..fefefffd2c 100644 --- a/pkg/trait/jvm_test.go +++ b/pkg/trait/jvm_test.go @@ -449,6 +449,49 @@ func TestApplyJvmTraitWithClasspath(t *testing.T) { "io.quarkus.bootstrap.runner.QuarkusEntryPoint", }, d.Spec.Template.Spec.Containers[0].Args) } + +func TestApplyJvmTraitWithClasspathAndExistingContainerCPArg(t *testing.T) { + trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform) + trait.Classpath = "/path/to/my-dep.jar:/path/to/another/dep.jar" + d := appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: defaultContainerName, + Args: []string{ + "-cp", + "my-precious-lib.jar", + }, + }, + }, + }, + }, + }, + } + + environment.Resources.Add(&d) + configure, condition, err := trait.Configure(environment) + require.NoError(t, err) + assert.True(t, configure) + assert.Nil(t, condition) + err = trait.Apply(environment) + + require.NoError(t, err) + assert.Equal(t, []string{ + // WARN: we don't care if there are multiple classpath arguments + // as the application will use the second one + "-cp", + "my-precious-lib.jar", + "-cp", + fmt.Sprintf("my-precious-lib.jar:./resources:%s:%s:%s:%s:%s:dependencies/*", + rdMountPath, cmrMountPath, scrMountPath, + "/path/to/another/dep.jar", "/path/to/my-dep.jar"), + "io.quarkus.bootstrap.runner.QuarkusEntryPoint", + }, d.Spec.Template.Spec.Containers[0].Args) +} + func TestApplyJvmTraitKitMissing(t *testing.T) { trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform) environment.IntegrationKit = nil