Skip to content

Commit ad46dc3

Browse files
fix: Cartotest can handle supply chains with options (#1352)
* test that cartotest handles options * refactor to create GetTemplateNameFromResource function * cartotest uses GetTemplateNameFromResource function
1 parent 608e236 commit ad46dc3

14 files changed

Lines changed: 308 additions & 22 deletions

File tree

pkg/realizer/component.go

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,9 @@ func (r *resourceRealizer) Do(ctx context.Context, resource OwnerResource, bluep
9191
// TODO: consider: should we build this only once, and pass it to the contextGenerator also?
9292
inputGenerator := NewInputGenerator(resource, outputs)
9393

94-
if len(resource.TemplateOptions) > 0 {
95-
var err error
96-
templateOption, err = r.findMatchingTemplateOption(resource, blueprintName)
97-
if err != nil {
98-
return nil, nil, nil, passThrough, templateName, err
99-
}
100-
if templateOption.PassThrough != "" {
101-
passThrough = true
102-
} else {
103-
templateName = templateOption.Name
104-
}
105-
} else {
106-
templateName = resource.TemplateRef.Name
94+
templateName, passThrough, templateOption, err = GetTemplateNameFromResource(resource, blueprintName, r.owner)
95+
if err != nil {
96+
return nil, nil, nil, passThrough, templateName, fmt.Errorf("get template name from resource: %w", err)
10797
}
10898

10999
if passThrough {
@@ -160,6 +150,30 @@ func (r *resourceRealizer) Do(ctx context.Context, resource OwnerResource, bluep
160150
}
161151
}
162152

153+
func GetTemplateNameFromResource(resource OwnerResource, blueprintName string, owner client.Object) (string, bool, v1alpha1.TemplateOption, error) {
154+
var (
155+
templateName string
156+
passThrough bool
157+
templateOption v1alpha1.TemplateOption
158+
)
159+
if len(resource.TemplateOptions) > 0 {
160+
var err error
161+
templateOption, err = findMatchingTemplateOption(resource, blueprintName, owner)
162+
if err != nil {
163+
return "", false, templateOption, fmt.Errorf("find matching template option: %w", err)
164+
}
165+
if templateOption.PassThrough != "" {
166+
passThrough = true
167+
} else {
168+
templateName = templateOption.Name
169+
}
170+
} else {
171+
templateName = resource.TemplateRef.Name
172+
}
173+
174+
return templateName, passThrough, templateOption, nil
175+
}
176+
163177
func (r *resourceRealizer) doImmutable(ctx context.Context, resource OwnerResource, blueprintName string,
164178
stampedObject *unstructured.Unstructured, labels templates.Labels, log logr.Logger, template templates.Reader,
165179
passThrough bool, templateName string, stampReader stamp.Outputter, mapper meta.RESTMapper,
@@ -315,8 +329,8 @@ func doPassthrough(log logr.Logger, templateOption v1alpha1.TemplateOption, reso
315329
return template, stampedObject, output, passThrough, templateName, nil
316330
}
317331

318-
func (r *resourceRealizer) findMatchingTemplateOption(resource OwnerResource, supplyChainName string) (v1alpha1.TemplateOption, error) {
319-
bestMatchingTemplateOptionsIndices, err := selector.BestSelectorMatchIndices(r.owner, v1alpha1.TemplateOptionSelectors(resource.TemplateOptions))
332+
func findMatchingTemplateOption(resource OwnerResource, supplyChainName string, owner client.Object) (v1alpha1.TemplateOption, error) {
333+
bestMatchingTemplateOptionsIndices, err := selector.BestSelectorMatchIndices(owner, v1alpha1.TemplateOptionSelectors(resource.TemplateOptions))
320334

321335
if err != nil {
322336
return v1alpha1.TemplateOption{}, errors.ResolveTemplateOptionError{

pkg/realizer/component_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -962,9 +962,11 @@ var _ = Describe("Resource", func() {
962962
Expect(isPassThrough).To(BeFalse())
963963

964964
Expect(err).To(HaveOccurred())
965-
Expect(reflect.TypeOf(err).String()).To(Equal("errors.ResolveTemplateOptionError"))
966-
Expect(err.Error()).To(ContainSubstring(`error matching against template option [template-not-chosen] for resource [resource-1] in supply chain [supply-chain-name]`))
967-
Expect(err.Error()).To(ContainSubstring(`failed to evaluate selector matchFields: unable to match field requirement with key [spec.env[] operator [Exists] values [[]]: evaluate: failed to parse jsonpath '{.spec.env[}': unterminated array`))
965+
var expectedError cerrors.ResolveTemplateOptionError
966+
Expect(errors.As(err, &expectedError)).To(BeTrue())
967+
968+
Expect(expectedError.Error()).To(ContainSubstring(`error matching against template option [template-not-chosen] for resource [resource-1] in supply chain [supply-chain-name]`))
969+
Expect(expectedError.Error()).To(ContainSubstring(`failed to evaluate selector matchFields: unable to match field requirement with key [spec.env[] operator [Exists] values [[]]: evaluate: failed to parse jsonpath '{.spec.env[}': unterminated array`))
968970
})
969971
})
970972

pkg/testing/supplychain.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/go-logr/logr"
2424
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25+
"sigs.k8s.io/controller-runtime/pkg/client"
2526
"sigs.k8s.io/yaml"
2627

2728
"github.com/vmware-tanzu/cartographer/pkg/apis/v1alpha1"
@@ -197,7 +198,12 @@ func (s *SupplyChainFileSet) stamp(ctx context.Context, workload *v1alpha1.Workl
197198
return nil, fmt.Errorf("get target resource: %w", err)
198199
}
199200

200-
if !templateMatchesResource(templateObject, resource) {
201+
properTemplateProvided, err := templateMatchesResource(templateObject, resource, workload)
202+
if err != nil {
203+
return nil, fmt.Errorf("template matches resource: %w", err)
204+
}
205+
206+
if !properTemplateProvided {
201207
return nil, fmt.Errorf("template '%s' is not selected by resource/stage '%s' in supply chain '%s'", templateObject.GetName(), resource.Name, supplyChain.Name)
202208
}
203209

@@ -223,8 +229,12 @@ func (s *SupplyChainFileSet) stamp(ctx context.Context, workload *v1alpha1.Workl
223229
return actualStampedObject, nil
224230
}
225231

226-
func templateMatchesResource(template ValidatableTemplate, resource *realizer.OwnerResource) bool {
227-
return template.GetName() == resource.TemplateRef.Name && template.GetObjectKind().GroupVersionKind().Kind == resource.TemplateRef.Kind
232+
func templateMatchesResource(template ValidatableTemplate, resource *realizer.OwnerResource, owner client.Object) (bool, error) {
233+
resourceTemplateName, _, _, err := realizer.GetTemplateNameFromResource(*resource, "", owner)
234+
if err != nil {
235+
return false, fmt.Errorf("get template name from resource: %w", err)
236+
}
237+
return template.GetName() == resourceTemplateName && template.GetObjectKind().GroupVersionKind().Kind == resource.TemplateRef.Kind, nil
228238
}
229239

230240
func getTargetResource(resources []realizer.OwnerResource, targetResourceName string) (*realizer.OwnerResource, error) {

tests/templates/cli_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
)
2222

2323
func TestCLIExample(t *testing.T) {
24-
directories := []string{"kpack", "deliverable", "deployment"}
24+
directories := []string{"kpack", "deliverable", "deployment", "options"}
2525

2626
for _, directory := range directories {
2727
err := cartotesting.CliTest(directory)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2021 VMware
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
---
16+
apiVersion: v1
17+
kind: ConfigMap
18+
metadata:
19+
name: example-configmap
20+
data:
21+
some_value: "1"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2021 VMware
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
---
16+
metadata:
17+
name: option1
18+
description: "test that supply chain with option chooses the correct template"
19+
compareOptions:
20+
ignoreMetadata: true
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright 2021 VMware
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
---
16+
apiVersion: carto.run/v1alpha1
17+
kind: ClusterTemplate
18+
metadata:
19+
name: config-template-1
20+
spec:
21+
template:
22+
apiVersion: v1
23+
kind: ConfigMap
24+
metadata:
25+
name: example-configmap
26+
data:
27+
some_value: "1"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2021 VMware
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
---
16+
apiVersion: carto.run/v1alpha1
17+
kind: Workload
18+
metadata:
19+
name: choose
20+
labels:
21+
workload-type: source-code
22+
option: "1"
23+
spec: {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2021 VMware
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
---
16+
apiVersion: v1
17+
kind: ConfigMap
18+
metadata:
19+
name: example-configmap
20+
data:
21+
some_value: "2"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2021 VMware
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
---
16+
metadata:
17+
name: option2
18+
description: "test that supply chain with option chooses the correct template"
19+
compareOptions:
20+
ignoreMetadata: true

0 commit comments

Comments
 (0)