Add Windows support to Chef provisioners
- Add guest os type to change the default Chef-Solo and Chef-Client provisioner behavior. Paths, commands etc. - Change Chef installation download location to chef.io domain - Add encrypted data bag secret configuration
This commit is contained in:
parent
affebcda86
commit
8014dac742
|
@ -16,9 +16,29 @@ import (
|
||||||
"github.com/mitchellh/packer/common/uuid"
|
"github.com/mitchellh/packer/common/uuid"
|
||||||
"github.com/mitchellh/packer/helper/config"
|
"github.com/mitchellh/packer/helper/config"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"github.com/mitchellh/packer/provisioner"
|
||||||
"github.com/mitchellh/packer/template/interpolate"
|
"github.com/mitchellh/packer/template/interpolate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type guestOSTypeConfig struct {
|
||||||
|
executeCommand string
|
||||||
|
installCommand string
|
||||||
|
stagingDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
var guestOSTypeConfigs = map[string]guestOSTypeConfig{
|
||||||
|
provisioner.UnixOSType: guestOSTypeConfig{
|
||||||
|
executeCommand: "{{if .Sudo}}sudo {{end}}chef-client --no-color -c {{.ConfigPath}} -j {{.JsonPath}}",
|
||||||
|
installCommand: "curl -L https://www.chef.io/chef/install.sh | {{if .Sudo}}sudo {{end}}bash",
|
||||||
|
stagingDir: "/tmp/packer-chef-client",
|
||||||
|
},
|
||||||
|
provisioner.WindowsOSType: guestOSTypeConfig{
|
||||||
|
executeCommand: "c:/opscode/chef/bin/chef-client.bat --no-color -c {{.ConfigPath}} -j {{.JsonPath}}",
|
||||||
|
installCommand: "powershell.exe -Command \"(New-Object System.Net.WebClient).DownloadFile('http://chef.io/chef/install.msi', 'C:\\Windows\\Temp\\chef.msi');Start-Process 'msiexec' -ArgumentList '/qb /i C:\\Windows\\Temp\\chef.msi' -NoNewWindow -Wait\"",
|
||||||
|
stagingDir: "C:/Windows/Temp/packer-chef-client",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
common.PackerConfig `mapstructure:",squash"`
|
common.PackerConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
|
@ -39,12 +59,16 @@ type Config struct {
|
||||||
ClientKey string `mapstructure:"client_key"`
|
ClientKey string `mapstructure:"client_key"`
|
||||||
ValidationKeyPath string `mapstructure:"validation_key_path"`
|
ValidationKeyPath string `mapstructure:"validation_key_path"`
|
||||||
ValidationClientName string `mapstructure:"validation_client_name"`
|
ValidationClientName string `mapstructure:"validation_client_name"`
|
||||||
|
GuestOSType string `mapstructure:"guest_os_type"`
|
||||||
|
EncryptedDataBagSecretPath string `mapstructure:"encrypted_data_bag_secret_path"`
|
||||||
|
|
||||||
ctx interpolate.Context
|
ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
type Provisioner struct {
|
type Provisioner struct {
|
||||||
config Config
|
config Config
|
||||||
|
guestOSTypeConfig guestOSTypeConfig
|
||||||
|
guestCommands *provisioner.GuestCommands
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigTemplate struct {
|
type ConfigTemplate struct {
|
||||||
|
@ -55,6 +79,7 @@ type ConfigTemplate struct {
|
||||||
ValidationClientName string
|
ValidationClientName string
|
||||||
ChefEnvironment string
|
ChefEnvironment string
|
||||||
SslVerifyMode string
|
SslVerifyMode string
|
||||||
|
EncryptedDataBagSecretPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecuteTemplate struct {
|
type ExecuteTemplate struct {
|
||||||
|
@ -82,15 +107,28 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.GuestOSType == "" {
|
||||||
|
p.config.GuestOSType = provisioner.DefaultOSType
|
||||||
|
}
|
||||||
|
p.config.GuestOSType = strings.ToLower(p.config.GuestOSType)
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
p.guestOSTypeConfig, ok = guestOSTypeConfigs[p.config.GuestOSType]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Invalid guest_os_type: \"%s\"", p.config.GuestOSType)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.guestCommands, err = provisioner.NewGuestCommands(p.config.GuestOSType, !p.config.PreventSudo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Invalid guest_os_type: \"%s\"", p.config.GuestOSType)
|
||||||
|
}
|
||||||
|
|
||||||
if p.config.ExecuteCommand == "" {
|
if p.config.ExecuteCommand == "" {
|
||||||
p.config.ExecuteCommand = "{{if .Sudo}}sudo {{end}}chef-client " +
|
p.config.ExecuteCommand = p.guestOSTypeConfig.executeCommand
|
||||||
"--no-color -c {{.ConfigPath}} -j {{.JsonPath}}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.InstallCommand == "" {
|
if p.config.InstallCommand == "" {
|
||||||
p.config.InstallCommand = "curl -L " +
|
p.config.InstallCommand = p.guestOSTypeConfig.installCommand
|
||||||
"https://www.chef.io/chef/install.sh | " +
|
|
||||||
"{{if .Sudo}}sudo {{end}}bash"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.RunList == nil {
|
if p.config.RunList == nil {
|
||||||
|
@ -98,7 +136,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.StagingDir == "" {
|
if p.config.StagingDir == "" {
|
||||||
p.config.StagingDir = "/tmp/packer-chef-client"
|
p.config.StagingDir = p.guestOSTypeConfig.stagingDir
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs *packer.MultiError
|
var errs *packer.MultiError
|
||||||
|
@ -113,6 +151,15 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.EncryptedDataBagSecretPath != "" {
|
||||||
|
pFileInfo, err := os.Stat(p.config.EncryptedDataBagSecretPath)
|
||||||
|
|
||||||
|
if err != nil || pFileInfo.IsDir() {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, fmt.Errorf("Bad encrypted data bag secret '%s': %s", p.config.EncryptedDataBagSecretPath, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if p.config.ServerUrl == "" {
|
if p.config.ServerUrl == "" {
|
||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
errs, fmt.Errorf("server_url must be set"))
|
errs, fmt.Errorf("server_url must be set"))
|
||||||
|
@ -168,15 +215,23 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||||
p.config.ClientKey = fmt.Sprintf("%s/client.pem", p.config.StagingDir)
|
p.config.ClientKey = fmt.Sprintf("%s/client.pem", p.config.StagingDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encryptedDataBagSecretPath := ""
|
||||||
|
if p.config.EncryptedDataBagSecretPath != "" {
|
||||||
|
encryptedDataBagSecretPath = fmt.Sprintf("%s/encrypted_data_bag_secret", p.config.StagingDir)
|
||||||
|
if err := p.uploadFile(ui, comm, encryptedDataBagSecretPath, p.config.EncryptedDataBagSecretPath); err != nil {
|
||||||
|
return fmt.Errorf("Error uploading encrypted data bag secret: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if p.config.ValidationKeyPath != "" {
|
if p.config.ValidationKeyPath != "" {
|
||||||
remoteValidationKeyPath = fmt.Sprintf("%s/validation.pem", p.config.StagingDir)
|
remoteValidationKeyPath = fmt.Sprintf("%s/validation.pem", p.config.StagingDir)
|
||||||
if err := p.copyValidationKey(ui, comm, remoteValidationKeyPath); err != nil {
|
if err := p.uploadFile(ui, comm, remoteValidationKeyPath, p.config.ValidationKeyPath); err != nil {
|
||||||
return fmt.Errorf("Error copying validation key: %s", err)
|
return fmt.Errorf("Error copying validation key: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configPath, err := p.createConfig(
|
configPath, err := p.createConfig(
|
||||||
ui, comm, nodeName, serverUrl, p.config.ClientKey, remoteValidationKeyPath, p.config.ValidationClientName, p.config.ChefEnvironment, p.config.SslVerifyMode)
|
ui, comm, nodeName, serverUrl, p.config.ClientKey, encryptedDataBagSecretPath, remoteValidationKeyPath, p.config.ValidationClientName, p.config.ChefEnvironment, p.config.SslVerifyMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error creating Chef config file: %s", err)
|
return fmt.Errorf("Error creating Chef config file: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -210,7 +265,7 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.removeDir(ui, comm, p.config.StagingDir); err != nil {
|
if err := p.removeDir(ui, comm, p.config.StagingDir); err != nil {
|
||||||
return fmt.Errorf("Error removing /etc/chef directory: %s", err)
|
return fmt.Errorf("Error removing %s: %s", p.config.StagingDir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -236,7 +291,7 @@ func (p *Provisioner) uploadDirectory(ui packer.Ui, comm packer.Communicator, ds
|
||||||
return comm.UploadDir(dst, src, nil)
|
return comm.UploadDir(dst, src, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, nodeName string, serverUrl string, clientKey string, remoteKeyPath string, validationClientName string, chefEnvironment string, sslVerifyMode string) (string, error) {
|
func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, nodeName string, serverUrl string, clientKey string, encryptedDataBagSecretPath string, remoteKeyPath string, validationClientName string, chefEnvironment string, sslVerifyMode string) (string, error) {
|
||||||
ui.Message("Creating configuration file 'client.rb'")
|
ui.Message("Creating configuration file 'client.rb'")
|
||||||
|
|
||||||
// Read the template
|
// Read the template
|
||||||
|
@ -265,6 +320,7 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, nodeN
|
||||||
ValidationClientName: validationClientName,
|
ValidationClientName: validationClientName,
|
||||||
ChefEnvironment: chefEnvironment,
|
ChefEnvironment: chefEnvironment,
|
||||||
SslVerifyMode: sslVerifyMode,
|
SslVerifyMode: sslVerifyMode,
|
||||||
|
EncryptedDataBagSecretPath: encryptedDataBagSecretPath,
|
||||||
}
|
}
|
||||||
configString, err := interpolate.Render(tpl, &ctx)
|
configString, err := interpolate.Render(tpl, &ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -337,12 +393,7 @@ func (p *Provisioner) createJson(ui packer.Ui, comm packer.Communicator) (string
|
||||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
|
|
||||||
mkdirCmd := fmt.Sprintf("mkdir -p '%s'", dir)
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
||||||
if !p.config.PreventSudo {
|
|
||||||
mkdirCmd = "sudo " + mkdirCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: mkdirCmd}
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -351,11 +402,7 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod the directory to 0777 just so that we can access it as our user
|
// Chmod the directory to 0777 just so that we can access it as our user
|
||||||
mkdirCmd = fmt.Sprintf("chmod 0777 '%s'", dir)
|
cmd = &packer.RemoteCmd{Command: p.guestCommands.Chmod(dir, "0777")}
|
||||||
if !p.config.PreventSudo {
|
|
||||||
mkdirCmd = "sudo " + mkdirCmd
|
|
||||||
}
|
|
||||||
cmd = &packer.RemoteCmd{Command: mkdirCmd}
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -415,15 +462,7 @@ func (p *Provisioner) knifeExec(ui packer.Ui, comm packer.Communicator, node str
|
||||||
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
ui.Message(fmt.Sprintf("Removing directory: %s", dir))
|
||||||
|
|
||||||
rmCmd := fmt.Sprintf("rm -rf '%s'", dir)
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
|
||||||
if !p.config.PreventSudo {
|
|
||||||
rmCmd = "sudo " + rmCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{
|
|
||||||
Command: rmCmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -470,6 +509,8 @@ func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.Message(command)
|
||||||
|
|
||||||
cmd := &packer.RemoteCmd{Command: command}
|
cmd := &packer.RemoteCmd{Command: command}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -483,11 +524,10 @@ func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provisioner) copyValidationKey(ui packer.Ui, comm packer.Communicator, remotePath string) error {
|
func (p *Provisioner) uploadFile(ui packer.Ui, comm packer.Communicator, remotePath string, localPath string) error {
|
||||||
ui.Message("Uploading validation key...")
|
ui.Message(fmt.Sprintf("Uploading %s...", localPath))
|
||||||
|
|
||||||
// First upload the validation key to a writable location
|
f, err := os.Open(localPath)
|
||||||
f, err := os.Open(p.config.ValidationKeyPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -587,6 +627,9 @@ log_level :info
|
||||||
log_location STDOUT
|
log_location STDOUT
|
||||||
chef_server_url "{{.ServerUrl}}"
|
chef_server_url "{{.ServerUrl}}"
|
||||||
client_key "{{.ClientKey}}"
|
client_key "{{.ClientKey}}"
|
||||||
|
{{if ne .EncryptedDataBagSecretPath ""}}
|
||||||
|
encrypted_data_bag_secret "{{.EncryptedDataBagSecretPath}}"
|
||||||
|
{{end}}
|
||||||
{{if ne .ValidationClientName ""}}
|
{{if ne .ValidationClientName ""}}
|
||||||
validation_client_name "{{.ValidationClientName}}"
|
validation_client_name "{{.ValidationClientName}}"
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -139,53 +139,63 @@ func TestProvisionerPrepare_serverUrl(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvisioner_createDir(t *testing.T) {
|
func TestProvisioner_createDir(t *testing.T) {
|
||||||
p1 := &Provisioner{config: Config{PreventSudo: true}}
|
for _, sudo := range []bool{true, false} {
|
||||||
p2 := &Provisioner{config: Config{PreventSudo: false}}
|
config := testConfig()
|
||||||
comm := &packer.MockCommunicator{}
|
config["prevent_sudo"] = !sudo
|
||||||
ui := &packer.BasicUi{
|
|
||||||
Reader: new(bytes.Buffer),
|
|
||||||
Writer: new(bytes.Buffer),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := p1.createDir(ui, comm, "/tmp/foo"); err != nil {
|
p := &Provisioner{}
|
||||||
t.Fatalf("err: %s", err)
|
comm := &packer.MockCommunicator{}
|
||||||
}
|
ui := &packer.BasicUi{
|
||||||
|
Reader: new(bytes.Buffer),
|
||||||
|
Writer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
err := p.Prepare(config)
|
||||||
t.Fatalf("createDir should not use sudo, got: \"%s\"", comm.StartCmd.Command)
|
if err != nil {
|
||||||
}
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := p2.createDir(ui, comm, "/tmp/foo"); err != nil {
|
if err := p.createDir(ui, comm, "/tmp/foo"); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
if !sudo && strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
||||||
t.Fatalf("createDir should use sudo, got: \"%s\"", comm.StartCmd.Command)
|
t.Fatalf("createDir should not use sudo, got: \"%s\"", comm.StartCmd.Command)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sudo && !strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
||||||
|
t.Fatalf("createDir should use sudo, got: \"%s\"", comm.StartCmd.Command)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvisioner_removeDir(t *testing.T) {
|
func TestProvisioner_removeDir(t *testing.T) {
|
||||||
p1 := &Provisioner{config: Config{PreventSudo: true}}
|
for _, sudo := range []bool{true, false} {
|
||||||
p2 := &Provisioner{config: Config{PreventSudo: false}}
|
config := testConfig()
|
||||||
comm := &packer.MockCommunicator{}
|
config["prevent_sudo"] = !sudo
|
||||||
ui := &packer.BasicUi{
|
|
||||||
Reader: new(bytes.Buffer),
|
p := &Provisioner{}
|
||||||
Writer: new(bytes.Buffer),
|
comm := &packer.MockCommunicator{}
|
||||||
}
|
ui := &packer.BasicUi{
|
||||||
|
Reader: new(bytes.Buffer),
|
||||||
|
Writer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
if err := p1.removeDir(ui, comm, "/tmp/foo"); err != nil {
|
err := p.Prepare(config)
|
||||||
t.Fatalf("err: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
if err := p.removeDir(ui, comm, "/tmp/foo"); err != nil {
|
||||||
t.Fatalf("removeDir should not use sudo, got: \"%s\"", comm.StartCmd.Command)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p2.removeDir(ui, comm, "/tmp/foo"); err != nil {
|
if !sudo && strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("removeDir should not use sudo, got: \"%s\"", comm.StartCmd.Command)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
if sudo && !strings.HasPrefix(comm.StartCmd.Command, "sudo") {
|
||||||
t.Fatalf("removeDir should use sudo, got: \"%s\"", comm.StartCmd.Command)
|
t.Fatalf("removeDir should use sudo, got: \"%s\"", comm.StartCmd.Command)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,29 @@ import (
|
||||||
"github.com/mitchellh/packer/common"
|
"github.com/mitchellh/packer/common"
|
||||||
"github.com/mitchellh/packer/helper/config"
|
"github.com/mitchellh/packer/helper/config"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"github.com/mitchellh/packer/provisioner"
|
||||||
"github.com/mitchellh/packer/template/interpolate"
|
"github.com/mitchellh/packer/template/interpolate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type guestOSTypeConfig struct {
|
||||||
|
executeCommand string
|
||||||
|
installCommand string
|
||||||
|
stagingDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
var guestOSTypeConfigs = map[string]guestOSTypeConfig{
|
||||||
|
provisioner.UnixOSType: guestOSTypeConfig{
|
||||||
|
executeCommand: "{{if .Sudo}}sudo {{end}}chef-solo --no-color -c {{.ConfigPath}} -j {{.JsonPath}}",
|
||||||
|
installCommand: "curl -L https://www.chef.io/chef/install.sh | {{if .Sudo}}sudo {{end}}bash",
|
||||||
|
stagingDir: "/tmp/packer-chef-client",
|
||||||
|
},
|
||||||
|
provisioner.WindowsOSType: guestOSTypeConfig{
|
||||||
|
executeCommand: "c:/opscode/chef/bin/chef-solo.bat --no-color -c {{.ConfigPath}} -j {{.JsonPath}}",
|
||||||
|
installCommand: "powershell.exe -Command \"(New-Object System.Net.WebClient).DownloadFile('http://chef.io/chef/install.msi', 'C:\\Windows\\Temp\\chef.msi');Start-Process 'msiexec' -ArgumentList '/qb /i C:\\Windows\\Temp\\chef.msi' -NoNewWindow -Wait\"",
|
||||||
|
stagingDir: "C:/Windows/Temp/packer-chef-client",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
common.PackerConfig `mapstructure:",squash"`
|
common.PackerConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
|
@ -36,12 +56,15 @@ type Config struct {
|
||||||
RunList []string `mapstructure:"run_list"`
|
RunList []string `mapstructure:"run_list"`
|
||||||
SkipInstall bool `mapstructure:"skip_install"`
|
SkipInstall bool `mapstructure:"skip_install"`
|
||||||
StagingDir string `mapstructure:"staging_directory"`
|
StagingDir string `mapstructure:"staging_directory"`
|
||||||
|
GuestOSType string `mapstructure:"guest_os_type"`
|
||||||
|
|
||||||
ctx interpolate.Context
|
ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
type Provisioner struct {
|
type Provisioner struct {
|
||||||
config Config
|
config Config
|
||||||
|
guestOSTypeConfig guestOSTypeConfig
|
||||||
|
guestCommands *provisioner.GuestCommands
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigTemplate struct {
|
type ConfigTemplate struct {
|
||||||
|
@ -86,12 +109,28 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.GuestOSType == "" {
|
||||||
|
p.config.GuestOSType = provisioner.DefaultOSType
|
||||||
|
}
|
||||||
|
p.config.GuestOSType = strings.ToLower(p.config.GuestOSType)
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
p.guestOSTypeConfig, ok = guestOSTypeConfigs[p.config.GuestOSType]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Invalid guest_os_type: \"%s\"", p.config.GuestOSType)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.guestCommands, err = provisioner.NewGuestCommands(p.config.GuestOSType, !p.config.PreventSudo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Invalid guest_os_type: \"%s\"", p.config.GuestOSType)
|
||||||
|
}
|
||||||
|
|
||||||
if p.config.ExecuteCommand == "" {
|
if p.config.ExecuteCommand == "" {
|
||||||
p.config.ExecuteCommand = "{{if .Sudo}}sudo {{end}}chef-solo --no-color -c {{.ConfigPath}} -j {{.JsonPath}}"
|
p.config.ExecuteCommand = p.guestOSTypeConfig.executeCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.InstallCommand == "" {
|
if p.config.InstallCommand == "" {
|
||||||
p.config.InstallCommand = "curl -L https://www.chef.io/chef/install.sh | {{if .Sudo}}sudo {{end}}bash"
|
p.config.InstallCommand = p.guestOSTypeConfig.installCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.RunList == nil {
|
if p.config.RunList == nil {
|
||||||
|
@ -99,7 +138,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.StagingDir == "" {
|
if p.config.StagingDir == "" {
|
||||||
p.config.StagingDir = "/tmp/packer-chef-solo"
|
p.config.StagingDir = p.guestOSTypeConfig.stagingDir
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs *packer.MultiError
|
var errs *packer.MultiError
|
||||||
|
@ -374,16 +413,13 @@ func (p *Provisioner) createJson(ui packer.Ui, comm packer.Communicator) (string
|
||||||
|
|
||||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||||
cmd := &packer.RemoteCmd{
|
|
||||||
Command: fmt.Sprintf("mkdir -p '%s'", dir),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cmd := &packer.RemoteCmd{Command: p.guestCommands.CreateDir(dir)}
|
||||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.ExitStatus != 0 {
|
if cmd.ExitStatus != 0 {
|
||||||
return fmt.Errorf("Non-zero exit status.")
|
return fmt.Errorf("Non-zero exit status. See output above for more info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in New Issue