diff --git a/README.md b/README.md index b3bfc28..f4ea9ab 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ There is an example packer build with goss tests in the `example/` directory. "vars_file": "", "username": "", "password": "", - "debug": false, "retry_timeout": "0s", "sleep": "1s" } diff --git a/packer-provisioner-goss.go b/packer-provisioner-goss.go index dfe09e7..19b418d 100644 --- a/packer-provisioner-goss.go +++ b/packer-provisioner-goss.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/hashicorp/hcl/v2/hcldec" @@ -28,9 +29,6 @@ type GossConfig struct { Password string SkipInstall bool - // Enable debug for goss (defaults to false) - Debug bool - // An array of tests to run. Tests []string @@ -66,10 +64,16 @@ type GossConfig struct { // Default: rspecish Format string `mapstructure:"format"` + // The format options to use for printing test output + // Available: [perfdata verbose pretty] + // Default: verbose + FormatOptions string `mapstructure:"format_options"` + ctx interpolate.Context } var validFormats = []string{"documentation", "json", "json_oneline", "junit", "nagios", "nagios_verbose", "rspecish", "silent", "tap"} +var validFormatOptions = []string{"perfdata", "verbose", "pretty"} // Provisioner implements a packer Provisioner type Provisioner struct { @@ -117,7 +121,14 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } if p.config.DownloadPath == "" { - p.config.DownloadPath = fmt.Sprintf("/tmp/goss-%s-linux-%s", p.config.Version, p.config.Arch) + if p.config.URL == "" { + p.config.DownloadPath = fmt.Sprintf("/tmp/goss-%s-linux-%s", p.config.Version, p.config.Arch) + } else { + list := strings.Split(p.config.URL, "/") + arch := strings.Split(list[len(list)-1], "-")[2] + version := strings.TrimPrefix(list[len(list)-2], "v") + p.config.DownloadPath = fmt.Sprintf("/tmp/goss-%s-linux-%s", version, arch) + } } if p.config.RemoteFolder == "" { @@ -152,6 +163,21 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } } + if p.config.FormatOptions != "" { + valid := false + for _, candidate := range validFormatOptions { + if p.config.FormatOptions == candidate { + valid = true + break + } + } + if !valid { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("Invalid format options choice %s. Valid options: %v", + p.config.FormatOptions, validFormatOptions)) + } + } + if len(p.config.Tests) == 0 { errs = packer.MultiErrorAppend(errs, errors.New("tests must be specified")) @@ -266,9 +292,9 @@ func (p *Provisioner) runGoss(ui packer.Ui, comm packer.Communicator) error { cmd := &packer.RemoteCmd{ Command: fmt.Sprintf( - "cd %s && %s %s %s %s %s validate --retry-timeout %s --sleep %s %s", + "cd %s && %s %s %s %s validate --retry-timeout %s --sleep %s %s %s", p.config.RemotePath, p.enableSudo(), goss, p.config.GossFile, - p.vars(), p.debug(), p.retryTimeout(), p.sleep(), p.format()), + p.vars(), p.retryTimeout(), p.sleep(), p.format(), p.formatOptions()), } if err := cmd.RunWithUi(ctx, comm, ui); err != nil { return err @@ -294,17 +320,16 @@ func (p *Provisioner) sleep() string { return p.config.Sleep } -// debug returns the debug flag if debug is configured -func (p *Provisioner) debug() string { - if p.config.Debug { - return "-d" +func (p *Provisioner) format() string { + if p.config.Format != "" { + return fmt.Sprintf("-f %s", p.config.Format) } return "" } -func (p *Provisioner) format() string { - if p.config.Format != "" { - return fmt.Sprintf("-f %s", p.config.Format) +func (p *Provisioner) formatOptions() string { + if p.config.FormatOptions != "" { + return fmt.Sprintf("-o %s", p.config.FormatOptions) } return "" } diff --git a/packer-provisioner-goss.hcl2spec.go b/packer-provisioner-goss.hcl2spec.go index 4c27230..ea525a6 100644 --- a/packer-provisioner-goss.hcl2spec.go +++ b/packer-provisioner-goss.hcl2spec.go @@ -9,24 +9,24 @@ import ( // FlatGossConfig is an auto-generated flat version of GossConfig. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatGossConfig struct { - Version *string `cty:"version"` - Arch *string `cty:"arch"` - URL *string `cty:"url"` - DownloadPath *string `cty:"download_path"` - Username *string `cty:"username"` - Password *string `cty:"password"` - SkipInstall *bool `cty:"skip_install"` - Debug *bool `cty:"debug"` - Tests []string `cty:"tests"` - RetryTimeout *string `mapstructure:"retry_timeout" cty:"retry_timeout"` - Sleep *string `mapstructure:"sleep" cty:"sleep"` - UseSudo *bool `mapstructure:"use_sudo" cty:"use_sudo"` - SkipSSLChk *bool `mapstructure:"skip_ssl" cty:"skip_ssl"` - GossFile *string `mapstructure:"goss_file" cty:"goss_file"` - VarsFile *string `mapstructure:"vars_file" cty:"vars_file"` - RemoteFolder *string `mapstructure:"remote_folder" cty:"remote_folder"` - RemotePath *string `mapstructure:"remote_path" cty:"remote_path"` - Format *string `mapstructure:"format" cty:"format"` + Version *string `cty:"version"` + Arch *string `cty:"arch"` + URL *string `cty:"url"` + DownloadPath *string `cty:"download_path"` + Username *string `cty:"username"` + Password *string `cty:"password"` + SkipInstall *bool `cty:"skip_install"` + Tests []string `cty:"tests"` + RetryTimeout *string `mapstructure:"retry_timeout" cty:"retry_timeout"` + Sleep *string `mapstructure:"sleep" cty:"sleep"` + UseSudo *bool `mapstructure:"use_sudo" cty:"use_sudo"` + SkipSSLChk *bool `mapstructure:"skip_ssl" cty:"skip_ssl"` + GossFile *string `mapstructure:"goss_file" cty:"goss_file"` + VarsFile *string `mapstructure:"vars_file" cty:"vars_file"` + RemoteFolder *string `mapstructure:"remote_folder" cty:"remote_folder"` + RemotePath *string `mapstructure:"remote_path" cty:"remote_path"` + Format *string `mapstructure:"format" cty:"format"` + FormatOptions *string `mapstructure:"format_options" cty:"format_options"` } // FlatMapstructure returns a new FlatGossConfig. @@ -41,24 +41,24 @@ func (*GossConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Sp // The decoded values from this spec will then be applied to a FlatGossConfig. func (*FlatGossConfig) HCL2Spec() map[string]hcldec.Spec { s := map[string]hcldec.Spec{ - "version": &hcldec.AttrSpec{Name: "version", Type: cty.String, Required: false}, - "arch": &hcldec.AttrSpec{Name: "arch", Type: cty.String, Required: false}, - "url": &hcldec.AttrSpec{Name: "url", Type: cty.String, Required: false}, - "download_path": &hcldec.AttrSpec{Name: "download_path", Type: cty.String, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "skip_install": &hcldec.AttrSpec{Name: "skip_install", Type: cty.Bool, Required: false}, - "debug": &hcldec.AttrSpec{Name: "debug", Type: cty.Bool, Required: false}, - "tests": &hcldec.AttrSpec{Name: "tests", Type: cty.List(cty.String), Required: false}, - "retry_timeout": &hcldec.AttrSpec{Name: "retry_timeout", Type: cty.String, Required: false}, - "sleep": &hcldec.AttrSpec{Name: "sleep", Type: cty.String, Required: false}, - "use_sudo": &hcldec.AttrSpec{Name: "use_sudo", Type: cty.Bool, Required: false}, - "skip_ssl": &hcldec.AttrSpec{Name: "skip_ssl", Type: cty.Bool, Required: false}, - "goss_file": &hcldec.AttrSpec{Name: "goss_file", Type: cty.String, Required: false}, - "vars_file": &hcldec.AttrSpec{Name: "vars_file", Type: cty.String, Required: false}, - "remote_folder": &hcldec.AttrSpec{Name: "remote_folder", Type: cty.String, Required: false}, - "remote_path": &hcldec.AttrSpec{Name: "remote_path", Type: cty.String, Required: false}, - "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, + "version": &hcldec.AttrSpec{Name: "version", Type: cty.String, Required: false}, + "arch": &hcldec.AttrSpec{Name: "arch", Type: cty.String, Required: false}, + "url": &hcldec.AttrSpec{Name: "url", Type: cty.String, Required: false}, + "download_path": &hcldec.AttrSpec{Name: "download_path", Type: cty.String, Required: false}, + "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, + "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, + "skip_install": &hcldec.AttrSpec{Name: "skip_install", Type: cty.Bool, Required: false}, + "tests": &hcldec.AttrSpec{Name: "tests", Type: cty.List(cty.String), Required: false}, + "retry_timeout": &hcldec.AttrSpec{Name: "retry_timeout", Type: cty.String, Required: false}, + "sleep": &hcldec.AttrSpec{Name: "sleep", Type: cty.String, Required: false}, + "use_sudo": &hcldec.AttrSpec{Name: "use_sudo", Type: cty.Bool, Required: false}, + "skip_ssl": &hcldec.AttrSpec{Name: "skip_ssl", Type: cty.Bool, Required: false}, + "goss_file": &hcldec.AttrSpec{Name: "goss_file", Type: cty.String, Required: false}, + "vars_file": &hcldec.AttrSpec{Name: "vars_file", Type: cty.String, Required: false}, + "remote_folder": &hcldec.AttrSpec{Name: "remote_folder", Type: cty.String, Required: false}, + "remote_path": &hcldec.AttrSpec{Name: "remote_path", Type: cty.String, Required: false}, + "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, + "format_options": &hcldec.AttrSpec{Name: "format_options", Type: cty.String, Required: false}, } return s }