Browse code

Merge pull request #5454 from deads2k/fix-project-request-quota

Merged by openshift-bot

OpenShift Bot authored on 2015/10/29 14:16:22
Showing 15 changed files
... ...
@@ -112,13 +112,7 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C
112 112
 			return cmdutil.AddSourceToErr("creating", info.Source, err)
113 113
 		}
114 114
 
115
-		// Serialize the object with the annotation applied.
116
-		data, err := info.Mapping.Codec.Encode(info.Object)
117
-		if err != nil {
118
-			return cmdutil.AddSourceToErr("creating", info.Source, err)
119
-		}
120
-
121
-		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, data)
115
+		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
122 116
 		if err != nil {
123 117
 			return cmdutil.AddSourceToErr("creating", info.Source, err)
124 118
 		}
... ...
@@ -206,11 +206,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
206 206
 	}
207 207
 
208 208
 	// Serialize the object with the annotation applied.
209
-	data, err := info.Mapping.Codec.Encode(object)
210
-	if err != nil {
211
-		return err
212
-	}
213
-	object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, data)
209
+	object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object)
214 210
 	if err != nil {
215 211
 		return err
216 212
 	}
... ...
@@ -134,12 +134,7 @@ func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
134 134
 		}
135 135
 
136 136
 		// Serialize the object with the annotation applied.
137
-		data, err := info.Mapping.Codec.Encode(info.Object)
138
-		if err != nil {
139
-			return cmdutil.AddSourceToErr("replacing", info.Source, err)
140
-		}
141
-
142
-		obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, data)
137
+		obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object)
143 138
 		if err != nil {
144 139
 			return cmdutil.AddSourceToErr("replacing", info.Source, err)
145 140
 		}
... ...
@@ -226,13 +221,7 @@ func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
226 226
 			return err
227 227
 		}
228 228
 
229
-		// Serialize the object with the annotation applied.
230
-		data, err := info.Mapping.Codec.Encode(info.Object)
231
-		if err != nil {
232
-			return err
233
-		}
234
-
235
-		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, data)
229
+		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
236 230
 		if err != nil {
237 231
 			return err
238 232
 		}
... ...
@@ -194,13 +194,7 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
194 194
 			return err
195 195
 		}
196 196
 
197
-		// Serialize the object with the annotation applied.
198
-		data, err := mapping.Codec.Encode(info.Object)
199
-		if err != nil {
200
-			return err
201
-		}
202
-
203
-		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, data)
197
+		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
204 198
 		if err != nil {
205 199
 			return err
206 200
 		}
... ...
@@ -414,12 +414,7 @@ func UpdateObject(info *resource.Info, updateFn func(runtime.Object) error) (run
414 414
 		return nil, err
415 415
 	}
416 416
 
417
-	data, err := helper.Codec.Encode(info.Object)
418
-	if err != nil {
419
-		return nil, err
420
-	}
421
-
422
-	if _, err := helper.Replace(info.Namespace, info.Name, true, data); err != nil {
417
+	if _, err := helper.Replace(info.Namespace, info.Name, true, info.Object); err != nil {
423 418
 		return nil, err
424 419
 	}
425 420
 
... ...
@@ -99,37 +99,26 @@ func (m *Helper) Delete(namespace, name string) error {
99 99
 		Error()
100 100
 }
101 101
 
102
-func (m *Helper) Create(namespace string, modify bool, data []byte) (runtime.Object, error) {
102
+func (m *Helper) Create(namespace string, modify bool, obj runtime.Object) (runtime.Object, error) {
103 103
 	if modify {
104
-		obj, err := m.Codec.Decode(data)
105
-		if err != nil {
106
-			// We don't know how to check a version on this object, but create it anyway
107
-			return m.createResource(m.RESTClient, m.Resource, namespace, data)
108
-		}
109
-
110 104
 		// Attempt to version the object based on client logic.
111 105
 		version, err := m.Versioner.ResourceVersion(obj)
112 106
 		if err != nil {
113 107
 			// We don't know how to clear the version on this object, so send it to the server as is
114
-			return m.createResource(m.RESTClient, m.Resource, namespace, data)
108
+			return m.createResource(m.RESTClient, m.Resource, namespace, obj)
115 109
 		}
116 110
 		if version != "" {
117 111
 			if err := m.Versioner.SetResourceVersion(obj, ""); err != nil {
118 112
 				return nil, err
119 113
 			}
120
-			newData, err := m.Codec.Encode(obj)
121
-			if err != nil {
122
-				return nil, err
123
-			}
124
-			data = newData
125 114
 		}
126 115
 	}
127 116
 
128
-	return m.createResource(m.RESTClient, m.Resource, namespace, data)
117
+	return m.createResource(m.RESTClient, m.Resource, namespace, obj)
129 118
 }
130 119
 
131
-func (m *Helper) createResource(c RESTClient, resource, namespace string, data []byte) (runtime.Object, error) {
132
-	return c.Post().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Body(data).Do().Get()
120
+func (m *Helper) createResource(c RESTClient, resource, namespace string, obj runtime.Object) (runtime.Object, error) {
121
+	return c.Post().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Body(obj).Do().Get()
133 122
 }
134 123
 func (m *Helper) Patch(namespace, name string, pt api.PatchType, data []byte) (runtime.Object, error) {
135 124
 	return m.RESTClient.Patch(pt).
... ...
@@ -141,27 +130,21 @@ func (m *Helper) Patch(namespace, name string, pt api.PatchType, data []byte) (r
141 141
 		Get()
142 142
 }
143 143
 
144
-func (m *Helper) Replace(namespace, name string, overwrite bool, data []byte) (runtime.Object, error) {
144
+func (m *Helper) Replace(namespace, name string, overwrite bool, obj runtime.Object) (runtime.Object, error) {
145 145
 	c := m.RESTClient
146 146
 
147
-	obj, err := m.Codec.Decode(data)
148
-	if err != nil {
149
-		// We don't know how to handle this object, but replace it anyway
150
-		return m.replaceResource(c, m.Resource, namespace, name, data)
151
-	}
152
-
153 147
 	// Attempt to version the object based on client logic.
154 148
 	version, err := m.Versioner.ResourceVersion(obj)
155 149
 	if err != nil {
156 150
 		// We don't know how to version this object, so send it to the server as is
157
-		return m.replaceResource(c, m.Resource, namespace, name, data)
151
+		return m.replaceResource(c, m.Resource, namespace, name, obj)
158 152
 	}
159 153
 	if version == "" && overwrite {
160 154
 		// Retrieve the current version of the object to overwrite the server object
161 155
 		serverObj, err := c.Get().Namespace(namespace).Resource(m.Resource).Name(name).Do().Get()
162 156
 		if err != nil {
163 157
 			// The object does not exist, but we want it to be created
164
-			return m.replaceResource(c, m.Resource, namespace, name, data)
158
+			return m.replaceResource(c, m.Resource, namespace, name, obj)
165 159
 		}
166 160
 		serverVersion, err := m.Versioner.ResourceVersion(serverObj)
167 161
 		if err != nil {
... ...
@@ -170,16 +153,11 @@ func (m *Helper) Replace(namespace, name string, overwrite bool, data []byte) (r
170 170
 		if err := m.Versioner.SetResourceVersion(obj, serverVersion); err != nil {
171 171
 			return nil, err
172 172
 		}
173
-		newData, err := m.Codec.Encode(obj)
174
-		if err != nil {
175
-			return nil, err
176
-		}
177
-		data = newData
178 173
 	}
179 174
 
180
-	return m.replaceResource(c, m.Resource, namespace, name, data)
175
+	return m.replaceResource(c, m.Resource, namespace, name, obj)
181 176
 }
182 177
 
183
-func (m *Helper) replaceResource(c RESTClient, resource, namespace, name string, data []byte) (runtime.Object, error) {
184
-	return c.Put().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Name(name).Body(data).Do().Get()
178
+func (m *Helper) replaceResource(c RESTClient, resource, namespace, name string, obj runtime.Object) (runtime.Object, error) {
179
+	return c.Put().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Name(name).Body(obj).Do().Get()
185 180
 }
... ...
@@ -170,7 +170,10 @@ func TestHelperCreate(t *testing.T) {
170 170
 		},
171 171
 		{
172 172
 			Modify: true,
173
-			Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
173
+			Object: &api.Pod{
174
+				ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"},
175
+				Spec:       apitesting.DeepEqualSafePodSpec(),
176
+			},
174 177
 			ExpectObject: &api.Pod{
175 178
 				ObjectMeta: api.ObjectMeta{Name: "foo"},
176 179
 				Spec:       apitesting.DeepEqualSafePodSpec(),
... ...
@@ -194,11 +197,7 @@ func TestHelperCreate(t *testing.T) {
194 194
 			Versioner:       testapi.Default.MetadataAccessor(),
195 195
 			NamespaceScoped: true,
196 196
 		}
197
-		data := []byte{}
198
-		if test.Object != nil {
199
-			data = []byte(runtime.EncodeOrDie(testapi.Default.Codec(), test.Object))
200
-		}
201
-		_, err := modifier.Create("bar", test.Modify, data)
197
+		_, err := modifier.Create("bar", test.Modify, test.Object)
202 198
 		if (err != nil) != test.Err {
203 199
 			t.Errorf("%d: unexpected error: %t %v", i, test.Err, err)
204 200
 		}
... ...
@@ -218,7 +217,7 @@ func TestHelperCreate(t *testing.T) {
218 218
 			expect = []byte(runtime.EncodeOrDie(testapi.Default.Codec(), test.ExpectObject))
219 219
 		}
220 220
 		if !reflect.DeepEqual(expect, body) {
221
-			t.Errorf("%d: unexpected body: %s", i, string(body))
221
+			t.Errorf("%d: unexpected body: %s (expected %s)", i, string(body), string(expect))
222 222
 		}
223 223
 
224 224
 	}
... ...
@@ -413,7 +412,10 @@ func TestHelperReplace(t *testing.T) {
413 413
 			Req: expectPut,
414 414
 		},
415 415
 		{
416
-			Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
416
+			Object: &api.Pod{
417
+				ObjectMeta: api.ObjectMeta{Name: "foo"},
418
+				Spec:       apitesting.DeepEqualSafePodSpec(),
419
+			},
417 420
 			ExpectObject: &api.Pod{
418 421
 				ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"},
419 422
 				Spec:       apitesting.DeepEqualSafePodSpec(),
... ...
@@ -449,11 +451,7 @@ func TestHelperReplace(t *testing.T) {
449 449
 			Versioner:       testapi.Default.MetadataAccessor(),
450 450
 			NamespaceScoped: true,
451 451
 		}
452
-		data := []byte{}
453
-		if test.Object != nil {
454
-			data = []byte(runtime.EncodeOrDie(testapi.Default.Codec(), test.Object))
455
-		}
456
-		_, err := modifier.Replace("bar", "foo", test.Overwrite, data)
452
+		_, err := modifier.Replace("bar", "foo", test.Overwrite, test.Object)
457 453
 		if (err != nil) != test.Err {
458 454
 			t.Errorf("%d: unexpected error: %t %v", i, test.Err, err)
459 455
 		}
... ...
@@ -97,14 +97,16 @@ func TestExampleObjectSchemas(t *testing.T) {
97 97
 			"ldapserver-service":             &kapi.Service{},
98 98
 		},
99 99
 		"../test/integration/fixtures": {
100
-			"test-deployment-config":    &deployapi.DeploymentConfig{},
101
-			"test-image":                &imageapi.Image{},
102
-			"test-image-stream":         &imageapi.ImageStream{},
103
-			"test-image-stream-mapping": nil, // skip &imageapi.ImageStreamMapping{},
104
-			"test-route":                &routeapi.Route{},
105
-			"test-service":              &kapi.Service{},
106
-			"test-buildcli":             &kapi.List{},
107
-			"test-buildcli-beta2":       &kapi.List{},
100
+			// TODO fix this test to  handle json and yaml
101
+			"project-request-template-with-quota": nil, // skip a yaml file
102
+			"test-deployment-config":              &deployapi.DeploymentConfig{},
103
+			"test-image":                          &imageapi.Image{},
104
+			"test-image-stream":                   &imageapi.ImageStream{},
105
+			"test-image-stream-mapping":           nil, // skip &imageapi.ImageStreamMapping{},
106
+			"test-route":                          &routeapi.Route{},
107
+			"test-service":                        &kapi.Service{},
108
+			"test-buildcli":                       &kapi.List{},
109
+			"test-buildcli-beta2":                 &kapi.List{},
108 110
 		},
109 111
 		"../test/templates/fixtures": {
110 112
 			"crunchydata-pod": nil, // Explicitly fails validation, but should pass transformation
... ...
@@ -252,11 +252,7 @@ func (o *EditOptions) RunEdit() error {
252 252
 			if err != nil {
253 253
 				return err
254 254
 			}
255
-			data, err := info.Mapping.Codec.Encode(info.Object)
256
-			if err != nil {
257
-				return err
258
-			}
259
-			updated, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, data)
255
+			updated, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, info.Object)
260 256
 			if err != nil {
261 257
 				fmt.Fprintln(o.out, results.AddError(err, info))
262 258
 				return nil
... ...
@@ -415,7 +411,11 @@ func applyPatch(delta *jsonmerge.Delta, info *resource.Info, version string) err
415 415
 	if err != nil {
416 416
 		return patchError{err}
417 417
 	}
418
-	updated, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, merged)
418
+	mergedObj, err := info.Mapping.Codec.Decode(merged)
419
+	if err != nil {
420
+		return patchError{err}
421
+	}
422
+	updated, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, mergedObj)
419 423
 	if err != nil {
420 424
 		return err
421 425
 	}
... ...
@@ -290,13 +290,7 @@ func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Comman
290 290
 
291 291
 	failed := false
292 292
 	for _, info := range infos {
293
-		data, err := info.Mapping.Codec.Encode(info.Object)
294
-		if err != nil {
295
-			fmt.Fprintf(cmd.Out(), "Error: %v\n", err)
296
-			failed = true
297
-			continue
298
-		}
299
-		obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, data)
293
+		obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object)
300 294
 		if err != nil {
301 295
 			handlePodUpdateError(cmd.Out(), err, "environment variables")
302 296
 			failed = true
... ...
@@ -439,17 +439,11 @@ func (v *VolumeOptions) RunVolume(args []string) error {
439 439
 
440 440
 	failed := false
441 441
 	for _, info := range updateInfos {
442
-		data, err := info.Mapping.Codec.Encode(info.Object)
443
-		if err != nil {
444
-			fmt.Fprintf(v.Err, "error: %v\n", err)
445
-			failed = true
446
-			continue
447
-		}
448 442
 		var obj runtime.Object
449 443
 		if len(info.ResourceVersion) == 0 {
450
-			obj, err = resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, false, data)
444
+			obj, err = resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, false, info.Object)
451 445
 		} else {
452
-			obj, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, data)
446
+			obj, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object)
453 447
 		}
454 448
 		if err != nil {
455 449
 			handlePodUpdateError(v.Err, err, "volume")
... ...
@@ -40,11 +40,7 @@ func NewPrintErrorAfter(mapper meta.RESTMapper, errs io.Writer) func(*resource.I
40 40
 }
41 41
 
42 42
 func encodeAndCreate(info *resource.Info, namespace string, obj runtime.Object) (runtime.Object, error) {
43
-	data, err := info.Mapping.Codec.Encode(obj)
44
-	if err != nil {
45
-		return nil, err
46
-	}
47
-	return resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, data)
43
+	return resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, obj)
48 44
 }
49 45
 
50 46
 // Create attempts to create each item generically, gathering all errors in the
51 47
new file mode 100644
... ...
@@ -0,0 +1,115 @@
0
+apiVersion: v1
1
+kind: Template
2
+metadata:
3
+  creationTimestamp: 2015-10-24T18:25:22Z
4
+  name: default-project-request
5
+  namespace: default
6
+objects:
7
+- apiVersion: v1
8
+  kind: Project
9
+  metadata:
10
+    annotations:
11
+      openshift.io/description: ${PROJECT_DESCRIPTION}
12
+      openshift.io/display-name: ${PROJECT_DISPLAYNAME}
13
+      extra: here
14
+    creationTimestamp: null
15
+    name: ${PROJECT_NAME}
16
+  spec: {}
17
+  status: {}
18
+- apiVersion: v1
19
+  kind: ResourceQuota
20
+  metadata:
21
+    name: ${PROJECT_NAME}-quota
22
+  spec:
23
+    hard:
24
+      cpu: 200m
25
+      memory: 512Mi
26
+      pods: 3
27
+      replicationcontrollers: 3
28
+      resourcequotas: 1
29
+      services: 3
30
+- apiVersion: v1
31
+  kind: LimitRange
32
+  metadata:
33
+    creationTimestamp: null
34
+    name: ${PROJECT_NAME}-limits
35
+  spec:
36
+    limits:
37
+    - max:
38
+        cpu: 500m
39
+        memory: 750Mi
40
+      min:
41
+        cpu: 10m
42
+        memory: 5Mi
43
+      type: Pod
44
+    - default:
45
+        cpu: 100m
46
+        memory: 100Mi
47
+      max:
48
+        cpu: 500m
49
+        memory: 750Mi
50
+      min:
51
+        cpu: 10m
52
+        memory: 5Mi
53
+      type: Container
54
+- apiVersion: v1
55
+  groupNames: []
56
+  kind: RoleBinding
57
+  metadata:
58
+    creationTimestamp: null
59
+    name: admins
60
+    namespace: ${PROJECT_NAME}
61
+  roleRef:
62
+    name: admin
63
+  subjects:
64
+  - kind: User
65
+    name: ${PROJECT_ADMIN_USER}
66
+  userNames:
67
+  - ${PROJECT_ADMIN_USER}
68
+- apiVersion: v1
69
+  groupNames:
70
+  - system:serviceaccounts:${PROJECT_NAME}
71
+  kind: RoleBinding
72
+  metadata:
73
+    creationTimestamp: null
74
+    name: system:image-pullers
75
+    namespace: ${PROJECT_NAME}
76
+  roleRef:
77
+    name: system:image-puller
78
+  subjects:
79
+  - kind: SystemGroup
80
+    name: system:serviceaccounts:${PROJECT_NAME}
81
+  userNames: []
82
+- apiVersion: v1
83
+  groupNames: []
84
+  kind: RoleBinding
85
+  metadata:
86
+    creationTimestamp: null
87
+    name: system:image-builders
88
+    namespace: ${PROJECT_NAME}
89
+  roleRef:
90
+    name: system:image-builder
91
+  subjects:
92
+  - kind: ServiceAccount
93
+    name: builder
94
+  userNames:
95
+  - system:serviceaccount:${PROJECT_NAME}:builder
96
+- apiVersion: v1
97
+  groupNames: []
98
+  kind: RoleBinding
99
+  metadata:
100
+    creationTimestamp: null
101
+    name: system:deployers
102
+    namespace: ${PROJECT_NAME}
103
+  roleRef:
104
+    name: system:deployer
105
+  subjects:
106
+  - kind: ServiceAccount
107
+    name: deployer
108
+  userNames:
109
+  - system:serviceaccount:${PROJECT_NAME}:deployer
110
+parameters:
111
+- name: PROJECT_NAME
112
+- name: PROJECT_DISPLAYNAME
113
+- name: PROJECT_DESCRIPTION
114
+- name: PROJECT_ADMIN_USER
0 115
\ No newline at end of file
... ...
@@ -19,7 +19,6 @@ import (
19 19
 	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
20 20
 	"github.com/openshift/origin/pkg/cmd/util/tokencmd"
21 21
 	projectapi "github.com/openshift/origin/pkg/project/api"
22
-	projectrequeststorage "github.com/openshift/origin/pkg/project/registry/projectrequest/delegated"
23 22
 	testutil "github.com/openshift/origin/test/util"
24 23
 	testserver "github.com/openshift/origin/test/util/server"
25 24
 )
... ...
@@ -132,11 +131,13 @@ func TestUnprivilegedNewProjectFromTemplate(t *testing.T) {
132 132
 		t.Fatalf("unexpected error: %v", err)
133 133
 	}
134 134
 
135
-	template := projectrequeststorage.DefaultTemplate()
135
+	template, err := testutil.GetTemplateFixture("fixtures/project-request-template-with-quota.yaml")
136
+	if err != nil {
137
+		t.Fatalf("unexpected error: %v", err)
138
+	}
136 139
 	template.Name = templateName
137 140
 	template.Namespace = namespace
138 141
 
139
-	template.Objects[0].(*projectapi.Project).Annotations["extra"] = "here"
140 142
 	_, err = clusterAdminClient.Templates(namespace).Create(template)
141 143
 	if err != nil {
142 144
 		t.Fatalf("unexpected error: %v", err)
... ...
@@ -4,10 +4,13 @@ import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6 6
 
7
-	buildapi "github.com/openshift/origin/pkg/build/api"
8
-	imageapi "github.com/openshift/origin/pkg/image/api"
9 7
 	kapi "k8s.io/kubernetes/pkg/api"
10 8
 	"k8s.io/kubernetes/pkg/api/latest"
9
+	kyaml "k8s.io/kubernetes/pkg/util/yaml"
10
+
11
+	buildapi "github.com/openshift/origin/pkg/build/api"
12
+	imageapi "github.com/openshift/origin/pkg/image/api"
13
+	templateapi "github.com/openshift/origin/pkg/template/api"
11 14
 )
12 15
 
13 16
 // CreateSampleImageStream creates an ImageStream in given namespace
... ...
@@ -58,3 +61,19 @@ func GetSecretFixture(filename string) *kapi.Secret {
58 58
 	latest.CodecForLegacyGroup().DecodeInto(jsonData, &secret)
59 59
 	return &secret
60 60
 }
61
+
62
+func GetTemplateFixture(filename string) (*templateapi.Template, error) {
63
+	data, err := ioutil.ReadFile(filename)
64
+	if err != nil {
65
+		return nil, err
66
+	}
67
+	jsonData, err := kyaml.ToJSON(data)
68
+	if err != nil {
69
+		return nil, err
70
+	}
71
+	obj, err := latest.CodecForLegacyGroup().Decode(jsonData)
72
+	if err != nil {
73
+		return nil, err
74
+	}
75
+	return obj.(*templateapi.Template), nil
76
+}