How do I populate my Elixir config from runtime variables? [duplicate] - erlang

Following the setup instructions, I have the following Ecto configuration in my config/config.exs file :
config :my_app, MyApp.Repo,
adapter: Ecto.Adapters.Postgres,
url: "postgresql://postgres#localhost/myrepo",
size: 20
If my understanding is correct, the config.exs is evaluated at compile-time.
Is there a way to do this configuration step at runtime ?
This is for an app which will be distributed as a compiled binary (via exrm). The end-user should be able to customize the database url and pool size via flags or environment variables, not by editing sys.config

Loading from the system is possible by using {:system, "KEY" } e.g.:
config :my_app Repo
url: {:system, "DATABASE_URL" },
size: {:system, "DATABASE_POOL_SIZE" }
instead
config :my_app, Repo,
url: "ecto://postgres:postgres#localhost/ecto_simple",
size: 20
In this case you set up Ecto to use the system properties. Of course, a user has to configure it.

Using {:system, "KEY"} has been deprecated in Ecto v3.
Instead, you are advised to define an init/2 callback function within your Repo module to set runtime config:
def init(_type, config) do
config = Keyword.put(config, :url, System.get_env("DATABASE_URL"))
{:ok, config}
end
Using a runtime init/2 function allows configuration to be read from more than just environment variables.

Related

next.js - env vs serverRuntimeConfig

I read about serverRuntimeConfig here: https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration
Now my next.config.js is:
module.exports = withCSS({
target: 'serverless',
reactStrictMode: false,
env: {
SECRET: 'SECRET'
}
});
I'm wondering, should I use serverRuntimeConfig for my secret env var instead of env ?
What are the pros / cons ?
Generally you'll want to use build-time environment variables to provide your configuration. The reason for this is that runtime configuration adds rendering / initialization overhead and is incompatible with Automatic Static Optimization.
# https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration
As they said, the runtime configuration in next.config.js may cause overhead.
So I suggest using env in next.config.js, or using the .env* files in this new method (https://nextjs.org/docs/basic-features/environment-variables)
The code using your secret env vars should be in the server-side (API routes, getStaticProps, getServerSideProps), not in client-side (components...). If you reference them in client-side, they may be exposed!

YAML - groovy - env var can't be an integer?

Project is in Groovy/Grails/Gradle/Camel Routes
This seems pretty reasonable:
server:
port: ${PORT}
But I get :
java.lang.NumberFormatException: For input string: "${PORT}"
at org.grails.config.CodeGenConfig.convertToType(CodeGenConfig.groovy:191)
at org.grails.config.CodeGenConfig.getProperty(CodeGenConfig.groovy:264)
at grails.config.ConfigMap$getProperty.call(Unknown Source)
at run-app.run(run-app.groovy:31)
at org.grails.cli.profile.commands.script.GroovyScriptCommand.handle(GroovyScriptCommand.groovy:152)
at org.grails.cli.profile.AbstractProfile.handleCommand(AbstractProfile.groovy:452)
at org.grails.cli.GrailsCli.handleCommand(GrailsCli.groovy:373)
at org.grails.cli.GrailsCli$_handleCommandWithCancellationSupport_closure6.doCall(GrailsCli.groovy:464)
at org.grails.cli.GrailsCli$_handleCommandWithCancellationSupport_closure6.call(GrailsCli.groovy)
String env vars do not have an issue and work just fine.
I cannot find any syntax to make cast to an int when I search.
Any thoughts?
In a Grails/Spring Boot app, if the configuration is short hand as below:
server:
port: ${PORT}
then the app expects --PORT=8090 (for example) to be provided as a System arg / environment property upon application startup. Make sure that environment variable is provided.
To make the environment variable value available in application.yml we would also need below task configuration in Grails apps:
bootRun {
systemProperties = System.properties
}
With plain vanilla Spring Boot Maven apps above is not required.
Also, to avoid any kind of exception we can also provide a default value for port if feasible like below:
server:
port: ${PORT:8085}

How To Get The Value Of An Environment Variable In Elixir On Windows?

Windows 10
Elixir 1.3.1
Per the advice in this article, I've tried to modify my config files to use the "${ENV_VAR}" syntax. But then when I try to compile the code Elixir complains about the values of the configuration settings. So I tried the syntax directly in iex and it doesn't seem to work.
iex(1)> "${PATH}"
"${PATH}"
iex(2)> System.get_env("PATH")
"C:\\Program Files\\erl8.0\\erts-8.0\\bin;C: . . ." (rest omitted for brevity's sake)
I'd really like to use the "${ENV_VAR}" notation because it'd be nice to not have to hand-edit the sys.config file. Am I doing something wrong or is this just a Windows specific issue?
Here's part of my config file (even though, as I say, it seems I can reproduce the behavior in iex):
config :riismi, ecto_repos: [Riismi.Repo]
config :riismi, Riismi.Mailer,
adapter: Bamboo.SMTPAdapter,
server: "smtp.gmail.com",
port: 465,
username: "${RMI_MAIL_SERVERUSER}",
password: "${RMI_MAIL_SERVERPWD}",
tls: :if_available, # can be `:always` or `:never` or `:if_available`
ssl: true, # can be `true`
retries: 3
As I say, I realize this is likely to be a Windows issue--just wanted to insure that I'm not missing something otherwise.

External properties file in grails 3

I need read configuration from a external file properties in grails 3. In grails 2.x I link the file with:
grails.config.locations = ["classpath:config.properties"]
In the config.groovy, but this file do not exists in grails 3.
Have you any idea for solve?
Because Grails 3 is built on Spring Boot, you can use the Spring Boot mechanisms for externalized properties. Namely, using the spring.config.location command line parameter, or the SPRING_BOOT_LOCATION environment variable. Here's the Spring documentation page on it.
The example the documentation provides for the command line parameter is this:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
The way I have been using it is by setting an environment variable, like this:
export SPRING_CONFIG_LOCATION="/home/user/application-name/application.yml"
One of the nice features is that you can leave some properties in the properties file that is bundled in the app, but if there are some properties you do not want to include (such as passwords), those can be set specifically in the external config file.
Take a look at https://gist.github.com/reduardo7/d14ea1cd09108425e0f5ecc8d3d7fca0
External configuration in Grails 3
Working on Grails 3 I realized that I no longer can specify external configuration using the standard grails.config.locations property in Config.groovy file.
Reason is obvious! There is no Config.groovy now in Grails 3. Instead we now use application.yml to configure the properties. However, you can't specify the external configuration using this file too!
What the hack?
Now Grails 3 uses Spring's property source concept. To enable external config file to work we need to do something extra now.
Suppose I want to override some properties in application.yml file with my external configuration file.
E.g., from this:
dataSource:
username: sa
password:
driverClassName: "org.h2.Driver"
To this:
dataSource:
username: root
password: mysql
driverClassName: "com.mysql.jdbc.Driver"
First I need to place this file in application's root. E.g., I've following structure of my Grails 3 application with external configuration file app-config.yml in place:
[human#machine tmp]$ tree -L 1 myapp
myapp
├── app-config.yml // <---- external configuration file!
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── grails-app
└── src
Now, to enable reading this file just add following:
To your build.gradle file
bootRun {
// local.config.location is just a random name. You can use yours.
jvmArgs = ['-Dlocal.config.location=app-config.yml']
}
To your Application.groovy file
package com.mycompany
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean
import org.springframework.context.EnvironmentAware
import org.springframework.core.env.Environment
import org.springframework.core.env.PropertiesPropertySource
import org.springframework.core.io.FileSystemResource
import org.springframework.core.io.Resource
class Application extends GrailsAutoConfiguration implements EnvironmentAware {
public final static String LOCAL_CONFIG_LOCATION = "local.config.location"
static void main(String[] args) {
GrailsApp.run(Application, args)
}
#Override
void setEnvironment(Environment environment) {
String configPath = System.properties[LOCAL_CONFIG_LOCATION]
if (!configPath) {
throw new RuntimeException("Local configuration location variable is required: " + LOCAL_CONFIG_LOCATION)
}
File configFile = new File(configPath)
if (!configFile.exists()) {
throw new RuntimeException("Configuration file is required: " + configPath)
}
Resource resourceConfig = new FileSystemResource(configPath)
YamlPropertiesFactoryBean ypfb = new YamlPropertiesFactoryBean()
ypfb.setResources([resourceConfig] as Resource[])
ypfb.afterPropertiesSet()
Properties properties = ypfb.getObject()
environment.propertySources.addFirst(new PropertiesPropertySource(LOCAL_CONFIG_LOCATION, properties))
}
}
Notice that Application class implements EnvironmentAware Interface and overrides its setEnvironment(Environment environment):void method.
Now this is all what you need to re-enable external config file in Grails 3 application.
Code and guidance is taken from following links with little modification:
http://grails.1312388.n4.nabble.com/Grails-3-External-config-td4658823.html
https://groups.google.com/forum/#!topic/grails-dev-discuss/_5VtFz4SpDY
Source: https://gist.github.com/ManvendraSK/8b166b47514ca817d36e
I am having the same problem to read the properties file from external location in Grails 3. I found this plugin which helpme to read the properties from external location. It has feature to read .yml, .groovy files as well.
Follow the steps mentioned in the documentation and it will work.
The steps are like:
Add dependency in build.gradle:
dependencies {compile 'org.grails.plugins:external-config:1.2.2'}
Add this in application.yml grails:
config:
locations:
- file:///opt/abc/application.yml
Create file at external location. In my case /opt/abc/application.yml.
Build the application and run.
You can use
def cfg = new ConfigSlurper.parse(getClass().classLoader.getResource('path/myExternalConfigfile.groovy'))
When running from a .jar file, I found that Spring Boot looks at the current directory for an application.yml file.
java -jar app-0.3.jar
In the current directory, I created an application.yml file with one line:
org.xyz.app.title: 'XYZZY'
I also used this file to specify the database and other such info.
Seems like there is no externalised config out of the box: http://grails.1312388.n4.nabble.com/Grails-3-External-config-td4658823.html

Setting Environment Variables in Rails 3 (Devise + Omniauth)

I've been trying to figure out how Ryan Bates, in his Facebook Authentication screencast, is setting the following "FACEBOOK_APP_ID" and "FACEBOOK_SECRET" environment variables.
provider :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_SECRET']
There are similar-ish questions around, but no answers that I've been able to get to work on Rails 3.2.1.
UPDATE:
As of May 2013, my preferred way to handle ENV variables is via the Figaro gem
You could take a look at the comments:
You can either set environment variables directly on the shell where you are starting your server:
FACEBOOK_APP_ID=12345 FACEBOOK_SECRET=abcdef rails server
Or (rather hacky), you could set them in your config/environments/development.rb:
ENV['FACEBOOK_APP_ID'] = "12345";
ENV['FACEBOOK_SECRET'] = "abcdef";
An alternative way
However I would do neither. I would create a config file (say config/facebook.yml) which holds the corresponding values for every environment. And then load this as a constant in an initializer:
config/facebook.yml
development:
app_id: 12345
secret: abcdef
test:
app_id: 12345
secret: abcdef
production:
app_id: 23456
secret: bcdefg
config/initializers/facebook.rb
FACEBOOK_CONFIG = YAML.load_file("#{::Rails.root}/config/facebook.yml")[::Rails.env]
Then replace ENV['FACEBOOK_APP_ID'] in your code by FACEBOOK_CONFIG['app_id'] and ENV['FACEBOOK_SECRET'] by FACEBOOK_CONFIG['secret'].
There are several options:
Set the environment variables from the command line:
export FACEBOOK_APP_ID=your_app_id
export FACEBOOK_SECRET=your_secret
You can put the above lines in your ~/.bashrc
Set the environment variables when running rails s:
FACEBOOK_APP_ID=your_app_id FACEBOOK_SECRET=your_secret rails s
Create a .env file with:
FACEBOOK_APP_ID=your_app_id
FACEBOOK_SECRET=your_secret
and use either Foreman (starting your app with foreman start) or the dotenv gem.
Here's another idea. Define the keys and values in provider.yml file, as suggested above. Then put this in your environment.rb (before the call to Application.initialize!):
YAML.load_file("#{::Rails.root}/config/provider.yml")[::Rails.env].each {|k,v| ENV[k] = v }
Then these environment variables can be referenced in the omniauth initializer without any ordering dependency among intializers.

Resources