@@ -14,6 +14,7 @@ import (
14
14
"k8s.io/apimachinery/pkg/runtime"
15
15
yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
16
16
"k8s.io/apimachinery/pkg/util/yaml"
17
+ "k8s.io/client-go/util/jsonpath"
17
18
18
19
templatesv1 "github.com/weaveworks/gitopssets-controller/api/v1alpha1"
19
20
"github.com/weaveworks/gitopssets-controller/controllers/templates/generators"
@@ -49,56 +50,106 @@ func Render(ctx context.Context, r *templatesv1.GitOpsSet, configuredGenerators
49
50
return rendered , nil
50
51
}
51
52
52
- func renderTemplateParams (tmpl templatesv1.GitOpsSetTemplate , params map [string ]any , ns string ) ([]* unstructured.Unstructured , error ) {
53
- rendered , err := render (tmpl .Content .Raw , params )
53
+ func repeat (tmpl templatesv1.GitOpsSetTemplate , params map [string ]any ) ([]any , error ) {
54
+ if tmpl .Repeat == "" {
55
+ return []any {
56
+ map [string ]any {
57
+ "element" : params ,
58
+ },
59
+ }, nil
60
+ }
61
+
62
+ jp := jsonpath .New ("repeat" )
63
+ err := jp .Parse (tmpl .Repeat )
54
64
if err != nil {
55
- return nil , err
65
+ return nil , fmt . Errorf ( "failed to parse repeat on template %q: %w" , tmpl . Repeat , err )
56
66
}
57
67
58
- // Technically multiple objects could be in the YAML...
59
- var objects []* unstructured.Unstructured
60
- decoder := yaml .NewYAMLOrJSONDecoder (bytes .NewReader (rendered ), 100 )
61
- for {
62
- var rawObj runtime.RawExtension
63
- if err := decoder .Decode (& rawObj ); err != nil {
64
- if err != io .EOF {
65
- return nil , fmt .Errorf ("failed to parse rendered template: %w" , err )
68
+ results , err := jp .FindResults (params )
69
+ if err != nil {
70
+ return nil , fmt .Errorf ("failed to find results from expression %q: %w" , tmpl .Repeat , err )
71
+ }
72
+
73
+ repeated := []any {}
74
+ for _ , result := range results {
75
+ for _ , v := range result {
76
+ slice , ok := v .Interface ().([]any )
77
+ if ok {
78
+ repeated = append (repeated , slice ... )
79
+ } else {
80
+ repeated = append (repeated , v )
66
81
}
67
- break
68
82
}
83
+ }
84
+
85
+ elements := []any {}
86
+ for _ , v := range repeated {
87
+ elements = append (elements , map [string ]any {
88
+ "element" : params ,
89
+ "repeat" : v ,
90
+ })
91
+ }
92
+
93
+ return elements , nil
94
+ }
95
+
96
+ func renderTemplateParams (tmpl templatesv1.GitOpsSetTemplate , params map [string ]any , ns string ) ([]* unstructured.Unstructured , error ) {
97
+ var objects []* unstructured.Unstructured
69
98
70
- m , _ , err := yamlserializer .NewDecodingSerializer (unstructured .UnstructuredJSONScheme ).Decode (rawObj .Raw , nil , nil )
99
+ repeatedParams , err := repeat (tmpl , params )
100
+ if err != nil {
101
+ return nil , err
102
+ }
103
+
104
+ for _ , p := range repeatedParams {
105
+ rendered , err := render (tmpl .Content .Raw , p )
71
106
if err != nil {
72
- return nil , fmt . Errorf ( "failed to decode rendered template: %w" , err )
107
+ return nil , err
73
108
}
74
109
75
- unstructuredMap , err := runtime .DefaultUnstructuredConverter .ToUnstructured (m )
76
- if err != nil {
77
- return nil , fmt .Errorf ("failed convert parsed template: %w" , err )
110
+ // Technically multiple objects could be in the YAML...
111
+ decoder := yaml .NewYAMLOrJSONDecoder (bytes .NewReader (rendered ), 100 )
112
+ for {
113
+ var rawObj runtime.RawExtension
114
+ if err := decoder .Decode (& rawObj ); err != nil {
115
+ if err != io .EOF {
116
+ return nil , fmt .Errorf ("failed to parse rendered template: %w" , err )
117
+ }
118
+ break
119
+ }
120
+
121
+ m , _ , err := yamlserializer .NewDecodingSerializer (unstructured .UnstructuredJSONScheme ).Decode (rawObj .Raw , nil , nil )
122
+ if err != nil {
123
+ return nil , fmt .Errorf ("failed to decode rendered template: %w" , err )
124
+ }
125
+
126
+ unstructuredMap , err := runtime .DefaultUnstructuredConverter .ToUnstructured (m )
127
+ if err != nil {
128
+ return nil , fmt .Errorf ("failed convert parsed template: %w" , err )
129
+ }
130
+ delete (unstructuredMap , "status" )
131
+ uns := & unstructured.Unstructured {Object : unstructuredMap }
132
+
133
+ if uns .GetKind () != "Namespace" {
134
+ uns .SetNamespace (ns )
135
+ }
136
+ objects = append (objects , uns )
78
137
}
79
- delete (unstructuredMap , "status" )
80
- uns := & unstructured.Unstructured {Object : unstructuredMap }
81
- uns .SetNamespace (ns )
82
- objects = append (objects , uns )
83
138
}
84
139
85
140
return objects , nil
86
141
}
87
142
88
143
// TODO: pass the `GitOpsSet` through to here so that we can fix the
89
144
// `template.New` to include the name/namespace.
90
- func render (b []byte , params map [ string ] any ) ([]byte , error ) {
145
+ func render (b []byte , params any ) ([]byte , error ) {
91
146
t , err := template .New ("gitopsset-template" ).Funcs (templateFuncs ).Parse (string (b ))
92
147
if err != nil {
93
148
return nil , fmt .Errorf ("failed to parse template: %w" , err )
94
149
}
95
150
96
- data := map [string ]any {
97
- "element" : params ,
98
- }
99
-
100
151
var out bytes.Buffer
101
- if err := t .Execute (& out , data ); err != nil {
152
+ if err := t .Execute (& out , params ); err != nil {
102
153
return nil , fmt .Errorf ("failed to render template: %w" , err )
103
154
}
104
155
0 commit comments