Skip to content

Commit

Permalink
feat(output_file): add option to specify the test result output file
Browse files Browse the repository at this point in the history
  • Loading branch information
FalcoSuessgott committed Jun 30, 2024
1 parent fb262d8 commit 652f867
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 30 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
example/packer_cache
example/packer_cache
.envrc
packer-plugin-goss
tests/debug-goss-spec.yaml
tests/goss-spec.yaml
tests/goss.json
32 changes: 32 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
default: help

.PHONY: help
help: ## list makefile targets
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: fmt
fmt: ## format go files
gofumpt -w .
gci write .
packer fmt -recursive -write .

.PHONY: build
build: ## build the plugin
go build -ldflags="-X github.com/YaleUniversity/packer-provisioner-goss/version.VersionPrerelease=dev" -o packer-plugin-goss

.PHONY: install
install: ## install the plugin
packer plugins install --path packer-plugin-goss github.com/YaleUniversity/goss

.PHONY: local
local: clean build install ## build and install the plugin locally
cd tests && packer init .
cd tests && packer build local.pkr.hcl

.PHONY: clean
clean: ## remove tmp files
rm -f packer-plugin-goss tests/goss.json tests/debug-goss-spec.yaml tests/goss-spec.yaml packer-plugin-goss

.PHONY: generate
generate: ## go generate
go generate ./...
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ build {
# Provisioner Args
arch ="amd64"
download_path = "/tmp/goss-VERSION-linux-ARCH"
inspect = "{{ inspect_mode }}",
inspect = "{{ inspect_mode }}"
password = ""
skip_install = false
url = "https://github.com/aelsabbahy/goss/releases/download/vVERSION/goss-linux-ARCH"
Expand Down
8 changes: 2 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,19 @@ import (
"fmt"
"os"

"github.com/YaleUniversity/packer-provisioner-goss/provisioner/goss"
"github.com/hashicorp/packer-plugin-sdk/plugin"
"github.com/hashicorp/packer-plugin-sdk/version"

"github.com/YaleUniversity/packer-provisioner-goss/provisioner/goss"
)

var (
Version = "0.0.1"
)
var Version = "0.0.1"

func main() {
pps := plugin.NewSet()
pps.RegisterProvisioner(plugin.DEFAULT_NAME, new(goss.Provisioner))
pps.SetVersion(version.InitializePluginVersion(Version, ""))

err := pps.Run()

if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
Expand Down
58 changes: 51 additions & 7 deletions provisioner/goss/packer-provisioner-goss.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (
"strings"

"github.com/hashicorp/hcl/v2/hcldec"

"github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
)

const (
gossVersion = "0.4.7"
gossSpecFile = "/tmp/goss-spec.yaml"
gossDebugSpecFile = "/tmp/debug-goss-spec.yaml"
linux = "Linux"
Expand Down Expand Up @@ -83,6 +83,9 @@ type GossConfig struct {
// Default: rspecish
Format string `mapstructure:"format"`

// Destination of the file to write the output to, only works for linux
OutputFile string `mapstructure:"output_file"`

// The format options to use for printing test output
// Available: [perfdata verbose pretty]
// Default: verbose
Expand All @@ -91,8 +94,10 @@ type GossConfig struct {
ctx interpolate.Context
}

var validFormats = []string{"documentation", "json", "json_oneline", "junit", "nagios", "nagios_verbose", "rspecish", "silent", "tap"}
var validFormatOptions = []string{"perfdata", "verbose", "pretty"}
var (
validFormats = []string{"documentation", "json", "json_oneline", "junit", "nagios", "nagios_verbose", "rspecish", "silent", "tap"}
validFormatOptions = []string{"perfdata", "verbose", "pretty"}
)

// Provisioner implements a packer Provisioner
type Provisioner struct {
Expand All @@ -117,7 +122,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}

if p.config.Version == "" {
p.config.Version = "0.4.2"
p.config.Version = gossVersion
}

if p.config.Arch == "" {
Expand Down Expand Up @@ -184,6 +189,13 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}
}

// output file only works for linux
if p.config.OutputFile != "" {
if p.config.TargetOs != linux {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Output file only works for linux"))
}
}

if p.config.FormatOptions != "" {
valid := false
for _, candidate := range validFormatOptions {
Expand Down Expand Up @@ -292,6 +304,13 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
return fmt.Errorf("Error running Goss: %s", err)
}

if p.config.OutputFile != "" {
ui.Say("\n\n\nDownloading Goss test result file")
if err := p.downloadTestResults(ui, comm); err != nil {
return err
}
}

if !p.config.SkipDownload {
ui.Say("\n\n\nDownloading spec file and debug info")
if err := p.downloadSpecs(ui, comm); err != nil {
Expand All @@ -304,6 +323,24 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
return nil
}

// downloadSpecs downloads the Goss specs from the remote host to current working dir on local machine
func (p *Provisioner) downloadTestResults(ui packer.Ui, comm packer.Communicator) error {
ui.Message(fmt.Sprintf("Downloading Goss test results from %s to current dir", p.config.OutputFile))

f, err := os.Create(filepath.Base(p.config.OutputFile))
if err != nil {
return fmt.Errorf("Error opening: %s", err)
}

defer f.Close()

if err := comm.Download(p.config.OutputFile, f); err != nil {
return fmt.Errorf("Error downloading %s: %s", p.config.OutputFile, err)
}

return nil
}

// downloadSpecs downloads the Goss specs from the remote host to current working dir on local machine
func (p *Provisioner) downloadSpecs(ui packer.Ui, comm packer.Communicator) error {
ui.Message(fmt.Sprintf("Downloading Goss specs from, %s and %s to current dir", gossSpecFile, gossDebugSpecFile))
Expand Down Expand Up @@ -361,9 +398,9 @@ func (p *Provisioner) runGoss(ui packer.Ui, comm packer.Communicator) error {
p.config.RemotePath, p.envVars(), goss, p.config.GossFile,
p.vars(), p.inline_vars(), gossDebugSpecFile,
),
"validate": fmt.Sprintf("cd %s && %s %s %s %s %s %s validate --retry-timeout %s --sleep %s %s %s",
"validate": fmt.Sprintf("cd %s && %s %s %s %s %s %s validate --retry-timeout %s --sleep %s %s %s %s",
p.config.RemotePath, p.enableSudo(), p.envVars(), goss, p.config.GossFile,
p.vars(), p.inline_vars(), p.retryTimeout(), p.sleep(), p.format(), p.formatOptions(),
p.vars(), p.inline_vars(), p.retryTimeout(), p.sleep(), p.format(), p.formatOptions(), p.outputFile(),
),
}

Expand Down Expand Up @@ -397,6 +434,14 @@ func (p *Provisioner) runGossCmd(ui packer.Ui, comm packer.Communicator, cmd *pa
return nil
}

func (p *Provisioner) outputFile() string {
if p.config.OutputFile == "" {
return ""
}

return fmt.Sprintf("| tee %s", p.config.OutputFile)
}

func (p *Provisioner) retryTimeout() string {
if p.config.RetryTimeout == "" {
return "0s" // goss default
Expand Down Expand Up @@ -479,7 +524,6 @@ func (p *Provisioner) envVars() string {
default:
sb.WriteString(fmt.Sprintf("%s=\"%s\" ", env_var, value))
}

}
return sb.String()
}
Expand Down
2 changes: 2 additions & 0 deletions provisioner/goss/packer-provisioner-goss.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 13 additions & 15 deletions provisioner/goss/packer-provisioner-goss_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:generate packer-sdc mapstructure-to-hcl2 -type GossConfig

package goss

import (
Expand Down Expand Up @@ -27,8 +25,7 @@ func fakeContext() interpolate.Context {
}

func TestProvisioner_Prepare(t *testing.T) {

var tests = []struct {
tests := []struct {
name string
input []interface{}
wantErr bool
Expand All @@ -43,10 +40,10 @@ func TestProvisioner_Prepare(t *testing.T) {
},
wantErr: false,
wantConfig: GossConfig{
Version: "0.4.2",
Version: "0.4.7",
Arch: "amd64",
URL: "https://github.com/goss-org/goss/releases/download/v0.4.2/goss-linux-amd64",
DownloadPath: "/tmp/goss-0.4.2-linux-amd64",
URL: "https://github.com/goss-org/goss/releases/download/v0.4.7/goss-linux-amd64",
DownloadPath: "/tmp/goss-0.4.7-linux-amd64",
Username: "",
Password: "",
SkipInstall: false,
Expand All @@ -65,6 +62,7 @@ func TestProvisioner_Prepare(t *testing.T) {
RemotePath: "/tmp/goss",
Format: "",
FormatOptions: "",
OutputFile: "",
ctx: fakeContext(),
},
},
Expand All @@ -81,10 +79,10 @@ func TestProvisioner_Prepare(t *testing.T) {
},
wantErr: false,
wantConfig: GossConfig{
Version: "0.4.2",
Version: "0.4.7",
Arch: "amd64",
URL: "https://github.com/goss-org/goss/releases/download/v0.4.2/goss-alpha-windows-amd64.exe",
DownloadPath: "/tmp/goss-0.4.2-windows-amd64.exe",
URL: "https://github.com/goss-org/goss/releases/download/v0.4.7/goss-alpha-windows-amd64.exe",
DownloadPath: "/tmp/goss-0.4.7-windows-amd64.exe",
Username: "",
Password: "",
SkipInstall: false,
Expand All @@ -105,6 +103,7 @@ func TestProvisioner_Prepare(t *testing.T) {
RemotePath: "/tmp/goss",
Format: "",
FormatOptions: "",
OutputFile: "",
ctx: fakeContext(),
},
},
Expand All @@ -118,10 +117,10 @@ func TestProvisioner_Prepare(t *testing.T) {
},
wantErr: false,
wantConfig: GossConfig{
Version: "0.4.2",
Version: "0.4.7",
Arch: "amd64",
URL: "https://github.com/goss-org/goss/releases/download/v0.4.2/goss-windows-amd64.exe",
DownloadPath: "/tmp/goss-0.4.2-windows-amd64.exe",
URL: "https://github.com/goss-org/goss/releases/download/v0.4.7/goss-windows-amd64.exe",
DownloadPath: "/tmp/goss-0.4.7-windows-amd64.exe",
Username: "",
Password: "",
SkipInstall: false,
Expand All @@ -140,6 +139,7 @@ func TestProvisioner_Prepare(t *testing.T) {
RemotePath: "/tmp/goss",
Format: "",
FormatOptions: "",
OutputFile: "",
ctx: fakeContext(),
},
},
Expand All @@ -161,13 +161,11 @@ func TestProvisioner_Prepare(t *testing.T) {
t.Logf("got config= %v", p.config)
t.Logf("want config= %v", tt.wantConfig)
}

})
}
}

func TestProvisioner_envVars(t *testing.T) {

tests := []struct {
name string
config GossConfig
Expand Down
3 changes: 3 additions & 0 deletions tests/goss.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
process:
sshd:
running: true
41 changes: 41 additions & 0 deletions tests/local.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
packer {
required_version = ">= 1.9.0"

required_plugins {
goss = {
version = "v0.0.1"
source = "github.com/YaleUniversity/goss"
}
}
}

variable "ssh_user" {
default = env("USER")
}

variable "ssh_password" {
default = env("SSH_PASSWORD")
}

variable "ssh_host" {
default = "127.0.0.1"
}

source "null" "local" {
ssh_host = var.ssh_host
ssh_username = var.ssh_user
ssh_password = var.ssh_password
}

build {
sources = ["null.local"]

provisioner "goss" {
download_path = "/tmp/goss_install"
skip_install = true
tests = ["./goss.yaml"]
remote_path = "/tmp/goss"
format = "junit"
output_file = "/tmp/goss.json"
}
}

0 comments on commit 652f867

Please sign in to comment.