Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jolokia trait configuration maps JVM agent options directly #400

Merged
merged 1 commit into from
Jan 30, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 121 additions & 28 deletions pkg/trait/jolokia.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,34 @@ package trait

import (
"errors"
"fmt"
"strconv"
"strings"

"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/apache/camel-k/pkg/util/envvar"
corev1 "k8s.io/api/core/v1"

"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
)

type jolokiaTrait struct {
BaseTrait `property:",squash"`

OpenShiftSSLAuth *bool `property:"openshift-ssl-auth"`
Options *string `property:"options"`
Port int `property:"port"`
RandomPassword *bool `property:"random-password"`
// Jolokia JVM agent configuration
// See https://jolokia.org/reference/html/agents.html
CaCert *string `property:"ca-cert"`
ClientPrincipal *string `property:"client-principal"`
DiscoveryEnabled *bool `property:"discovery-enabled"`
ExtendedClientCheck *bool `property:"extended-client-check"`
Host *string `property:"host"`
Password *string `property:"password"`
Port int `property:"port"`
Protocol *string `property:"protocol"`
User *string `property:"user"`
UseSslClientAuthentication *bool `property:"use-ssl-client-authentication"`

// Extra configuration options
Options *string `property:"options"`
}

// The Jolokia trait must be executed prior to the deployment trait
Expand All @@ -49,10 +61,25 @@ func newJolokiaTrait() *jolokiaTrait {
}

func (t *jolokiaTrait) Configure(e *Environment) (bool, error) {
options, err := parseJolokiaOptions(t.Options)
if err != nil {
return false, err
}

setDefaultJolokiaOption(options, &t.Host, "host", "*")
setDefaultJolokiaOption(options, &t.DiscoveryEnabled, "discoveryEnabled", false)

// Configure HTTPS by default for OpenShift
if e.DetermineProfile() == v1alpha1.TraitProfileOpenShift {
setDefaultJolokiaOption(options, &t.Protocol, "protocol", "https")
setDefaultJolokiaOption(options, &t.CaCert, "caCert", "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
setDefaultJolokiaOption(options, &t.ExtendedClientCheck, "extendedClientCheck", true)
setDefaultJolokiaOption(options, &t.UseSslClientAuthentication, "useSslClientAuthentication", true)
}

return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
}

// Configure the Jolokia Java agent
func (t *jolokiaTrait) Apply(e *Environment) (err error) {
if t.Enabled == nil || !*t.Enabled {
// Deactivate the Jolokia Java agent
Expand All @@ -61,29 +88,34 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) {
return nil
}

// OpenShift proxy SSL client authentication
if e.DetermineProfile() == v1alpha1.TraitProfileOpenShift {
if t.OpenShiftSSLAuth != nil && !*t.OpenShiftSSLAuth {
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_AUTH_OPENSHIFT", "false")
} else {
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_AUTH_OPENSHIFT", "true")
}
} else {
if t.OpenShiftSSLAuth != nil {
logrus.Warn("Jolokia trait property [openshiftSSLAuth] is only applicable for the OpenShift profile!")
}
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_AUTH_OPENSHIFT", "false")
}
// Jolokia options
if t.Options != nil {
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_OPTS", *t.Options)
// Need to set it explicitely as it default to true
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_AUTH_OPENSHIFT", "false")

// Configure the Jolokia Java agent
// Populate first with the extra options
options, err := parseJolokiaOptions(t.Options)
if err != nil {
return err
}
// Agent port
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_PORT", strconv.Itoa(t.Port))
// Random password
if t.RandomPassword != nil {
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_PASSWORD_RANDOM", strconv.FormatBool(*t.RandomPassword))

// Then add explicitely set trait configuration properties
addToJolokiaOptions(options, "caCert", t.CaCert)
addToJolokiaOptions(options, "clientPrincipal", t.ClientPrincipal)
addToJolokiaOptions(options, "discoveryEnabled", t.DiscoveryEnabled)
addToJolokiaOptions(options, "extendedClientCheck", t.ExtendedClientCheck)
addToJolokiaOptions(options, "host", t.Host)
addToJolokiaOptions(options, "password", t.Password)
addToJolokiaOptions(options, "port", t.Port)
addToJolokiaOptions(options, "protocol", t.Protocol)
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
optionValues := make([]string, 0, len(options))
for k, v := range options {
optionValues = append(optionValues, k+"="+v)
}
envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_OPTS", strings.Join(optionValues, ","))

// Register a post processor to add a container port to the integration deployment
e.PostProcessors = append(e.PostProcessors, func(environment *Environment) error {
Expand All @@ -107,3 +139,64 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) {

return nil
}

func setDefaultJolokiaOption(options map[string]string, option interface{}, key string, value interface{}) {
// Do not override existing option
if _, ok := options[key]; ok {
return
}
switch option.(type) {
case **bool:
if o := option.(**bool); *o == nil {
v := value.(bool)
*o = &v
}
case **int:
if o := option.(**int); *o == nil {
v := value.(int)
*o = &v
}
case **string:
if o := option.(**string); *o == nil {
v := value.(string)
*o = &v
}
}
}

func addToJolokiaOptions(options map[string]string, key string, value interface{}) {
switch value.(type) {
case *bool:
if v := value.(*bool); v != nil {
options[key] = strconv.FormatBool(*v)
}
case *int:
if v := value.(*int); v != nil {
options[key] = strconv.Itoa(*v)
}
case int:
options[key] = strconv.Itoa(value.(int))
case *string:
if v := value.(*string); v != nil {
options[key] = *v
}
}
}

func parseJolokiaOptions(options *string) (map[string]string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very similar to

func parseLabels(labels string) (map[string]string, error) {
, we may consolidate it as trait/kubernetes helper function

m := make(map[string]string)

if options == nil || len(*options) == 0 {
return m, nil
}

for _, option := range strings.Split(*options, ",") {
kv := strings.Split(option, "=")
if len(kv) != 2 {
return nil, fmt.Errorf("invalid option [%s] in options [%s]", option, *options)
}
m[kv[0]] = kv[1]
}

return m, nil
}