For my Play 2.2/Scala application (built with SBT), I would like to deploy different configuration files depending on the environment I'm deploying to (e.g. to couple a deployment with a particular database server). How does one create different variants of the application's configuration file (conf/application.conf) for different deployment targets? Hopefully variants can be generated from a base version?
What I'm used to from .NET is to have a base configuration file (Web.config), which undergoes a certain transformation depending on the profile one is deploying (e.g. Production). Does one use a similar technique in the Play/Scala world?
Alternative configuration files are covered in Play's documentation quite well in section Specifying alternative configuration file.
In short - in application.conf you place default configuration of your app, and additionally you need to create additional files for you environment(s) ie. life.conf, dev.conf etc. In these files you first need to include application.conf (which will read whole default configuration) and next just overwrite only parts which have to be changed - ie. DB credentials, it could be dev.conf:
include "application.conf"
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:alternative-database-for-dev-testing"
db.default.user=developer
db.default.password="developerpass"
So finally you start your application (after dist) as
./start -Dconfig.resource=dev.conf
or with the Play console
play -Dconfig.resource=dev.conf run
Several tips:
It's good idea to do not place your 'life' DB credentials in default application.conf file, if some dev will forget to include his dev.conf he won't damage the production DB, instead you should put it in prod.conf.
Also these additional configs shouldn't be placed in any VCS (ie. git) repository - creating them directly on target machine (and ignoring in repository) give you sure, that people who shouldn't know the life database credentials won't see it.
It's also possible to use remote alternative config file, which can be useful ie. when you deploying several instances of the same app ie. on several hosts in the cloud.
Each dev can has own config file ie dev_aknuds1.conf, dev_biesior.conf etc, so you can ignore them with one pattern dev_*.conf in repo.
Finally you can just create a shell script (unix) or bat file (Windows) to start using choosen config file like start_dev.sh, run_dev.sh etc. so you won't need to write -Dconfig.resource=... each time
Related
I have EJBs deployed on several different servers, for different environments. I have many projects that use these EJBs. I usually just run my projects against the DEV server EJBs, but sometimes I need to run against the TEST or PROD environment EJBs. This necessitates having to comment out all of the DEV nodes in my jboss-client-ejb.properties file and uncomment all of the TEST nodes. But then if I forget to change them back, I may mess up some data if I run it later. What I would like to do is create a different runtime configuration for each environment, and have each runtime config use a different version of the jboss-client-ejb.properties. Is there a way to do this? If so how? I have looked at all of properties of a run configuration, and don't see anything helpful.
In eclipse preferences search for string variable substitution. Here create variables that point to multiple config files for each of your environments. Then create multiple run configurations and for each one (like dev or prod) add a program argument that points to your string variable defined in your preferences like this -DmyconfigFile={$MyDevPropertiesFilePath}, or you could hard code the config path and have multiple runtime configurations that use different config files. Key point here is create multiple runtime launch configurations for each environment and add the properties for each environment that point to the config file respective to each environment. This way you can easily select the launch menu and decide to run "dev" "prod" or whatever you name your multiple configurations. Trying to do this with one runtime configuration will cause pain as you say, because it is easy to forget to revert or change the config file you want to to use. Hope that helps. Also if you create a new workspace you can export your runtime configurations using the export wizard which is also helpful for passing on to other developers or putting in source control.
P.S Looking more at your question you wan to pass in the config file path as a program argument, you are correct there are no specific options for setting this file path. Using program arguments with multiple launch configurations.
Is it possible to use environmental variable substitution when including another configuration file?
I would like to have something like that:
include "${HOME}/.foo/credentials.conf"
Configuration documentation mentions locating resources and include substitution but not together.
This works:
include "/home/me/.foo/credentials.conf"
and my HOME is correctly set.
But all attempts to make include "${HOME}/.foo/credentials.conf" so far failed
Background:
I deliberately want to keep credentials and other sensitive data out of our code base but have them available for local dev environments for testing. I am aware of more sophisticated solutions using external storage like hinted here Playframework 2 - Storing your credentials and we use something similar for live and preview environments but these are not suitable for local dev setup.
An alternative is to include credentials file to code base after all but use git ignore to prevent pushing it, but it is fragile solution and risk is someone will eventually push it and compromise credentials.
TBH I'm not even able to include file with absolute path /home/me... anyway approach which will work for you is just using alternative conf file as described in the same doc:
In file /home/me/.foo/credentials.conf you need to include application.conf - Play will fallback it to the file in classpath (this which is under VCS):
include "application.conf"
myCredentials.user="Espinosa"
myCredentials.password="fooBar123"
then run/start your app with this config file locally:
play -Dconfig.file=${HOME}/.foo/credentials.conf ~run
and that's it.
Note: of course it's easier to setup this addition in your IDE (i.e. IntelliJ: Run > Edit configurations) or write a shell script containing this command
I've chosen a solution to our config file process and need to justify it. I'd appreciate insight and criticism. Thanks!
Problem:
Our web applications have a single application.cfm file containing variables and conditionals
<cfif url = "*dev*" or "jargon123">
this is a dev enviroment, do devy things
</cfif>
So a dev new to the application will deploy a local instance. Fire it up and start poking around. Problem is that the config file contains production values. It starts hitting production data and sending production emails. Also, since the url they are hitting is http://App_name:PORT or http://localhost - the dev conditionals are never set. So there is more production stuff happening in dev.
What other co-workers want:
A Switch statement. The app.cfm will lead with an environment variable set to "development", then declares general variables. It will then go into a switch statement and declare environment specific variables. I disagree with this method as some of our config files are 100 - 250 lines. That can be a massive Switch statement I don't want to muck around in.
My chosen solution:
App.cfm has been deleted and removed from version control. We now have multiple Applicaiton.Enviroment.cfm files, i.e. Applicaiton.Prod.cfm, Application.Dev.cfm, Applicaiton.MyName.cfm etc. This file contains all of the environment specific data. I moved Production specific settings out of conditionals and into App.Prod.cfm. Deployments to new environments are now 1. Duplicate App.Dev.cfm as App.Me.cfm and commit. 2. Update all variables to my personal data (email, login, etc) 3. Duplicate App.me.cfm as App.cfm and use for config file.
I won't go into why I'm not doing the other solutions but here is my reason for my solutions:
Forces the deployment engineer into selecting the right config file for the environment. The app won't work without an app.cfm
Limits potential of user error. Scenario would be a user copies data into a new environment mode and accidentally copies production content.
It's cleaner and easier to work with - config value's are completely compartmentalized from each other.
I've found a lot of articles on working with environment specific config files but not why they are better. That's the motivation behind this post.
I would also delete the production config and provide only development versions of the config file. Reasons:
a config file could contain security relevant data
many developers are just lazzy, if the application runs, the don't care about the config
if the developer do not use the currently provided mechanisms (the dev url), who could you be sure they set the environment variable?
using the live config during testing could result in active debug options on the production later (forgotten to remove from configuration)
You (development) need to be able to switch between different configurations for different versions of your software at any time. If each setup has its own configuration file, this is a lot easier than if they all share the same file.
If you have all configuration in a single file, you have to read the whole big file, deciding which parts to ignore. This is messier than just reading the whole file.
(I assume that you can have multiple versions of the software installed concurrently in different locations on the same machine. If you can't, you have a bigger problem. But even so, having separate configuration files is beneficial.)
Those are strong 'pros' for separate configuration files - they outweigh the minor 'con': you have to identify where the configuration file is by some mechanism or another. It might be via an environment variable or via a command-line option, with a suitable default if neither is specified. Command-line should override environment.
I'm using NAnt to build an ASP.NET MVC project.
The NAnt script then creates a zip package, containing a deploy script and all the necessary files.
The deploy script backs up the current running website, sets up the newer version of the website and updates the DB.
This works fine for a single environment.
However, we're asked more and more to set up a Staging/Acceptance environment next to the production. These environments, of course, differ in file structure, DB server, config settings etc.
How can I best handle this in the deploy scripts? I don't want to create separate variables for each environment, distinguishable by name only.
Providing defaults and providing the variables in separate files seems more logical.
Does anyone have practical experiences with this?
Store the things that you think are likely to change between environments in config files.
Visual Studio can do the heavy lifting here if you like; you can create settings and specify default values from the Settings tab of a Visual Studio project's properties.
This will create the config file for you and provide strongly-typed access through Properties.Settings.Default.
As for handling multiple environments through your build, I've seen some people recommend maintaining multiple copies of the config files - one for each environment for example - and others recommend using nant to modify the config files during the build or deployment phase. You can use a property passed to nant on the command line (for example) to select which environment you are building (or deploying, depending on how you're doing it).
I don't recommend either of these approaches because:
They both require changes to your build to support new environments.
If you change a setting in a deployed environment and forget to update the build then the next deployment will reset the change (somewhat defeating the point of config settings).
If someone creates a new environment (lets say they want to explore issues arising from upgrading to a new version of SQL Server for example) and doesn't fancy creating all new config files in the build system, they might decide to just use an existing environment's settings. Let's say they choose to deploy using the live settings and forget to change something afterwards. Your new 'test' environment could now be pointing to live kit.
I create a copy of each config file (called web.config.example, for example) and comment out the settings within them (unless they have meaningful defaults). I check these in and have those deployed instead of the real web.config (that is, web.config is NOT deployed automatically. web.config.example is deployed as web.config.example.
The admin of the new environment will have to copy and rename the file to web.config and provide meaningful values). I also put all the calls to the settings behind my own wrapper class - if a mandatory setting is missing I throw an exception.
The build and my environments no longer depend on each other - one build can be deployed to any environment.
If a setting is missing (a new environment or a new setting in an existing environment) then you get a nice clear exception raised to tell the admin what to do.
Existing settings are not altered after an upgrade because only the .example files were updated. It's an admin task to compare the current settings with the latest example and revise if necessary.
To configure the deployment, you could put all the environmental settings (install paths, etc) into nant properties and move them into a separate file (settings.build for example) then use the nant include task to include that file at the top of your deployment file (deploy.build for example). You can then deploy a new version of deploy.build without overwriting your config changes as they are in settings.build. If a new property is introduced into deploy.build nant will fail with a nice message to tell you that you haven't set that property.
I am developing a logging framework using Log4j. I am not able to figure out how to maintain separate log files for different environment, i.e., development, testing, staging and production.
Firstly you'll need a different copy of your log4j.xml for each environment.
Lets call it log4j-dev.xml, log4j-test.xml, log4j-stage.xml and log4j-prod.xml each having their own settings like log file name and log levels.
You then pass in the corresponding file at the the server startup as a system property like below -
-Dlog4j.configuration=log4j-dev.xml
This URL has the example on how to pass this for Tomcat. The concept is the same for whichever server you are deploying on.
On Windows, I have used "set CATALINA_OPTS=-Dlog4j.configurationFile=log4j2-dev.xml" instead of log4j.configuration