Skip to content

Commit

Permalink
Add initial helm post renderer. (#1670)
Browse files Browse the repository at this point in the history
* Add initial helm post renderer.

* Simplify error check in test.

* Switch to yaml.v2
  • Loading branch information
absoludity committed Apr 16, 2020
1 parent 17d1f42 commit 3f3f76a
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 0 deletions.
56 changes: 56 additions & 0 deletions pkg/agent/docker_secrets_postrenderer.go
@@ -0,0 +1,56 @@
package agent

import (
"bytes"
"io"

"gopkg.in/yaml.v2"
)

// DockerSecretsPostRenderer is a helm post-renderer (see https://helm.sh/docs/topics/advanced/#post-rendering)
// which appends image pull secrets to container images which match specified registry domains.
type DockerSecretsPostRenderer struct {
// secrets maps a registry domain to a single secret to be used for that domain.
secrets map[string]string
}

// NewDockerSecretsPostRenderer returns a post renderer configured with the specified secrets.
func NewDockerSecretsPostRenderer(secrets map[string]string) *DockerSecretsPostRenderer {
return &DockerSecretsPostRenderer{secrets}
}

// Run returns the rendered yaml including any additions of the post-renderer.
func (r *DockerSecretsPostRenderer) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) {
if r.secrets == nil {
return renderedManifests, nil
}

decoder := yaml.NewDecoder(renderedManifests)
var resourceList []interface{}
for {
var resource interface{}
err := decoder.Decode(&resource)
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
resourceList = append(resourceList, resource)
}

// TODO: Update relevant container images with image pull secrets

modifiedManifests = bytes.NewBuffer([]byte{})
encoder := yaml.NewEncoder(modifiedManifests)
defer encoder.Close()

for _, resource := range resourceList {
err = encoder.Encode(resource)
if err != nil {
return nil, err
}
}

return modifiedManifests, nil
}
91 changes: 91 additions & 0 deletions pkg/agent/docker_secrets_postrenderer_test.go
@@ -0,0 +1,91 @@
package agent

import (
"bytes"
"testing"

"github.com/google/go-cmp/cmp"
)

func TestDockerSecretsPostRenderer(t *testing.T) {
testCases := []struct {
name string
input *bytes.Buffer
secrets map[string]string
output *bytes.Buffer
expectErr bool
}{
{
name: "it returns the input without parsing when no secrets set",
input: bytes.NewBuffer([]byte(`anything at : all`)),
output: bytes.NewBuffer([]byte(`anything at : all`)),
},
{
name: "it returns an error if the input cannot be parsed as yaml",
input: bytes.NewBuffer([]byte("v: [A,")),
secrets: map[string]string{"foo.example.com": "secret-name"},
expectErr: true,
},
{
name: "it re-renders the yaml with ordering and indent changes only",
input: bytes.NewBuffer([]byte(`apiVersion: v1
kind: Pod
metadata:
name: image-secret-test
annotations:
annotation-1: some-annotation
spec:
containers:
- command:
- sh
- -c
- echo 'foo'
env:
- name: SOME_ENV
value: env_value
image: example.com/bitnami/nginx:1.16.1-debian-10-r42
name: container-name
restartPolicy: Never
---
other: doc
`)),
output: bytes.NewBuffer([]byte(`apiVersion: v1
kind: Pod
metadata:
annotations:
annotation-1: some-annotation
name: image-secret-test
spec:
containers:
- command:
- sh
- -c
- echo 'foo'
env:
- name: SOME_ENV
value: env_value
image: example.com/bitnami/nginx:1.16.1-debian-10-r42
name: container-name
restartPolicy: Never
---
other: doc
`)),
secrets: map[string]string{"foo.example.com": "secret-name"},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := NewDockerSecretsPostRenderer(tc.secrets)

renderedManifests, err := r.Run(tc.input)
if got, want := err != nil, tc.expectErr; got != want {
t.Fatalf("got: %t, want: %t. err: %+v", got, want, err)
}

if got, want := renderedManifests.String(), tc.output.String(); !cmp.Equal(got, want) {
t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(want, got))
}
})
}
}

0 comments on commit 3f3f76a

Please sign in to comment.