This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 90fe4e194b3 camel-aws - Add dev console for AWS secrets
90fe4e194b3 is described below
commit 90fe4e194b354fa3c6ee3f773441dc9bfb01ea2b
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 7 20:10:06 2022 +0200
camel-aws - Add dev console for AWS secrets
---
.../camel-aws/camel-aws-secrets-manager/pom.xml | 4 +
.../org/apache/camel/dev-console/aws-secrets | 2 +
.../aws/secretsmanager/SecretsDevConsole.java | 90 ++++++++++++++++++++++
.../SecretsManagerPropertiesFunction.java | 18 +++++
.../vault/CloudTrailReloadTriggerTask.java | 33 +++++++-
.../org/apache/camel/spi/PeriodTaskScheduler.java | 9 ++-
.../impl/engine/DefaultPeriodTaskScheduler.java | 18 +++++
.../apache/camel/support/TimerListenerManager.java | 8 ++
8 files changed, 178 insertions(+), 4 deletions(-)
diff --git a/components/camel-aws/camel-aws-secrets-manager/pom.xml
b/components/camel-aws/camel-aws-secrets-manager/pom.xml
index f11708d5124..74b56d01427 100644
--- a/components/camel-aws/camel-aws-secrets-manager/pom.xml
+++ b/components/camel-aws/camel-aws-secrets-manager/pom.xml
@@ -40,6 +40,10 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-support</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-console</artifactId>
+ </dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>secretsmanager</artifactId>
diff --git
a/components/camel-aws/camel-aws-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/dev-console/aws-secrets
b/components/camel-aws/camel-aws-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/dev-console/aws-secrets
new file mode 100644
index 00000000000..9817b4172b7
--- /dev/null
+++
b/components/camel-aws/camel-aws-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/dev-console/aws-secrets
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.aws.secretsmanager.SecretsDevConsole
diff --git
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsDevConsole.java
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsDevConsole.java
new file mode 100644
index 00000000000..d87d839e8b1
--- /dev/null
+++
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsDevConsole.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.aws.secretsmanager;
+
+import java.util.Map;
+
+import
org.apache.camel.component.aws.secretsmanager.vault.CloudTrailReloadTriggerTask;
+import org.apache.camel.impl.console.AbstractDevConsole;
+import org.apache.camel.spi.PropertiesFunction;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+@DevConsole("aws-secrets")
+public class SecretsDevConsole extends AbstractDevConsole {
+
+ private SecretsManagerPropertiesFunction propertiesFunction;
+ private CloudTrailReloadTriggerTask secretsRefreshTask; // TODO:
+
+ public SecretsDevConsole() {
+ super("camel", "aws-secrets", "AWS Secrets", "AWS Secrets Manager");
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+
+ PropertiesFunction pf =
getCamelContext().getPropertiesComponent().getPropertiesFunction("aws");
+ if (pf instanceof SecretsManagerPropertiesFunction) {
+ propertiesFunction = (SecretsManagerPropertiesFunction) pf;
+ }
+ }
+
+ @Override
+ protected String doCallText(Map<String, Object> options) {
+ StringBuilder sb = new StringBuilder();
+
+ if (propertiesFunction != null) {
+ sb.append("AWS Secrets Manager:");
+ sb.append(String.format("\n Region: %s",
propertiesFunction.getRegion()));
+ if (propertiesFunction.isDefaultCredentialsProvider()) {
+ sb.append("\n Login: DefaultCredentialsProvider");
+ } else {
+ sb.append("\n Login: Access and Secret Keys");
+ }
+ sb.append("\n\nSecrets in use:");
+ for (String sec : propertiesFunction.getSecrets()) {
+ sb.append(String.format("\n %s", sec)); // TODO: update time
+ }
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ protected JsonObject doCallJson(Map<String, Object> options) {
+ JsonObject root = new JsonObject();
+ if (propertiesFunction != null) {
+ root.put("region", propertiesFunction.getRegion());
+ if (propertiesFunction.isDefaultCredentialsProvider()) {
+ root.put("login", "DefaultCredentialsProvider");
+ } else {
+ root.put("login", "Access and Secret Keys");
+ }
+ JsonArray arr = new JsonArray();
+ root.put("secrets", arr);
+ for (String sec : propertiesFunction.getSecrets()) {
+ JsonObject jo = new JsonObject();
+ jo.put("name", sec);
+ // TODO: update time
+ arr.add(jo);
+ }
+ }
+ return root;
+ }
+}
diff --git
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsManagerPropertiesFunction.java
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsManagerPropertiesFunction.java
index ae147d7f974..547581c5133 100644
---
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsManagerPropertiesFunction.java
+++
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/SecretsManagerPropertiesFunction.java
@@ -87,6 +87,9 @@ public class SecretsManagerPropertiesFunction extends
ServiceSupport implements
private final Set<String> secrets = new HashSet<>();
+ private String region;
+ private boolean defaultCredentialsProvider;
+
@Override
protected void doStart() throws Exception {
super.doStart();
@@ -105,6 +108,7 @@ public class SecretsManagerPropertiesFunction extends
ServiceSupport implements
useDefaultCredentialsProvider =
awsVaultConfiguration.isDefaultCredentialsProvider();
}
}
+ this.region = region;
if (ObjectHelper.isNotEmpty(accessKey) &&
ObjectHelper.isNotEmpty(secretKey) && ObjectHelper.isNotEmpty(region)) {
SecretsManagerClientBuilder clientBuilder =
SecretsManagerClient.builder();
AwsBasicCredentials cred = AwsBasicCredentials.create(accessKey,
secretKey);
@@ -112,6 +116,7 @@ public class SecretsManagerPropertiesFunction extends
ServiceSupport implements
clientBuilder.region(Region.of(region));
client = clientBuilder.build();
} else if (useDefaultCredentialsProvider &&
ObjectHelper.isNotEmpty(region)) {
+ this.defaultCredentialsProvider = true;
SecretsManagerClientBuilder clientBuilder =
SecretsManagerClient.builder();
clientBuilder.region(Region.of(region));
client = clientBuilder.build();
@@ -251,4 +256,17 @@ public class SecretsManagerPropertiesFunction extends
ServiceSupport implements
return secrets;
}
+ /**
+ * The region in use for connecting to AWS Secrets Manager
+ */
+ public String getRegion() {
+ return region;
+ }
+
+ /**
+ * Whether login is using default credentials provider, or access/secret
keys
+ */
+ public boolean isDefaultCredentialsProvider() {
+ return defaultCredentialsProvider;
+ }
}
diff --git
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
index 31cd63f0a10..10edb759a9f 100644
---
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
+++
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
@@ -18,8 +18,10 @@ package org.apache.camel.component.aws.secretsmanager.vault;
import java.time.Instant;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.apache.camel.CamelContext;
@@ -60,10 +62,12 @@ public class CloudTrailReloadTriggerTask extends
ServiceSupport implements Camel
private static final String SECRETSMANAGER_AMAZONAWS_COM =
"secretsmanager.amazonaws.com";
private CamelContext camelContext;
- private CloudTrailClient cloudTrailClient;
+ private boolean reloadEnabled = true;
private String secrets;
+ private CloudTrailClient cloudTrailClient;
private SecretsManagerPropertiesFunction propertiesFunction;
private volatile Instant lastTime;
+ private final Map<String, Instant> updates = new HashMap<>();
public CloudTrailReloadTriggerTask() {
}
@@ -78,6 +82,24 @@ public class CloudTrailReloadTriggerTask extends
ServiceSupport implements Camel
this.camelContext = camelContext;
}
+ public boolean isReloadEnabled() {
+ return reloadEnabled;
+ }
+
+ /**
+ * Whether Camel should be reloaded on AWS secret updated
+ */
+ public void setReloadEnabled(boolean reloadEnabled) {
+ this.reloadEnabled = reloadEnabled;
+ }
+
+ /**
+ * A map of the updated secrets with the latest updated time.
+ */
+ public Map<String, Instant> getUpdates() {
+ return Collections.unmodifiableMap(updates);
+ }
+
@Override
protected void doStart() throws Exception {
super.doStart();
@@ -121,6 +143,8 @@ public class CloudTrailReloadTriggerTask extends
ServiceSupport implements Camel
}
cloudTrailClient = null;
}
+
+ updates.clear();
}
@Override
@@ -153,8 +177,11 @@ public class CloudTrailReloadTriggerTask extends
ServiceSupport implements Camel
for (Resource res : a) {
String name = res.resourceName();
if (matchSecret(name)) {
- LOG.info("Update for secret: {} detected,
triggering a CamelContext reload", name);
- triggerReloading = true;
+ updates.put(name, event.eventTime());
+ if (isReloadEnabled()) {
+ LOG.info("Update for secret: {} detected,
triggering a CamelContext reload", name);
+ triggerReloading = true;
+ }
break;
}
}
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java
b/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java
index cf29b710953..2dc5fcb2af9 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java
@@ -23,7 +23,6 @@ package org.apache.camel.spi;
* For example the AWS vault is using this to periodically check for secrets
refreshed in AWS to trigger Camel to reload
* to use the updated secrets.
*/
-@FunctionalInterface
public interface PeriodTaskScheduler {
/**
@@ -35,4 +34,12 @@ public interface PeriodTaskScheduler {
*/
void schedulePeriodTask(Runnable task, long period);
+ /**
+ * Gets an existing task by a given type, assuming there is only one task
of the given type.
+ *
+ * @param type the type of the task
+ * @return the task, or <tt>null</tt> if no tasks exists
+ */
+ <T> T getTaskByType(Class<T> type);
+
}
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
index 754e3f6d43a..948f9c5b92e 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
@@ -35,6 +35,20 @@ public final class DefaultPeriodTaskScheduler extends
TimerListenerManager imple
addTimerListener(new TaskWrapper(task, period));
}
+ @Override
+ public <T> T getTaskByType(Class<T> type) {
+ for (TimerListener listener : getListeners()) {
+ Object task = listener;
+ if (listener instanceof TaskWrapper) {
+ task = ((TaskWrapper) listener).getTask();
+ }
+ if (type.isInstance(task)) {
+ return type.cast(task);
+ }
+ }
+ return null;
+ }
+
@Override
public void addTimerListener(TimerListener listener) {
if (listener instanceof TaskWrapper) {
@@ -55,6 +69,10 @@ public final class DefaultPeriodTaskScheduler extends
TimerListenerManager imple
this.period = period;
}
+ public Runnable getTask() {
+ return task;
+ }
+
@Override
public void onTimer() {
if (watch.taken() > period) {
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/TimerListenerManager.java
b/core/camel-support/src/main/java/org/apache/camel/support/TimerListenerManager.java
index 252f6a86ba5..8ffa869dc44 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/TimerListenerManager.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/TimerListenerManager.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.support;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
@@ -133,6 +134,13 @@ public class TimerListenerManager extends ServiceSupport
implements Runnable, Ca
LOG.debug("Removed TimerListener: {}", listener);
}
+ /**
+ * A read-only set of the registered listeners
+ */
+ protected Set<TimerListener> getListeners() {
+ return Collections.unmodifiableSet(listeners);
+ }
+
@Override
protected void doStart() throws Exception {
ObjectHelper.notNull(camelContext, "camelContext", this);