ISIS-1510: allows configuration properties to be overridden from either system properties or a new ISIS_OPTS environment variable
Project: http://git-wip-us.apache.org/repos/asf/isis/repo Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/62853b95 Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/62853b95 Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/62853b95 Branch: refs/heads/master Commit: 62853b95249d48212ca340765fa498e82b14d0a3 Parents: b09f968 Author: Dan Haywood <[email protected]> Authored: Wed Oct 5 11:44:58 2016 +0200 Committer: Dan Haywood <[email protected]> Committed: Wed Oct 5 11:44:58 2016 +0200 ---------------------------------------------------------------------- .../guides/_ugbtb_deployment_docker.adoc | 56 ++++++++++++++++- .../configbuilder/IsisConfigurationBuilder.java | 23 +++++-- .../PrimerForEnvironmentVariableISIS_OPT.java | 66 ++++++++++++++++++++ ...PrimerForEnvironmentVariablesIsisPrefix.java | 35 +++++++++++ .../PrimerForSystemProperties.java | 52 +++++++++++++++ .../runtime/optionhandler/OptionHandler.java | 3 +- .../core/webapp/IsisWebAppBootstrapper.java | 4 +- .../wicket/viewer/IsisWicketApplication.java | 2 +- 8 files changed, 230 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/adocs/documentation/src/main/asciidoc/guides/_ugbtb_deployment_docker.adoc ---------------------------------------------------------------------- diff --git a/adocs/documentation/src/main/asciidoc/guides/_ugbtb_deployment_docker.adoc b/adocs/documentation/src/main/asciidoc/guides/_ugbtb_deployment_docker.adoc index 26ed652..1a42d17 100644 --- a/adocs/documentation/src/main/asciidoc/guides/_ugbtb_deployment_docker.adoc +++ b/adocs/documentation/src/main/asciidoc/guides/_ugbtb_deployment_docker.adoc @@ -5,6 +5,21 @@ :_imagesdir: images/ +When running the application within a Docker container, the problem that must be solved is to override the +configuration properties baked into the war file, eg to point to the app to a different JDBC URL. + +There are several options. + +[WARNING] +==== +All the options here rely on starting the Docker container with a set of arguments, some of which would very likely +be passwords for database connections etc. As such these techniques are only suitable where the security of the +Docker host can be assured. +==== + + +== Using an `overrides.properties` file + In addition to loading the regular configuration properties from `WEB-INF` directory (described xref:rgcfg.adoc#_rgcfg_configuration-files[here]), Apache Isis will also load the `overrides.properties` file. @@ -16,7 +31,7 @@ While the regular configuration files are "baked into" the application WAR file, created dynamically as part of the Docker `ENTRYPOINT` script, eg as documented in the link:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/[Dockerfile best practices]. -This, Docker can be supported relatively trivially: +Thus, Docker can be supported as follows: * use `mvn` (as currently) to create a WAR file; set up with the `pom.xml` with the JDBC drivers of all DB servers that you might want to connect to (hsqldb, sql server, postgresql etc) @@ -33,3 +48,42 @@ over the WAR file itself. * use `ENTRYPOINT` (and probably also `CMD`) to invoke above script. + + +== Using system properties + +(As of `1.13.1-SNAPSHOT`), the servlet context initializer will search for any system properties called `isis.xxx` + and if present will use them as overrides. + +Thus, an alternative option for a Docker image is to bootstrap the servlet container (Tomcat, Jetty) with appropriate +system properties set up. For example, with Tomcat this can be done by writing into the `conf/catalina.properties` file +(see for example link:http://stackoverflow.com/a/16566920[this stackoverflow] post). + +The Docker's `ENTRYPOINT` therefore just needs to parse the Docker container's own command line arguments and use to +create this file. + + +== Using the `ISIS_OPT` environment variable + +(As of `1.13.1-SNAPSHOT`), the servlet context initializer will search for an environment variable called `$ISIS_OPTS` + and if present will parse the content as a set of key/value pairs. Each key/value pair is separated by "||". + +For example: + +[source,bash] +---- +export ISIS_OPTS="isis.appManifest=domainapp.app.DomainAppAppManifestWithFixtures||isis.objects.editing=false" +---- + +can be used to run with a different app manifest, and also to disable editing of properties. + +To use a different separator, set the (optional) `$ISIS_OPTS_SEPARATOR` variable. + +[source,bash] +---- +export ISIS_OPTS_SEPARATOR=";" +export ISIS_OPTS="isis.appManifest=domainapp.app.DomainAppAppManifestWithFixtures;isis.objects.editing=false" +---- + +The Docker's `ENTRYPOINT` therefore just needs to parse the Docker container's own command line arguments and use to +set this environment variable. http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/IsisConfigurationBuilder.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/IsisConfigurationBuilder.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/IsisConfigurationBuilder.java index 447983d..ba75b22 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/IsisConfigurationBuilder.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/IsisConfigurationBuilder.java @@ -106,7 +106,12 @@ public final class IsisConfigurationBuilder { return composite; } - public void addDefaultConfigurationResources() { + public void addDefaultConfigurationResourcesAndPrimers() { + addDefaultConfigurationResources(); + addDefaultPrimers(); + } + + private void addDefaultConfigurationResources() { IsisConfigurationDefault.ContainsPolicy ignorePolicy = IsisConfigurationDefault.ContainsPolicy.IGNORE; NotFoundPolicy continuePolicy = NotFoundPolicy.CONTINUE; @@ -147,6 +152,11 @@ public final class IsisConfigurationBuilder { addConfigurationResource("overrides.properties", NotFoundPolicy.CONTINUE, IsisConfigurationDefault.ContainsPolicy.OVERWRITE); } + private void addDefaultPrimers() { + primeWith(new PrimerForSystemProperties()); + primeWith(new PrimerForEnvironmentVariablesIsisPrefix()); + primeWith(new PrimerForEnvironmentVariableISIS_OPT()); + } //endregion @@ -300,11 +310,15 @@ public final class IsisConfigurationBuilder { return true; } - public void primeWith(final OptionHandler optionHandler) { + public interface Primer { + void prime(IsisConfigurationBuilder isisConfigurationBuilder); + } + + public void primeWith(final Primer primer) { ensureNotLocked(); - LOG.debug("priming configurations for '{}'", optionHandler); - optionHandler.prime(this); + LOG.debug("priming configurations for '{}'", primer); + primer.prime(this); } //endregion @@ -376,5 +390,4 @@ public final class IsisConfigurationBuilder { //endregion - } http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariableISIS_OPT.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariableISIS_OPT.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariableISIS_OPT.java new file mode 100644 index 0000000..e0bebd9 --- /dev/null +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariableISIS_OPT.java @@ -0,0 +1,66 @@ +/* + * 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.isis.core.commons.configbuilder; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.base.Splitter; +import com.google.common.collect.Maps; + +public class PrimerForEnvironmentVariableISIS_OPT implements IsisConfigurationBuilder.Primer { + + public static final String OPT_ENV = "ISIS_OPTS"; + public static final String SEPARATOR_ENV = "ISIS_OPTS_SEPARATOR"; + public static final String SEPARATOR_DEFAULT = "||"; + + @Override + public void prime(final IsisConfigurationBuilder builder) { + final String separator = determineSeparator(); + final String env = System.getenv(OPT_ENV); + for (Map.Entry<String, String> entry : fromEnv(env, separator).entrySet()) { + final String envVarName = entry.getKey(); + final String envVarValue = entry.getValue(); + builder.put(envVarName, envVarValue); + } + } + + private static String determineSeparator() { + final String separator = System.getenv(SEPARATOR_ENV); + if (separator != null) { + return separator; + } + return SEPARATOR_DEFAULT; + } + + private static Map<String, String> fromEnv(final String env, final String separator) { + final LinkedHashMap<String, String> map = Maps.newLinkedHashMap(); + if (env != null) { + final List<String> keyAndValues = Splitter.on(separator).splitToList(env); + for (String keyAndValue : keyAndValues) { + final List<String> parts = Splitter.on("=").splitToList(keyAndValue); + if (parts.size() == 2) { + map.put(parts.get(0), parts.get(1)); + } + } + } + return map; + } +} http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariablesIsisPrefix.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariablesIsisPrefix.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariablesIsisPrefix.java new file mode 100644 index 0000000..b5e5a4d --- /dev/null +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForEnvironmentVariablesIsisPrefix.java @@ -0,0 +1,35 @@ +/* + * 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.isis.core.commons.configbuilder; + +import java.util.Map; + +public class PrimerForEnvironmentVariablesIsisPrefix implements IsisConfigurationBuilder.Primer { + @Override + public void prime(final IsisConfigurationBuilder builder) { + final Map<String, String> envVars = System.getenv(); + for (Map.Entry<String, String> entry : envVars.entrySet()) { + final String envVarName = entry.getKey(); + final String envVarValue = entry.getValue(); + if (envVarName.startsWith("isis.")) { + builder.put(envVarName, envVarValue); + } + } + } +} http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForSystemProperties.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForSystemProperties.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForSystemProperties.java new file mode 100644 index 0000000..1dc9002 --- /dev/null +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/configbuilder/PrimerForSystemProperties.java @@ -0,0 +1,52 @@ +/* + * 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.isis.core.commons.configbuilder; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import com.google.common.collect.Maps; + +public class PrimerForSystemProperties implements IsisConfigurationBuilder.Primer { + + @Override + public void prime(final IsisConfigurationBuilder builder) { + final Properties properties = System.getProperties(); + for (Map.Entry<String, String> entry : fromProperties(properties).entrySet()) { + final String envVarName = entry.getKey(); + final String envVarValue = entry.getValue(); + if (envVarName.startsWith("isis.")) { + builder.put(envVarName, envVarValue); + } + } + } + + private static Map<String, String> fromProperties(final Properties properties) { + final LinkedHashMap<String, String> map = Maps.newLinkedHashMap(); + for (final Map.Entry<Object, Object> entry : properties.entrySet()) { + final Object key = entry.getKey(); + final Object value = entry.getValue(); + if (key instanceof String && value instanceof String) { + map.put((String) key, (String) value); + } + } + return map; + } +} http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/metamodel/src/main/java/org/apache/isis/core/runtime/optionhandler/OptionHandler.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/runtime/optionhandler/OptionHandler.java b/core/metamodel/src/main/java/org/apache/isis/core/runtime/optionhandler/OptionHandler.java index 1419063..366af3c 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/runtime/optionhandler/OptionHandler.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/runtime/optionhandler/OptionHandler.java @@ -24,12 +24,11 @@ import org.apache.commons.cli.Options; import org.apache.isis.core.commons.configbuilder.IsisConfigurationBuilder; -public interface OptionHandler { +public interface OptionHandler extends IsisConfigurationBuilder.Primer { void addOption(Options options); boolean handle(CommandLine commandLine, BootPrinter bootPrinter, Options options); - void prime(IsisConfigurationBuilder isisConfigurationBuilder); } http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/runtime/src/main/java/org/apache/isis/core/webapp/IsisWebAppBootstrapper.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/isis/core/webapp/IsisWebAppBootstrapper.java b/core/runtime/src/main/java/org/apache/isis/core/webapp/IsisWebAppBootstrapper.java index 603d44e..9123aea 100644 --- a/core/runtime/src/main/java/org/apache/isis/core/webapp/IsisWebAppBootstrapper.java +++ b/core/runtime/src/main/java/org/apache/isis/core/webapp/IsisWebAppBootstrapper.java @@ -40,9 +40,9 @@ import org.apache.isis.core.runtime.logging.IsisLoggingConfigurer; import org.apache.isis.core.runtime.runner.IsisInjectModule; import org.apache.isis.core.runtime.runner.opts.OptionHandlerInitParameters; import org.apache.isis.core.runtime.system.DeploymentType; -import org.apache.isis.core.runtime.system.session.IsisSessionFactoryBuilder; import org.apache.isis.core.runtime.system.SystemConstants; import org.apache.isis.core.runtime.system.session.IsisSessionFactory; +import org.apache.isis.core.runtime.system.session.IsisSessionFactoryBuilder; import org.apache.isis.core.webapp.config.ResourceStreamSourceForWebInf; /** @@ -84,7 +84,7 @@ public class IsisWebAppBootstrapper implements ServletContextListener { loggingConfigurer.configureLogging(webInfDir, new String[0]); final IsisConfigurationBuilder isisConfigurationBuilder = obtainIsisConfigurationBuilder(servletContext); - isisConfigurationBuilder.addDefaultConfigurationResources(); + isisConfigurationBuilder.addDefaultConfigurationResourcesAndPrimers(); final DeploymentType deploymentType = determineDeploymentType(servletContext, isisConfigurationBuilder); addConfigurationResourcesForDeploymentType(isisConfigurationBuilder, deploymentType); http://git-wip-us.apache.org/repos/asf/isis/blob/62853b95/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java ---------------------------------------------------------------------- diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java index 5839215..c40b7d9 100644 --- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java +++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java @@ -256,7 +256,7 @@ public class IsisWicketApplication getResourceSettings().setParentFolderPlaceholder("$up$"); final IsisConfigurationBuilder isisConfigurationBuilder = obtainConfigBuilder(); - isisConfigurationBuilder.addDefaultConfigurationResources(); + isisConfigurationBuilder.addDefaultConfigurationResourcesAndPrimers(); final IsisConfigurationDefault configuration = isisConfigurationBuilder.getConfiguration();
