Skip to content

Commit

Permalink
Merge pull request #119 from vmware-tanzu/103-reference-by-name
Browse files Browse the repository at this point in the history
Reference sources, images, configs, params by name
  • Loading branch information
emmjohnson authored Sep 20, 2021
2 parents 40df4f9 + dae9438 commit 335c6ef
Show file tree
Hide file tree
Showing 20 changed files with 298 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ spec:
name: go-builder
source:
blob:
url: $(sources[0].url)$
url: $(sources.source.url)$

---
#
#
# `app-deploy` instantiates a `kapp-ctrl/App` making use of an image that comes
# as input in the form of `$(images[0].image)$`.
# as input in the form of `$(images.image.image)$`.
#
# the use of `App` here is important because of how `knative` updates the
# knative service under the hood to include some extra annotations that _can't_
Expand Down Expand Up @@ -137,7 +137,7 @@ spec:
spec:
containers:
- name: workload
image: $(images[0].image)$
image: $(images.image.image)$
securityContext:
runAsUser: 1000
imagePullSecrets:
Expand Down
36 changes: 17 additions & 19 deletions pkg/realizer/workload/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ import (

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate

type WorkloadTemplatingContext struct {
Params templates.Params `json:"params"`
Workload *v1alpha1.Workload `json:"workload"`
Sources []templates.SourceInput `json:"sources"`
Images []templates.ImageInput `json:"images"`
Configs []templates.ConfigInput `json:"configs"`
}

//counterfeiter:generate . ComponentRealizer
type ComponentRealizer interface {
Do(ctx context.Context, component *v1alpha1.SupplyChainComponent, supplyChainName string, outputs Outputs) (*templates.Output, error)
Expand Down Expand Up @@ -68,18 +60,24 @@ func (r *componentRealizer) Do(ctx context.Context, component *v1alpha1.SupplyCh
}

inputs := outputs.GenerateInputs(component)
stampContext := templates.StamperBuilder(
r.workload,
WorkloadTemplatingContext{
Workload: r.workload,
Params: templates.ParamsBuilder(template.GetDefaultParams(), component.Params),
Sources: inputs.Sources,
Images: inputs.Images,
Configs: inputs.Configs,
},
labels,
)
workloadTemplatingContext := map[string]interface{}{
"workload": r.workload,
"params": templates.ParamsBuilder(template.GetDefaultParams(), component.Params),
"sources": inputs.Sources,
"images": inputs.Images,
"configs": inputs.Configs,
}
if inputs.OnlyConfig() != nil {
workloadTemplatingContext["config"] = inputs.OnlyConfig()
}
if inputs.OnlyImage() != nil {
workloadTemplatingContext["image"] = inputs.OnlyImage()
}
if inputs.OnlySource() != nil {
workloadTemplatingContext["source"] = inputs.OnlySource()
}

stampContext := templates.StamperBuilder(r.workload, workloadTemplatingContext, labels)
stampedObject, err := stampContext.Stamp(ctx, template.GetResourceTemplate())
if err != nil {
return nil, StampError{
Expand Down
8 changes: 4 additions & 4 deletions pkg/realizer/workload/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ var _ = Describe("Component", func() {
Namespace: "some-namespace",
},
Data: map[string]string{
"player_current_lives": "$(sources[0].url)$",
"some_other_info": "$(sources[?(@.name==\"source-provider\")].revision)$",
"player_current_lives": `$(source.url)$`,
"some_other_info": `$(sources.source-provider.revision)$`,
},
}

Expand Down Expand Up @@ -271,8 +271,8 @@ var _ = Describe("Component", func() {
Namespace: "some-namespace",
},
Data: map[string]string{
"player_current_lives": "$(sources[0].url)$",
"some_other_info": "$(sources[?(@.name==\"source-provider\")].revision)$",
"player_current_lives": `$(sources.source-provider.url)$`,
"some_other_info": `$(sources.source-provider.revision)$`,
},
}

Expand Down
18 changes: 11 additions & 7 deletions pkg/realizer/workload/outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,40 @@ func (o Outputs) getComponentConfig(componentName string) templates.Config {
}

func (o Outputs) GenerateInputs(component *v1alpha1.SupplyChainComponent) *templates.Inputs {
inputs := &templates.Inputs{}
inputs := &templates.Inputs{
Sources: map[string]templates.SourceInput{},
Images: map[string]templates.ImageInput{},
Configs: map[string]templates.ConfigInput{},
}

for _, referenceSource := range component.Sources {
source := o.getComponentSource(referenceSource.Component)
if source != nil {
inputs.Sources = append(inputs.Sources, templates.SourceInput{
inputs.Sources[referenceSource.Name] = templates.SourceInput{
URL: source.URL,
Revision: source.Revision,
Name: referenceSource.Name,
})
}
}
}

for _, referenceImage := range component.Images {
image := o.getComponentImage(referenceImage.Component)
if image != nil {
inputs.Images = append(inputs.Images, templates.ImageInput{
inputs.Images[referenceImage.Name] = templates.ImageInput{
Image: image,
Name: referenceImage.Name,
})
}
}
}

for _, referenceConfig := range component.Configs {
config := o.getComponentConfig(referenceConfig.Component)
if config != nil {
inputs.Configs = append(inputs.Configs, templates.ConfigInput{
inputs.Configs[referenceConfig.Name] = templates.ConfigInput{
Config: config,
Name: referenceConfig.Name,
})
}
}
}

Expand Down
14 changes: 7 additions & 7 deletions pkg/realizer/workload/outputs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ var _ = Describe("Outputs", func() {
}
inputs := outs.GenerateInputs(component)
Expect(inputs.Sources).To(HaveLen(1))
Expect(inputs.Sources[0].Name).To(Equal("source-ref"))
Expect(inputs.Sources[0].URL).To(Equal("source-url"))
Expect(inputs.Sources[0].Revision).To(Equal("source-revision"))
Expect(inputs.Sources["source-ref"].Name).To(Equal("source-ref"))
Expect(inputs.Sources["source-ref"].URL).To(Equal("source-url"))
Expect(inputs.Sources["source-ref"].Revision).To(Equal("source-revision"))
})
})

Expand Down Expand Up @@ -94,8 +94,8 @@ var _ = Describe("Outputs", func() {
}
inputs := outs.GenerateInputs(component)
Expect(inputs.Images).To(HaveLen(1))
Expect(inputs.Images[0].Name).To(Equal("image-ref"))
Expect(inputs.Images[0].Image).To(Equal("image12345"))
Expect(inputs.Images["image-ref"].Name).To(Equal("image-ref"))
Expect(inputs.Images["image-ref"].Image).To(Equal("image12345"))
})
})

Expand Down Expand Up @@ -138,8 +138,8 @@ var _ = Describe("Outputs", func() {
}
inputs := outs.GenerateInputs(component)
Expect(inputs.Configs).To(HaveLen(1))
Expect(inputs.Configs[0].Name).To(Equal("config-ref"))
Expect(inputs.Configs[0].Config).To(Equal("config12345"))
Expect(inputs.Configs["config-ref"].Name).To(Equal("config-ref"))
Expect(inputs.Configs["config-ref"].Config).To(Equal("config12345"))
})
})

Expand Down
33 changes: 33 additions & 0 deletions pkg/templates/inputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,36 @@ type ConfigInput struct {
Config interface{} `json:"config"`
Name string `json:"name"`
}

type Inputs struct {
Sources map[string]SourceInput
Images map[string]ImageInput
Configs map[string]ConfigInput
}

func (i Inputs) OnlySource() *SourceInput {
if len(i.Sources) == 1 {
for _, sourceInput := range i.Sources {
return &sourceInput
}
}
return nil
}

func (i Inputs) OnlyImage() interface{} {
if len(i.Images) == 1 {
for _, imageInput := range i.Images {
return imageInput.Image
}
}
return nil
}

func (i Inputs) OnlyConfig() interface{} {
if len(i.Configs) == 1 {
for _, configInput := range i.Configs {
return configInput.Config
}
}
return nil
}
119 changes: 119 additions & 0 deletions pkg/templates/inputs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2021 VMware
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package templates_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/vmware-tanzu/cartographer/pkg/templates"
)

var _ = Describe("Inputs", func() {
var inputs templates.Inputs

BeforeEach(func() {
inputs = templates.Inputs{
Sources: map[string]templates.SourceInput{},
Images: map[string]templates.ImageInput{},
Configs: map[string]templates.ConfigInput{},
}
})

Describe("OnlySource", func() {
It("is nil when there are no sources", func() {
Expect(inputs.OnlySource()).To(BeNil())
})

Context("when there is only one source", func() {
BeforeEach(func() {
inputs.Sources["one"] = templates.SourceInput{Name: "one"}
})

It("returns a pointer to that source", func() {
Expect(*inputs.OnlySource()).To(Equal(inputs.Sources["one"]))
})
})

Context("when there is more than one source", func() {
BeforeEach(func() {
inputs.Sources["one"] = templates.SourceInput{Name: "one"}
inputs.Sources["deux"] = templates.SourceInput{Name: "deux"}
})

It("returns nil", func() {
Expect(inputs.OnlySource()).To(BeNil())
})
})
})

Describe("OnlyImage", func() {
It("is nil when there are no images", func() {
Expect(inputs.OnlyImage()).To(BeNil())
})

Context("when there is only one image", func() {
var actualImage interface{}
BeforeEach(func() {
actualImage = struct{ This string }{This: "actualImage could be *anything*, as this anonymous struct shows"}
inputs.Images["one"] = templates.ImageInput{Name: "one", Image: actualImage}
})

It("returns that image's nested image", func() {
Expect(inputs.OnlyImage()).To(Equal(actualImage))
})
})

Context("when there is more than one image", func() {
BeforeEach(func() {
inputs.Images["one"] = templates.ImageInput{Name: "one", Image: "01"}
inputs.Images["deux"] = templates.ImageInput{Name: "deux", Image: "10"}
})

It("returns nil", func() {
Expect(inputs.OnlyImage()).To(BeNil())
})
})
})

Describe("OnlyConfig", func() {
It("is nil when there are no configs", func() {
Expect(inputs.OnlyConfig()).To(BeNil())
})

Context("when there is only one config", func() {
var actualConfig interface{}
BeforeEach(func() {
actualConfig = struct{ ArbitraryThingVeryMuch string }{ArbitraryThingVeryMuch: "much like images, it could be anything."}
inputs.Configs["one"] = templates.ConfigInput{Name: "one", Config: actualConfig}
})

It("returns that config's nested config", func() {
Expect(inputs.OnlyConfig()).To(Equal(actualConfig))
})
})

Context("when there is more than one config", func() {
BeforeEach(func() {
inputs.Configs["one"] = templates.ConfigInput{Name: "one", Config: "01"}
inputs.Configs["deux"] = templates.ConfigInput{Name: "deux", Config: "10"}
})

It("returns nil", func() {
Expect(inputs.OnlyConfig()).To(BeNil())
})
})
})
})
Loading

0 comments on commit 335c6ef

Please sign in to comment.