Merge pull request #10956 from hashicorp/extract-converge
Extract converge provisioner
This commit is contained in:
commit
d0a15f9a15
|
@ -39,7 +39,6 @@ import (
|
|||
yandeximportpostprocessor "github.com/hashicorp/packer/post-processor/yandex-import"
|
||||
azuredtlartifactprovisioner "github.com/hashicorp/packer/provisioner/azure-dtlartifact"
|
||||
breakpointprovisioner "github.com/hashicorp/packer/provisioner/breakpoint"
|
||||
convergeprovisioner "github.com/hashicorp/packer/provisioner/converge"
|
||||
fileprovisioner "github.com/hashicorp/packer/provisioner/file"
|
||||
inspecprovisioner "github.com/hashicorp/packer/provisioner/inspec"
|
||||
powershellprovisioner "github.com/hashicorp/packer/provisioner/powershell"
|
||||
|
@ -77,7 +76,6 @@ var Builders = map[string]packersdk.Builder{
|
|||
var Provisioners = map[string]packersdk.Provisioner{
|
||||
"azure-dtlartifact": new(azuredtlartifactprovisioner.Provisioner),
|
||||
"breakpoint": new(breakpointprovisioner.Provisioner),
|
||||
"converge": new(convergeprovisioner.Provisioner),
|
||||
"file": new(fileprovisioner.Provisioner),
|
||||
"inspec": new(inspecprovisioner.Provisioner),
|
||||
"powershell": new(powershellprovisioner.Provisioner),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
convergeprovisioner "github.com/hashicorp/packer-plugin-converge/provisioner/converge"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
|
||||
// Previously core-bundled components, split into their own plugins but
|
||||
|
@ -120,6 +121,7 @@ var VendoredProvisioners = map[string]packersdk.Provisioner{
|
|||
"ansible-local": new(ansiblelocalprovisioner.Provisioner),
|
||||
"chef-client": new(chefclientprovisioner.Provisioner),
|
||||
"chef-solo": new(chefsoloprovisioner.Provisioner),
|
||||
"converge": new(convergeprovisioner.Provisioner),
|
||||
"puppet-masterless": new(puppetmasterlessprovisioner.Provisioner),
|
||||
"puppet-server": new(puppetserverprovisioner.Provisioner),
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -42,6 +42,7 @@ require (
|
|||
github.com/hashicorp/packer-plugin-ansible v0.0.2
|
||||
github.com/hashicorp/packer-plugin-chef v0.0.1
|
||||
github.com/hashicorp/packer-plugin-cloudstack v0.0.1
|
||||
github.com/hashicorp/packer-plugin-converge v0.0.1
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.7
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1
|
||||
github.com/hashicorp/packer-plugin-hyperone v0.0.1
|
||||
|
|
2
go.sum
2
go.sum
|
@ -499,6 +499,8 @@ github.com/hashicorp/packer-plugin-chef v0.0.1 h1:1zQwnnvftwg9PJyWjMfHfDyzfWDdb0
|
|||
github.com/hashicorp/packer-plugin-chef v0.0.1/go.mod h1:4iSyWfvrb4QwUDZqJ3iCb+kIsnDwOTL1yTEDXBtk3Ew=
|
||||
github.com/hashicorp/packer-plugin-cloudstack v0.0.1 h1:BF9nXRlA0xQV5W/+CoLjWn0aLO60gTbsxnLi/o37ktc=
|
||||
github.com/hashicorp/packer-plugin-cloudstack v0.0.1/go.mod h1:fx13TY2szz6cm2e99xzU3gQzKdGVwysxY2TyKr0r8MQ=
|
||||
github.com/hashicorp/packer-plugin-converge v0.0.1 h1:cjrNt2Q/BuSH2o2bpNV91DhWYSTN7vb4LwxwFXULcok=
|
||||
github.com/hashicorp/packer-plugin-converge v0.0.1/go.mod h1:3Rm0fAiVwFriSRrwt3dsuKInYYzuOa6tqPFGMOW7noI=
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.7 h1:hMTrH7vrkFIjphtbbtpuzffTzSjMNgxayo2DPLz9y+c=
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.7/go.mod h1:IpeKlwOSy2kdgQcysqd3gCsoqjME9jtmpFoKxn7RRNI=
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1 h1:Shjio88MraB+ocj0VI5+M65r4UBKbYI4eCqLNyPXKEo=
|
||||
|
|
|
@ -1,241 +0,0 @@
|
|||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,ModuleDir
|
||||
|
||||
// This package implements a provisioner for Packer that executes
|
||||
// Converge to provision a remote machine
|
||||
|
||||
package converge
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
)
|
||||
|
||||
// Config for Converge provisioner
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
|
||||
// Bootstrapping
|
||||
Bootstrap bool `mapstructure:"bootstrap"`
|
||||
Version string `mapstructure:"version"`
|
||||
BootstrapCommand string `mapstructure:"bootstrap_command"`
|
||||
PreventBootstrapSudo bool `mapstructure:"prevent_bootstrap_sudo"`
|
||||
|
||||
// Modules
|
||||
ModuleDirs []ModuleDir `mapstructure:"module_dirs"`
|
||||
|
||||
// Execution
|
||||
Module string `mapstructure:"module"`
|
||||
WorkingDirectory string `mapstructure:"working_directory"`
|
||||
Params map[string]string `mapstructure:"params"`
|
||||
ExecuteCommand string `mapstructure:"execute_command"`
|
||||
PreventSudo bool `mapstructure:"prevent_sudo"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
// ModuleDir is a directory to transfer to the remote system
|
||||
type ModuleDir struct {
|
||||
Source string `mapstructure:"source"`
|
||||
Destination string `mapstructure:"destination"`
|
||||
Exclude []string `mapstructure:"exclude"`
|
||||
}
|
||||
|
||||
// Provisioner for Converge
|
||||
type Provisioner struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func (p *Provisioner) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() }
|
||||
|
||||
func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
err := config.Decode(
|
||||
&p.config,
|
||||
&config.DecodeOpts{
|
||||
PluginType: "converge",
|
||||
Interpolate: true,
|
||||
InterpolateContext: &p.config.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"execute_command",
|
||||
"bootstrap_command",
|
||||
},
|
||||
},
|
||||
},
|
||||
raws...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// require a single module
|
||||
if p.config.Module == "" {
|
||||
return errors.New("Converge requires a module to provision the system")
|
||||
}
|
||||
|
||||
// set defaults
|
||||
if p.config.WorkingDirectory == "" {
|
||||
p.config.WorkingDirectory = "/tmp"
|
||||
}
|
||||
|
||||
if p.config.ExecuteCommand == "" {
|
||||
p.config.ExecuteCommand = "cd {{.WorkingDirectory}} && {{if .Sudo}}sudo {{end}}converge apply --local --log-level=WARNING --paramsJSON '{{.ParamsJSON}}' {{.Module}}"
|
||||
}
|
||||
|
||||
if p.config.BootstrapCommand == "" {
|
||||
p.config.BootstrapCommand = "curl -s https://get.converge.sh | {{if .Sudo}}sudo {{end}}sh {{if ne .Version \"\"}}-s -- -v {{.Version}}{{end}}"
|
||||
}
|
||||
|
||||
// validate sources and destinations
|
||||
for i, dir := range p.config.ModuleDirs {
|
||||
if dir.Source == "" {
|
||||
return fmt.Errorf("Source (\"source\" key) is required in Converge module dir #%d", i)
|
||||
}
|
||||
if dir.Destination == "" {
|
||||
return fmt.Errorf("Destination (\"destination\" key) is required in Converge module dir #%d", i)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Provision node somehow. TODO: actual docs
|
||||
func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packersdk.Communicator, _ map[string]interface{}) error {
|
||||
ui.Say("Provisioning with Converge")
|
||||
|
||||
// bootstrapping
|
||||
if err := p.maybeBootstrap(ui, comm); err != nil {
|
||||
return err // error messages are already user-friendly
|
||||
}
|
||||
|
||||
// send module directories to the remote host
|
||||
if err := p.sendModuleDirectories(ui, comm); err != nil {
|
||||
return err // error messages are already user-friendly
|
||||
}
|
||||
|
||||
// apply all the modules
|
||||
if err := p.applyModules(ui, comm); err != nil {
|
||||
return err // error messages are already user-friendly
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) maybeBootstrap(ui packersdk.Ui, comm packersdk.Communicator) error {
|
||||
ctx := context.TODO()
|
||||
if !p.config.Bootstrap {
|
||||
return nil
|
||||
}
|
||||
ui.Message("bootstrapping converge")
|
||||
|
||||
p.config.ctx.Data = struct {
|
||||
Version string
|
||||
Sudo bool
|
||||
}{
|
||||
Version: p.config.Version,
|
||||
Sudo: !p.config.PreventBootstrapSudo,
|
||||
}
|
||||
command, err := interpolate.Render(p.config.BootstrapCommand, &p.config.ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not interpolate bootstrap command: %s", err)
|
||||
}
|
||||
|
||||
var out, outErr bytes.Buffer
|
||||
cmd := &packersdk.RemoteCmd{
|
||||
Command: command,
|
||||
Stdin: nil,
|
||||
Stdout: &out,
|
||||
Stderr: &outErr,
|
||||
}
|
||||
|
||||
if err = comm.Start(ctx, cmd); err != nil {
|
||||
return fmt.Errorf("Error bootstrapping converge: %s", err)
|
||||
}
|
||||
|
||||
cmd.Wait()
|
||||
if cmd.ExitStatus() != 0 {
|
||||
ui.Error(out.String())
|
||||
ui.Error(outErr.String())
|
||||
return errors.New("Error bootstrapping converge")
|
||||
}
|
||||
|
||||
ui.Message(strings.TrimSpace(out.String()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) sendModuleDirectories(ui packersdk.Ui, comm packersdk.Communicator) error {
|
||||
for _, dir := range p.config.ModuleDirs {
|
||||
if err := comm.UploadDir(dir.Destination, dir.Source, dir.Exclude); err != nil {
|
||||
return fmt.Errorf("Could not upload %q: %s", dir.Source, err)
|
||||
}
|
||||
ui.Message(fmt.Sprintf("transferred %q to %q", dir.Source, dir.Destination))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) applyModules(ui packersdk.Ui, comm packersdk.Communicator) error {
|
||||
ctx := context.TODO()
|
||||
// create params JSON file
|
||||
params, err := json.Marshal(p.config.Params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not marshal parameters as JSON: %s", err)
|
||||
}
|
||||
|
||||
p.config.ctx.Data = struct {
|
||||
ParamsJSON, WorkingDirectory, Module string
|
||||
Sudo bool
|
||||
}{
|
||||
ParamsJSON: string(params),
|
||||
WorkingDirectory: p.config.WorkingDirectory,
|
||||
Module: p.config.Module,
|
||||
Sudo: !p.config.PreventSudo,
|
||||
}
|
||||
command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not interpolate execute command: %s", err)
|
||||
}
|
||||
|
||||
// run Converge in the specified directory
|
||||
var runOut, runErr bytes.Buffer
|
||||
cmd := &packersdk.RemoteCmd{
|
||||
Command: command,
|
||||
Stdin: nil,
|
||||
Stdout: &runOut,
|
||||
Stderr: &runErr,
|
||||
}
|
||||
if err := comm.Start(ctx, cmd); err != nil {
|
||||
return fmt.Errorf("Error applying %q: %s", p.config.Module, err)
|
||||
}
|
||||
|
||||
cmd.Wait()
|
||||
if cmd.ExitStatus() == 127 {
|
||||
ui.Error("Could not find Converge. Is it installed and in PATH?")
|
||||
if !p.config.Bootstrap {
|
||||
ui.Error("Bootstrapping was disabled for this run. That might be why Converge isn't present.")
|
||||
}
|
||||
|
||||
return errors.New("Could not find Converge")
|
||||
|
||||
} else if cmd.ExitStatus() != 0 {
|
||||
ui.Error(strings.TrimSpace(runOut.String()))
|
||||
ui.Error(strings.TrimSpace(runErr.String()))
|
||||
ui.Error(fmt.Sprintf("Exited with error code %d.", cmd.ExitStatus()))
|
||||
return fmt.Errorf("Error applying %q", p.config.Module)
|
||||
}
|
||||
|
||||
ui.Message(strings.TrimSpace(runOut.String()))
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package converge
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatConfig is an auto-generated flat version of Config.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatConfig struct {
|
||||
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
|
||||
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
|
||||
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
|
||||
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
|
||||
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
|
||||
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
|
||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||
Bootstrap *bool `mapstructure:"bootstrap" cty:"bootstrap" hcl:"bootstrap"`
|
||||
Version *string `mapstructure:"version" cty:"version" hcl:"version"`
|
||||
BootstrapCommand *string `mapstructure:"bootstrap_command" cty:"bootstrap_command" hcl:"bootstrap_command"`
|
||||
PreventBootstrapSudo *bool `mapstructure:"prevent_bootstrap_sudo" cty:"prevent_bootstrap_sudo" hcl:"prevent_bootstrap_sudo"`
|
||||
ModuleDirs []FlatModuleDir `mapstructure:"module_dirs" cty:"module_dirs" hcl:"module_dirs"`
|
||||
Module *string `mapstructure:"module" cty:"module" hcl:"module"`
|
||||
WorkingDirectory *string `mapstructure:"working_directory" cty:"working_directory" hcl:"working_directory"`
|
||||
Params map[string]string `mapstructure:"params" cty:"params" hcl:"params"`
|
||||
ExecuteCommand *string `mapstructure:"execute_command" cty:"execute_command" hcl:"execute_command"`
|
||||
PreventSudo *bool `mapstructure:"prevent_sudo" cty:"prevent_sudo" hcl:"prevent_sudo"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
// FlatConfig is an auto-generated flat version of Config.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a Config.
|
||||
// This spec is used by HCL to read the fields of Config.
|
||||
// The decoded values from this spec will then be applied to a FlatConfig.
|
||||
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
|
||||
"packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false},
|
||||
"packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false},
|
||||
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
|
||||
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
|
||||
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
|
||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||
"bootstrap": &hcldec.AttrSpec{Name: "bootstrap", Type: cty.Bool, Required: false},
|
||||
"version": &hcldec.AttrSpec{Name: "version", Type: cty.String, Required: false},
|
||||
"bootstrap_command": &hcldec.AttrSpec{Name: "bootstrap_command", Type: cty.String, Required: false},
|
||||
"prevent_bootstrap_sudo": &hcldec.AttrSpec{Name: "prevent_bootstrap_sudo", Type: cty.Bool, Required: false},
|
||||
"module_dirs": &hcldec.BlockListSpec{TypeName: "module_dirs", Nested: hcldec.ObjectSpec((*FlatModuleDir)(nil).HCL2Spec())},
|
||||
"module": &hcldec.AttrSpec{Name: "module", Type: cty.String, Required: false},
|
||||
"working_directory": &hcldec.AttrSpec{Name: "working_directory", Type: cty.String, Required: false},
|
||||
"params": &hcldec.AttrSpec{Name: "params", Type: cty.Map(cty.String), Required: false},
|
||||
"execute_command": &hcldec.AttrSpec{Name: "execute_command", Type: cty.String, Required: false},
|
||||
"prevent_sudo": &hcldec.AttrSpec{Name: "prevent_sudo", Type: cty.Bool, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatModuleDir is an auto-generated flat version of ModuleDir.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatModuleDir struct {
|
||||
Source *string `mapstructure:"source" cty:"source" hcl:"source"`
|
||||
Destination *string `mapstructure:"destination" cty:"destination" hcl:"destination"`
|
||||
Exclude []string `mapstructure:"exclude" cty:"exclude" hcl:"exclude"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatModuleDir.
|
||||
// FlatModuleDir is an auto-generated flat version of ModuleDir.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*ModuleDir) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatModuleDir)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a ModuleDir.
|
||||
// This spec is used by HCL to read the fields of ModuleDir.
|
||||
// The decoded values from this spec will then be applied to a FlatModuleDir.
|
||||
func (*FlatModuleDir) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"source": &hcldec.AttrSpec{Name: "source", Type: cty.String, Required: false},
|
||||
"destination": &hcldec.AttrSpec{Name: "destination", Type: cty.String, Required: false},
|
||||
"exclude": &hcldec.AttrSpec{Name: "exclude", Type: cty.List(cty.String), Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
package converge
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"module_dirs": []map[string]interface{}{
|
||||
{
|
||||
"source": "from",
|
||||
"destination": "/opt/converge",
|
||||
},
|
||||
},
|
||||
"module": "/opt/converge/test.hcl",
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisioner_Impl(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Provisioner{}
|
||||
if _, ok := raw.(packersdk.Provisioner); !ok {
|
||||
t.Fatal("must be a Provisioner")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisionerPrepare(t *testing.T) {
|
||||
t.Run("defaults", func(t *testing.T) {
|
||||
t.Run("working_directory", func(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "working_directory")
|
||||
|
||||
if err := p.Prepare(config); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if p.config.WorkingDirectory != "/tmp" {
|
||||
t.Fatalf("unexpected module directory: %s", p.config.WorkingDirectory)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("execute_command", func(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "execute_command")
|
||||
|
||||
if err := p.Prepare(config); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if p.config.ExecuteCommand == "" {
|
||||
t.Fatal("execute command unexpectedly blank")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bootstrap_command", func(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "bootstrap_command")
|
||||
|
||||
if err := p.Prepare(config); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if p.config.BootstrapCommand == "" {
|
||||
t.Fatal("bootstrap command unexpectedly blank")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("validate", func(t *testing.T) {
|
||||
t.Run("module dir", func(t *testing.T) {
|
||||
t.Run("missing source", func(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
delete(config["module_dirs"].([]map[string]interface{})[0], "source")
|
||||
|
||||
err := p.Prepare(config)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
} else if err.Error() != "Source (\"source\" key) is required in Converge module dir #0" {
|
||||
t.Errorf("bad error message: %s", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missing destination", func(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
delete(config["module_dirs"].([]map[string]interface{})[0], "destination")
|
||||
|
||||
err := p.Prepare(config)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
} else if err.Error() != "Destination (\"destination\" key) is required in Converge module dir #0" {
|
||||
t.Errorf("bad error message: %s", err)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("no module specified", func(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
delete(config, "module")
|
||||
|
||||
err := p.Prepare(config)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
} else if err.Error() != "Converge requires a module to provision the system" {
|
||||
t.Errorf("bad error message: %s", err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var ConvergePluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
ConvergePluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
---
|
||||
description: >-
|
||||
The converge Packer provisioner uses Converge modules to provision the
|
||||
machine.
|
||||
page_title: Converge - Provisioners
|
||||
---
|
||||
|
||||
# Converge Provisioner
|
||||
|
||||
@include 'provisioners/unmaintained-plugin.mdx'
|
||||
|
||||
Type: `converge`
|
||||
|
||||
The [Converge](http://converge.aster.is) Packer provisioner uses Converge
|
||||
modules to provision the machine. It uploads module directories to use as
|
||||
source, or you can use remote modules.
|
||||
|
||||
The provisioner can optionally bootstrap the Converge client/server binary onto
|
||||
new images.
|
||||
|
||||
## Basic Example
|
||||
|
||||
The example below is fully functional.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "converge",
|
||||
"module": "https://raw.githubusercontent.com/asteris-llc/converge/master/samples/fileContent.hcl",
|
||||
"params": {
|
||||
"message": "Hello, Packer!"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
The reference of available configuration options is listed below. The only
|
||||
required element is "module". Every other option is optional.
|
||||
|
||||
- `module` (string) - Path (or URL) to the root module that Converge will
|
||||
apply.
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- `bootstrap` (boolean, defaults to false) - Set to allow the provisioner to
|
||||
download the latest Converge bootstrap script and the specified `version`
|
||||
of Converge from the internet.
|
||||
|
||||
- `version` (string) - Set to a [released Converge
|
||||
version](https://github.com/asteris-llc/converge/releases) for bootstrap.
|
||||
|
||||
- `module_dirs` (array of directory specifications) - Module directories to
|
||||
transfer to the remote host for execution. See below for the specification.
|
||||
|
||||
- `working_directory` (string) - The directory that Converge will change to
|
||||
before execution.
|
||||
|
||||
- `params` (maps of string to string) - parameters to pass into the root
|
||||
module.
|
||||
|
||||
- `execute_command` (string) - the command used to execute Converge. This is a
|
||||
[configuration template variables](/docs/templates/legacy_json_templates/engine).
|
||||
See below for detailed usage instructions.
|
||||
|
||||
- `prevent_sudo` (boolean) - stop Converge from running with administrator
|
||||
privileges via sudo
|
||||
|
||||
- `bootstrap_command` (string) - the command used to bootstrap Converge. This
|
||||
is a [template engine](/docs/templates/legacy_json_templates/engine). Therefore, you may use
|
||||
user variables and template functions in this field. The following extra
|
||||
variables are also avilable in this engine:
|
||||
|
||||
- `Version`: The version of Converge to use.
|
||||
- `Sudo`: Boolean; intended to say whether to use sudo or not.
|
||||
|
||||
By default, this is `"curl -s https://get.converge.sh | {{if .Sudo}}sudo {{end}}sh {{if ne .Version \"\"}}-s -- -v {{.Version}}{{end}}"`
|
||||
|
||||
- `prevent_bootstrap_sudo` (boolean) - stop Converge from bootstrapping with
|
||||
administrator privileges via sudo
|
||||
|
||||
@include 'provisioners/common-config.mdx'
|
||||
|
||||
### Module Directories
|
||||
|
||||
The provisioner can transfer module directories to the remote host for
|
||||
provisioning. Of these fields, `source` and `destination` are required in every
|
||||
directory.
|
||||
|
||||
- `source` (string) - the path to the folder on the local machine.
|
||||
|
||||
- `destination` (string) - the path to the folder on the remote machine.
|
||||
Parent directories will not be created; use the shell module to do this.
|
||||
|
||||
- `exclude` (array of string) - files and directories to exclude from
|
||||
transfer.
|
||||
|
||||
### Execute Command
|
||||
|
||||
By default, Packer uses the following command (broken across multiple lines for
|
||||
readability) to execute Converge:
|
||||
|
||||
```liquid
|
||||
cd {{.WorkingDirectory}} && \
|
||||
{{if .Sudo}}sudo {{end}}converge apply \
|
||||
--local \
|
||||
--log-level=WARNING \
|
||||
--paramsJSON '{{.ParamsJSON}}' \
|
||||
{{.Module}}
|
||||
```
|
||||
|
||||
This command can be customized using the `execute_command` configuration. As
|
||||
you can see from the default value above, the value of this configuration can
|
||||
contain various template variables:
|
||||
|
||||
- `WorkingDirectory` - `directory` from the configuration.
|
||||
- `Sudo` - the opposite of `prevent_sudo` from the configuration.
|
||||
- `ParamsJSON` - The unquoted JSONified form of `params` from the
|
||||
configuration.
|
||||
- `Module` - `module` from the configuration.
|
||||
|
||||
### Bootstrap Command
|
||||
|
||||
By default, Packer uses the following command to bootstrap Converge:
|
||||
|
||||
```liquid
|
||||
curl -s https://get.converge.sh | {{if .Sudo}}sudo {{end}}sh {{if ne .Version ""}}-s -- -v {{.Version}}{{end}}
|
||||
```
|
||||
|
||||
This command can be customized using the `bootstrap_command` configuration. As
|
||||
you can see from the default values above, the value of this configuration can
|
||||
contain various template variables:
|
||||
|
||||
- `Sudo` - the opposite of `prevent_bootstrap_sudo` from the configuration.
|
||||
- `Version` - `version` from the configuration.
|
|
@ -787,10 +787,6 @@
|
|||
"title": "Breakpoint",
|
||||
"path": "provisioners/breakpoint"
|
||||
},
|
||||
{
|
||||
"title": "Converge",
|
||||
"path": "provisioners/converge"
|
||||
},
|
||||
{
|
||||
"title": "File",
|
||||
"path": "provisioners/file"
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
"title": "Chef",
|
||||
"path": "chef",
|
||||
"repo": "hashicorp/packer-plugin-chef",
|
||||
"version": "latest",
|
||||
"pluginTier": "community",
|
||||
"version": "latest"
|
||||
},
|
||||
|
@ -33,6 +32,13 @@
|
|||
"pluginTier": "community",
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
"title": "Converge",
|
||||
"path": "converge",
|
||||
"repo": "hashicorp/packer-plugin-converge",
|
||||
"pluginTier": "community",
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
"title": "Docker",
|
||||
"path": "docker",
|
||||
|
|
Loading…
Reference in New Issue