Spring boot application not fetching cloud configs on S3 - spring-boot

I have a Java spring boot application with gradle. I have my config file in S3. This is the file I have:
description: Service Configuration
source:
profile: prod
server:
port: 8080
servlet:
context-path: /myservice-service
firebase:
authorization-header: "Basic XYZ"
base: baseurl
token-uri: tokenurl
it is named service-dev.yml on S3
I also have the appropriate prop classes:
#Configuration
#ComponentScan
#EnableConfigurationProperties(value = {
MyProps.class
})
public class PropConfiguration {
}
#Data
#Configuration
#Primary
#ConfigurationProperties(prefix = "firebase")
public class FirebaseProps {
private String authorizationHeader;
private String base;
private String tokenUri;
}
but when I try to use the props in my code, I get the error: "could not resolve placeholder in string". For instance when I do "${firebase.base}".
When I run in intelliJ, I have the environment variables set to my S3 bucket with the password and such.
Any suggestions on where I may be going wrong?

Related

Spring Boot: Autowiring app credentials within custom autoconfiguration bean returns null

I am working with a custom AWS Simple System Management client just to avoid the original from using the default AWS authentication chain, so I placed my class in /META-INF/spring.factories and excluded the original from being autconfigured in bootstrap.yml . What I'm facing right now is to get the credentials from application.yml and pass them to my new conf, but when I try to autowire them all I get is null. I wonder if there is any way to achieve it
Here is the code:
package es.example;
import lombok.*;
import org.springframework.boot.context.properties.*;
#ConfigurationProperties(prefix = "aws.credentials")
#Data
public class CustomAWSSSMAuthProperties {
private String accessKey;
private String secretKey;
}
package es.example;
import com.amazonaws.services.simplesystemsmanagement.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.context.properties.*;
#EnableConfigurationProperties(CustomAWSSSMAuthProperties.class)
public class CustomAWSSSMClient extends AWSSimpleSystemsManagementClient {
#Autowired
private CustomAWSSSMAuthProperties customProperties;
public CustomAWSSSMClient() {
String accessKey = customProperties.getAccessKey();
String secretKey = customProperties.getSecretKey();
}
}
/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
es.example.CustomAWSSSMClient
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
es.example.CustomAWSSSMClient
bootstrap.yml
spring:
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
autoconfigure.exclude: com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClient
Many thanks
#ConfigurationProperties does not create a bean like #Configuration or #Component does. In your case CustomAWSSSMAuthProperties type bean/object will not be instantiated in the Spring context.
Generally #ConfigurationProperties is used with #Configuration or #Bean to bind the some properties to the bean.
You can annotate CustomAWSSSMAuthProperties with #Configuration to fix the issue.

Why Spring Boot ignores configuration file inside its jar?

I have Spring Boot app with application-aficheDataProvider.yml in resources folder.
Content of application-aficheDataProvider.yml:
application:
afiches:
endpoints:
- http://localhost:8080
That content mapped into config class
class AfichesConfiguration #ConstructorBinding constructor(
val endpoints: Set<String>
)
#Configuration
#ConfigurationProperties(prefix = "application")
class ApplicationConfiguration {
#NestedConfigurationProperty
lateinit var afiches: AfichesConfiguration
}
And fetched with SpEL
#Service
class AficheService #Autowired constructor(
#Value("#{applicationConfiguration.afiches.endpoints}")
endpoints: Collection<String>
)
I build my app, jar it (configuration file moved into jar archive) and launch it with profile aficheDataProvider.
But it throw exception:
How can I fix it?

Spring Cloud Vault Configuration without YAML file

I have mentioned the Spring Cloud Vault Configuration in my bootstrap.ymlfile
spring:
cloud:
vault:
authentication: APPROLE
app-role:
role-id: *****
secret-id: ****
host: ****
port: 80
scheme: http
But i dont want to have these in my YML file, rather i would like to have these configured as a bean
#configuration / #bean
Please help. Thanks
I was able to do this successfully by configuring a Bean of type VaultProperties. Below is the code snippet which completely eliminated the need for maintaining the same in bootstrap.yml
#Configuration
public class VaultConfiguration {
#Bean
public VaultProperties vaultProperties() {
VaultProperties vaultProperties = new VaultProperties();
vaultProperties.setAuthentication(VaultProperties.AuthenticationMethod.APPROLE);
VaultProperties.AppRoleProperties appRoleProperties = new VaultProperties.AppRoleProperties();
appRoleProperties.setRoleId("****");
appRoleProperties.setSecretId("****");
vaultProperties.setAppRole(appRoleProperties);
vaultProperties.setHost("***");
vaultProperties.setPort(80);
vaultProperties.setScheme("http");
return vaultProperties;
}
}
Note : When you are having a configuration that should be treated as bootstrap-configuration, then you need to mention the class name under src/main/resources/META-INF/spring.factories
The content in spring.factories is
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.arun.local.cloudconfig.VaultConfiguration

SpringBoot LDAPTemplate Embedded vs Real LDAP

I am using the below mentioned properties in my SpringBoot App, in application.yml file to have the LDAP Code run in my local machine.
spring:
ldap:
# Use this embedded configuration for local ldap testing
embedded:
base-dn: o=localcompany,c=US
credential:
username: uid=admin
password: secret
ldif: classpath:schemas.ldif
port: 12345
validation:
enabled: false
# Use this below configuration for Ford ldap
# urls: ldaps://mmm.mmm.com:754
# base-dn: o=****,c=US
# username:
# password: {your password goes here}
I want to have both my embedded configuration & actual configuration exist in my Application, so that it works locally as well as in my Cloud Environment. But having Embedded properties in my yml file is overwriting the actual ones even in Cloud Environment. Is there a way to have both the properties and then according to the Environment, wire the LDAPTemplate
I configured my LDAPTemplate using #profile annotation that would differentiate the local and Server environment and achieved what I asked above. Below is my configuration. For the Local environment, having the embedded-properties are sufficient to have LDAPTemplate wired properly
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
#Configuration
#Profile("cloud")
public class LDAPConfiguration {
#Value("${ldap.url}")
private String ldapUrl;
#Value("${ldap.base}")
private String ldapBase;
#Value("${ldap.username}")
private String ldapUser;
#Value("${ldap.password}")
private String ldapPassword;
#Bean
public LdapTemplate configureLdapTemplateForCloud() {
return new LdapTemplate(contextSource()) ;
}
private LdapContextSource contextSource() {
LdapContextSource ldapContextSource = new LdapContextSource();
ldapContextSource.setUrl(ldapUrl);
ldapContextSource.setBase(ldapBase);
ldapContextSource.setUserDn(ldapUser);
ldapContextSource.setPassword(ldapPassword);
ldapContextSource.afterPropertiesSet();
return ldapContextSource;
}
}
So now, when I run in my local, Spring Boot will play with my Embedded LDAP, but in the cloud profile, it will execute the actual LDAP Server.

Share configuration between Spring cloud config clients

I'm trying to share configuration between Spring Cloud clients with a Spring Cloud config server which have a file-based repository:
#Configuration
#EnableAutoConfiguration
#EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
// application.yml
server:
port: 8888
spring:
profiles:
active: native
test:
foo: world
One of my Spring Cloud client use the test.foo configuration, defined in the config server, and it is configured like below:
#SpringBootApplication
#RestController
public class HelloWorldServiceApplication {
#Value("${test.foo}")
private String foo;
#RequestMapping(path = "/", method = RequestMethod.GET)
#ResponseBody
public String helloWorld() {
return "Hello " + this.foo;
}
public static void main(String[] args) {
SpringApplication.run(HelloWorldServiceApplication.class, args);
}
}
// boostrap.yml
spring:
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
fail-fast: true
// application.yml
spring:
application:
name: hello-world-service
Despite this configuration, the Environment in the Spring Cloud Client doesn't contains the test.foo entry (cf java.lang.IllegalArgumentException: Could not resolve placeholder 'test.foo')
However it's works perfectly if i put the properties in a hello-world-service.yml file, in my config server file-based repository.
Maven dependencies on Spring Cloud Brixton.M5 and Spring Boot 1.3.3.RELEASE with spring-cloud-starter-config and spring-cloud-config-server
From Spring Cloud documentation
With the "native" profile (local file system backend) it is
recommended that you use an explicit search location that isn’t part
of the server’s own configuration. Otherwise the application*
resources in the default search locations are removed because they are
part of the server.
So i should put the shared configuration in an external directory and add the path in the application.yml file of the config-server.
// application.yml
spring:
profiles:
active: native
cloud:
config:
server:
native:
search-locations: file:/Users/herau/config-repo
// /Users/herau/config-repo/application.yml
test:
foo: world

Resources