@@ -385,6 +385,7 @@ func (azappcfg *AzureAppConfiguration) loadKeyValues(ctx context.Context, settin
385385 var useAIConfiguration , useAIChatCompletionConfiguration bool
386386 kvSettings := make (map [string ]any , len (settingsResponse .settings ))
387387 keyVaultRefs := make (map [string ]string )
388+ snapshotRefs := make (map [string ]string )
388389 for trimmedKey , setting := range rawSettings {
389390 if setting .ContentType == nil || setting .Value == nil {
390391 kvSettings [trimmedKey ] = setting .Value
@@ -396,6 +397,9 @@ func (azappcfg *AzureAppConfiguration) loadKeyValues(ctx context.Context, settin
396397 continue // ignore feature flag while getting key value settings
397398 case secretReferenceContentType :
398399 keyVaultRefs [trimmedKey ] = * setting .Value
400+ case snapshotReferenceContentType :
401+ snapshotRefs [trimmedKey ] = * setting .Value
402+ azappcfg .tracingOptions .UseSnapshotReference = true
399403 default :
400404 if isJsonContentType (setting .ContentType ) {
401405 var v any
@@ -424,6 +428,21 @@ func (azappcfg *AzureAppConfiguration) loadKeyValues(ctx context.Context, settin
424428 azappcfg .tracingOptions .UseAIConfiguration = useAIConfiguration
425429 azappcfg .tracingOptions .UseAIChatCompletionConfiguration = useAIChatCompletionConfiguration
426430
431+ if len (snapshotRefs ) > 0 {
432+ var loadSnapshot snapshotSettingsLoader
433+ if client , ok := settingsClient .(* selectorSettingsClient ); ok {
434+ loadSnapshot = func (ctx context.Context , snapshotName string ) ([]azappconfig.Setting , error ) {
435+ return loadSnapshotSettings (ctx , client .client , snapshotName )
436+ }
437+ }
438+
439+ if loadSnapshot != nil {
440+ if err := azappcfg .loadSettingsFromSnapshotRefs (ctx , loadSnapshot , snapshotRefs , kvSettings , keyVaultRefs ); err != nil {
441+ return err
442+ }
443+ }
444+ }
445+
427446 secrets , err := azappcfg .loadKeyVaultSecrets (ctx , keyVaultRefs )
428447 if err != nil {
429448 return fmt .Errorf ("failed to load Key Vault secrets: %w" , err )
@@ -437,6 +456,78 @@ func (azappcfg *AzureAppConfiguration) loadKeyValues(ctx context.Context, settin
437456 return nil
438457}
439458
459+ func (azappcfg * AzureAppConfiguration ) loadSettingsFromSnapshotRefs (ctx context.Context , loadSnapshot snapshotSettingsLoader , snapshotRefs map [string ]string , kvSettings map [string ]any , keyVaultRefs map [string ]string ) error {
460+ var useAIConfiguration , useAIChatCompletionConfiguration bool
461+ for key , snapshotRef := range snapshotRefs {
462+ // Parse the snapshot reference
463+ snapshotName , err := parseSnapshotReference (snapshotRef )
464+ if err != nil {
465+ return fmt .Errorf ("invalid format for Snapshot reference setting %s: %w" , key , err )
466+ }
467+
468+ // Load the snapshot settings
469+ settingsFromSnapshot , err := loadSnapshot (ctx , snapshotName )
470+ if err != nil {
471+ return fmt .Errorf ("failed to load snapshot settings: key=%s, error=%w" , key , err )
472+ }
473+
474+ for _ , setting := range settingsFromSnapshot {
475+ if setting .Key == nil {
476+ continue
477+ }
478+
479+ trimmedKey := azappcfg .trimPrefix (* setting .Key )
480+ if len (trimmedKey ) == 0 {
481+ log .Printf ("Key of the setting '%s' is trimmed to the empty string, just ignore it" , * setting .Key )
482+ continue
483+ }
484+
485+ if setting .ContentType == nil || setting .Value == nil {
486+ kvSettings [trimmedKey ] = setting .Value
487+ continue
488+ }
489+
490+ contentType := strings .TrimSpace (strings .ToLower (* setting .ContentType ))
491+ if contentType == featureFlagContentType {
492+ continue
493+ }
494+
495+ if contentType == secretReferenceContentType {
496+ keyVaultRefs [trimmedKey ] = * setting .Value
497+ continue
498+ }
499+
500+ // Handle JSON content types (similar to regular key-value loading)
501+ if isJsonContentType (setting .ContentType ) {
502+ var v any
503+ if err := json .Unmarshal ([]byte (* setting .Value ), & v ); err != nil {
504+ // If the value is not valid JSON, try to remove comments and parse again
505+ if err := json .Unmarshal (jsonc .StripComments ([]byte (* setting .Value )), & v ); err != nil {
506+ // If still invalid, log the error and treat it as a plain string
507+ log .Printf ("Failed to unmarshal JSON value from snapshot: key=%s, error=%s" , * setting .Key , err .Error ())
508+ kvSettings [trimmedKey ] = setting .Value
509+ continue
510+ }
511+ }
512+ kvSettings [trimmedKey ] = v
513+ if isAIConfigurationContentType (setting .ContentType ) {
514+ useAIConfiguration = true
515+ }
516+ if isAIChatCompletionContentType (setting .ContentType ) {
517+ useAIChatCompletionConfiguration = true
518+ }
519+ } else {
520+ kvSettings [trimmedKey ] = setting .Value
521+ }
522+ }
523+ }
524+
525+ azappcfg .tracingOptions .UseAIConfiguration = useAIConfiguration
526+ azappcfg .tracingOptions .UseAIChatCompletionConfiguration = useAIChatCompletionConfiguration
527+
528+ return nil
529+ }
530+
440531func (azappcfg * AzureAppConfiguration ) loadKeyVaultSecrets (ctx context.Context , keyVaultRefs map [string ]string ) (map [string ]any , error ) {
441532 secrets := make (map [string ]any )
442533 if len (keyVaultRefs ) == 0 {
@@ -1019,3 +1110,20 @@ func isFailoverable(err error) bool {
10191110
10201111 return false
10211112}
1113+
1114+ // "{\"snapshot_name\":\"referenced-snapshot\"}"
1115+ func parseSnapshotReference (ref string ) (string , error ) {
1116+ var snapshotRef struct {
1117+ SnapshotName string `json:"snapshot_name"`
1118+ }
1119+
1120+ if err := json .Unmarshal ([]byte (ref ), & snapshotRef ); err != nil {
1121+ return "" , fmt .Errorf ("failed to parse snapshot reference: %w" , err )
1122+ }
1123+
1124+ if snapshotRef .SnapshotName == "" {
1125+ return "" , fmt .Errorf ("snapshot_name is empty in snapshot reference" )
1126+ }
1127+
1128+ return snapshotRef .SnapshotName , nil
1129+ }
0 commit comments