Commit 4a5a8c60 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

provisioner/chef-solo: installChef fixed up to use tpl and StartWithUi

parent c0d02b15
// This package implements a provisioner for Packer that executes // This package implements a provisioner for Packer that uses
// shell scripts within the remote machine. // Chef to provision the remote machine, specifically with chef-solo (that is,
package chefSolo // without a Chef server).
package chefsolo
import ( import (
"bufio" "bufio"
...@@ -8,7 +9,7 @@ import ( ...@@ -8,7 +9,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/mitchellh/iochan" "github.com/mitchellh/iochan"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"io" "io"
"io/ioutil" "io/ioutil"
...@@ -28,26 +29,21 @@ const ( ...@@ -28,26 +29,21 @@ const (
var Ui packer.Ui var Ui packer.Ui
type config struct { type Config struct {
// An array of local paths of cookbooks to upload. common.PackerConfig `mapstructure:",squash"`
CookbooksPaths []string `mapstructure:"cookbooks_paths"`
// An array of recipes to run.
Recipes []string
// A string of JSON that will be used as the JSON attributes for the
// Chef run.
Json map[string]interface{}
// Option to avoid sudo use when executing commands. Defaults to false. CookbooksPaths []string `mapstructure:"cookbooks_paths"`
PreventSudo bool `mapstructure:"prevent_sudo"` InstallCommand string `mapstructure:"install_command"`
Recipes []string
Json map[string]interface{}
PreventSudo bool `mapstructure:"prevent_sudo"`
SkipInstall bool `mapstructure:"skip_install"`
// If true, skips installing Chef. Defaults to false. tpl *packer.ConfigTemplate
SkipInstall bool `mapstructure:"skip_install"`
} }
type Provisioner struct { type Provisioner struct {
config config config Config
} }
type ExecuteRecipeTemplate struct { type ExecuteRecipeTemplate struct {
...@@ -56,29 +52,41 @@ type ExecuteRecipeTemplate struct { ...@@ -56,29 +52,41 @@ type ExecuteRecipeTemplate struct {
Sudo bool Sudo bool
} }
type ExecuteInstallChefTemplate struct { type InstallChefTemplate struct {
PreventSudo bool Sudo bool
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
errs := make([]error, 0) md, err := common.DecodeConfig(&p.config, raws...)
for _, raw := range raws { if err != nil {
if err := mapstructure.Decode(raw, &p.config); err != nil { return err
return err
}
} }
p.config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return err
}
p.config.tpl.UserVars = p.config.PackerUserVars
// Accumulate any errors
errs := common.CheckUnusedConfig(md)
if p.config.CookbooksPaths == nil { if p.config.CookbooksPaths == nil {
p.config.CookbooksPaths = []string{DefaultCookbooksPath} p.config.CookbooksPaths = []string{DefaultCookbooksPath}
} }
if p.config.InstallCommand == "" {
p.config.InstallCommand = "curl -L https://www.opscode.com/chef/install.sh | {{if .Sudo}}sudo {{end}}bash"
}
if p.config.Recipes == nil { if p.config.Recipes == nil {
p.config.Recipes = make([]string, 0) p.config.Recipes = make([]string, 0)
} }
if p.config.Json != nil { if p.config.Json != nil {
if _, err := json.Marshal(p.config.Json); err != nil { if _, err := json.Marshal(p.config.Json); err != nil {
errs = append(errs, fmt.Errorf("Bad JSON: %s", err)) errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Bad JSON: %s", err))
} }
} else { } else {
p.config.Json = make(map[string]interface{}) p.config.Json = make(map[string]interface{})
...@@ -88,12 +96,13 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { ...@@ -88,12 +96,13 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
pFileInfo, err := os.Stat(path) pFileInfo, err := os.Stat(path)
if err != nil || !pFileInfo.IsDir() { if err != nil || !pFileInfo.IsDir() {
errs = append(errs, fmt.Errorf("Bad cookbook path '%s': %s", path, err)) errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Bad cookbook path '%s': %s", path, err))
} }
} }
if len(errs) > 0 { if errs != nil && len(errs.Errors) > 0 {
return &packer.MultiError{errs} return errs
} }
return nil return nil
...@@ -104,9 +113,8 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ...@@ -104,9 +113,8 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
Ui = ui Ui = ui
if !p.config.SkipInstall { if !p.config.SkipInstall {
err = InstallChefSolo(p.config.PreventSudo, comm) if err := p.installChef(ui, comm); err != nil {
if err != nil { return fmt.Errorf("Error installing Chef: %s", err)
return fmt.Errorf("Error installing Chef Solo: %s", err)
} }
} }
...@@ -315,16 +323,24 @@ func CreateAttributesJson(jsonAttrs map[string]interface{}, recipes []string, co ...@@ -315,16 +323,24 @@ func CreateAttributesJson(jsonAttrs map[string]interface{}, recipes []string, co
return remotePath, nil return remotePath, nil
} }
func InstallChefSolo(preventSudo bool, comm packer.Communicator) (err error) { func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error {
Ui.Say("Installing Chef Solo") ui.Message("Installing Chef...")
var command bytes.Buffer command, err := p.config.tpl.Process(p.config.InstallCommand, &InstallChefTemplate{
t := template.Must(template.New("install-chef").Parse("curl -L https://www.opscode.com/chef/install.sh | {{if .sudo}}sudo {{end}}bash")) Sudo: !p.config.PreventSudo,
t.Execute(&command, map[string]bool{"sudo": !preventSudo}) })
err = executeCommand(command.String(), comm)
if err != nil { if err != nil {
return fmt.Errorf("Unable to install Chef Solo: %d", err) return err
}
cmd := &packer.RemoteCmd{Command: command}
if err := cmd.StartWithUi(comm, ui); err != nil {
return err
}
if cmd.ExitStatus != 0 {
return fmt.Errorf(
"Install script exited with non-zero exit status %d", cmd.ExitStatus)
} }
return nil return nil
......
package chefSolo package chefsolo
import ( import (
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment