diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go index 4f1ef04f84..e08eca03d0 100644 --- a/pkg/trait/jolokia.go +++ b/pkg/trait/jolokia.go @@ -26,7 +26,6 @@ import ( v1 "github.com/apache/camel-k/pkg/apis/camel/v1" "github.com/apache/camel-k/pkg/util" - "github.com/apache/camel-k/pkg/util/envvar" ) // The Jolokia trait activates and configures the Jolokia Java agent. @@ -84,35 +83,7 @@ func (t *jolokiaTrait) isEnabled() bool { } func (t *jolokiaTrait) Configure(e *Environment) (bool, error) { - options, err := parseCsvMap(t.Options) - if err != nil { - return false, err - } - - if len(t.ClientPrincipal) == 1 { - // Work-around the lack of proper support for multi-valued trait options from the CLI - t.ClientPrincipal = strings.Split(t.ClientPrincipal[0], ",") - } - - setDefaultJolokiaOption(options, &t.Host, "host", "*") - setDefaultJolokiaOption(options, &t.DiscoveryEnabled, "discoveryEnabled", false) - - // Configure HTTPS by default for OpenShift - if e.DetermineProfile() == v1.TraitProfileOpenShift { - setDefaultJolokiaOption(options, &t.Protocol, "protocol", "https") - setDefaultJolokiaOption(options, &t.CaCert, "caCert", "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt") - setDefaultJolokiaOption(options, &t.ExtendedClientCheck, "extendedClientCheck", true) - setDefaultJolokiaOption(options, &t.UseSslClientAuthentication, "useSslClientAuthentication", true) - setDefaultJolokiaOption(options, &t.ClientPrincipal, "clientPrincipal", []string{ - // Master API proxy for OpenShift 3 - "cn=system:master-proxy", - // Default Hawtio and Fuse consoles for OpenShift 4 - "cn=hawtio-online.hawtio.svc", - "cn=fuse-console.fuse.svc", - }) - } - - return e.IntegrationInPhase( + return t.isEnabled() && e.IntegrationInPhase( v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning, @@ -124,6 +95,9 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) { if t.isEnabled() { // Add Camel management dependency util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, "mvn:org.apache.camel/camel-management") + // And Jolokia agent + // TODO: We may want to make the Jolokia version configurable + util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, "mvn:org.jolokia/jolokia-jvm:jar:agent:1.6.2") } return nil } @@ -139,16 +113,6 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) { return nil } - if !t.isEnabled() { - // Deactivate the Jolokia Java agent - // Note: the AB_JOLOKIA_OFF environment variable acts as an option flag - envvar.SetVal(&container.Env, "AB_JOLOKIA_OFF", "true") - return nil - } - - // Need to set it explicitly as it default to true - envvar.SetVal(&container.Env, "AB_JOLOKIA_AUTH_OPENSHIFT", "false") - // Configure the Jolokia Java agent // Populate first with the extra options options, err := parseCsvMap(t.Options) @@ -156,6 +120,29 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) { return err } + if len(t.ClientPrincipal) == 1 { + // Work-around the lack of proper support for multi-valued trait options from the CLI + t.ClientPrincipal = strings.Split(t.ClientPrincipal[0], ",") + } + + setDefaultJolokiaOption(options, &t.Host, "host", "*") + setDefaultJolokiaOption(options, &t.DiscoveryEnabled, "discoveryEnabled", false) + + // Configure HTTPS by default for OpenShift + if e.DetermineProfile() == v1.TraitProfileOpenShift { + setDefaultJolokiaOption(options, &t.Protocol, "protocol", "https") + setDefaultJolokiaOption(options, &t.CaCert, "caCert", "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt") + setDefaultJolokiaOption(options, &t.ExtendedClientCheck, "extendedClientCheck", true) + setDefaultJolokiaOption(options, &t.UseSslClientAuthentication, "useSslClientAuthentication", true) + setDefaultJolokiaOption(options, &t.ClientPrincipal, "clientPrincipal", []string{ + // Master API proxy for OpenShift 3 + "cn=system:master-proxy", + // Default Hawtio and Fuse consoles for OpenShift 4 + "cn=hawtio-online.hawtio.svc", + "cn=fuse-console.fuse.svc", + }) + } + // Then add explicitly set trait configuration properties addToJolokiaOptions(options, "caCert", t.CaCert) addToJolokiaOptions(options, "clientPrincipal", t.ClientPrincipal) @@ -168,14 +155,14 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) { addToJolokiaOptions(options, "user", t.User) addToJolokiaOptions(options, "useSslClientAuthentication", t.UseSslClientAuthentication) - // Lastly set the AB_JOLOKIA_OPTS environment variable from the fabric8/s2i-java base image // Options must be sorted so that the environment variable value is consistent over iterations, // otherwise the value changes which results in triggering a new deployment. optionValues := make([]string, len(options)) for i, k := range util.SortedStringMapKeys(options) { optionValues[i] = k + "=" + options[k] } - envvar.SetVal(&container.Env, "AB_JOLOKIA_OPTS", strings.Join(optionValues, ",")) + + container.Args = append(container.Args, "-javaagent:dependencies/org.jolokia.jolokia-jvm-1.6.2-agent.jar="+strings.Join(optionValues, ",")) containerPort := corev1.ContainerPort{ Name: "jolokia", diff --git a/pkg/trait/jolokia_test.go b/pkg/trait/jolokia_test.go index bbaf4e4644..63e0fe822a 100644 --- a/pkg/trait/jolokia_test.go +++ b/pkg/trait/jolokia_test.go @@ -21,105 +21,69 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" v1 "github.com/apache/camel-k/pkg/apis/camel/v1" - "github.com/apache/camel-k/pkg/util/envvar" "github.com/apache/camel-k/pkg/util/kubernetes" - "github.com/apache/camel-k/pkg/util/test" - - "github.com/stretchr/testify/assert" ) -func TestConfigureJolokiaTraitInRightPhaseDoesSucceed(t *testing.T) { +func TestConfigureJolokiaTraitInRunningPhaseDoesSucceed(t *testing.T) { trait, environment := createNominalJolokiaTest() + environment.Integration.Status.Phase = v1.IntegrationPhaseRunning configured, err := trait.Configure(environment) assert.Nil(t, err) assert.True(t, configured) - assert.Equal(t, *trait.Host, "*") - assert.Equal(t, *trait.DiscoveryEnabled, false) - assert.Nil(t, trait.Protocol) - assert.Nil(t, trait.CaCert) - assert.Nil(t, trait.ExtendedClientCheck) - assert.Nil(t, trait.ClientPrincipal) - assert.Nil(t, trait.UseSslClientAuthentication) } -func TestConfigureJolokiaTraitInWrongPhaseDoesNotSucceed(t *testing.T) { +func TestApplyJolokiaTraitNominalShouldSucceed(t *testing.T) { trait, environment := createNominalJolokiaTest() - environment.Integration.Status.Phase = v1.IntegrationPhaseRunning - configured, err := trait.Configure(environment) + err := trait.Apply(environment) assert.Nil(t, err) - assert.True(t, configured) -} - -func TestConfigureJolokiaTraitWithUnparseableOptionsDoesNotSucceed(t *testing.T) { - trait, environment := createNominalJolokiaTest() - options := "unparseable csv" - trait.Options = &options - configured, err := trait.Configure(environment) - assert.NotNil(t, err) - assert.False(t, configured) -} + container := environment.Resources.GetContainerByName(defaultContainerName) + assert.NotNil(t, container) -func TestConfigureJolokiaTraitForOpenShiftProfileShouldSetDefaultHttpsJolokiaOptions(t *testing.T) { - trait, environment := createNominalJolokiaTest() - environment.IntegrationKit.Spec.Profile = v1.TraitProfileOpenShift + assert.Equal(t, container.Args, []string{ + "-javaagent:dependencies/org.jolokia.jolokia-jvm-1.6.2-agent.jar=discoveryEnabled=false,host=*,port=8778", + }) - configured, err := trait.Configure(environment) + assert.Len(t, container.Ports, 1) + containerPort := container.Ports[0] + assert.Equal(t, "jolokia", containerPort.Name) + assert.Equal(t, int32(8778), containerPort.ContainerPort) + assert.Equal(t, corev1.ProtocolTCP, containerPort.Protocol) - assert.Nil(t, err) - assert.True(t, configured) - assert.Equal(t, *trait.Protocol, "https") - assert.Equal(t, *trait.CaCert, "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt") - assert.Equal(t, *trait.ExtendedClientCheck, true) - assert.Equal(t, *trait.UseSslClientAuthentication, true) + assert.Len(t, environment.Integration.Status.Conditions, 1) + condition := environment.Integration.Status.Conditions[0] + assert.Equal(t, v1.IntegrationConditionJolokiaAvailable, condition.Type) + assert.Equal(t, corev1.ConditionTrue, condition.Status) } -func TestConfigureJolokiaTraitWithOptionsShouldPreventDefaultJolokiaOptions(t *testing.T) { +func TestApplyJolokiaTraitForOpenShiftProfileShouldSucceed(t *testing.T) { trait, environment := createNominalJolokiaTest() environment.IntegrationKit.Spec.Profile = v1.TraitProfileOpenShift - options := "host=explicit-host," + - "discoveryEnabled=true," + - "protocol=http," + - "caCert=.cacert," + - "extendedClientCheck=false," + - "clientPrincipal=cn:any," + - "useSslClientAuthentication=false" - trait.Options = &options - configured, err := trait.Configure(environment) + err := trait.Apply(environment) assert.Nil(t, err) - assert.True(t, configured) - assert.Nil(t, trait.Host) - assert.Nil(t, trait.DiscoveryEnabled) - assert.Nil(t, trait.Protocol) - assert.Nil(t, trait.CaCert) - assert.Nil(t, trait.ExtendedClientCheck) - assert.Nil(t, trait.ClientPrincipal) - assert.Nil(t, trait.UseSslClientAuthentication) -} - -func TestApplyJolokiaTraitNominalShouldSucceed(t *testing.T) { - trait, environment := createNominalJolokiaTest() - - err := trait.Apply(environment) container := environment.Resources.GetContainerByName(defaultContainerName) + assert.NotNil(t, container) - assert.Nil(t, err) - test.EnvVarHasValue(t, container.Env, "AB_JOLOKIA_AUTH_OPENSHIFT", "false") - test.EnvVarHasValue(t, container.Env, "AB_JOLOKIA_OPTS", "port=8778") - assert.Len(t, environment.Integration.Status.Conditions, 1) + assert.Equal(t, container.Args, []string{ + "-javaagent:dependencies/org.jolokia.jolokia-jvm-1.6.2-agent.jar=caCert=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt," + + "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", + }) - assert.NotNil(t, container) assert.Len(t, container.Ports, 1) containerPort := container.Ports[0] assert.Equal(t, "jolokia", containerPort.Name) @@ -158,13 +122,15 @@ func TestApplyJolokiaTraitWithOptionShouldOverrideDefault(t *testing.T) { err := trait.Apply(environment) + assert.Nil(t, err) + container := environment.Resources.GetContainerByName(defaultContainerName) - assert.Nil(t, err) - ev := envvar.Get(container.Env, "AB_JOLOKIA_OPTS") - assert.NotNil(t, ev) - assert.Contains(t, ev.Value, "port=8778", "host=explicit-host", "discoveryEnabled=true", "protocol=http", "caCert=.cacert") - assert.Contains(t, ev.Value, "extendedClientCheck=false", "clientPrincipal=cn:any", "useSslClientAuthentication=false") + assert.Equal(t, container.Args, []string{ + "-javaagent:dependencies/org.jolokia.jolokia-jvm-1.6.2-agent.jar=caCert=.cacert,clientPrincipal=cn:any," + + "discoveryEnabled=true,extendedClientCheck=false,host=explicit-host,port=8778,protocol=http," + + "useSslClientAuthentication=false", + }) } func TestApplyJolokiaTraitWithUnparseableOptionShouldReturnError(t *testing.T) { @@ -177,18 +143,6 @@ func TestApplyJolokiaTraitWithUnparseableOptionShouldReturnError(t *testing.T) { assert.NotNil(t, err) } -func TestApplyDisabledJolokiaTraitShouldNotSucceed(t *testing.T) { - trait, environment := createNominalJolokiaTest() - trait.Enabled = new(bool) - - err := trait.Apply(environment) - - container := environment.Resources.GetContainerByName(defaultContainerName) - - assert.Nil(t, err) - test.EnvVarHasValue(t, container.Env, "AB_JOLOKIA_OFF", "true") -} - func TestSetDefaultJolokiaOptionShoudlNotOverrideOptionsMap(t *testing.T) { options := map[string]string{"key": "value"} optionValue := ""