diff --git a/templates/templates.go b/templates/templates.go index cfd42e4c..b5920974 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -106,6 +106,7 @@ type Template struct { TemplatePath string `json:"template"` Path string `json:"path"` Comment string `json:"comment"` + Content []byte `json:"-"` } // Validate returns an error if the template is not valid. @@ -117,10 +118,12 @@ func (t *Template) Validate() error { return errors.New("template name cannot be empty") case t.Type != Snippet && t.Type != File && t.Type != Directory: return errors.Errorf("invalid template type %s, it must be %s, %s, or %s", t.Type, Snippet, File, Directory) - case t.TemplatePath == "" && t.Type != Directory: + case t.TemplatePath == "" && t.Type != Directory && len(t.Content) == 0: return errors.New("template template cannot be empty") case t.TemplatePath != "" && t.Type == Directory: return errors.New("template template must be empty with directory type") + case t.TemplatePath != "" && len(t.Content) > 0: + return errors.New("template template must be empty with content") case t.Path == "": return errors.New("template path cannot be empty") } @@ -148,20 +151,30 @@ func (t *Template) Validate() error { // template fails. func (t *Template) Load() error { if t.Template == nil && t.Type != Directory { - filename := config.StepAbs(t.TemplatePath) - b, err := ioutil.ReadFile(filename) - if err != nil { - return errors.Wrapf(err, "error reading %s", filename) + switch { + case t.TemplatePath != "": + filename := config.StepAbs(t.TemplatePath) + b, err := ioutil.ReadFile(filename) + if err != nil { + return errors.Wrapf(err, "error reading %s", filename) + } + return t.LoadBytes(b) + default: + return t.LoadBytes(t.Content) } - tmpl, err := template.New(t.Name).Funcs(sprig.TxtFuncMap()).Parse(string(b)) - if err != nil { - return errors.Wrapf(err, "error parsing %s", filename) - } - t.Template = tmpl } return nil } +func (t *Template) LoadBytes(b []byte) error { + tmpl, err := template.New(t.Name).Funcs(sprig.TxtFuncMap()).Parse(string(b)) + if err != nil { + return errors.Wrapf(err, "error parsing template %s", t.Name) + } + t.Template = tmpl + return nil +} + // Render executes the template with the given data and returns the rendered // version. func (t *Template) Render(data interface{}) ([]byte, error) { diff --git a/templates/templates_test.go b/templates/templates_test.go index c3d252ad..e00217c8 100644 --- a/templates/templates_test.go +++ b/templates/templates_test.go @@ -62,6 +62,12 @@ func TestSSHTemplates_Validate(t *testing.T) { host := []Template{ {Name: "ca.tpl", Type: File, TemplatePath: "../authority/testdata/templates/ca.tpl", Path: "/etc/ssh/ca.pub", Comment: "#"}, } + content := []Template{ + {Name: "test.tpl", Type: File, Content: []byte("some content"), Path: "/test.pub", Comment: "#"}, + } + badContent := []Template{ + {Name: "ca.tpl", Type: File, TemplatePath: "../authority/testdata/templates/ca.tpl", Content: []byte("some content"), Path: "/etc/ssh/ca.pub", Comment: "#"}, + } type fields struct { User []Template @@ -75,8 +81,10 @@ func TestSSHTemplates_Validate(t *testing.T) { {"ok", fields{user, host}, false}, {"user", fields{user, nil}, false}, {"host", fields{nil, host}, false}, + {"content", fields{content, nil}, false}, {"badUser", fields{[]Template{{}}, nil}, true}, {"badHost", fields{nil, []Template{{}}}, true}, + {"badContent", fields{badContent, nil}, true}, } var nilValue *SSHTemplates assert.NoError(t, nilValue.Validate()) @@ -163,8 +171,8 @@ func TestLoadAll(t *testing.T) { {"ok", args{tmpl}, false}, {"empty", args{&Templates{}}, false}, {"nil", args{nil}, false}, - {"badUser", args{&Templates{SSH: &SSHTemplates{User: []Template{{}}}}}, true}, - {"badHost", args{&Templates{SSH: &SSHTemplates{Host: []Template{{}}}}}, true}, + {"badUser", args{&Templates{SSH: &SSHTemplates{User: []Template{{TemplatePath: "missing"}}}}}, true}, + {"badHost", args{&Templates{SSH: &SSHTemplates{Host: []Template{{TemplatePath: "missing"}}}}}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {