Skip to content

Commit

Permalink
chore(trait): Use container args to configure Jolokia agent
Browse files Browse the repository at this point in the history
  • Loading branch information
astefanutti committed Jan 22, 2020
1 parent 2836a5e commit cc67814
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 124 deletions.
71 changes: 29 additions & 42 deletions pkg/trait/jolokia.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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
}
Expand All @@ -139,23 +113,36 @@ 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)
if err != nil {
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)
Expand All @@ -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",
Expand Down
118 changes: 36 additions & 82 deletions pkg/trait/jolokia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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 := ""
Expand Down

0 comments on commit cc67814

Please sign in to comment.