2019-01-20 10:43:47 -05:00
|
|
|
package inspec
|
|
|
|
|
|
|
|
import (
|
2021-03-12 10:47:21 -05:00
|
|
|
"bytes"
|
|
|
|
"context"
|
2019-01-20 10:43:47 -05:00
|
|
|
"crypto/rand"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path"
|
2021-03-12 10:47:21 -05:00
|
|
|
"runtime"
|
2019-01-20 10:43:47 -05:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2020-12-17 16:29:25 -05:00
|
|
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
2019-01-20 10:43:47 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// Be sure to remove the InSpec stub file in each test with:
|
|
|
|
// defer os.Remove(config["command"].(string))
|
|
|
|
func testConfig(t *testing.T) map[string]interface{} {
|
|
|
|
m := make(map[string]interface{})
|
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
inspec_stub := path.Join(wd, "packer-inspec-stub.sh")
|
|
|
|
|
|
|
|
err = ioutil.WriteFile(inspec_stub, []byte("#!/usr/bin/env bash\necho 2.2.16"), 0777)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
m["command"] = inspec_stub
|
|
|
|
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvisioner_Impl(t *testing.T) {
|
|
|
|
var raw interface{}
|
|
|
|
raw = &Provisioner{}
|
2020-12-01 17:25:14 -05:00
|
|
|
if _, ok := raw.(packersdk.Provisioner); !ok {
|
2019-01-20 10:43:47 -05:00
|
|
|
t.Fatalf("must be a Provisioner")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvisionerPrepare_Defaults(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
config := testConfig(t)
|
|
|
|
defer os.Remove(config["command"].(string))
|
|
|
|
|
|
|
|
err := p.Prepare(config)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("should have error")
|
|
|
|
}
|
|
|
|
|
|
|
|
hostkey_file, err := ioutil.TempFile("", "hostkey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(hostkey_file.Name())
|
|
|
|
|
|
|
|
publickey_file, err := ioutil.TempFile("", "publickey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(publickey_file.Name())
|
|
|
|
|
|
|
|
profile_file, err := ioutil.TempFile("", "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(profile_file.Name())
|
|
|
|
|
|
|
|
config["ssh_host_key_file"] = hostkey_file.Name()
|
|
|
|
config["ssh_authorized_key_file"] = publickey_file.Name()
|
|
|
|
config["profile"] = profile_file.Name()
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(profile_file.Name())
|
|
|
|
|
|
|
|
err = os.Unsetenv("USER")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvisionerPrepare_ProfileFile(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
config := testConfig(t)
|
|
|
|
defer os.Remove(config["command"].(string))
|
|
|
|
|
|
|
|
hostkey_file, err := ioutil.TempFile("", "hostkey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(hostkey_file.Name())
|
|
|
|
|
|
|
|
publickey_file, err := ioutil.TempFile("", "publickey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(publickey_file.Name())
|
|
|
|
|
|
|
|
config["ssh_host_key_file"] = hostkey_file.Name()
|
|
|
|
config["ssh_authorized_key_file"] = publickey_file.Name()
|
|
|
|
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("should have error")
|
|
|
|
}
|
|
|
|
|
|
|
|
profile_file, err := ioutil.TempFile("", "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(profile_file.Name())
|
|
|
|
|
|
|
|
config["profile"] = profile_file.Name()
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
test_dir, err := ioutil.TempDir("", "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(test_dir)
|
|
|
|
|
|
|
|
config["profile"] = test_dir
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvisionerPrepare_HostKeyFile(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
config := testConfig(t)
|
|
|
|
defer os.Remove(config["command"].(string))
|
|
|
|
|
|
|
|
publickey_file, err := ioutil.TempFile("", "publickey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(publickey_file.Name())
|
|
|
|
|
|
|
|
profile_file, err := ioutil.TempFile("", "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(profile_file.Name())
|
|
|
|
|
|
|
|
filename := make([]byte, 10)
|
|
|
|
n, err := io.ReadFull(rand.Reader, filename)
|
|
|
|
if n != len(filename) || err != nil {
|
|
|
|
t.Fatal("could not create random file name")
|
|
|
|
}
|
|
|
|
|
|
|
|
config["ssh_host_key_file"] = fmt.Sprintf("%x", filename)
|
|
|
|
config["ssh_authorized_key_file"] = publickey_file.Name()
|
|
|
|
config["profile"] = profile_file.Name()
|
|
|
|
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("should error if ssh_host_key_file does not exist")
|
|
|
|
}
|
|
|
|
|
|
|
|
hostkey_file, err := ioutil.TempFile("", "hostkey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(hostkey_file.Name())
|
|
|
|
|
|
|
|
config["ssh_host_key_file"] = hostkey_file.Name()
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvisionerPrepare_AuthorizedKeyFiles(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
config := testConfig(t)
|
|
|
|
defer os.Remove(config["command"].(string))
|
|
|
|
|
|
|
|
hostkey_file, err := ioutil.TempFile("", "hostkey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(hostkey_file.Name())
|
|
|
|
|
|
|
|
profile_file, err := ioutil.TempFile("", "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(profile_file.Name())
|
|
|
|
|
|
|
|
filename := make([]byte, 10)
|
|
|
|
n, err := io.ReadFull(rand.Reader, filename)
|
|
|
|
if n != len(filename) || err != nil {
|
|
|
|
t.Fatal("could not create random file name")
|
|
|
|
}
|
|
|
|
|
|
|
|
config["ssh_host_key_file"] = hostkey_file.Name()
|
|
|
|
config["profile"] = profile_file.Name()
|
|
|
|
config["ssh_authorized_key_file"] = fmt.Sprintf("%x", filename)
|
|
|
|
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("should error if ssh_authorized_key_file does not exist")
|
|
|
|
}
|
|
|
|
|
|
|
|
publickey_file, err := ioutil.TempFile("", "publickey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(publickey_file.Name())
|
|
|
|
|
|
|
|
config["ssh_authorized_key_file"] = publickey_file.Name()
|
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvisionerPrepare_LocalPort(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
config := testConfig(t)
|
|
|
|
defer os.Remove(config["command"].(string))
|
|
|
|
|
|
|
|
hostkey_file, err := ioutil.TempFile("", "hostkey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(hostkey_file.Name())
|
|
|
|
|
|
|
|
publickey_file, err := ioutil.TempFile("", "publickey")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(publickey_file.Name())
|
|
|
|
|
|
|
|
profile_file, err := ioutil.TempFile("", "test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(profile_file.Name())
|
|
|
|
|
|
|
|
config["ssh_host_key_file"] = hostkey_file.Name()
|
|
|
|
config["ssh_authorized_key_file"] = publickey_file.Name()
|
|
|
|
config["profile"] = profile_file.Name()
|
|
|
|
|
2019-03-19 09:47:21 -04:00
|
|
|
config["local_port"] = 65537
|
2019-01-20 10:43:47 -05:00
|
|
|
err = p.Prepare(config)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("should have error")
|
|
|
|
}
|
|
|
|
|
2019-03-19 09:47:21 -04:00
|
|
|
config["local_port"] = 22222
|
2019-01-20 10:43:47 -05:00
|
|
|
err = p.Prepare(config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInspecGetVersion(t *testing.T) {
|
2021-03-12 10:47:21 -05:00
|
|
|
var p Provisioner
|
|
|
|
if os.Getenv("PACKER_ACC") == "1" {
|
|
|
|
p.config.Command = "inspec"
|
|
|
|
} else {
|
|
|
|
p.config.Command = "./test-fixtures/inspec_version.sh"
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("This test is only run with PACKER_ACC=1 and it requires InSpec to be installed")
|
|
|
|
}
|
2019-01-20 10:43:47 -05:00
|
|
|
}
|
|
|
|
|
2021-03-12 10:47:21 -05:00
|
|
|
p.config.Backend = "local"
|
2019-01-20 10:43:47 -05:00
|
|
|
err := p.getVersion()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInspecGetVersionError(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
p.config.Command = "./test-fixtures/exit1"
|
|
|
|
err := p.getVersion()
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Should return error")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "./test-fixtures/exit1 version") {
|
|
|
|
t.Fatal("Error message should include command name")
|
|
|
|
}
|
|
|
|
}
|
2021-03-12 10:47:21 -05:00
|
|
|
|
|
|
|
func TestInspecValidExitCodes(t *testing.T) {
|
|
|
|
var p Provisioner
|
|
|
|
if os.Getenv("PACKER_ACC") == "1" {
|
|
|
|
p.config.Command = "inspec"
|
|
|
|
} else {
|
|
|
|
p.config.Command = "./test-fixtures/valid_exit_codes.sh"
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("This test is only run with PACKER_ACC=1 and it requires InSpec to be installed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.config.Backend = "local"
|
|
|
|
p.config.Profile = "test-fixtures/skip_control.rb"
|
|
|
|
err := p.Prepare()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
comm := &packersdk.MockCommunicator{}
|
|
|
|
ui := &packersdk.BasicUi{
|
|
|
|
Reader: new(bytes.Buffer),
|
|
|
|
Writer: new(bytes.Buffer),
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|