@@ -20,16 +20,23 @@ import (
20
20
"bytes"
21
21
"context"
22
22
"fmt"
23
+ "os"
24
+ "os/exec"
25
+ "path"
26
+ "runtime"
23
27
"sort"
24
28
"strings"
29
+ "time"
25
30
26
31
"github.com/go-logr/logr"
27
32
"github.com/google/go-containerregistry/pkg/authn/k8schain"
28
33
"github.com/vmware-labs/reconciler-runtime/apis"
29
34
"github.com/vmware-labs/reconciler-runtime/reconcilers"
30
35
"github.com/vmware-labs/reconciler-runtime/tracker"
36
+ "gopkg.in/yaml.v2"
31
37
corev1 "k8s.io/api/core/v1"
32
38
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
39
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
33
40
"k8s.io/apimachinery/pkg/labels"
34
41
"k8s.io/apimachinery/pkg/runtime/schema"
35
42
"k8s.io/apimachinery/pkg/types"
@@ -132,19 +139,15 @@ func ResolveConventions() reconcilers.SubReconciler {
132
139
convention .ClientConfig = * clientConfig
133
140
} else if source .Spec .Ytt != nil {
134
141
log .Info ("handling a ytt based convention" )
135
- // read template spec and convenert to a sptream of bytes
136
- // template
137
- template := & parent .Spec .Template
138
- // convert template as a stream of bytes
139
- // templatesAsBytes = bytes.NewBuffer([]byte(template(string)))
140
-
141
- // convert template to a stream of bytes
142
- // kubectl = "kubectl"
143
- // ytt = "ytt"
144
- // args
145
- log .Info ("your template spec" , template .GetObjectMeta ())
146
-
147
- return nil
142
+
143
+ // read template spec and convert to string
144
+
145
+ log .Info ("retrieved pod template spec from the workload" , parent )
146
+ stampedObj , err := ApplyYtt (ctx , * parent )
147
+ if err != nil {
148
+ return nil
149
+ }
150
+ log .Info ("stamped out object" , stampedObj )
148
151
}
149
152
conventions = append (conventions , convention )
150
153
}
@@ -162,6 +165,51 @@ func ResolveConventions() reconcilers.SubReconciler {
162
165
}
163
166
}
164
167
168
+ func ApplyYtt (ctx context.Context , workload conventionsv1alpha1.PodIntent ) (interface {}, error ) {
169
+ template := workload .Spec .Template .AsPodTemplateSpec ()
170
+ log := logr .FromContextOrDiscard (ctx )
171
+
172
+ ctx , cancel := context .WithTimeout (ctx , 4 * time .Second )
173
+ defer cancel ()
174
+
175
+ ytt := "ytt"
176
+ if kodata , ok := os .LookupEnv ("KO_DATA_PATH" ); ok {
177
+ ytt = path .Join (kodata , fmt .Sprintf ("ytt-%s-%s" , runtime .GOOS , runtime .GOARCH ))
178
+ }
179
+
180
+ args := []string {"--version" }
181
+ stdin := bytes .NewReader ([]byte (template .Spec .String ()))
182
+ stdout := bytes .NewBuffer ([]byte {})
183
+ stderr := bytes .NewBuffer ([]byte {})
184
+
185
+ cmd := exec .CommandContext (ctx , ytt , args ... )
186
+ cmd .Stdin = stdin
187
+ cmd .Stdout = stdout
188
+ cmd .Stderr = stderr
189
+
190
+ log .Info ("ytt call args" , args )
191
+ log .Info ("ytt call input" , template )
192
+
193
+ if err := cmd .Run (); err != nil {
194
+ msg := stderr .String ()
195
+ if msg == "" {
196
+ log .Error (err , "failed handle ytt" )
197
+ return nil , err
198
+ }
199
+ return nil , err
200
+ }
201
+ output := stdout .String ()
202
+ log .Info ("ytt result" , "output" , output )
203
+
204
+ stampedObject := & unstructured.Unstructured {}
205
+ log .Info ("your stamped object" , stampedObject )
206
+ if err := yaml .Unmarshal ([]byte (output ), stampedObject ); err != nil {
207
+ // ytt should never return invalid yaml
208
+ return nil , err
209
+ }
210
+ return stampedObject , nil
211
+ }
212
+
165
213
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch
166
214
// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch
167
215
0 commit comments