diff --git a/pkg/printers/BUILD b/pkg/printers/BUILD index 4e2dd00009..cafea75659 100644 --- a/pkg/printers/BUILD +++ b/pkg/printers/BUILD @@ -69,7 +69,10 @@ filegroup( go_test( name = "go_default_test", - srcs = ["humanreadable_test.go"], + srcs = [ + "humanreadable_test.go", + "template_test.go", + ], embed = [":go_default_library"], deps = [ "//pkg/apis/core:go_default_library", diff --git a/pkg/printers/template.go b/pkg/printers/template.go index c54c511a20..f95d50b437 100644 --- a/pkg/printers/template.go +++ b/pkg/printers/template.go @@ -17,6 +17,7 @@ limitations under the License. package printers import ( + "encoding/base64" "encoding/json" "fmt" "io" @@ -33,7 +34,10 @@ type TemplatePrinter struct { func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) { t, err := template.New("output"). - Funcs(template.FuncMap{"exists": exists}). + Funcs(template.FuncMap{ + "exists": exists, + "base64decode": base64decode, + }). Parse(string(tmpl)) if err != nil { return nil, err @@ -112,3 +116,11 @@ func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error { } return retErr } + +func base64decode(v string) (string, error) { + data, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return "", fmt.Errorf("base64 decode failed: %v", err) + } + return string(data), nil +} diff --git a/pkg/printers/template_test.go b/pkg/printers/template_test.go new file mode 100644 index 0000000000..43526fd611 --- /dev/null +++ b/pkg/printers/template_test.go @@ -0,0 +1,97 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 printers + +import ( + "bytes" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + api "k8s.io/kubernetes/pkg/apis/core" +) + +func TestTemplate(t *testing.T) { + testCase := map[string]struct { + template string + obj runtime.Object + expectOut string + expectErr func(error) (string, bool) + }{ + "support base64 decoding of secret data": { + template: "{{ .Data.username | base64decode }}", + obj: &api.Secret{ + Data: map[string][]byte{ + "username": []byte("hunter"), + }, + }, + expectOut: "hunter", + }, + "test error path for base64 decoding": { + template: "{{ .Data.username | base64decode }}", + obj: &badlyMarshaledSecret{}, + expectErr: func(err error) (string, bool) { + matched := strings.Contains(err.Error(), "base64 decode") + return "a base64 decode error", matched + }, + }, + } + for name, test := range testCase { + buffer := &bytes.Buffer{} + + p, err := NewTemplatePrinter([]byte(test.template)) + if err != nil { + if test.expectErr == nil { + t.Errorf("[%s]expected success but got:\n %v\n", name, err) + continue + } + if expected, ok := test.expectErr(err); !ok { + t.Errorf("[%s]expect:\n %v\n but got:\n %v\n", name, expected, err) + } + continue + } + + err = p.PrintObj(test.obj, buffer) + if err != nil { + if test.expectErr == nil { + t.Errorf("[%s]expected success but got:\n %v\n", name, err) + continue + } + if expected, ok := test.expectErr(err); !ok { + t.Errorf("[%s]expect:\n %v\n but got:\n %v\n", name, expected, err) + } + continue + } + + if test.expectErr != nil { + t.Errorf("[%s]expect:\n error\n but got:\n no error\n", name) + continue + } + + if test.expectOut != buffer.String() { + t.Errorf("[%s]expect:\n %v\n but got:\n %v\n", name, test.expectOut, buffer.String()) + } + } +} + +type badlyMarshaledSecret struct { + api.Secret +} + +func (a badlyMarshaledSecret) MarshalJSON() ([]byte, error) { + return []byte(`{"apiVersion":"v1","Data":{"username":"--THIS IS NOT BASE64--"},"kind":"Secret"}`), nil +}