Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/clusters-service/pkg/server/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ func (s *server) CreatePullRequest(ctx context.Context, msg *capiv1_proto.Create
return nil, fmt.Errorf("failed to render template with parameter values: %w", err)
}

tmplWithValues, err = templates.InjectJSONAnnotation(tmplWithValues, "templates.weave.works/create-request", msg)
if err != nil {
return nil, fmt.Errorf("failed to annotate template with parameter values: %w", err)
}

err = templates.ValidateRenderedTemplates(tmplWithValues)
if err != nil {
return nil, fmt.Errorf("validation error rendering template %v, %v", msg.TemplateName, err)
Expand Down
9 changes: 9 additions & 0 deletions cmd/clusters-service/pkg/server/clusters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ metadata:
annotations:
capi.weave.works/display-name: ClusterName
kustomize.toolkit.fluxcd.io/prune: disabled
templates.weave.works/create-request: '{"repository_url":"https://github.com/org/repo.git","head_branch":"feature-01","base_branch":"main","title":"New
Cluster","description":"Creates a cluster through a CAPI template","template_name":"cluster-template-1","parameter_values":{"CLUSTER_NAME":"dev","NAMESPACE":"default"},"commit_message":"Add
cluster manifest","values":[{"name":"demo-profile","version":"0.0.1"}]}'
name: dev
namespace: default
`,
Expand Down Expand Up @@ -594,6 +597,9 @@ metadata:
annotations:
capi.weave.works/display-name: ClusterName
kustomize.toolkit.fluxcd.io/prune: disabled
templates.weave.works/create-request: '{"repository_url":"https://github.com/org/repo.git","head_branch":"feature-01","base_branch":"main","title":"New
Cluster","description":"Creates a cluster through a CAPI template","template_name":"cluster-template-1","parameter_values":{"CLUSTER_NAME":"dev","NAMESPACE":"clusters-namespace"},"commit_message":"Add
cluster manifest","values":[{"name":"demo-profile","version":"0.0.1","namespace":"test-system"}]}'
name: dev
namespace: clusters-namespace
`,
Expand Down Expand Up @@ -704,6 +710,9 @@ metadata:
annotations:
capi.weave.works/display-name: ClusterName
kustomize.toolkit.fluxcd.io/prune: disabled
templates.weave.works/create-request: '{"repository_url":"https://github.com/org/repo.git","head_branch":"feature-01","base_branch":"main","title":"New
Cluster","description":"Creates a cluster through a CAPI template","template_name":"cluster-template-1","parameter_values":{"CLUSTER_NAME":"dev","NAMESPACE":"clusters-namespace"},"commit_message":"Add
cluster manifest","kustomizations":[{"metadata":{"name":"apps-capi","namespace":"flux-system"},"spec":{"path":"./apps/capi","source_ref":{"name":"flux-system","namespace":"flux-system"}}},{"metadata":{"name":"apps-billing","namespace":"flux-system"},"spec":{"path":"./apps/billing","source_ref":{"name":"flux-system","namespace":"flux-system"}}}]}'
name: dev
namespace: clusters-namespace
`,
Expand Down
6 changes: 6 additions & 0 deletions cmd/clusters-service/pkg/templates/processors.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ type TemplateProcessor struct {
Processor
}

// Params returns the set of parameters discovered in the resource templates.
//
// These are discovered in the templates, and enriched from the parameters
// declared on the template.
//
// The returned slice is sorted by Name.
func (p TemplateProcessor) Params() ([]Param, error) {
paramNames := sets.NewString()
for _, v := range p.GetSpec().ResourceTemplates {
Expand Down
42 changes: 42 additions & 0 deletions cmd/clusters-service/pkg/templates/resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package templates

import (
"encoding/json"
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// InjectJSONAnnotation marshals a value as JSON and adds an annotation to the
// first resource in a slice of bytes.
func InjectJSONAnnotation(resources [][]byte, annotation string, value interface{}) ([][]byte, error) {
b, err := json.Marshal(value)
if err != nil {
return nil, fmt.Errorf("error marshaling data when annotating resource: %w", err)
}
updated := make([][]byte, len(resources))
for i := range resources {
if i != 0 {
updated[i] = resources[i]
continue
}
annotated, err := processUnstructured(resources[i], func(uns *unstructured.Unstructured) error {
ann, _, err := unstructured.NestedStringMap(uns.Object, "metadata", "annotations")
if err != nil {
return fmt.Errorf("error getting existing annotations: %w", err)
}
if ann == nil {
ann = make(map[string]string)
}
ann[annotation] = string(b)
uns.SetAnnotations(ann)
return nil
})
if err != nil {
return nil, err
}
updated[i] = annotated
}

return updated, nil
}
93 changes: 93 additions & 0 deletions cmd/clusters-service/pkg/templates/resources_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package templates

import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
)

type testData struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
}

func TestInjectJSONAnnotation(t *testing.T) {
sb := func(s string) []byte {
return []byte(s)
}

raw := [][]byte{
sb(`
apiVersion: cluster.x-k8s.io/v1alpha3
kind: Cluster
metadata:
name: testing
annotations:
alpha: "true"
`),
sb(`apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: AWSMachineTemplate
metadata:
name: testing-md-0
`),
}

updated, err := InjectJSONAnnotation(raw, "example.com/test", testData{Name: "testing", Namespace: "test-ns"})
if err != nil {
t.Fatal(err)
}

want := `---
apiVersion: cluster.x-k8s.io/v1alpha3
kind: Cluster
metadata:
annotations:
alpha: "true"
example.com/test: '{"name":"testing","namespace":"test-ns"}'
name: testing
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: AWSMachineTemplate
metadata:
name: testing-md-0
`
if diff := cmp.Diff(want, writeMultiDoc(t, updated)); diff != "" {
t.Fatalf("rendering with option failed:\n%s", diff)
}
}

func TestInjectJSONAnnotation_no_elements(t *testing.T) {
raw := [][]byte{}
updated, err := InjectJSONAnnotation(raw, "example.com/test", testData{Name: "testing", Namespace: "test-ns"})
if err != nil {
t.Fatal(err)
}

if diff := cmp.Diff("", writeMultiDoc(t, updated)); diff != "" {
t.Fatalf("rendering with option failed:\n%s", diff)
}
}

func TestInjectJSONAnnotation_bad_annotation(t *testing.T) {
sb := func(s string) []byte {
return []byte(s)
}
raw := [][]byte{
sb(`
apiVersion: cluster.x-k8s.io/v1alpha3
kind: Cluster
metadata:
name: testing
annotations:
testing: {{ testing }}
`),
sb(`apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: AWSMachineTemplate
metadata:
name: testing-md-0
`)}

_, err := InjectJSONAnnotation(raw, "example.com/test", testData{Name: "testing", Namespace: "test-ns"})
assert.ErrorContains(t, err, "failed to decode the YAML")
}