This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feature/CAMEL-22616-cluster-config in repository https://gitbox.apache.org/repos/asf/camel.git
commit 4f3794acbe646866ff436a45369dfd969d880431 Author: Claus Ibsen <[email protected]> AuthorDate: Mon Jul 6 16:09:45 2026 +0200 CAMEL-22616: camel-main - Add cluster service configuration metadata for tooling Co-Authored-By: Claude <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../camel-main-configuration-metadata.json | 77 ++++++++++- core/camel-main/src/main/docs/main.adoc | 123 +++++++++++++++++ .../maven/packaging/PrepareCamelMainMojo.java | 147 +++++++++++++++++++++ 3 files changed, 346 insertions(+), 1 deletion(-) diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index ebf86b1e192c..ca9332ad5c6f 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -28,7 +28,13 @@ { "name": "camel.faulttolerance", "description": "Fault Tolerance EIP Circuit Breaker configurations", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties" }, { "name": "camel.resilience4j", "description": "Resilience4j EIP Circuit Breaker configurations", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties" }, { "name": "camel.lra", "description": "Camel Saga EIP (Long Running Actions) configurations", "sourceType": "org.apache.camel.main.LraConfigurationProperties" }, - { "name": "camel.errorRegistry", "description": "Camel Error Registry configurations", "sourceType": "org.apache.camel.main.ErrorRegistryConfigurationProperties" } + { "name": "camel.errorRegistry", "description": "Camel Error Registry configurations", "sourceType": "org.apache.camel.main.ErrorRegistryConfigurationProperties" }, + { "name": "camel.cluster.file", "description": "Camel File Cluster Service configurations", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService" }, + { "name": "camel.cluster.kubernetes", "description": "Camel Kubernetes Cluster Service configurations", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService" }, + { "name": "camel.cluster.zookeeper", "description": "Camel ZooKeeper Cluster Service configurations", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService" }, + { "name": "camel.cluster.consul", "description": "Camel Consul Cluster Service configurations", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService" }, + { "name": "camel.cluster.jgroups-raft", "description": "Camel JGroups Raft Cluster Service configurations", "sourceType": "org.apache.camel.component.jgroups.raft.cluster.JGroupsRaftClusterService" }, + { "name": "camel.cluster.infinispan", "description": "Camel Infinispan Remote Cluster Service configurations", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService" } ], "properties": [ { "name": "camel.main.additionalSensitiveKeywords", "required": false, "description": "Camel comes with a default set of sensitive keywords which are automatically masked. This option allows to add additional custom keywords to be masked as well. Multiple keywords can be separated by comma.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, @@ -160,6 +166,75 @@ { "name": "camel.main.uuidGenerator", "required": false, "description": "UUID generator to use. default (32 bytes), short (16 bytes), classic (32 bytes or longer), simple (long incrementing counter), off (turned off for exchanges - only intended for performance profiling)", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "enum", "javaType": "java.lang.String", "defaultValue": "default", "secret": false, "enum": [ "classic", "default", "short", "simple", [...] { "name": "camel.main.virtualThreadsEnabled", "required": false, "description": "Whether to enable virtual threads when creating thread pools. When enabled, Camel will use virtual threads instead of platform threads for its thread pools. This can also be enabled via the JVM system property {code camel.threads.virtual.enabled=true} . This option must be read early during bootstrap, so it is set as a system property before thread pools are created.", "sourceType": "org.apache.camel.mai [...] { "name": "camel.main.yamlDslCompactNotationWarn", "required": false, "description": "Whether to log a WARN when YAML DSL routes use compact (shorthand) notation instead of the canonical (explicit\/normalized) form. The canonical style is recommended as it is more tooling and AI friendly. Use Camel CLI to normalize existing routes: camel validate normalize <file>", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "d [...] + { "name": "camel.cluster.consul.aclToken", "required": false, "description": "Sets the ACL token to be used with Consul", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, + { "name": "camel.cluster.consul.blockSeconds", "required": false, "description": "The second to wait for a watch event, default 10 seconds", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "defaultValue": 10, "secret": false }, + { "name": "camel.cluster.consul.connectTimeout", "required": false, "description": "Connect timeout in millis", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "secret": false }, + { "name": "camel.cluster.consul.datacenter", "required": false, "description": "The data center", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.consul.enabled", "required": false, "description": "Whether to enable this cluster service.", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, + { "name": "camel.cluster.consul.id", "required": true, "description": "Client id registered as _consul.service.registry.id", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.consul.password", "required": false, "description": "Sets the password to be used for basic authentication", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, + { "name": "camel.cluster.consul.readTimeout", "required": false, "description": "Read timeout in millis", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "secret": false }, + { "name": "camel.cluster.consul.rootPath", "required": false, "description": "The Consul cluster root directory path", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "defaultValue": "\/camel", "secret": false }, + { "name": "camel.cluster.consul.sessionLockDelay", "required": false, "description": "Session lock delay in seconds", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "defaultValue": 5, "secret": false }, + { "name": "camel.cluster.consul.sessionRefreshInterval", "required": false, "description": "Session refresh interval in seconds", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "defaultValue": 5, "secret": false }, + { "name": "camel.cluster.consul.sessionTtl", "required": false, "description": "Session time to live in seconds", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "defaultValue": 60, "secret": false }, + { "name": "camel.cluster.consul.sslContextParameters", "required": false, "description": "SSL configuration for advanced security configuration", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "secret": false }, + { "name": "camel.cluster.consul.url", "required": false, "description": "The Consul agent URL", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.consul.userName", "required": false, "description": "Sets the username to be used for basic authentication", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, + { "name": "camel.cluster.consul.writeTimeout", "required": false, "description": "Write timeout in mills", "sourceType": "org.apache.camel.component.consul.cluster.ConsulClusterService", "type": "integer", "javaType": "int", "secret": false }, + { "name": "camel.cluster.file.acquireLockDelay", "required": false, "description": "The time to wait before starting to try to acquire the cluster lock. Note that if FileLockClusterService determines no cluster members are running or cannot reliably determine the cluster state, the initial delay is computed from the acquireLockInterval.", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "integer", "javaType": "long", "defaultValue": 1, "secret": [...] + { "name": "camel.cluster.file.acquireLockDelayUnit", "required": false, "description": "The time unit for the acquireLockDelay", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "object", "javaType": "java.util.concurrent.TimeUnit", "defaultValue": "SECONDS", "secret": false }, + { "name": "camel.cluster.file.acquireLockInterval", "required": false, "description": "The time to wait between attempts to try to acquire the cluster lock evaluated using wall-clock time. All cluster members must use the same value so leadership checks and leader liveness detection remain consistent.", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "integer", "javaType": "long", "defaultValue": 10, "secret": false }, + { "name": "camel.cluster.file.acquireLockIntervalUnit", "required": false, "description": "The time unit for the acquireLockInterval", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "object", "javaType": "java.util.concurrent.TimeUnit", "defaultValue": "SECONDS", "secret": false }, + { "name": "camel.cluster.file.clusterDataTaskMaxAttempts", "required": false, "description": "Sets how many times a cluster data task will run, counting both the first execution and subsequent retries in case of failure or timeout. The default is 5 attempts. This can be useful when the cluster data root is on network based file storage, where I\/O operations may occasionally block for long or unpredictable periods.", "sourceType": "org.apache.camel.component.file.cluster.FileLockClus [...] + { "name": "camel.cluster.file.clusterDataTaskTimeout", "required": false, "description": "Sets the timeout for a cluster data task (reading or writing cluster data). The default is 10 seconds. Timeouts are useful when the cluster data root is on network storage, where I\/O operations may occasionally block for long or unpredictable periods.", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "integer", "javaType": "long", "defaultValue": 10, "sec [...] + { "name": "camel.cluster.file.clusterDataTaskTimeoutUnit", "required": false, "description": "The time unit for the clusterDataTaskTimeoutUnit", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "object", "javaType": "java.util.concurrent.TimeUnit", "defaultValue": "SECONDS", "secret": false }, + { "name": "camel.cluster.file.enabled", "required": false, "description": "Whether to enable this cluster service.", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, + { "name": "camel.cluster.file.heartbeatTimeoutMultiplier", "required": false, "description": "Multiplier applied to the cluster leader acquireLockInterval to determine how long followers should wait before considering the leader stale. For example, if the leader updates its heartbeat every 2 seconds and the heartbeatTimeoutMultiplier is 3, followers will tolerate up to 2s * 3 = 6s of silence before declaring the leader unavailable.", "sourceType": "org.apache.camel.component.file.clu [...] + { "name": "camel.cluster.file.root", "required": true, "description": "The root file path", "sourceType": "org.apache.camel.component.file.cluster.FileLockClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.cacheContainer", "required": false, "description": "Specifies the cache Container to connect", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "object", "javaType": "org.infinispan.client.hotrod.RemoteCacheManager", "secret": false }, + { "name": "camel.cluster.infinispan.configurationProperties", "required": false, "description": "Implementation specific properties for the CacheManager", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "object", "javaType": "java.util.Map", "secret": false }, + { "name": "camel.cluster.infinispan.configurationUri", "required": false, "description": "An implementation specific URI for the CacheManager", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.enabled", "required": false, "description": "Whether to enable this cluster service.", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, + { "name": "camel.cluster.infinispan.hosts", "required": false, "description": "Specifies the host of the cache on Infinispan instance. Multiple hosts can be separated by semicolon.", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.id", "required": true, "description": "Node id", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.lifespan", "required": false, "description": "The lifespan of the cache entry for the local cluster member registered to the inventory", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "integer", "javaType": "long", "defaultValue": 30, "secret": false }, + { "name": "camel.cluster.infinispan.lifespanTimeUnit", "required": false, "description": "The TimeUnit of the lifespan", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "object", "javaType": "java.util.concurrent.TimeUnit", "defaultValue": "SECONDS", "secret": false }, + { "name": "camel.cluster.infinispan.password", "required": false, "description": "Define the password to access the infinispan instance", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, + { "name": "camel.cluster.infinispan.saslMechanism", "required": false, "description": "Define the SASL Mechanism to access the infinispan instance", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.secure", "required": false, "description": "Define if we are connecting to a secured Infinispan instance", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, + { "name": "camel.cluster.infinispan.securityRealm", "required": false, "description": "Define the security realm to access the infinispan instance", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.securityServerName", "required": false, "description": "Define the security server name to access the infinispan instance", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.infinispan.username", "required": false, "description": "Define the username to access the infinispan instance", "sourceType": "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.jgroups-raft.enabled", "required": false, "description": "Whether to enable this cluster service.", "sourceType": "org.apache.camel.component.jgroups.raft.cluster.JGroupsRaftClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, + { "name": "camel.cluster.jgroups-raft.id", "required": true, "description": "Unique Raft id", "sourceType": "org.apache.camel.component.jgroups.raft.cluster.JGroupsRaftClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.jgroups-raft.jgroupsClusterName", "required": false, "description": "The name of the cluster", "sourceType": "org.apache.camel.component.jgroups.raft.cluster.JGroupsRaftClusterService", "type": "string", "javaType": "java.lang.String", "defaultValue": "jgroupsraft-master", "secret": false }, + { "name": "camel.cluster.jgroups-raft.jgroupsConfig", "required": false, "description": "The path to the JGroups Raft configuration", "sourceType": "org.apache.camel.component.jgroups.raft.cluster.JGroupsRaftClusterService", "type": "string", "javaType": "java.lang.String", "defaultValue": "raft.xml", "secret": false }, + { "name": "camel.cluster.kubernetes.clusterLabels", "required": false, "description": "Labels used to identify the members of the cluster.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "object", "javaType": "java.util.Map", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.connectionTimeout", "required": false, "description": "Connection timeout in milliseconds to use when making requests to the Kubernetes API server.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "integer", "javaType": "java.lang.Integer", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.enabled", "required": false, "description": "Whether to enable this cluster service.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, + { "name": "camel.cluster.kubernetes.groupName", "required": false, "description": "Name of the lock group (or namespace according to the Camel cluster convention) within the chosen ConfigMap.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "string", "javaType": "java.lang.String", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.jitterFactor", "required": false, "description": "A jitter factor to apply in order to prevent all pods to call Kubernetes APIs in the same instant.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "number", "javaType": "double", "defaultValue": "1.2", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.kubernetesResourceName", "required": false, "description": "Name of the resource used for locking (or prefix, in case multiple ones are used).", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "string", "javaType": "java.lang.String", "defaultValue": "leaders", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.kubernetesResourcesNamespace", "required": false, "description": "Kubernetes namespace containing the pods and the ConfigMap used for locking.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "string", "javaType": "java.lang.String", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.leaseDurationMillis", "required": false, "description": "The default duration of the lease for the current leader.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "integer", "javaType": "long", "defaultValue": 15000, "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.leaseResourceType", "required": false, "description": "Kubernetes resource type used to hold the leases.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "object", "javaType": "org.apache.camel.component.kubernetes.cluster.LeaseResourceType", "defaultValue": "Lease", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.masterUrl", "required": false, "description": "URL to a remote Kubernetes API server. This should only be used when your Camel application is connecting from outside Kubernetes. If you run your Camel application inside Kubernetes, then you can use local or client as the URL to tell Camel to run in local mode. If you connect remotely to Kubernetes, then you may also need some of the many other configuration options for secured connection with certif [...] + { "name": "camel.cluster.kubernetes.namespace", "required": false, "description": "Kubernetes namespace", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "string", "javaType": "java.lang.String", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.podName", "required": false, "description": "Name of the current pod (defaults to host name).", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "string", "javaType": "java.lang.String", "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.renewDeadlineMillis", "required": false, "description": "The deadline after which the leader must stop its services because it may have lost the leadership.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "integer", "javaType": "long", "defaultValue": 10000, "secret": false, "deprecated": true }, + { "name": "camel.cluster.kubernetes.retryPeriodMillis", "required": false, "description": "The time between two subsequent attempts to check and acquire the leadership. It is randomized using the jitter factor.", "sourceType": "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService", "type": "integer", "javaType": "long", "defaultValue": 2000, "secret": false, "deprecated": true }, + { "name": "camel.cluster.zookeeper.basePath", "required": true, "description": "The base path to store in ZooKeeper", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.zookeeper.connectTimeout", "required": false, "description": "Connect timeout (millis)", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "integer", "javaType": "long", "defaultValue": 15000, "secret": false }, + { "name": "camel.cluster.zookeeper.enabled", "required": false, "description": "Whether to enable this cluster service.", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, + { "name": "camel.cluster.zookeeper.id", "required": true, "description": "Node id", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.zookeeper.maxCloseWait", "required": false, "description": "Time to wait (millis) during close to join background threads", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "integer", "javaType": "long", "defaultValue": 1000, "secret": false }, + { "name": "camel.cluster.zookeeper.namespace", "required": false, "description": "ZooKeeper namespace. If a namespace is set here, all paths will get pre-pended with the namespace", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.zookeeper.nodes", "required": true, "description": "The Zookeeper server hosts (multiple servers can be separated by comma)", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.cluster.zookeeper.reconnectBaseSleepTime", "required": false, "description": "Initial amount of time (millis) to wait between retries", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "integer", "javaType": "long", "defaultValue": 1000, "secret": false }, + { "name": "camel.cluster.zookeeper.reconnectMaxRetries", "required": false, "description": "Max number of times to retry", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "integer", "javaType": "int", "defaultValue": 3, "secret": false }, + { "name": "camel.cluster.zookeeper.reconnectMaxSleepTime", "required": false, "description": "Max time (millis) to sleep on each retry", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "integer", "javaType": "long", "secret": false }, + { "name": "camel.cluster.zookeeper.sessionTimeout", "required": false, "description": "Session timeout (millis)", "sourceType": "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService", "type": "integer", "javaType": "long", "defaultValue": 60000, "secret": false }, { "name": "camel.debug.bodyIncludeFiles", "required": false, "description": "Whether to include the message body of file based messages. The overhead is that the file content has to be read from the file.", "sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true, "secret": false }, { "name": "camel.debug.bodyIncludeStreams", "required": false, "description": "Whether to include the message body of stream based messages. If enabled then beware the stream may not be re-readable later. See more about Stream Caching.", "sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.debug.bodyMaxChars", "required": false, "description": "To limit the message body to a maximum size in the traced message. Use 0 or negative value to use unlimited size.", "sourceType": "org.apache.camel.main.DebuggerConfigurationProperties", "type": "integer", "javaType": "int", "defaultValue": 32768, "secret": false }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 3af1204ab2bc..c2b0aa4f4576 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -734,6 +734,129 @@ The camel.errorRegistry supports 8 options, which are listed below. | *camel.errorRegistry.maximumEntries* | The maximum number of error entries to keep in the registry. When the limit is exceeded, the oldest entries are evicted. | 100 | int | *camel.errorRegistry.timeToLiveSeconds* | The time-to-live in seconds for error entries. Entries older than this are evicted. The default value is 0 (disabled). | 0 | int |=== + + +=== Camel File Cluster Service configurations +The camel.cluster.file supports 10 options, which are listed below. + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *camel.cluster.file.acquireLockDelay* | The time to wait before starting to try to acquire the cluster lock. Note that if FileLockClusterService determines no cluster members are running or cannot reliably determine the cluster state, the initial delay is computed from the acquireLockInterval. | 1 | long +| *camel.cluster.file.acquireLockDelayUnit* | The time unit for the acquireLockDelay | SECONDS | TimeUnit +| *camel.cluster.file.acquireLockInterval* | The time to wait between attempts to try to acquire the cluster lock evaluated using wall-clock time. All cluster members must use the same value so leadership checks and leader liveness detection remain consistent. | 10 | long +| *camel.cluster.file.acquireLockIntervalUnit* | The time unit for the acquireLockInterval | SECONDS | TimeUnit +| *camel.cluster.file.clusterDataTaskMaxAttempts* | Sets how many times a cluster data task will run, counting both the first execution and subsequent retries in case of failure or timeout. The default is 5 attempts. This can be useful when the cluster data root is on network based file storage, where I/O operations may occasionally block for long or unpredictable periods. | 5 | int +| *camel.cluster.file.clusterDataTaskTimeout* | Sets the timeout for a cluster data task (reading or writing cluster data). The default is 10 seconds. Timeouts are useful when the cluster data root is on network storage, where I/O operations may occasionally block for long or unpredictable periods. | 10 | long +| *camel.cluster.file.clusterDataTaskTimeoutUnit* | The time unit for the clusterDataTaskTimeoutUnit | SECONDS | TimeUnit +| *camel.cluster.file.enabled* | Whether to enable this cluster service. | true | boolean +| *camel.cluster.file.heartbeatTimeoutMultiplier* | Multiplier applied to the cluster leader acquireLockInterval to determine how long followers should wait before considering the leader stale. For example, if the leader updates its heartbeat every 2 seconds and the heartbeatTimeoutMultiplier is 3, followers will tolerate up to 2s * 3 = 6s of silence before declaring the leader unavailable. | 5 | int +| *camel.cluster.file.root* | The root file path | | String +|=== + + +=== Camel Kubernetes Cluster Service configurations +The camel.cluster.kubernetes supports 14 options, which are listed below. + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *camel.cluster.kubernetes.clusterLabels* | Labels used to identify the members of the cluster. | | Map +| *camel.cluster.kubernetes.connectionTimeout* | Connection timeout in milliseconds to use when making requests to the Kubernetes API server. | | Integer +| *camel.cluster.kubernetes.enabled* | Whether to enable this cluster service. | true | boolean +| *camel.cluster.kubernetes.groupName* | Name of the lock group (or namespace according to the Camel cluster convention) within the chosen ConfigMap. | | String +| *camel.cluster.kubernetes.jitterFactor* | A jitter factor to apply in order to prevent all pods to call Kubernetes APIs in the same instant. | 1.2 | double +| *camel.cluster.kubernetes.kubernetesResourceName* | Name of the resource used for locking (or prefix, in case multiple ones are used). | leaders | String +| *camel.cluster.kubernetes.kubernetesResourcesNamespace* | Kubernetes namespace containing the pods and the ConfigMap used for locking. | | String +| *camel.cluster.kubernetes.leaseDurationMillis* | The default duration of the lease for the current leader. | 15000 | long +| *camel.cluster.kubernetes.leaseResourceType* | Kubernetes resource type used to hold the leases. | Lease | LeaseResourceType +| *camel.cluster.kubernetes.masterUrl* | URL to a remote Kubernetes API server. This should only be used when your Camel application is connecting from outside Kubernetes. If you run your Camel application inside Kubernetes, then you can use local or client as the URL to tell Camel to run in local mode. If you connect remotely to Kubernetes, then you may also need some of the many other configuration options for secured connection with certificates, etc. | | String +| *camel.cluster.kubernetes.namespace* | Kubernetes namespace | | String +| *camel.cluster.kubernetes.podName* | Name of the current pod (defaults to host name). | | String +| *camel.cluster.kubernetes.renewDeadlineMillis* | The deadline after which the leader must stop its services because it may have lost the leadership. | 10000 | long +| *camel.cluster.kubernetes.retryPeriodMillis* | The time between two subsequent attempts to check and acquire the leadership. It is randomized using the jitter factor. | 2000 | long +|=== + + +=== Camel ZooKeeper Cluster Service configurations +The camel.cluster.zookeeper supports 11 options, which are listed below. + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *camel.cluster.zookeeper.basePath* | The base path to store in ZooKeeper | | String +| *camel.cluster.zookeeper.connectTimeout* | Connect timeout (millis) | 15000 | long +| *camel.cluster.zookeeper.enabled* | Whether to enable this cluster service. | true | boolean +| *camel.cluster.zookeeper.id* | Node id | | String +| *camel.cluster.zookeeper.maxCloseWait* | Time to wait (millis) during close to join background threads | 1000 | long +| *camel.cluster.zookeeper.namespace* | ZooKeeper namespace. If a namespace is set here, all paths will get pre-pended with the namespace | | String +| *camel.cluster.zookeeper.nodes* | The Zookeeper server hosts (multiple servers can be separated by comma) | | String +| *camel.cluster.zookeeper.reconnectBaseSleepTime* | Initial amount of time (millis) to wait between retries | 1000 | long +| *camel.cluster.zookeeper.reconnectMaxRetries* | Max number of times to retry | 3 | int +| *camel.cluster.zookeeper.reconnectMaxSleepTime* | Max time (millis) to sleep on each retry | | long +| *camel.cluster.zookeeper.sessionTimeout* | Session timeout (millis) | 60000 | long +|=== + + +=== Camel Consul Cluster Service configurations +The camel.cluster.consul supports 16 options, which are listed below. + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *camel.cluster.consul.aclToken* | Sets the ACL token to be used with Consul | | String +| *camel.cluster.consul.blockSeconds* | The second to wait for a watch event, default 10 seconds | 10 | int +| *camel.cluster.consul.connectTimeout* | Connect timeout in millis | | int +| *camel.cluster.consul.datacenter* | The data center | | String +| *camel.cluster.consul.enabled* | Whether to enable this cluster service. | true | boolean +| *camel.cluster.consul.id* | Client id registered as _consul.service.registry.id | | String +| *camel.cluster.consul.password* | Sets the password to be used for basic authentication | | String +| *camel.cluster.consul.readTimeout* | Read timeout in millis | | int +| *camel.cluster.consul.rootPath* | The Consul cluster root directory path | /camel | String +| *camel.cluster.consul.sessionLockDelay* | Session lock delay in seconds | 5 | int +| *camel.cluster.consul.sessionRefreshInterval* | Session refresh interval in seconds | 5 | int +| *camel.cluster.consul.sessionTtl* | Session time to live in seconds | 60 | int +| *camel.cluster.consul.sslContextParameters* | SSL configuration for advanced security configuration | | SSLContextParameters +| *camel.cluster.consul.url* | The Consul agent URL | | String +| *camel.cluster.consul.userName* | Sets the username to be used for basic authentication | | String +| *camel.cluster.consul.writeTimeout* | Write timeout in mills | | int +|=== + + +=== Camel JGroups Raft Cluster Service configurations +The camel.cluster.jgroups-raft supports 4 options, which are listed below. + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *camel.cluster.jgroups-raft.enabled* | Whether to enable this cluster service. | true | boolean +| *camel.cluster.jgroups-raft.id* | Unique Raft id | | String +| *camel.cluster.jgroups-raft.jgroupsClusterName* | The name of the cluster | jgroupsraft-master | String +| *camel.cluster.jgroups-raft.jgroupsConfig* | The path to the JGroups Raft configuration | raft.xml | String +|=== + + +=== Camel Infinispan Remote Cluster Service configurations +The camel.cluster.infinispan supports 14 options, which are listed below. + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *camel.cluster.infinispan.cacheContainer* | Specifies the cache Container to connect | | RemoteCacheManager +| *camel.cluster.infinispan.configurationProperties* | Implementation specific properties for the CacheManager | | Map +| *camel.cluster.infinispan.configurationUri* | An implementation specific URI for the CacheManager | | String +| *camel.cluster.infinispan.enabled* | Whether to enable this cluster service. | true | boolean +| *camel.cluster.infinispan.hosts* | Specifies the host of the cache on Infinispan instance. Multiple hosts can be separated by semicolon. | | String +| *camel.cluster.infinispan.id* | Node id | | String +| *camel.cluster.infinispan.lifespan* | The lifespan of the cache entry for the local cluster member registered to the inventory | 30 | long +| *camel.cluster.infinispan.lifespanTimeUnit* | The TimeUnit of the lifespan | SECONDS | TimeUnit +| *camel.cluster.infinispan.password* | Define the password to access the infinispan instance | | String +| *camel.cluster.infinispan.saslMechanism* | Define the SASL Mechanism to access the infinispan instance | | String +| *camel.cluster.infinispan.secure* | Define if we are connecting to a secured Infinispan instance | false | boolean +| *camel.cluster.infinispan.securityRealm* | Define the security realm to access the infinispan instance | | String +| *camel.cluster.infinispan.securityServerName* | Define the security server name to access the infinispan instance | | String +| *camel.cluster.infinispan.username* | Define the username to access the infinispan instance | | String +|=== // main options: END == Package Scanning diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java index c2ada8247cb2..259740416d85 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java @@ -18,9 +18,12 @@ package org.apache.camel.maven.packaging; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; @@ -31,6 +34,8 @@ import org.apache.camel.tooling.model.MainModel; import org.apache.camel.tooling.model.MainModel.MainGroupModel; import org.apache.camel.tooling.util.JavadocHelper; import org.apache.camel.tooling.util.PackageHelper; +import org.apache.camel.util.json.JsonObject; +import org.apache.camel.util.json.Jsoner; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -150,6 +155,98 @@ public class PrepareCamelMainMojo extends AbstractGeneratorMojo { return answer; } + private static final Set<String> SETTABLE_JAVA_TYPES = Set.of( + "java.lang.String", "java.lang.Integer", "java.lang.Long", "java.lang.Boolean", + "java.lang.Double", "java.lang.Float", "java.lang.Short", "java.lang.Byte", + "int", "long", "boolean", "double", "float", "short", "byte", + "java.util.Map", "java.util.concurrent.TimeUnit", + "org.apache.camel.support.jsse.SSLContextParameters"); + + /** + * Loads cluster service configuration metadata from a bean JSON file. + */ + public static List<MainModel.MainOptionModel> loadClusterServiceMetadata( + String prefix, File beanJsonFile) + throws Exception { + + final List<MainModel.MainOptionModel> answer = new ArrayList<>(); + + String json = Files.readString(beanJsonFile.toPath()); + JsonObject root = (JsonObject) Jsoner.deserialize(json); + JsonObject bean = root.getMap("bean"); + String sourceType = bean.getString("javaType"); + boolean classDeprecated = Boolean.TRUE.equals(bean.get("deprecated")); + + // add synthetic "enabled" property + MainModel.MainOptionModel enabledModel = new MainModel.MainOptionModel(); + enabledModel.setName(prefix + "enabled"); + enabledModel.setJavaType("boolean"); + enabledModel.setType("boolean"); + enabledModel.setDefaultValue(true); + enabledModel.setDescription("Whether to enable this cluster service."); + enabledModel.setSourceType(sourceType); + answer.add(enabledModel); + + JsonObject properties = bean.getMap("properties"); + if (properties != null) { + for (Map.Entry<String, Object> entry : properties.entrySet()) { + String name = entry.getKey(); + JsonObject prop = (JsonObject) entry.getValue(); + + String javaType = prop.getString("javaType"); + String label = prop.getString("label"); + + // skip advanced properties with component-specific types + if (label != null && label.contains("advanced") && !SETTABLE_JAVA_TYPES.contains(javaType)) { + continue; + } + + MainModel.MainOptionModel model = new MainModel.MainOptionModel(); + model.setName(prefix + name); + model.setJavaType(javaType); + model.setSourceType(sourceType); + model.setRequired(Boolean.TRUE.equals(prop.get("required"))); + model.setDeprecated(classDeprecated || Boolean.TRUE.equals(prop.get("deprecated"))); + model.setSecret(Boolean.TRUE.equals(prop.get("secret"))); + model.setDescription(prop.getString("description")); + + String security = prop.getString("security"); + if (security != null) { + model.setSecurity(security); + if ("secret".equals(security) && !model.isSecret()) { + model.setSecret(true); + } + } + + // determine type and handle enums + String type = prop.getString("type"); + List<String> enums = null; + Object enumObj = prop.get("enum"); + if (enumObj instanceof List) { + enums = ((List<?>) enumObj).stream().map(Object::toString).collect(Collectors.toList()); + type = "enum"; + } + if (type == null) { + type = MojoHelper.getType(javaType, enums != null, false); + } + model.setType(type); + model.setEnums(enums); + + // default value + Object defaultValue = prop.get("defaultValue"); + if (defaultValue != null) { + model.setDefaultValue(defaultValue); + } else if ("boolean".equals(type)) { + model.setDefaultValue("false"); + } + + answer.add(model); + } + } + + return answer; + } + private static Object asDefaultValue(String type, String defaultValue) { if (defaultValue != null) { if ("boolean".equals(type)) { @@ -359,6 +456,38 @@ public class PrepareCamelMainMojo extends AbstractGeneratorMojo { throw new MojoFailureException("Error parsing file " + cyberarkVaultConfig + " due " + e.getMessage(), e); } + // include cluster service configuration from component bean metadata + String[][] clusterServices = { + { "file", "components/camel-file", "FileLockClusterService" }, + { "kubernetes", "components/camel-kubernetes", "KubernetesClusterService" }, + { "zookeeper", "components/camel-zookeeper", "ZooKeeperClusterService" }, + { "consul", "components/camel-consul", "ConsulClusterService" }, + { "jgroups-raft", "components/camel-jgroups-raft", "JGroupsRaftClusterService" }, + { "infinispan", "components/camel-infinispan/camel-infinispan", "InfinispanRemoteClusterService" }, + }; + for (String[] cs : clusterServices) { + String type = cs[0]; + String componentPath = cs[1]; + String beanName = cs[2]; + try { + File componentDir = PackageHelper.findCamelDirectory(project.getBasedir(), componentPath); + File beanJson = new File( + componentDir, + "src/generated/resources/META-INF/services/org/apache/camel/bean/" + beanName + ".json"); + if (beanJson.isFile()) { + String prefix = "camel.cluster." + type + "."; + List<MainModel.MainOptionModel> clusterModel = loadClusterServiceMetadata(prefix, beanJson); + data.addAll(clusterModel); + getLog().info("Loaded cluster service metadata: " + type + " (" + clusterModel.size() + " options)"); + } else { + getLog().warn("Cluster service bean metadata not found: " + beanJson); + } + } catch (Exception e) { + throw new MojoFailureException( + "Error loading cluster service metadata for " + type + " due " + e.getMessage(), e); + } + } + // lets sort so they are always ordered (but camel.main in top) data.sort((o1, o2) -> { if (o1.getName().startsWith("camel.main.") && !o2.getName().startsWith("camel.main.")) { @@ -477,6 +606,24 @@ public class PrepareCamelMainMojo extends AbstractGeneratorMojo { model.getGroups().add(new MainGroupModel( "camel.errorRegistry", "Camel Error Registry configurations", "org.apache.camel.main.ErrorRegistryConfigurationProperties")); + model.getGroups().add(new MainGroupModel( + "camel.cluster.file", "Camel File Cluster Service configurations", + "org.apache.camel.component.file.cluster.FileLockClusterService")); + model.getGroups().add(new MainGroupModel( + "camel.cluster.kubernetes", "Camel Kubernetes Cluster Service configurations", + "org.apache.camel.component.kubernetes.cluster.KubernetesClusterService")); + model.getGroups().add(new MainGroupModel( + "camel.cluster.zookeeper", "Camel ZooKeeper Cluster Service configurations", + "org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService")); + model.getGroups().add(new MainGroupModel( + "camel.cluster.consul", "Camel Consul Cluster Service configurations", + "org.apache.camel.component.consul.cluster.ConsulClusterService")); + model.getGroups().add(new MainGroupModel( + "camel.cluster.jgroups-raft", "Camel JGroups Raft Cluster Service configurations", + "org.apache.camel.component.jgroups.raft.cluster.JGroupsRaftClusterService")); + model.getGroups().add(new MainGroupModel( + "camel.cluster.infinispan", "Camel Infinispan Remote Cluster Service configurations", + "org.apache.camel.component.infinispan.remote.cluster.InfinispanRemoteClusterService")); String json = JsonMapper.createJsonSchema(model);
