Spring Cloud Vault Configuration without YAML file - spring

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

Related

Spring boot application not fetching cloud configs on S3

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?

Spring Boot (Batch) - Inject Datasource

I have a Spring Boot (batch-oriented) application that uses a datasource in order to finalize a batch job and write stuff to the database.
I have the datasource(s) defined inside the application.yml like:
spring:
datasource:
url: jdbc:h2:mem:JavaSpringBootBatch
username: sa
password:
profiles: # default, development, production
active: default, development
---
spring:
h2:
# ...config/settings here
profiles: development
---
spring:
datasource:
# ...datasource config here
profiles: production
The issue is when I try to inject the datasource into one of the Spring config files:
#Configuration
public class PlayerBatchConfig {
...
#Bean
public ItemWriter<Player> writer(final DataSource dataSource) {
final JdbcBatchItemWriter<Player> jdbcItemWriter = new JdbcBatchItemWriter<>();
...
jdbcItemWriter.setDataSource(dataSource);
jdbcItemWriter.setSql(sql.toString());
return jdbcItemWriter;
}
}
...it tells me that:
Could not autowire. There is more than one bean of 'DataSource' type.
Beans:
dataSource (DataSourceConfiguration.class)
dataSource (EmbeddedDataSourceConfiguration.class)
I also tried to inject the datasource like:
#Configuration
public class PlayerBatchConfig {
#Bean
#ConfigurationProperties(prefix = "datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
...
}
...but no luck :( , although the issue with the two datasources goes away eventually.
Any clues how to "circumvent" that?
Since you have 2 datasources you need the annotate them with the #Qualifier the datasources bean and when you use them as well. Spring is telling you it doesn't know which one you want to use.
The DataSource which you want to use annotate it with #Primary, refer spring-boot documentation here for further info. Along with #Primary you might also need to use #Qualifier for controlling the bean injection.

Rabbitmq camel spring boot auto config

I have camel and rabbitmq configured like the following and it is working. I am looking to improve the config setup.
pom.xml
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-rabbitmq-starter</artifactId>
<version>2.19.1</version>
</dependency>
application.yml
spring:
rabbitmq:
host: rabbithost-url
port: 5672
username: my-user
password: my-password
config bean
#Configuration
public class CamelConfig {
#Resource private Environment env;
#Bean
public ConnectionFactory rabbitConnectionFactory(){
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost(env.getProperty("spring.rabbitmq.host"));
connectionFactory.setPort(Integer.valueOf(env.getProperty("spring.rabbitmq.port")));
connectionFactory.setAutomaticRecoveryEnabled(true);
// more config options here etc
return connectionFactory;
}
}
Route Example
#Component
public class MyRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:startQueuePoint")
.id("idOfQueueHere")
.to("rabbitmq://rabbithost-url:5672/TEST-QUEUE.exchange?queue=TEST-QUEUE.queue&autoDelete=false&connectionFactory=#rabbitConnectionFactory")
.end();
}
}
Would like to improve the following? Or at least see if its possible?
1) How do I leverage spring boot autowiring. I feel like im duplicating beans by added the custom CamelConfig > rabbitConnectionFactory? Its not using the RabbitAutoconfiguration?
2) When I am using the connection factory I am referencing the rabbitmq-url and port twice? I am adding it in the rabbitConnectionFactory bean object and in the camel url? e.g.
.to("rabbitmq://rabbithost-url:5672/ ..etc.. &connectionFactory=#rabbitConnectionFactory")
can I not just reference it once in the connection factory? tried the following without the host as its included in connectionFactory but it did not work.
.to("rabbitmq://TEST-QUEUE.exchange?queue=TEST-QUEUE.queue&autoDelete=false&connectionFactory=#rabbitConnectionFactory")
The 1st working example I am using is based off this.
camel.apache.org/rabbitmq example (see Custom connection factory )
Found from looking at the newer docs on github.
Notice that now no url needed in the start of the route.
.to(rabbitmq:exchangeName?options
Full camel route example below
.to(rabbitmq:exchangeName?queueName&exchangeType=direct&connectionFactory=#rabbitConnectionFactory&autoDelete=false
Here is url:
https://github.com/apache/camel/blob/master/components/camel-rabbitmq/src/main/docs/rabbitmq-component.adoc

Issues with Spring cloud consul config while starting a Groovy app through Spring cloud cli

I am Exploring Consul for discovery and config server. I have added the required dependencies and yml file is set up. When i try to start the server using spring cloud cli (Spring run .) I am getting the below error which i am unable to resolve. Any help is appreciated.
Error :
"A component required a bean named 'configServerRetryInterceptor' that could >not be found."
I tried to define this bean but when i start the app through spring cloud cli it is not recognizing it.
Please see the code below
App.groovy
#Grab("spring-cloud-starter-consul-config")
#Grab("spring-cloud-starter-consul-discovery")
#EnableDiscoveryClient
#EnableCircuitBreaker
#RestController
#Log
class Application{
#Autowired
Greeter greeter
int counter = 0
#RequestMapping(value = "/counter", produces = "application/json")
String produce() {
counter++
log.info("Produced a value: ${counter}")
"{\"value\": ${counter}}"
}
#RequestMapping("/")
String home() {
"${greeter.greeting} World!"
}
#RequestMapping(value = '/questions/{questionId}')
#HystrixCommand(fallbackMethod = "defaultQuestion")
def question(#PathVariable String questionId) {
if(Math.random() < 0.5) {
throw new RuntimeException('random');
}
[questionId: questionId]
}
def defaultQuestion(String questionId) {
[questionId: 'defaultQuestion']
}
}
#Component
#RefreshScope
class Greeter {
#Value('${greeting}')
String greeting
}
bootstrap.yml
consul:
host: localhost
port: 8500
config:
enabled: true
prefix: config
defaultContext: master
profileSeparator: '::'
format: FILES
discovery:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
health-check-url: http://127.0.0.1:${server.port}/health
This issue was due to unwanted dependencies being pulled.
Explicitly disabling spring cloud config and spring cloud discovery fixed it.
spring:
cloud:
config:
enabled: false
discovery:
enabled: false
serviceId: CONFIG
eureka:
client:
register-with-eureka: false
fetch-registry: false

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