in pkg/trait/jvm.go [78:253]
func (t *jvmTrait) Apply(e *Environment) error {
kit := e.IntegrationKit
if kit == nil && e.Integration.Status.IntegrationKit != nil {
name := e.Integration.Status.IntegrationKit.Name
ns := e.Integration.GetIntegrationKitNamespace(e.Platform)
k := v1.NewIntegrationKit(ns, name)
if err := t.Client.Get(e.Ctx, ctrl.ObjectKeyFromObject(k), k); err != nil {
return fmt.Errorf("unable to find integration kit %s/%s: %w", ns, name, err)
}
kit = k
}
if kit == nil {
if e.Integration.Status.IntegrationKit != nil {
return fmt.Errorf("unable to find integration kit %s/%s", e.Integration.GetIntegrationKitNamespace(e.Platform), e.Integration.Status.IntegrationKit.Name)
}
return fmt.Errorf("unable to find integration kit for integration %s", e.Integration.Name)
}
classpath := sets.NewSet()
classpath.Add("./resources")
classpath.Add(filepath.ToSlash(camel.ConfigResourcesMountPath))
classpath.Add(filepath.ToSlash(camel.ResourcesDefaultMountPath))
if t.Classpath != "" {
classpath.Add(strings.Split(t.Classpath, ":")...)
}
for _, artifact := range kit.Status.Artifacts {
classpath.Add(artifact.Target)
}
if kit.Labels[v1.IntegrationKitTypeLabel] == v1.IntegrationKitTypeExternal {
// In case of an external created kit, we do not have any information about
// the classpath, so we assume the all jars in /deployments/dependencies/ have
// to be taken into account.
dependencies := filepath.Join(builder.DeploymentDir, builder.DependenciesDir)
classpath.Add(
dependencies+"/*",
dependencies+"/app/*",
dependencies+"/lib/boot/*",
dependencies+"/lib/main/*",
dependencies+"/quarkus/*",
)
}
container := e.GetIntegrationContainer()
if container == nil {
return fmt.Errorf("unable to find integration container")
}
// Build the container command
// Other traits may have already contributed some arguments
args := container.Args
// Remote debugging
if pointer.BoolDeref(t.Debug, false) {
suspend := "n"
if pointer.BoolDeref(t.DebugSuspend, false) {
suspend = "y"
}
args = append(args,
fmt.Sprintf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=%s,address=%s",
suspend, t.DebugAddress))
// Add label to mark the pods with debug enabled
e.Resources.VisitPodTemplateMeta(func(meta *metav1.ObjectMeta) {
if meta.Labels == nil {
meta.Labels = make(map[string]string)
}
meta.Labels["camel.apache.org/debug"] = "true"
})
}
hasHeapSizeOption := false
// Add JVM options
if len(t.Options) > 0 {
hasHeapSizeOption = util.StringSliceContainsAnyOf(t.Options, "-Xmx", "-XX:MaxHeapSize", "-XX:MinRAMPercentage", "-XX:MaxRAMPercentage")
args = append(args, t.Options...)
}
// Translate HTTP proxy environment variables, that are set by the environment trait,
// into corresponding JVM system properties.
if HTTPProxy := envvar.Get(container.Env, "HTTP_PROXY"); HTTPProxy != nil {
u, err := url.Parse(HTTPProxy.Value)
if err != nil {
return err
}
if !util.StringSliceContainsAnyOf(t.Options, "http.proxyHost") {
args = append(args, fmt.Sprintf("-Dhttp.proxyHost=%q", u.Hostname()))
}
if port := u.Port(); !util.StringSliceContainsAnyOf(t.Options, "http.proxyPort") && port != "" {
args = append(args, fmt.Sprintf("-Dhttp.proxyPort=%q", u.Port()))
}
if user := u.User; !util.StringSliceContainsAnyOf(t.Options, "http.proxyUser") && user != nil {
args = append(args, fmt.Sprintf("-Dhttp.proxyUser=%q", user.Username()))
if password, ok := user.Password(); !util.StringSliceContainsAnyOf(t.Options, "http.proxyUser") && ok {
args = append(args, fmt.Sprintf("-Dhttp.proxyPassword=%q", password))
}
}
}
if HTTPSProxy := envvar.Get(container.Env, "HTTPS_PROXY"); HTTPSProxy != nil {
u, err := url.Parse(HTTPSProxy.Value)
if err != nil {
return err
}
if !util.StringSliceContainsAnyOf(t.Options, "https.proxyHost") {
args = append(args, fmt.Sprintf("-Dhttps.proxyHost=%q", u.Hostname()))
}
if port := u.Port(); !util.StringSliceContainsAnyOf(t.Options, "https.proxyPort") && port != "" {
args = append(args, fmt.Sprintf("-Dhttps.proxyPort=%q", u.Port()))
}
if user := u.User; !util.StringSliceContainsAnyOf(t.Options, "https.proxyUser") && user != nil {
args = append(args, fmt.Sprintf("-Dhttps.proxyUser=%q", user.Username()))
if password, ok := user.Password(); !util.StringSliceContainsAnyOf(t.Options, "https.proxyUser") && ok {
args = append(args, fmt.Sprintf("-Dhttps.proxyPassword=%q", password))
}
}
}
if noProxy := envvar.Get(container.Env, "NO_PROXY"); noProxy != nil {
if !util.StringSliceContainsAnyOf(t.Options, "http.nonProxyHosts") {
// Convert to the format expected by the JVM http.nonProxyHosts system property
hosts := strings.Split(strings.ReplaceAll(noProxy.Value, " ", ""), ",")
for i, host := range hosts {
if strings.HasPrefix(host, ".") {
hosts[i] = strings.Replace(host, ".", "*.", 1)
}
}
args = append(args, fmt.Sprintf("-Dhttp.nonProxyHosts=%q", strings.Join(hosts, "|")))
}
}
// Tune JVM maximum heap size based on the container memory limit, if any.
// This is configured off-container, thus is limited to explicit user configuration.
// We may want to inject a wrapper script into the container image, so that it can
// be performed in-container, based on CGroups memory resource control files.
if memory, hasLimit := container.Resources.Limits[corev1.ResourceMemory]; !hasHeapSizeOption && hasLimit {
// Simple heuristic that caps the maximum heap size to 50% of the memory limit
percentage := int64(50)
// Unless the memory limit is lower than 300M, in which case we leave more room for the non-heap memory
if resource.NewScaledQuantity(300, 6).Cmp(memory) > 0 {
percentage = 25
}
memScaled := memory.ScaledValue(resource.Mega) * percentage / 100
args = append(args, fmt.Sprintf("-Xmx%dM", memScaled))
}
// Add mounted resources to the class path
for _, m := range container.VolumeMounts {
classpath.Add(m.MountPath)
}
items := classpath.List()
// Keep class path sorted so that it's consistent over reconciliation cycles
sort.Strings(items)
args = append(args, "-cp", strings.Join(items, ":"))
args = append(args, e.CamelCatalog.Runtime.ApplicationClass)
if pointer.BoolDeref(t.PrintCommand, false) {
args = append([]string{"exec", "java"}, args...)
container.Command = []string{"/bin/sh", "-c"}
cmd := strings.Join(args, " ")
container.Args = []string{"echo " + cmd + " && " + cmd}
} else {
container.Command = []string{"java"}
container.Args = args
}
container.WorkingDir = builder.DeploymentDir
return nil
}