How to tell Grails application which environment it is in? - grails

I would like to load Environment specific configurations in my grails application so that depending on which JVM the grails application is running on, I can point to that environment specific urls. In my case, I have 4 different environments to work with (instead of the default 3 that grails app assumes) when my app goes from dev to prod.
My JVMs all have a System property defined that, when I do "System.getProperty()", tell me which environment that application is running on.
My question is, what is the best place to check and load the environment-specific configurations during run-time? Inside BootStrap.groovy? I do not have the option to build my war file using command line or grails {env_name} war.
Thanks.

Set the variable grailsEnv as a environment Java variable for Tomcat below is an example:
set CATALINA_OPTS=%CATALINA_OPTS% -Xms256m -Xmx1024m -Dgrails.env=development
On a grails command line you add the environment variable:
grails run-app -Dgrails.env=stage
You can use check the environment variable like this:
if (grails.util.Environment.current.name == "development") {
UsageCodeDefinition ucd = new UsageCodeDefinition()
ucd.setDescription("UFARSFileUpload Upload Development")
ucd.setFiscalYear("12-13")
ucd.setInstructions("Welcome to UFARSFileUpload Development were Open")
ucd.save(failOnError: true)
}
You can use the Enumerated values instead of the name variable but if you use custom environmental values then they are mapped to the enumeration custom and using the name works to distinguish between the custom values.
if (grails.util.Environment.current == grails.util.Environment.DEVELOPMENT) {

Without setting the JVM startup parameter:
-Dgrails.env=whatever
Your grails app will use the value set in
<yourapp>/WEB-INF/classes/application.properties
There will be a value set like this:
grails.env=development
This default environment value is determined by what options are used when building the war. You can build the war with
-Dgrails.env=development war
Then the application.properties will have grails.env=development, if you leave that off, it defaults to grails.env=production
As far as your question, you are not specific about what is being configured to use "environment specific urls". And it is not clear how you are storing these environment specific urls. If, for example, the URL variable is a member variable of a Grails service and you are storing the environment specific URLs in the Config.groovy, then you could
import grails.util.Environment
...
//inject the GrailsApplication Configuration in Config.groovy
def grailsApplication
//Hold the URL value from Config.groovy
String environmentUrl
...
Environment current = Environment.getCurrent()
if(Environment.PRODUCTION == current) {
environmentUrl = grailsApplication.config.PRODUCTION_URL
} else {
environmentUrl = grailsApplication.config.DEVELOPMENT_URL
}
Where Config.groovy has
PRODUCTION_URL = "http://blah.com/blah/"
DEVELOPMENT_URL = "http://blah.dev/blah"
Hope that helps.

If you have a System property available that tells you what environment you're in you can simply add if statements or a switch statement in your Config.groovy file, like this:
if (System.getProperty("foo") == "myTestEnvironment") {
myConfigSetting = "test"
} else if (System.getProperty("foo") == "myProductionEnvironment") {
myConfigSetting = "production"
}
This solution also works in other config files under grails-app/conf
Grails config files are parsed using groovy ConfigSlurper so you can put executable code in there without a problem.

Sorry this is way late, but another way is to inject a configuration property in BootStrap.groovy.
For Example:
if (currentEnv == Environment.DEVELOPMENT) {
...
grailsApplication.config.some.property = DEVELOPMENT_ENVRIONMENT
...
}
else if (currentEnv == Environment.TEST) {
...
grailsApplication.config.some.property = TEST_ENVIRONMENT
...
}
I have used this recently and it works really well. We are using Grails 2.5.2

As an addendum to the other answers:
You can use Environment.isDevelopmentMode() or in a groovier way Environment.developmentMode to check if the environment is set to development. This is useful when you take the aproach of only modifying settings for development on your code where production settings are default.

Related

How does Cypress read the Windows environment variables?

I have set my environment variables in 'Cypress.env.json' file.
While running the cypress test, it reads the Cypress.env variables successfully.
But to be more secure, rather than 'hard-cording' the values, my team asked me to keep these variables as separate 'parameters' which are read from Windows 10 Environment variables.
How do I achieve this ?
I need to set an environment variable in Windows level.
Take a look at this answer How to use process.env variables in browser running by Cypress - essentially the dotenv package will read any variables you have set on the Windows environment. Also works for other OS like Linux.
The answer given is a bit naive for what you want to do, as there will be a lot of variables you do not need in the test.
This modification would be better
cypress.config.js
const {defineConfig} = require('cypress')
require('dotenv').config()
const { secret1, secret2 } = process.env; // extract two secret variables
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
config.env = {
...config.env,
secret1,
secret2,
}
return config
}
}
})
Note the process.env values should come after the config.env values, so you are over-writing any defaults.
Those defaults would be in cypress.env.json, and stops the tests crashing if someone forgets to set their Windows environment values.
{
"host": "veronica.dev.local",
"api_server": "http://localhost:8888/api/v1/",
"secret1": "default-secret-value1",
"secret2": "default-secret-value2",
}
You can set operating system environment variable that's name starts with CYPRESS_ and it will be parsed and used in Cypress.
Example:
CYPRESS_HOST
will be available as
Cypress.env('HOST')

How to run pipeline with constant variables between production and non production

I have my jenkins pipelines working and all in source code management, within my pipelines I have some constants which are variables that do not change/rarely change, so these would rarely change and the pipelines requires these values, 90% of it doesnt change but I have some that does change based on the environment type (production/pre-production/test etc)
The problem I have right now is that I would like to take thesame code from non-production to production without having to change things like the file server details, as production/non-production use different file servers, as it stands one has to remember to change the file server when promoting code to production, is it possible to have like a configuration file and the pipeline can read the values from the configuration file, I do not want to change the pipelines or make as little changes as possible when my code moves from non-production to production.
Thanks in advance.
Install the Pipeline Utility Steps plugin and create a properties file each in the repositories/branches for production and non-production respectively. Then read and populate the properties from the file in your pipeline during the build.
Sample server.properties
fileServerUrl=ftp://prod.company.net
fileServerPort=21
// more properties here
Sample Jenkinsfile
pipeline {
agent {
label 'production'
}
stages {
stage('prepare-env') {
script {
def props = readProperties file: 'server.properties'
env.fileServerUrl = props.fileServerUrl
env.fileServerPort = props.fileServerPort
// more properties here
}
}
stage('deploy') {
println("INFO: The file server is ${env.fileServerUrl}:${env.fileServerPort}")
// do stuff here
}
}
}

grails 3 - Update grails config during Plugin "doWithApplicationContext"

I've got a plugin that, during startup, reads some properties from the applications Config file, creates some domain objects and then needs to update the configuration with some additional information. However, it seems that the config object available during doWithApplicationContext is not the actual grailsApplication.config object.
For instance, attempting to do something straightforward in the MyPluginGrailsPlugin.groovy file like:
void doWithApplicationContext() {
grailsApplication.config.put('test', 'testValue')
}
does not update the config.
If this plugin is incldued in an application, at any point after startup, grailsApplication.config.getProperty('test') will return null.
How does one go about updating the config map during plugin startup?
NOTE: In grails 2, this used to work.
With this code snippet in MyPluginGrailsPlugin.groovy's doWithApplicationContext, new properties were successfully added into the application's config object.
ConfigObject myConfigObject = new ConfigSlurper().parse(props)
PropertySource propertySource = new MapPropertySource('grails.plugins.myPlugin', [:] << myConfigObject)
def propertySources = grailsApplication.mainContext.environment.propertySources
propertySources.addFirst propertySource
As an additional note: in doWithApplicationContext in my plugin, changing the config object like this worked in Grails 2 and no longer works in Grails 3.
grailsApplication.config.merge(myConfigObject)
grailsApplication.configChanged()

“Inject environment variables” Jenkins 2.0

I recently upgraded to Jenkins 2.0.
I’m trying to add a build step to a jenkins job of "Inject environment variables" along the lines of this SO post, but it’s not showing up as an option.
Is this not feature in Jenkins 2.0 (or has it always been a separate plugin)? Do I have to install another plugin, such as Envinject?
If you are using Jenkins 2.0
you can load the property file (which consists of all required Environment variables along with their corresponding values) and read all the environment variables listed there automatically and inject it into the Jenkins provided env entity.
Here is a method which performs the above stated action.
def loadProperties(path) {
properties = new Properties()
File propertiesFile = new File(path)
properties.load(propertiesFile.newDataInputStream())
Set<Object> keys = properties.keySet();
for(Object k:keys){
String key = (String)k;
String value =(String) properties.getProperty(key)
env."${key}" = "${value}"
}
}
To call this method we need to pass the path of property file as a string variable
For example, in our Jenkins file using groovy script we can call like
path = "${workspace}/pic_env_vars.properties"
loadProperties(path)
Please ask me if you have any doubt

How override grails configuration from command line

I am trying to override dataSource.url value running grails from the command line, example
grails <set property> dbm-status
My first try was using -D command line parameter as
grails -DdataSource.url=jdbc:sqlserver://xx.xx.xx.xx;databaseName=db_name
I have tried to add an additional config file to grails.config.locations that get values from System.getProperty but does not seems to work.
Exist a built in way to override config values from the command line, otherwise how I can inject parameter from the command line to the grails configuration ?
EDIT: I don't want to use another environment/datasource to avoid datasource configuration duplication and the need to configure things for this new environment.
By including the following if in DataSource.groovy I'm able to override url,password and username property if url is provided. (Valid for Grails 2.x)
....
environments {
development {
dataSource {
url = "jdbc:postgresql://localhost/db"
username = "user"
password = "pass"
if (System.properties['dataSourceUrl']) {
println 'Taking dataSource url, password, username from command line overrides'
url = System.properties['dataSourceUrl']
password = System.properties['dataSourcePassword']
username = System.properties['dataSourceUsername']
}
}
}
...
Now when I run the command, the overrides get applied:
grails dev -DdataSourceUrl=newUrl -DdataSourcePassword=newPass -DdataSourceUsername=newUser run-app
Unfortunately if you want to be able to override on every environment you have to duplicate this code for every env block. If you pull it up to root it won't work since config merging kicks in and the last run will actually apply what's in the env {} block and not what's in the System properties.
Looking at it again something like that looks even better:
...
url = System.properties['dataSourceUrl'] ?: 'jdbc:postgresql://localhost/db'
//and for every property...
...
DATASOURCE_URL=jdbc:sqlserver://xx.xx.xx.xx;databaseName=db_name grials run-app
For any variable you want to set, you can set it in the environment. Change to upper case and replace dots with underscores. This is a feature of spring boot.

Resources