1
1
package argocd
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"fmt"
6
7
"path/filepath"
@@ -21,7 +22,7 @@ import (
21
22
22
23
"github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
23
24
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
24
- "gopkg.in/yaml.v2 "
25
+ "gopkg.in/yaml.v3 "
25
26
)
26
27
27
28
// Stores some statistics about the results of a run
@@ -418,6 +419,45 @@ func setAppImage(app *v1alpha1.Application, img *image.ContainerImage) error {
418
419
return err
419
420
}
420
421
422
+ func marshalWithIndent (in interface {}, indent int ) (out []byte , err error ) {
423
+ var b bytes.Buffer
424
+ encoder := yaml .NewEncoder (& b )
425
+ defer encoder .Close ()
426
+ // note: yaml.v3 will only respect indents from 1 to 9 inclusive.
427
+ encoder .SetIndent (indent )
428
+ if err = encoder .Encode (in ); err != nil {
429
+ return nil , err
430
+ }
431
+ if err = encoder .Close (); err != nil {
432
+ return nil , err
433
+ }
434
+ return b .Bytes (), nil
435
+ }
436
+
437
+ func guessIndent (root * yaml.Node ) int {
438
+ node := root
439
+ if root .Kind == yaml .DocumentNode {
440
+ if len (node .Content ) == 0 {
441
+ return 2
442
+ }
443
+ node = root .Content [0 ]
444
+ }
445
+ // anything other than a map at the root makes guessing difficult
446
+ if node .Kind != yaml .MappingNode || len (node .Content ) == 0 {
447
+ return 2
448
+ }
449
+ // first level map entries that are themselves mappings or sequences,
450
+ // in block style, and are indented, allow guessing the preferred indent.
451
+ for i , child := range node .Content {
452
+ if i % 2 == 1 && child .Column > 1 && child .Column < 10 && child .Style != yaml .FlowStyle {
453
+ if child .Kind == yaml .MappingNode || child .Kind == yaml .SequenceNode {
454
+ return child .Column - 1
455
+ }
456
+ }
457
+ }
458
+ return 2
459
+ }
460
+
421
461
// marshalParamsOverride marshals the parameter overrides of a given application
422
462
// into YAML bytes
423
463
func marshalParamsOverride (app * v1alpha1.Application , originalData []byte ) ([]byte , error ) {
@@ -441,16 +481,16 @@ func marshalParamsOverride(app *v1alpha1.Application, originalData []byte) ([]by
441
481
}
442
482
443
483
if len (originalData ) == 0 {
444
- override , err = yaml . Marshal (newParams )
484
+ override , err = marshalWithIndent (newParams , 2 )
445
485
break
446
486
}
447
487
err = yaml .Unmarshal (originalData , & params )
448
488
if err != nil {
449
- override , err = yaml . Marshal (newParams )
489
+ override , err = marshalWithIndent (newParams , 2 )
450
490
break
451
491
}
452
492
mergeKustomizeOverride (& params , & newParams )
453
- override , err = yaml . Marshal (params )
493
+ override , err = marshalWithIndent (params , 2 )
454
494
case ApplicationTypeHelm :
455
495
if appSource .Helm == nil {
456
496
return []byte {}, nil
@@ -459,11 +499,12 @@ func marshalParamsOverride(app *v1alpha1.Application, originalData []byte) ([]by
459
499
if strings .HasPrefix (app .Annotations [common .WriteBackTargetAnnotation ], common .HelmPrefix ) {
460
500
images := GetImagesAndAliasesFromApplication (app )
461
501
462
- helmNewValues := yaml.MapSlice {}
502
+ helmNewValues := yaml.Node {}
463
503
err = yaml .Unmarshal (originalData , & helmNewValues )
464
504
if err != nil {
465
505
return nil , err
466
506
}
507
+ indent := guessIndent (& helmNewValues )
467
508
468
509
for _ , c := range images {
469
510
if c .ImageAlias == "" {
@@ -505,7 +546,7 @@ func marshalParamsOverride(app *v1alpha1.Application, originalData []byte) ([]by
505
546
}
506
547
}
507
548
508
- override , err = yaml . Marshal ( helmNewValues )
549
+ override , err = marshalWithIndent ( & helmNewValues , indent )
509
550
} else {
510
551
var params helmOverride
511
552
newParams := helmOverride {
@@ -518,16 +559,16 @@ func marshalParamsOverride(app *v1alpha1.Application, originalData []byte) ([]by
518
559
log .WithContext ().AddField ("application" , app ).Debugf ("values: '%s'" , outputParams )
519
560
520
561
if len (originalData ) == 0 {
521
- override , err = yaml . Marshal (newParams )
562
+ override , err = marshalWithIndent (newParams , 2 )
522
563
break
523
564
}
524
565
err = yaml .Unmarshal (originalData , & params )
525
566
if err != nil {
526
- override , err = yaml . Marshal (newParams )
567
+ override , err = marshalWithIndent (newParams , 2 )
527
568
break
528
569
}
529
570
mergeHelmOverride (& params , & newParams )
530
- override , err = yaml . Marshal (params )
571
+ override , err = marshalWithIndent (params , 2 )
531
572
}
532
573
default :
533
574
err = fmt .Errorf ("unsupported application type" )
@@ -572,72 +613,98 @@ func mergeKustomizeOverride(t *kustomizeOverride, o *kustomizeOverride) {
572
613
}
573
614
}
574
615
575
- // Check if a key exists in a MapSlice and return its index and value
576
- func findHelmValuesKey (m yaml.MapSlice , key string ) (int , bool ) {
577
- for i , item := range m {
578
- if item .Key == key {
579
- return i , true
616
+ // Check if a key exists in a MappingNode and return the index of its value
617
+ func findHelmValuesKey (m * yaml.Node , key string ) (int , bool ) {
618
+ for i , item := range m . Content {
619
+ if i % 2 == 0 && item .Value == key {
620
+ return i + 1 , true
580
621
}
581
622
}
582
623
return - 1 , false
583
624
}
584
625
626
+ func nodeKindString (k yaml.Kind ) string {
627
+ return map [yaml.Kind ]string {
628
+ yaml .DocumentNode : "DocumentNode" ,
629
+ yaml .SequenceNode : "SequenceNode" ,
630
+ yaml .MappingNode : "MappingNode" ,
631
+ yaml .ScalarNode : "ScalarNode" ,
632
+ yaml .AliasNode : "AliasNode" ,
633
+ }[k ]
634
+ }
635
+
585
636
// set value of the parameter passed from the annotations.
586
- func setHelmValue (currentValues * yaml.MapSlice , key string , value interface {}) error {
637
+ func setHelmValue (currentValues * yaml.Node , key string , value interface {}) error {
638
+ current := currentValues
639
+
640
+ // an unmarshalled document has a DocumentNode at the root, but
641
+ // we navigate from a MappingNode.
642
+ if current .Kind == yaml .DocumentNode {
643
+ current = current .Content [0 ]
644
+ }
645
+
646
+ if current .Kind != yaml .MappingNode {
647
+ return fmt .Errorf ("unexpected type %s for root" , nodeKindString (current .Kind ))
648
+ }
649
+
587
650
// Check if the full key exists
588
- if idx , found := findHelmValuesKey (* currentValues , key ); found {
589
- (* currentValues ) [idx ].Value = value
651
+ if idx , found := findHelmValuesKey (current , key ); found {
652
+ (* current ). Content [idx ].Value = value .( string )
590
653
return nil
591
654
}
592
655
593
656
var err error
594
657
keys := strings .Split (key , "." )
595
- current := currentValues
596
- var parent * yaml.MapSlice
597
- parentIdx := - 1
598
658
599
659
for i , k := range keys {
600
- if idx , found := findHelmValuesKey (* current , k ); found {
660
+ if idx , found := findHelmValuesKey (current , k ); found {
661
+ // Navigate deeper into the map
662
+ current = (* current ).Content [idx ]
663
+ // unpack one level of alias; an alias of an alias is not supported
664
+ if current .Kind == yaml .AliasNode {
665
+ current = current .Alias
666
+ }
601
667
if i == len (keys )- 1 {
602
668
// If we're at the final key, set the value and return
603
- (* current )[idx ].Value = value
604
- return nil
605
- } else {
606
- // Navigate deeper into the map
607
- if nestedMap , ok := (* current )[idx ].Value .(yaml.MapSlice ); ok {
608
- parent = current
609
- parentIdx = idx
610
- current = & nestedMap
669
+ if current .Kind == yaml .ScalarNode {
670
+ current .Value = value .(string )
671
+ current .Tag = "!!str"
611
672
} else {
612
- return fmt .Errorf ("unexpected type %T for key %s" , ( * current )[ idx ]. Value , k )
673
+ return fmt .Errorf ("unexpected type %s for key %s" , nodeKindString ( current . Kind ) , k )
613
674
}
675
+ return nil
676
+ } else if current .Kind != yaml .MappingNode {
677
+ return fmt .Errorf ("unexpected type %s for key %s" , nodeKindString (current .Kind ), k )
614
678
}
615
679
} else {
616
- newCurrent := yaml.MapSlice {}
617
- var newParent yaml.MapSlice
618
-
619
680
if i == len (keys )- 1 {
620
- newParent = append (* current , yaml.MapItem {Key : k , Value : value })
621
- } else {
622
- newParent = append (* current , yaml.MapItem {Key : k , Value : newCurrent })
623
- }
624
-
625
- if parent == nil {
626
- * currentValues = newParent
681
+ current .Content = append (current .Content ,
682
+ & yaml.Node {
683
+ Kind : yaml .ScalarNode ,
684
+ Value : k ,
685
+ Tag : "!!str" ,
686
+ },
687
+ & yaml.Node {
688
+ Kind : yaml .ScalarNode ,
689
+ Value : value .(string ),
690
+ Tag : "!!str" ,
691
+ },
692
+ )
693
+ return nil
627
694
} else {
628
- // if parentIdx has not been set (parent element is also new), set it to the last element
629
- if parentIdx == - 1 {
630
- parentIdx = len (* parent ) - 1
631
- if parentIdx < 0 {
632
- parentIdx = 0
633
- }
634
- }
635
- (* parent )[parentIdx ].Value = newParent
695
+ current .Content = append (current .Content ,
696
+ & yaml.Node {
697
+ Kind : yaml .ScalarNode ,
698
+ Value : k ,
699
+ Tag : "!!str" ,
700
+ },
701
+ & yaml.Node {
702
+ Kind : yaml .MappingNode ,
703
+ Content : []* yaml.Node {},
704
+ },
705
+ )
706
+ current = current .Content [len (current .Content )- 1 ]
636
707
}
637
-
638
- parent = & newParent
639
- current = & newCurrent
640
- parentIdx = - 1
641
708
}
642
709
}
643
710
0 commit comments