mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
improve error reporting for bad templates
This commit is contained in:
parent
6916235513
commit
16c624b2e6
@ -327,7 +327,8 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
|
|||||||
|
|
||||||
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
|
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
|
||||||
type TemplatePrinter struct {
|
type TemplatePrinter struct {
|
||||||
template *template.Template
|
rawTemplate string
|
||||||
|
template *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
|
func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
|
||||||
@ -335,17 +336,27 @@ func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &TemplatePrinter{t}, nil
|
return &TemplatePrinter{string(tmpl), t}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print parses the data as JSON, and re-formats it with the Go Template.
|
// Print parses the data as JSON, and re-formats it with the Go Template.
|
||||||
func (t *TemplatePrinter) Print(data []byte, w io.Writer) error {
|
func (t *TemplatePrinter) Print(data []byte, w io.Writer) error {
|
||||||
obj := map[string]interface{}{}
|
out := map[string]interface{}{}
|
||||||
err := json.Unmarshal(data, &obj)
|
err := json.Unmarshal(data, &out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.template.Execute(w, obj)
|
if err := t.template.Execute(w, out); err != nil {
|
||||||
|
// It is way easier to debug this stuff when it shows up in
|
||||||
|
// stdout instead of just stdin. So in addition to returning
|
||||||
|
// a nice error, also print useful stuff with the writer.
|
||||||
|
fmt.Fprintf(w, "Error executing template: %v\n", err)
|
||||||
|
fmt.Fprintf(w, "template was:\n%v\n", t.rawTemplate)
|
||||||
|
fmt.Fprintf(w, "raw data was:\n%v\n", string(data))
|
||||||
|
fmt.Fprintf(w, "object given to template engine was:\n%+v\n", out)
|
||||||
|
return fmt.Errorf("error executing template '%v': '%v'\n----data----\n%#v\n", t.rawTemplate, err, out)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintObj formats the obj with the Go Template.
|
// PrintObj formats the obj with the Go Template.
|
||||||
|
@ -177,3 +177,20 @@ func TestTemplateEmitsVersionedObjects(t *testing.T) {
|
|||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTemplatePanic(t *testing.T) {
|
||||||
|
tmpl := `{{and ((index .currentState.info "update-demo").state.running.startedAt) .currentState.info.net.state.running.startedAt}}`
|
||||||
|
// kind is always blank in memory and set on the wire
|
||||||
|
printer, err := NewTemplatePrinter([]byte(tmpl))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("tmpl fail: %v", err)
|
||||||
|
}
|
||||||
|
buffer := &bytes.Buffer{}
|
||||||
|
err = printer.PrintObj(&api.Pod{}, buffer)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected that template to crash")
|
||||||
|
}
|
||||||
|
if buffer.String() == "" {
|
||||||
|
t.Errorf("no debugging info was printed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -417,7 +417,14 @@ func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = p.template.Execute(w, out); err != nil {
|
if err = p.template.Execute(w, out); err != nil {
|
||||||
return fmt.Errorf("error executing template '%v': '%v'\n----data----\n%#v\n", p.rawTemplate, err, out)
|
// It is way easier to debug this stuff when it shows up in
|
||||||
|
// stdout instead of just stdin. So in addition to returning
|
||||||
|
// a nice error, also print useful stuff with the writer.
|
||||||
|
fmt.Fprintf(w, "Error executing template: %v\n", err)
|
||||||
|
fmt.Fprintf(w, "template was:\n\t%v\n", p.rawTemplate)
|
||||||
|
fmt.Fprintf(w, "raw data was:\n\t%v\n", string(data))
|
||||||
|
fmt.Fprintf(w, "object given to template engine was:\n\t%+v\n", out)
|
||||||
|
return fmt.Errorf("error executing template '%v': '%v'\n----data----\n%+v\n", p.rawTemplate, err, out)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -290,6 +290,23 @@ func TestTemplateEmitsVersionedObjects(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTemplatePanic(t *testing.T) {
|
||||||
|
tmpl := `{{and ((index .currentState.info "update-demo").state.running.startedAt) .currentState.info.net.state.running.startedAt}}`
|
||||||
|
// kind is always blank in memory and set on the wire
|
||||||
|
printer, err := NewTemplatePrinter([]byte(tmpl), testapi.Version(), api.Scheme)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("tmpl fail: %v", err)
|
||||||
|
}
|
||||||
|
buffer := &bytes.Buffer{}
|
||||||
|
err = printer.PrintObj(&api.Pod{}, buffer)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected that template to crash")
|
||||||
|
}
|
||||||
|
if buffer.String() == "" {
|
||||||
|
t.Errorf("no debugging info was printed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrinters(t *testing.T) {
|
func TestPrinters(t *testing.T) {
|
||||||
om := func(name string) api.ObjectMeta { return api.ObjectMeta{Name: name} }
|
om := func(name string) api.ObjectMeta { return api.ObjectMeta{Name: name} }
|
||||||
templatePrinter, err := NewTemplatePrinter([]byte("{{.name}}"), testapi.Version(), api.Scheme)
|
templatePrinter, err := NewTemplatePrinter([]byte("{{.name}}"), testapi.Version(), api.Scheme)
|
||||||
|
Loading…
Reference in New Issue
Block a user