You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by da...@apache.org on 2019/07/26 09:54:24 UTC
svn commit: r1863795 - in /felix/trunk/configadmin-plugins/interpolation/src:
main/java/org/apache/felix/configadmin/plugin/interpolation/
test/java/org/apache/felix/configadmin/plugin/interpolation/
Author: davidb
Date: Fri Jul 26 09:54:23 2019
New Revision: 1863795
URL: http://svn.apache.org/viewvc?rev=1863795&view=rev
Log:
Rename substitution config admin plugin to interpolation.
Added:
felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
felix/trunk/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
Removed:
felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/K8SSecretsConfigurationPlugin.java
felix/trunk/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/K8SSecretsConfigurationPluginTest.java
Modified:
felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java
Modified: felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java?rev=1863795&r1=1863794&r2=1863795&view=diff
==============================================================================
--- felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java (original)
+++ felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java Fri Jul 26 09:54:23 2019
@@ -29,7 +29,7 @@ public class Activator implements Bundle
static final String DIR_PROPERTY = "org.apache.felix.configadmin.plugin.interpolation.dir";
static final int PLUGIN_RANKING = 500;
- static final Logger LOG = LoggerFactory.getLogger(K8SSecretsConfigurationPlugin.class);
+ static final Logger LOG = LoggerFactory.getLogger(InterpolationConfigurationPlugin.class);
@Override
public void start(BundleContext context) throws Exception {
@@ -39,7 +39,7 @@ public class Activator implements Bundle
return;
}
- ConfigurationPlugin plugin = new K8SSecretsConfigurationPlugin(directory);
+ ConfigurationPlugin plugin = new InterpolationConfigurationPlugin(directory);
Dictionary<String, Object> props = new Hashtable<>();
props.put(ConfigurationPlugin.CM_RANKING, PLUGIN_RANKING);
props.put(DIR_PROPERTY, directory);
Added: felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java?rev=1863795&view=auto
==============================================================================
--- felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java (added)
+++ felix/trunk/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java Fri Jul 26 09:54:23 2019
@@ -0,0 +1,131 @@
+/*
+ * 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.felix.configadmin.plugin.interpolation;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationPlugin;
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class InterpolationConfigurationPlugin implements ConfigurationPlugin {
+ private static final String PREFIX = "$[";
+ private static final String SUFFIX = "]";
+
+ private static final String SECRET_PREFIX = PREFIX + "secret:";
+ private static final Pattern SECRET_PATTERN = createPattern(SECRET_PREFIX);
+ private static final String ENV_PREFIX = PREFIX + "env:";
+ private static final Pattern ENV_PATTERN = createPattern(ENV_PREFIX);
+
+ private static Pattern createPattern(String prefix) {
+ return Pattern.compile("\\Q" + prefix + "\\E.+\\Q" + SUFFIX + "\\E");
+ }
+
+ private final File directory;
+
+ InterpolationConfigurationPlugin(String dir) {
+ directory = new File(dir);
+ getLog().info("Configured directory for secrets: {}", dir);
+ }
+
+ private Logger getLog() {
+ return Activator.LOG;
+ }
+
+ @Override
+ public void modifyConfiguration(ServiceReference<?> reference, Dictionary<String, Object> properties) {
+ for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements(); ) {
+ String key = keys.nextElement();
+ Object val = properties.get(key);
+ if (val instanceof String) {
+ String sv = (String) val;
+ int idx = sv.indexOf(PREFIX);
+ if (idx != -1) {
+ String varStart = sv.substring(idx);
+ Object pid = properties.get(Constants.SERVICE_PID);
+ Object newVal = null;
+ if (varStart.startsWith(SECRET_PREFIX)) {
+ newVal = replaceVariablesFromFile(key, sv, pid);
+ } else if (varStart.startsWith(ENV_PREFIX)) {
+ newVal = replaceVariablesFromEnvironment(key, sv, pid);
+ }
+
+ if (newVal != null)
+ properties.put(key, newVal);
+
+ getLog().info("Replaced value of configuration property '{}' for PID {}", key, pid);
+ }
+ }
+ }
+ }
+
+ Object replaceVariablesFromEnvironment(final String key, final String value, final Object pid) {
+ return replaceVariables(ENV_PREFIX, ENV_PATTERN, key, value, pid, n -> System.getenv(n));
+ }
+
+ Object replaceVariablesFromFile(final String key, final String value, final Object pid) {
+ return replaceVariables(SECRET_PREFIX, SECRET_PATTERN, key, value, pid, n -> {
+ if (n.contains("..")) {
+ getLog().error("Illegal secret location: " + n + " Going up in the directory structure is not allowed");
+ return null;
+ }
+
+ File file = new File(directory, n);
+ if (!file.isFile()) {
+ getLog().warn("Cannot replace variable. Configured path is not a regular file: " + file);
+ return null;
+ }
+ byte[] bytes;
+ try {
+ bytes = Files.readAllBytes(file.toPath());
+ } catch (IOException e) {
+ getLog().error("Problem replacing configuration property '{}' for PID {} from file {}",
+ key, pid, file, e);
+
+ return null;
+ }
+ return new String(bytes).trim();
+ });
+ }
+
+ Object replaceVariables(final String prefix, final Pattern pattern,
+ final String key, final String value, final Object pid,
+ final Function<String, String> valueSource) {
+ final Matcher m = pattern.matcher(value);
+ final StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ final String var = m.group();
+
+ final int len = var.length();
+ final String varName = var.substring(prefix.length(), len - SUFFIX.length());
+ String replacement = valueSource.apply(varName);
+ if (replacement != null)
+ m.appendReplacement(sb, Matcher.quoteReplacement(replacement));
+ }
+ m.appendTail(sb);
+
+ return sb.toString();
+ }
+}
Added: felix/trunk/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java?rev=1863795&view=auto
==============================================================================
--- felix/trunk/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java (added)
+++ felix/trunk/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java Fri Jul 26 09:54:23 2019
@@ -0,0 +1,101 @@
+/*
+ * 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.felix.configadmin.plugin.interpolation;
+
+import org.apache.felix.configadmin.plugin.interpolation.InterpolationConfigurationPlugin;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.junit.Assert.assertEquals;
+
+public class InterpolationConfigurationPluginTest {
+ @Test
+ public void testModifyConfiguration() throws Exception {
+ String envUser = System.getenv("USER");
+ String userVar;
+ if (envUser == null) {
+ envUser = System.getenv("USERNAME"); // maybe we're on Windows
+ userVar = "USERNAME";
+ } else {
+ userVar = "USER";
+ }
+
+ String rf = getClass().getResource("/testfile").getFile();
+
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(
+ new File(rf).getParent());
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("foo", "bar");
+ dict.put("replaced", "$[secret:testfile]");
+ dict.put("cur.user", "$[env:" + userVar + "]");
+ dict.put("intval", 999);
+ dict.put(Constants.SERVICE_PID, "my.service");
+ plugin.modifyConfiguration(null, dict);
+
+ assertEquals(5, dict.size());
+ assertEquals("bar", dict.get("foo"));
+ assertEquals("line1\nline2", dict.get("replaced"));
+ assertEquals(envUser, dict.get("cur.user"));
+ assertEquals("my.service", dict.get(Constants.SERVICE_PID));
+ assertEquals(999, dict.get("intval"));
+ }
+
+ @Test
+ public void testSubdirReplacement() throws Exception {
+ String rf = getClass().getResource("/sub/sub2/testfile2").getFile();
+
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(
+ new File(rf).getParentFile().getParent());
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("substed", "$[secret:sub2/testfile2]");
+ dict.put("not1", "$[secret:../testfile]");
+ dict.put("not2", "$[secret:sub2/../../testfile.txt]");
+ plugin.modifyConfiguration(null, dict);
+
+ assertEquals(3, dict.size());
+ assertEquals("the_content", dict.get("substed"));
+ assertEquals("$[secret:../testfile]", dict.get("not1"));
+ assertEquals("$[secret:sub2/../../testfile.txt]", dict.get("not2"));
+ }
+
+ @Test
+ public void testReplacement() throws Exception {
+ String rf = getClass().getResource("/testfile.txt").getFile();
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(
+ new File(rf).getParent());
+
+ assertEquals("xxla la layy", plugin.replaceVariablesFromFile("akey", "xx$[secret:testfile.txt]yy", "apid"));
+ String doesNotReplace = "xx$[" + rf + "]yy";
+ assertEquals(doesNotReplace, plugin.replaceVariablesFromFile("akey", doesNotReplace, "apid"));
+ }
+
+ @Test
+ public void testNoReplacement() throws IOException {
+ String rf = getClass().getResource("/testfile.txt").getFile();
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(
+ new File(rf).getParent());
+
+ assertEquals("foo", plugin.replaceVariablesFromFile("akey", "foo", "apid"));
+ }
+}