Hello Spring Cloud Config Team,
On a Spring Cloud Config Server + Spring Cloud Config Client with Hashicorp Vault backend, the behavior is not the same between 2.0.3.RELEASE+Finchley.RC2 and 2.4.2+Ilford 2020.0.0
Following this tutorial: https://blog.marcosbarbero.com/integrating-vault-spring-cloud-config/#:~:text=%20Integrating%20Vault%20with%20Spring%20Cloud%20Config%20Server,Config%20Server%20in...%204%20Footnote.%20%20More%20
on a simple server:
package com.marcosbarbero.wd.configserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@EnableConfigServer
@RestController
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
application.properties, not bootstrap
logging.level.root=DEBUG
management.endpoints.web.exposure.include=info, health, env
server.port=8888
spring.profiles.active=vault
spring.application.name=configserver
spring.cloud.config.server.vault.kvVersion=2
spring.cloud.config.server.vault.port=8200
spring.cloud.config.server.vault.host=127.0.0.1
spring.cloud.config.server.vault.backend=cubbyhole
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.marcosbarbero.wd</groupId>
<artifactId>config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>config-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
Client:
package com.marcosbarbero.wd.configclient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${client.pseudo.property}")
private String pseudoProperty;
@GetMapping("/property")
public ResponseEntity<String> getProperty() {
return ResponseEntity.ok(pseudoProperty);
}
}
bootstrap.propeties, not application.properties
logging.level.root=DEBUG
spring.application.name=myservice
spring.cloud.config.token=myroot
spring.cloud.config.uri=http://localhost:8888
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.marcosbarbero.wd</groupId>
<artifactId>config-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>config-client</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
Everything is working fine.
Actually, even after bumping just the client to 2.4.2 + 2020.0.0, and converting to application.properties
spring.application.name=myservice
spring.cloud.config.token=myroot
spring.cloud.config.uri=http://localhost:8888
spring.config.import=optional:configserver:http://localhost:8888
It is still working!
Now, last step, bumping the server to 2.4.2: sadly, bug, the client is not picking the property anymore.
Any help please? Thank you
Comment From: spencergibb
Ilford was a major release and contained breaking changes. See https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2020.0-Release-Notes#breaking-changes
Comment From: patpatpat123
Understood @spencergibb , many thanks.
I have been reading the paragraph "Breaking changes" for the last hour now, even out loud.
However, I do not understand.
I changed the application.properties file to
spring.application.name=myservice
spring.cloud.config.token=myroot
spring.config.import=vault:http://localhost:8888
in respect to ```Support has been added for the new Spring Boot spring.config.import syntax for Config Server, Consul, Zookeeper and Vault. The existing properties to configure the different services are still supported but need to be put in application.properties or application.yml.
spring.config.import=configserver: spring.config.import=consul: spring.config.import=zookeeper: spring.config.import=vault:
However, I am getting
[main] ERROR org.springframework.boot.SpringApplication - Application run failed java.lang.IllegalStateException: Unable to load config data from 'vault:http://localhost:8888' at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences(StandardConfigDataLocationResolver.java:128) at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolve(StandardConfigDataLocationResolver.java:115) at org.springframework.boot.context.config.ConfigDataLocationResolvers.lambda$resolve$1(ConfigDataLocationResolvers.java:114) at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:125) at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:114) at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:106) at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:101) at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:93) at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:81) at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:119) at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:237) at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:225) at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:97) at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89) at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:100) at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:86) at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131) at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82) at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63) at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117) at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111) at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62) at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:362) at org.springframework.boot.SpringApplication.run(SpringApplication.java:320) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at com.marcosbarbero.wd.configclient.ConfigClientApplication.main(ConfigClientApplication.java:15) Caused by: java.lang.IllegalStateException: File extension is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/' at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferencesForFile(StandardConfigDataLocationResolver.java:214) at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences(StandardConfigDataLocationResolver.java:125) ... 30 common frames omitted
Process finished with exit code 1
What is the new way to set the token and the config server with Vault backend please?
**Comment From: spencergibb**
You'll want `configserver:` since you are using configserver. Vault is configured in configserver
**Comment From: patpatpat123**
Many thank, then indeed, there might be a bug?
if I leave the property file: (with configserver)
spring.application.name=myservice spring.cloud.config.token=myroot spring.config.import=optional:configserver:http://localhost:8888
Indeed ,the client does not encounter "[main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Unable to load config data from 'vault:http://localhost:8888'"
I can even see on the server side the call to retrieve the key value from client (btw, from 2.0 to 2.4, there is am unexpected **/data** added to the URL
Log from 2.0: App starts and property is being picked
o.s.web.client.RestTemplate : Created GET request for "http://127.0.0.1:8200/v1/cubbyhole/myservice" org.apache.http.wire : http-outgoing-0 << "{"request_id":"aa709c12-6c60-03b8-cc16-c05794ec8c58","lease_id":"","renewable":false,"lease_duration":0,"data":{"client.pseudo.property":"2.0"},"wrap_info":null,"warnings":null,"auth":null}[\n]" m.m.a.RequestResponseBodyMethodProcessor : Written [Environment [name=myservice, profiles=[default], label=null, propertySources=[PropertySource [name=vault:myservice]], version=null, state=null]] as "application/vnd.spring-cloud.config-server.v2+json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@73a0f2b]
Log from 2.4: cannot resolve property
o.s.web.client.RestTemplate : HTTP GET http://127.0.0.1:8200/v1/cubbyhole/data/myservice org.apache.http.wire : http-outgoing-0 << "{"request_id":"71fe1d2f-d176-72c3-58da-d716c69bfc7e","lease_id":"","renewable":false,"lease_duration":0,"data":{"client.pseudo.property":"2.4.2"},"wrap_info":null,"warnings":null,"auth":null}[\n]" m.m.a.RequestResponseBodyMethodProcessor : Writing [Environment [name=myservice, profiles=[default], label=null, propertySources=[], version=null, s (truncated)...] ```
Although the client starts without "[main] ERROR org.springframework.boot.SpringApplication - Application run failed java.lang.IllegalStateException: Unable to load config data from 'vault:http://localhost:8888'" But still, on client side, the property cannot be resolved 😭
Comment From: patpatpat123
ok, after reading the section "Vault Backend" from https://github.com/spring-cloud/spring-cloud-config/blob/13b9030e0f168499a93207af590ba4d6cb196091/docs/src/main/asciidoc/spring-cloud-config.adoc I now understand about the /data part.
However, still a bit puzzled why the property is being retrieve at server side, put the client still cannot java.lang.IllegalArgumentException: Could not resolve placeholder 'client.pseudo.property' in value "${client.pseudo.property}"
Comment From: spencergibb
What does /actuator/env
say?
Comment From: spring-cloud-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: patpatpat123
Unfortunately, I am not able to reproduce this issue anymore.
Thank you