From 1b0d05097b879723afd68e89abe6f4c8e5fefa19 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Fri, 11 Oct 2019 18:59:50 -0700 Subject: [PATCH] Add Write method to templates.Output. --- pki/templates.go | 21 ++++++++-------- templates/templates.go | 57 +++++++++++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/pki/templates.go b/pki/templates.go index 1d873ed4..c5789573 100644 --- a/pki/templates.go +++ b/pki/templates.go @@ -4,23 +4,24 @@ import ( "os" "path/filepath" - "github.com/smallstep/cli/utils" - "github.com/pkg/errors" "github.com/smallstep/certificates/templates" + "github.com/smallstep/cli/config" "github.com/smallstep/cli/errs" + "github.com/smallstep/cli/utils" ) // sshTemplates contains the configuration of default templates used on ssh. +// Relative paths are relative to the StepPath. var sshTemplates = &templates.SSHTemplates{ User: []templates.Template{ - {Name: "include.tpl", Type: templates.Snippet, TemplatePath: "ssh/include.tpl", Path: "~/.ssh/config", Comment: "#"}, - {Name: "config.tpl", Type: templates.File, TemplatePath: "ssh/config.tpl", Path: "ssh/config", Comment: "#"}, - {Name: "known_hosts.tpl", Type: templates.File, TemplatePath: "ssh/known_hosts.tpl", Path: "ssh/known_hosts", Comment: "#"}, + {Name: "include.tpl", Type: templates.Snippet, TemplatePath: "templates/ssh/include.tpl", Path: "~/.ssh/config", Comment: "#"}, + {Name: "config.tpl", Type: templates.File, TemplatePath: "templates/ssh/config.tpl", Path: "ssh/config", Comment: "#"}, + {Name: "known_hosts.tpl", Type: templates.File, TemplatePath: "templates/ssh/known_hosts.tpl", Path: "ssh/known_hosts", Comment: "#"}, }, Host: []templates.Template{ - {Name: "sshd_config.tpl", Type: templates.Snippet, TemplatePath: "ssh/sshd_config.tpl", Path: "/etc/ssh/sshd_config", Comment: "#"}, - {Name: "ca.tpl", Type: templates.Snippet, TemplatePath: "ssh/ca.tpl", Path: "/etc/ssh/ca.pub", Comment: "#"}, + {Name: "sshd_config.tpl", Type: templates.Snippet, TemplatePath: "templates/ssh/sshd_config.tpl", Path: "/etc/ssh/sshd_config", Comment: "#"}, + {Name: "ca.tpl", Type: templates.Snippet, TemplatePath: "templates/ssh/ca.tpl", Path: "/etc/ssh/ca.pub", Comment: "#"}, }, } @@ -36,7 +37,7 @@ var sshTemplateData = map[string]string{ ForwardAgent yes UserKnownHostsFile {{.User.StepPath}}/config/ssh/known_hosts`, - // known_hosts.tpl authorizes the ssh hosst key + // known_hosts.tpl authorizes the ssh hosts key "known_hosts.tpl": "@cert-authority * {{.Step.SSH.HostKey.Type}} {{.Step.SSH.HostKey.Marshal | toString | b64enc}}", // sshd_config.tpl adds the configuration to support certificates @@ -82,7 +83,7 @@ func generateTemplates(t *templates.Templates) error { if !ok { return errors.Errorf("template %s does not exists", t.Name) } - if err := utils.WriteFile(filepath.Join(base, t.TemplatePath), []byte(data), 0644); err != nil { + if err := utils.WriteFile(config.StepAbs(t.TemplatePath), []byte(data), 0644); err != nil { return err } } @@ -91,7 +92,7 @@ func generateTemplates(t *templates.Templates) error { if !ok { return errors.Errorf("template %s does not exists", t.Name) } - if err := utils.WriteFile(filepath.Join(base, t.TemplatePath), []byte(data), 0644); err != nil { + if err := utils.WriteFile(config.StepAbs(t.TemplatePath), []byte(data), 0644); err != nil { return err } } diff --git a/templates/templates.go b/templates/templates.go index 1ff5cdf2..ee4a5791 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -3,10 +3,14 @@ package templates import ( "bytes" "io/ioutil" + "os" + "path/filepath" "text/template" "github.com/Masterminds/sprig" "github.com/pkg/errors" + "github.com/smallstep/cli/config" + "github.com/smallstep/cli/utils" ) // TemplateType defines how a template will be written in disk. @@ -17,17 +21,10 @@ const ( Snippet TemplateType = "snippet" // File will mark a templates as a full file. File TemplateType = "file" + // Directory will mark a template as a directory. + Directory TemplateType = "directory" ) -// Output represents the text representation of a rendered template. -type Output struct { - Name string `json:"name"` - Type TemplateType `json:"type"` - Comment string `json:"comment"` - Path string `json:"path"` - Content []byte `json:"content"` -} - // Templates is a collection of templates and variables. type Templates struct { SSH *SSHTemplates `json:"ssh,omitempty"` @@ -137,13 +134,14 @@ func (t *Template) Validate() error { // template fails. func (t *Template) Load() error { if t.Template == nil { - b, err := ioutil.ReadFile(t.TemplatePath) + filename := config.StepAbs(t.TemplatePath) + b, err := ioutil.ReadFile(filename) if err != nil { - return errors.Wrapf(err, "error reading %s", t.TemplatePath) + return errors.Wrapf(err, "error reading %s", filename) } tmpl, err := template.New(t.Name).Funcs(sprig.TxtFuncMap()).Parse(string(b)) if err != nil { - return errors.Wrapf(err, "error parsing %s", t.TemplatePath) + return errors.Wrapf(err, "error parsing %s", filename) } t.Template = tmpl } @@ -179,3 +177,38 @@ func (t *Template) Output(data interface{}) (Output, error) { Content: b, }, nil } + +// Output represents the text representation of a rendered template. +type Output struct { + Name string `json:"name"` + Type TemplateType `json:"type"` + Comment string `json:"comment"` + Path string `json:"path"` + Content []byte `json:"content"` +} + +// Write writes the Output to the filesystem as a directory, file or snippet. +func (o *Output) Write() error { + path := config.StepAbs(o.Path) + if o.Type == Directory { + return mkdir(path, 0700) + } + + dir := filepath.Dir(path) + if err := mkdir(dir, 0700); err != nil { + return err + } + + if o.Type == File { + return utils.WriteFile(path, o.Content, 0600) + } + + return utils.WriteSnippet(path, o.Content, 0600) +} + +func mkdir(path string, perm os.FileMode) error { + if err := os.MkdirAll(path, perm); err != nil { + return errors.Wrapf(err, "error creating %s", path) + } + return nil +}