Expanding application.yml during Gradle processResources gives MissingPropertyException - gradle

To replaces properties in my Spring Boot application.yml I've added:
processResources {
filesMatching("**/application.yml") {
expand(project.properties)
}
}
The replacement fails but gives a MissingPropertyException:
Caused by: groovy.lang.MissingPropertyException: No such property: OPENSHIFT_MYSQL_DB_HOST for class: SimpleTemplateScript1
at SimpleTemplateScript1.run(SimpleTemplateScript1.groovy:49)
at org.gradle.api.internal.file.copy.FilterChain$3.transform(FilterChain.java:95)
at org.gradle.api.internal.file.copy.FilterChain$3.transform(FilterChain.java:84)
at org.gradle.api.internal.ChainingTransformer.transform(ChainingTransformer.java:37)
at org.gradle.api.internal.file.copy.FilterChain.transform(FilterChain.java:39)
at org.gradle.api.internal.file.copy.FilterChain.transform(FilterChain.java:46)
at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.open(DefaultFileCopyDetails.java:86)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:56)
at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.copyTo(DefaultFileCopyDetails.java:94)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyFile(AbstractFileTreeElement.java:93)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:74)
... 81 more
Originally my application.yml contained:
url: jdbc:mysql://${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/${OPENSHIFT_APP_NAME}
Note these Openshift variables are only know on Openshift production environment but not when running locally in dev mode.
As stated on http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.Copy.html: You can also include arbitrary Groovy code in the file, such as ${version ?: 'unknown'} so I changed my application.yml to:
url: jdbc:mysql://${OPENSHIFT_MYSQL_DB_HOST ?: ''}:${OPENSHIFT_MYSQL_DB_PORT ?: ''}/${OPENSHIFT_APP_NAME ?: ''}
But this gives the same MissingPropertyException.
Am I missing something here?

The Gradle expand ${..} style conflicts with the same Spring property placeholder style and therefor needs to be escaped like \${..}.
This is added to Spring Boot docs now: https://github.com/spring-projects/spring-boot/commit/c0c67f2593dbfd17aa304b43f4da3a3678fa58eb

Related

How to read Gitlab (.gitlab-ci.yml ) environment variable from Spring Boot code?

I am trying to read an environment variable is being set from within Gitlab configuration when the application is being built, I am doing this for achieving that purpose:
I setup a variable in the application.properties.yml of my spring boot app:
sf:
apiKey: $SF_API_KEY
In the .gitlab-ci.yml, I defined the variable to be set, as follows:
variables:
SF_API_KEY: $SF_API_KEY
all I want, is to be able to read that variable from within one of my services, as the below code depicts:
#Service
class MyService(#Value("\${sf.apiKey}") val apiKey: String)
{
fun doSomething(){
//i am seeing the variable is being set by gitlab in the build logs but
// it is not being read here properly
var result = apiKey;
logger.info { "***check apiKey: $apiKey" }
//This line lgs $SF_API_KEY as a value of my variable, but not the
// real value
}
}
Am I doing something wrong? I would appreciate any help.
Try (note the {} around SF_API_KEY):
sf:
apiKey: ${SF_API_KEY}
Take a look at the docs where this placeholder notation is detailed.

How do I disable spring security in a Grails 4 integration test?

I had a grails 3 app including spring security, which I recently upgraded to grails 4.
My application.yml includes the following:
environments:
test:
grails:
plugin:
springsecurity:
active: false
security:
ignored: '/**'
basic:
enabled: false
spring:
security:
enabled: false
Why doesn't this work in Grails 4? What's a good alternative solution?
Grails 4 seems to be ignoring this configuration. When I run integration tests, I am getting a 403 error with a message:
Could not verify the provided CSRF token because your session was not found.
It seems like spring security enabled, and it's using SecurityFilterAutoConfiguration, which is normally excluded for my app.
Update
I am using the following dependencies:
compile('org.grails.plugins:spring-security-core:3.2.3') {
exclude group: 'org.springframework.security'
}
compile ('org.springframework.security:spring-security-core:4.2.13.RELEASE') {
force = true
}
compile 'org.springframework.security:spring-security-web:4.2.13.RELEASE'
compile 'org.springframework.security:spring-security-config:4.2.13.RELEASE'
Update 2:
In my debugger, I found that the spring security core plugin actually is being disabled. The following code from the plugin class is executed:
SpringSecurityUtils.resetSecurityConfig()
def conf = SpringSecurityUtils.securityConfig
boolean printStatusMessages = (conf.printStatusMessages instanceof Boolean) ? conf.printStatusMessages : true
if (!conf || !conf.active) {
if (printStatusMessages) {
// <-- the code in this block is executed; active flag is false
String message = '\n\nSpring Security is disabled, not loading\n\n'
log.info message
println message
}
return
}
...however, I am still getting the CSRF filter error, so Spring Security must be configuring itself somehow regardless.
Update 3:
The CSRF filter is being set up by ManagementWebSecurityConfigurerAdapter, using the default configuration.
I tried adding the following to resources.groovy:
if (grailsApplication.config.disableSecurity == true && !Environment.isWarDeployed()) {
webSecurityConfigurerAdapter(new WebSecurityConfigurerAdapter(true) {})
}
This did not fix the issue. Although my anonymous WSCA bean is being constructed, the MWSCA default bean is still being used by spring.
Try this in
grails-app/conf/application.groovy
environments {
development {
}
test {
grails.plugin.springsecurity.active = false
}
production {
}
}

how do i configure static versioning (digest) for the asset-pipeline (bertramlabs) in my spring boot 2 application?

spring boot version: 2.0.4.RELEASE
asset-pipeline version: 3.0.3
Hi
we're using this plugin, because we know it from our grails applications.
We liked it, because it has a simple configuration (for our requirements)
Now we're developing a spring boot application and we used this plugin too and we're (almost) happy with it.
But when we run the application in the development mode the assets don't have a digest like /assets/my-styles-b5d2d7380a49af2d7ca7943a9aa74f62s.css
How do i configure the plugin to create a digest for all our resources?
currently we're using this configuration:
assets {
minifyJs = true
minifyCss = true
enableSourceMaps = false
includes = ["application.js", "application.scss"]
}
And we're using thymeleaf for our templates:
<link th:href="#{/assets/application.css}" rel="stylesheet">
I found a solution...
when you use the asset-pipeline, you get a gradle task assetCompile.
when creating a .war file, you can add this gradle task and replace all the assets with the versioned files.
when you want to use the versioned files in your production mode you have to use this configuration (build.gradle)
assets {
minifyJs = true
minifyCss = true
skipNonDigests = true
packagePlugin = true
includes = ["application.js", "application.scss"]
}
...
war {
dependsOn 'assetCompile'
from( "${buildDir}/assets", {
into "/WEB-INF/classes/META-INF/assets"
})
baseName = '<your project>'
enabled = true
}
that's all.
When running the assetCompile task, a manifest.properties file is created. This file contains the mapping of the original filename and the versioned one.
This file is used by the application to find the correct resource, e.g. application.css=application-79a3c8a2f085ecefadgfca3cda6fe3d12.css
I created a plugin which enables the url replacement for assets with digest in the production mode:
Dependency
compile 'ch.itds.taglib:asset-pipeline-thymeleaf-taglib:1.0.0'
Configuration
#Configuration
public class ThymeleafConfig {
#Bean
public AssetDialect assetDialect() {
return new AssetDialect();
}
}
Usage
<html xmlns:asset="https://www.itds.ch/taglib/asset">
<script asset:src="#{/assets/main.js}"></script>
</html>
The asset:src="#{/assets/main.js}" will be replaced with src="/assets/main-DIGEST.js".
The replacement happens only if the developmentRuntime of the asset pipeline is disabled.
A little bit more details are available on my blog post: https://kobelnet.ch/Blog/2019/03/12/assetpipelinethymeleaftaglib

SonarQube - specify location of sonar.properties

I'm trying to deploy SonarQube on Kubernetes using configMaps.
The latest 7.1 image I use has a config in sonar.properties embedded in $SONARQUBE_HOME/conf/ . The directory is not empty and contain also a wrapper.conf file.
I would like to mount the configMap inside my container in a other location than /opt/sonar/conf/ and specify to sonarQube the new path to read the properties.
Is there a way to do that ? (environment variable ? JVM argument ? ...)
It is not recommended to modify this standard configuration in any way. But we can have a look at the SonarQube sourcecode. In this file you can find this code for reading the configuration file:
private static Properties loadPropertiesFile(File homeDir) {
Properties p = new Properties();
File propsFile = new File(homeDir, "conf/sonar.properties");
if (propsFile.exists()) {
...
} else {
LoggerFactory.getLogger(AppSettingsLoaderImpl.class).warn("Configuration file not found: {}", propsFile);
}
return p;
}
So the conf-path and filename is hard coded and you get a warning if the file does not exist. The home directory is found this way:
private static File detectHomeDir() {
try {
File appJar = new File(Class.forName("org.sonar.application.App").getProtectionDomain().getCodeSource().getLocation().toURI());
return appJar.getParentFile().getParentFile();
} catch (...) {
...
}
So this can also not be changed. The code above is used here:
#Override
public AppSettings load() {
Properties p = loadPropertiesFile(homeDir);
p.putAll(CommandLineParser.parseArguments(cliArguments));
p.setProperty(PATH_HOME.getKey(), homeDir.getAbsolutePath());
p = ConfigurationUtils.interpolateVariables(p, System.getenv());
....
}
This suggests that you can use commandline parameters or environment variables in order to change your settings.
For my problem, I defined environment variable to configure database settings in my Kubernetes deployment :
env:
- name: SONARQUBE_JDBC_URL
value: jdbc:sqlserver://mydb:1433;databaseName=sonarqube
- name: SONARQUBE_JDBC_USERNAME
value: sonarqube
- name: SONARQUBE_JDBC_PASSWORD
valueFrom:
secretKeyRef:
name: sonarsecret
key: dbpassword
I needed to use also ldap plugin but it was not possible to configure environment variable in this case. As /opt/sonarqube/conf/ is not empty, I can't use configMap to decouple configuration from image content. So, I build my own sonarqube image adding the ldap jar plugin and ldap setting in sonar.properties :
# General Configuration
sonar.security.realm=LDAP
ldap.url=ldap://myldap:389
ldap.bindDn=CN=mysa=_ServicesAccounts,OU=Users,OU=SVC,DC=net
ldap.bindPassword=****
# User Configuration
ldap.user.baseDn=OU=Users,OU=SVC,DC=net
ldap.user.request=(&(sAMAccountName={0})(objectclass=user))
ldap.user.realNameAttribute=cn
ldap.user.emailAttribute=mail
# Group Configuration
ldap.group.baseDn=OU=Users,OU=SVC,DC=net
ldap.group.request=(&(objectClass=group)(member={dn}))

CloudFoundry manifest.yml with objects as env variables

so I am building a SpringBootApplication and I currently have the following settings in the yml:
my:
caller:
- id: someId
url: someUrl
context: someContext
- id: someId2
url: someUrl2
context: someContext2
So basically it's a list of objects (I've created a POJO which has the 3 fields). Those objects are represented as a List in another class which is a #Component and has a #ConfigurationProperties(prefix = "my") and the List of POJOs is with #NestedConfigurationproperty.
So far everything works perfectly, Spring constructs the objects from the application.yml and fills the List just fine, however I can't simulate this configuration in CloudFoundry. I'm using a different manifest.yml for cloudfoundry, and I'm trying to place this structure in the env part of the manifest but it's not working (Cloudfoundry ignores it).
It looks something like this:
env:
my:
caller:
- id: someId
url: someUrl
context: someContext
- id: someId2
url: someUrl2
context: someContext2
I know with simple lines it works (for example ev_my_caller_id) but that way I can construct only 1 object, not a whole list and I haven't found anything in the CloudFoundry doc on how to construct multiple objects from the manifest.
If anyone has any ideas I would be really grateful!
The env block of the Cloud Foundry cli's manifest.yml file has a specific format. You cannot use an arbitrary structure and expect it to work.
The format is:
env:
var_name_1: val_1
var_name_2: val_2
See docs for more details -> https://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html#env-block
If you set the env variable with the correct name, you can use that to override certain values in Spring. Thanks to Spring Boot's external configuration support. Maybe that would be an option for you here.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Ex: MY_PROPERTY=1234 would override my.property in application.properties.
You could use the SPRING_APPLICATION_JSON environment variable mentioned in the Spring Boot external config link that Daniel provided.
In your case, that would like something like this:
env:
SPRING_APPLICATION_JSON: '{ "my": { "caller": [{ "id": "someId", "url": "someUrl", "context": "someContext" }, { "id": "someId2", "url": "someUrl2", "context": "someContext2" }]}}'
Not sure what you are trying to do, but you can try something like this:
env:
test: '{ whatever complex object/variables }'
e.g.
env:
test: '{ variable = value, variable2 = value2 }'

Resources