Closed jyotijauhari closed 1 month ago
@jyotijauhari, I think your issue is that by default the app configuration provider library trims all key filters off configurations. i.e. delegato.application.name became just application.name.
To stop this you need to set the spring.cloud.azure/appconfiguration.stores[0].trim-key-prefix
value to be ''
.
This library defaults to the key format of /<application-name>/configuration-properties-name.config
to match how spring config files work.
Also, I can't see everything you have, but your @ConfigurationProperties
value might need to have a prefix set, @ConfigurationProperties(prefix = "global")
Hi @mrm9084 thanks for your comment, my goal is to fetch both delegato and global keys from this personal app config.
I can get one key using key-filter: global and it loads that key directly in configurationClass. But I want to load both in 2 different configuration classes.
As shared by you I tried spring.cloud.azure/appconfiguration.stores[0].trim-key-prefix: ' '
my updated bootstrap.yaml
my global configuration class
my delegato configuration class
But value is not injected now in those classes
If that is the format you want this should work:
spring:
cloud:
azure:
appconfiguration:
stores:
selects:
-
key-filter: "global"
label-filter: "dev"
-
key-filter: "delegato"
label-filter: "dev"
trim-key-prefix:
- ""
The issue is that we require a prefix to load, and the default one is /application/
, this is no way to not have a key filter, if one isn't provided it goes to the default. You may want to check this out, https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/spring/spring-cloud-azure-starter-appconfiguration-config#supported-properties, it provides all of our
Thanks @mrm9084 , It's working now. Loading multiple keys was not much clear from documentation link .
On side note I have another question, we are using managed identity for pod, the value of connectionString is coming as null
I have following libraries:
springboot version : 2.7.7 azure spring cloud version: 4.14.0
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-appconfiguration-config</artifactId>
</dependency>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>4.14.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
cloud version : ( as using springboot 2, reffering to this article: https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-java-spring-app?tabs=spring-boot-2#connect-to-an-app-configuration-store)
I have this configuration file where i am trying to inject:
My bootstrap.yaml
spring:
cloud:
azure:
appconfiguration:
stores:
- endpoint: <endpoint>
selects:
- key-filter: global
label-filter: dev
- key-filter: globaltest
label-filter: dev
trim-key-prefix:
- ""
feature-flags:
enabled: true
selects:
- label-filter: dev
credential:
managed-identity-enabled: true
enabled: true
Its not loading configurations and its coming as null. note: 1.I confirm that manged identity is working as I am able to fetch feature flag from feature manager using managed identity.
I'm unsure why that would be happening the easiest way to see what is going on would be to add the Environment
somewhere in your code, and check out which configs we loaded. You will find them under: Environment.propertySources
which is a list of all the property sources. One will be of type BootstrapPropertySource
with the name something like bootstrapProperties-<key-filter><store-name><label-filter>
. Then in that object under delegate you will is a properties
object with a map of all the loaded key values.
All of the key values in the map are the names after the trim-key-prefix operation. so they would be as you are looking for them. i.e. global test.applicationinsight.connectionstring
.
Side Note, it isn't suggest to store secrets like connection strings in app configuration. We support key vault references to load key vault secrets as configuration. See: https://learn.microsoft.com/en-us/azure/azure-app-configuration/faq#how-is-app-configuration-different-from-azure-key-vault
Hi @mrm9084 , we tried to debug the same way you mentioned i.e to load BootstrapProperty. In properties we found its having FM_configurl/label-filter.
(managed identity approach)
In connection string approach we analysed same object there as well same property we found i.e FM_configurl/label-filter. (looks like configs are not there in bootstrap properties in both)
The interesting thing is with connectionString approach the configs are loading and having value inglobaltest.applicationinsight.connectionstring
while same key is null when using managed identity.
I am not able to figure out why. Do you know any other way to debug? the approach you mention bootstrap properties its just having feature management in properties.
Also, thanks for mentioning the point of not storing secrets directly. We are using key-vault itself. Initially while testing loading config with fetch value from key-vault was also returning null, so we tried with normal value.
@jyotijauhari, there should be a non FM_*
object. The FM stands for feature management and would be any loaded feature flags. The same thing without that prefix should exist.
Hi @mrm9084 , I have tried to log the properties, I was not able to log the whole properties object as its protected method, but I was able to log the keys in properties and I can see the keys are getting fetched and environment is dev (correct one). The problem is values are null when I am trying to access/log it.
I tried to log values from env as you mentioned and its having values, but injection of those values by @Configuration @ConfigurationProperties(prefix="global") is not working.
Same configuration in my other project which uses springboot 3 and latest app config and connection string works (able to inject value).
@jyotijauhari I think I figured it out. I missed that your configuration are not initialized. Spring doesn't auto create the classes for you, it just fills out the properties. So, you need to initialize your 3 classes.
I am not able to understand about initislisation part.
This is my one of configuration class
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration
@Configuration
@ConfigurationProperties(prefix = "globaltest")
open class GlobalConfigurationTest {
var applicationInsight: ApplicationInsight? = null
}
I am enabling configuration properties in main class
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.EnableConfigurationProperties
@SpringBootApplication
@EnableConfigurationProperties(GlobalConfiguration::class)
open class TestAppConfigApplication
fun main(args: Array<String>) {
ApplicationInsights.attach()
SpringApplication.run(TestAppConfigApplication::class.java, *args)
}
controller which I am using to test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource
import org.springframework.core.env.ConfigurableEnvironment
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/test/v1")
class AppConfigController {
@Autowired private lateinit var environment: ConfigurableEnvironment
@Autowired private lateinit var globalConfiguration: GlobalConfiguration
@Autowired private lateinit var globalConfigurationTest: GlobalConfigurationTest
@GetMapping("/configs-test")
fun getConfigsTest() {
val configurableEnvironment = environment
println("FINALLLYYYY global-> ${globalConfiguration.applicationInsight?.connectionString}")
println("FINALLLYYYY globaltest-> ${globalConfigurationTest.applicationInsight?.connectionString}")
}
I am not getting what I am missing here for initialisation? I thought @Autowired private lateinit var globalConfigurationTest: GlobalConfigurationTest
initialise the object
I'm not familiar with how Kotlin works but, I don't think var applicationInsight
in your GlobalConfiguration
file is being set to a non null value, which it needs to be before the property can be set into it. Spring will not auto create it.
Just to mention if it helps, I have same code in my other application which uses springboot 3 and latest config dependency (but it has connection string approach to fetch config) and it works. Its having non null value in applicationInsight. I am not able to figure out on how can I debug it.
Able to get it working. Its bit strange that with var in connection string approach is working, but not with managed identity. We made it val and it worked. Thanks @mrm9084 !
@jyotijauhari, I think this is good to be closed then. If you have another issue another issue can be opened.
We are trying to load multiple keys (keys name: global, delegato) in 2 different configuration classes
our app configuration looks like this:
libraries:
bootstrap.yaml:
Configuration classes:
We are trying to autowire this configuration classes and trying to read the value, but we are not able to read value of delegationconfiguration, and seems like global key-filter overwriting it.
we tried adding prefix to configuration as well that is also not working.
Our controller:
we even tried using key-filter: "" (i.e empty string as mentioned in https://microsoft.github.io/spring-cloud-azure/docs/azure-app-configuration/2.9.0/reference/html/index.html#loading-configuration, but thats also not working to load all keys)
Problem is we want to load both keys together in application, but seems like we cant load multiple keys.