Where to store globally accessible variables using Dancer - config

I'd like store variables in a configuration file so that I can just set them in one place and access them whenever needed.
Where is the place to put such variables in a Dancer app, and how do I access them?

The best way is to have one config.yml file with default global settings, like the following:
# appdir/config.yml
logger: 'file'
layout: 'main'
Your Question: How to access?
Ans: A Dancer application can use the 'config' keyword to easily access the settings within its config file, for instance:
get '/appname' => sub {
return "This is " . config->{appname};
};
This makes keeping your application's settings all in one place simple and easy - you shouldn't need to worry about implementing all that yourself.
You may well want to access your webapp's configuration from outside your webapp. Using Dancer, you can use the values from config.yml and some additional default values:
# bin/script1.pl
use Dancer ':script';
print "template:".config->{template}."\n"; #simple
print "log:".config->{log}."\n"; #undef
Note that config->{log} should result undef error on a default scaffold since you did not load the environment and in the default scaffold log is defined in the environment and not in config.yml. Hence undef.
If you want to load an environment you need to tell Dancer where to look for it. One way to do so, is to tell Dancer where the webapp lives. From there Dancer deducts where the config.yml file is (typically $webapp/config.yml).
# bin/script2.pl
use FindBin;
use Cwd qw/realpath/;
use Dancer ':script';
#tell the Dancer where the app lives
my $appdir=realpath( "$FindBin::Bin/..");
Dancer::Config::setting('appdir',$appdir);
Dancer::Config::load();
#getter
print "environment:".config->{environment}."\n"; #development
print "log:".config->{log}."\n"; #value from development environment
By default Dancer loads development environment (typically $webapp/environment/development.yml). If you want to load an environment other than the default, try this:
# bin/script2.pl
use Dancer ':script';
#tell the Dancer where the app lives
Dancer::Config::setting('appdir','/path/to/app/dir');
#which environment to load
config->{environment}='production';
Dancer::Config::load();
#getter
print "log:".config->{log}."\n"; #has value from production environment

Related

How can appSettings.{environment}.json be loaded before environment is known? (AspNetCore)

According to microsoft blog the ASPNETCORE_ENVIRONMENT variable is loaded in order:
appsettings.json file
appsettings.{env.EnvironmentName}.json file
The local User Secrets File
Environment Variables
Command Line Arguments (or equivalently launchSettings.json)
and "The last key loaded wins".
Questions:
But how can the file appsettings.{env.EnvironmentName}.json be loaded before the final Environment is known?
Can it happen that I set 'Staging' environment through command-line and appSettings.Development.json is loaded because during step 2 it is not yet known?
There are two sets of configuration for an ASP.NET Core application:
The configuration for the WebHost.
The configuration for the application itself.
First the WebHost configuration is built (source):
_config = new ConfigurationBuilder()
.AddEnvironmentVariables(prefix: "ASPNETCORE_")
.Build();
As the source code shows, the configuration for the WebHost uses only environment variables and only those that are prefixed with ASPNETCORE_. One of those environment variables is, unsurprisingly, ASPNETCORE_ENVIRONMENT.
A little later down the line, an implementation of IHostingEnvironment is instantiated. This ends up using _config to retrieve a configuration setting named environment, which comes from the ASPNETCORE_ENVIRONMENT variable. If there is no such value, it defaults to Production.
Next up, the configuration for the application itself gets built. At step 2 in your question, the value of env.EnvironmentName is from the IHostingEnvironment I've already mentioned. If you were to set an environment value of e.g. Staging as a command-line argument, it would not change the value used in the WebHost configuration, as this applies only to the application configuration.
Andew Lock goes into more detail about how this all works and also demonstrates how to configure the WebHost to use additional configuration sources.

Artifactory not using specified home directory

I'm currently hosting Artifactory on Tomcat8/JDK1.8.
If I check the system info screen, I can see that files are being written in /u01/usr/share/tomcat8/.artifactory/
However, in the servlet configuration in bin/setenv.sh, I specified the Artifactory home to be somewhere else:
-DARTIFACTORY_HOME=/u01/opt/artifactory
Then, I discovered in the docs, it's supposed to be lower case:
-Dartifactory_home=/u01/opt/artifactory
I rebooted Tomcat after the changes and the path targetted is still /u01/usr/share/tomcat8/.artifactory. The folder is owned by the user running Tomcat as well.
Why isn't it using the specified home dir?
This seems a bit old but for others that struggle with it, you need to set an Environment variable ARTIFACTORY_HOME in your Tomcat startup script not a System variable via -D parameter.
Linux
set ARTIFACTORY_HOME=/pathto/your/artifactory
Windows
"set ARTIFACTORY_HOME=C:\path to your/artifactory"
Notice the quotes for Windows
System properties are set on the Java command line using the -Dpropertyname=value syntax. They can also be added at runtime using System.setProperty(String key, String value) or via the various System.getProperties().load() methods.
To get a specific system property you can use System.getProperty(String key) or System.getProperty(String key, String def).
Environment variables are set in the OS, e.g. in Linux export HOME=/Users/myusername or on Windows SET WINDIR=C:\Windows etc, and, unlike properties, may not be set at runtime.
To get a specific environment variable you can use System.getenv(String name).

Using environment variables in camel.xml to configure endpoints

I have a cxf endpoint configuration in my camel.xml like this:
<cxf:cxfEndpoint id="callbackInbound"
serviceClass="ch.axpo.emis.v1.timeseriesservice.Callback"
wsdlURL="wsdl/timeseries.wsdl" endpointName="tss:CallbackPort"
address="http://somehost.com:9090/CallbackService" serviceName="tss:CallbackService"/>
In one of my routes I call this endpoint like this:
.to("cxf:bean:callbackInbound?dataFormat=PAYLOAD")
So, now instead of having a fix address (http://somehost.com:9090/CallbackService) I want to be able to configure the address for different environments (DEV, TEST, PROD, ...) using system variables. This is because I use JBoss 7 as runtime environment for camel and there is a quite simple way to add system variables with JBoss.
Is there a way to do that? Or is there a better way to configure cxf endpoints in different environments?
Thanks,
Sven
You can use the properties components and define the cxfEndpoint like this
System.setProperty("environment", "junit");
<cxf:cxfEndpoint id="routerEndpoint" address="{{router.address}}"
serviceClass="org.apache.camel.component.cxf.HelloService"/>
You can define the property file just like this
router.address={{{{environment}}.router.address}}
# LOCAL SERVER
junit.router.address=junit
# LOCAL SERVER
local.router.address=local
# TEST
test.router.address=test
# PROD
prod.router.address=prod

Accessing shell environment variables in catalyst web app using Apache/FastCGI

I have a catalyst web application on an Amazon EC2 Linux instance and its content is being served by Apache/FastCGI.
Whenever I start a new instance, I need to get the internal IP of the database server and assign it to an environment variable by running this command at startup:
export MYSQL_HOST=$(dig +short ec2-*-*-*-*.compute-1.amazonaws.com);
I have a perl module that should create the database connection after looking up the $MYSQL_HOST environment variable value.
My problem is fairly well documented in that FastCGI cannot directly access these shell environment variables.
I see that you can use PassEnv from Apache mod_env to access environment variables and that you can assign values to FastCGI environment variables using the Apache directive, FcgidInitialEnv (if I hard-code a value in here, I can retrieve it using my Perl module).
My Apache configuration skills are rather basic so I was wondering if someone could recommend a way to tie these together in order for my perl module to access $MYSQL_HOST.
Thanks!
If you're trying to read environment variables, have a look at $c->engine->env:
use Data::Dumper;
sub debugEnv :Local
{
my ( $self, $c ) = #_;
$c->res->headers->header("Content-type"=> 'text/plain');
my $req = $c->req;
$c->response->body('$c->engine->env is : '.Dumper($c->engine->env)
."c->req is $req\n"
.'c->config is ' .Dumper($c->config)
."\nENV is : ".Dumper(\%ENV))
}

Git - Push to Deploy and Removing Dev Config

So I'm writing a Facebook App using Rails, and hosted on Heroku.
On Heroku, you deploy by pushing your repo to the server.
When I do this, I'd like it to automatically change a few dev settings (facebook secret, for example) to production settings.
What's the best way to do this? Git hook?
There are a couple of common practices to handle this situation if you don't want to use Git hooks or other methods to modify the actual code upon deploy.
Environment Based Configuration
If you don't mind having the production values your configuration settings in your repository, you can make them environment based. I sometimes use something like this:
# config/application.yml
default:
facebook:
app_id: app_id_for_dev_and_test
app_secret: app_secret_for_dev_and_test
api_key: api_key_for_dev_and_test
production:
facebook:
app_id: app_id_for_production
app_secret: app_secret_for_production
api_key: api_key_for_production
# config/initializers/app_config.rb
require 'yaml'
yaml_data = YAML::load(ERB.new(IO.read(File.join(Rails.root, 'config', 'application.yml'))).result)
config = yaml_data["default"]
begin
config.merge! yaml_data[Rails.env]
rescue TypeError
# nothing specified for this environment; do nothing
end
APP_CONFIG = HashWithIndifferentAccess.new(config)
Now you can access the data via, for instance, APP_CONFIG[:facebook][:app_id], and the value will automatically be different based on which environment the application was booted in.
Environment Variables Based Configuration
Another option is to specify production data via environment variables. Heroku allows you to do this via config vars.
Set up your code to use a value based on the environment (maybe with optional defaults):
facebook_app_id = ENV['FB_APP_ID'] || 'some default value'
Create the production config var on Heroku by typing on a console:
heroku config:add FB_APP_ID=the_fb_app_id_to_use
Now ENV['FB_APP_ID'] is the_fb_app_id_to_use on production (Heroku), and 'some default value' in development and test.
The Heroku documentation linked above has some more detailed information on this strategy.
You can explore the idea of a content filter, based on a 'smudge' script executed automatically on checkout.
You would declare:
some (versioned) template files
some value files
a (versioned) smudge script able to recognize its execution environment and generate the necessary (non-versioned) final files from the value files or (for more sensitive information) from other sources external to the Git repo.