provisioner/chef-solo: ability to specify custom chef template
This commit is contained in:
parent
9f52b78602
commit
dc0232975d
|
@ -1,5 +1,10 @@
|
||||||
## 0.3.8 (unreleased)
|
## 0.3.8 (unreleased)
|
||||||
|
|
||||||
|
FEATURES:
|
||||||
|
|
||||||
|
* provisioner/chef-solo: Ability to specify a custom Chef configuration
|
||||||
|
template.
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
|
||||||
* builder/amazon/*: Interrupts work while waiting for AMI to be ready.
|
* builder/amazon/*: Interrupts work while waiting for AMI to be ready.
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/packer/common"
|
"github.com/mitchellh/packer/common"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
common.PackerConfig `mapstructure:",squash"`
|
common.PackerConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
|
ConfigTemplate string `mapstructure:"config_template"`
|
||||||
CookbookPaths []string `mapstructure:"cookbook_paths"`
|
CookbookPaths []string `mapstructure:"cookbook_paths"`
|
||||||
ExecuteCommand string `mapstructure:"execute_command"`
|
ExecuteCommand string `mapstructure:"execute_command"`
|
||||||
InstallCommand string `mapstructure:"install_command"`
|
InstallCommand string `mapstructure:"install_command"`
|
||||||
|
@ -80,6 +82,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
errs := common.CheckUnusedConfig(md)
|
errs := common.CheckUnusedConfig(md)
|
||||||
|
|
||||||
templates := map[string]*string{
|
templates := map[string]*string{
|
||||||
|
"config_template": &p.config.ConfigTemplate,
|
||||||
"staging_dir": &p.config.StagingDir,
|
"staging_dir": &p.config.StagingDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +124,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.ConfigTemplate != "" {
|
||||||
|
fi, err := os.Stat(p.config.ConfigTemplate)
|
||||||
|
if err != nil {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, fmt.Errorf("Bad config template path: %s", err))
|
||||||
|
} else if fi.IsDir() {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, fmt.Errorf("Config template path must be a file: %s", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, path := range p.config.CookbookPaths {
|
for _, path := range p.config.CookbookPaths {
|
||||||
pFileInfo, err := os.Stat(path)
|
pFileInfo, err := os.Stat(path)
|
||||||
|
|
||||||
|
@ -216,7 +230,24 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, local
|
||||||
cookbook_paths[i] = fmt.Sprintf(`"%s"`, path)
|
cookbook_paths[i] = fmt.Sprintf(`"%s"`, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
configString, err := p.config.tpl.Process(DefaultConfigTemplate, &ConfigTemplate{
|
// Read the template
|
||||||
|
tpl := DefaultConfigTemplate
|
||||||
|
if p.config.ConfigTemplate != "" {
|
||||||
|
f, err := os.Open(p.config.ConfigTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
tplBytes, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl = string(tplBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
configString, err := p.config.tpl.Process(tpl, &ConfigTemplate{
|
||||||
CookbookPaths: strings.Join(cookbook_paths, ","),
|
CookbookPaths: strings.Join(cookbook_paths, ","),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -19,6 +19,49 @@ func TestProvisioner_Impl(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProvisionerPrepare_configTemplate(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var p Provisioner
|
||||||
|
|
||||||
|
// Test no config template
|
||||||
|
config := testConfig()
|
||||||
|
delete(config, "config_template")
|
||||||
|
err = p.Prepare(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with a file
|
||||||
|
tf, err := ioutil.TempFile("", "packer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tf.Name())
|
||||||
|
|
||||||
|
config = testConfig()
|
||||||
|
config["config_template"] = tf.Name()
|
||||||
|
p = Provisioner{}
|
||||||
|
err = p.Prepare(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with a directory
|
||||||
|
td, err := ioutil.TempDir("", "packer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(td)
|
||||||
|
|
||||||
|
config = testConfig()
|
||||||
|
config["config_template"] = td
|
||||||
|
p = Provisioner{}
|
||||||
|
err = p.Prepare(config)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("should have err")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestProvisionerPrepare_cookbookPaths(t *testing.T) {
|
func TestProvisionerPrepare_cookbookPaths(t *testing.T) {
|
||||||
var p Provisioner
|
var p Provisioner
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,13 @@ The example below is fully functional and expects cookbooks in the
|
||||||
The reference of available configuration options is listed below. No
|
The reference of available configuration options is listed below. No
|
||||||
configuration is actually required, but at least `run_list` is recommended.
|
configuration is actually required, but at least `run_list` is recommended.
|
||||||
|
|
||||||
|
* `config_template` (string) - Path to a template that will be used for
|
||||||
|
the Chef configuration file. By default Packer only sets configuration
|
||||||
|
it needs to match the settings set in the provisioner configuration. If
|
||||||
|
you need to set configurations that the Packer provisioner doesn't support,
|
||||||
|
then you should use a custom configuration template. See the dedicated
|
||||||
|
"Chef Configuration" section below for more details.
|
||||||
|
|
||||||
* `cookbook_paths` (array of strings) - This is an array of paths to
|
* `cookbook_paths` (array of strings) - This is an array of paths to
|
||||||
"cookbooks" directories on your local filesystem. These will be uploaded
|
"cookbooks" directories on your local filesystem. These will be uploaded
|
||||||
to the remote machine in the directory specified by the `staging_directory`.
|
to the remote machine in the directory specified by the `staging_directory`.
|
||||||
|
@ -70,6 +77,25 @@ configuration is actually required, but at least `run_list` is recommended.
|
||||||
this folder. If the permissions are not correct, use a shell provisioner
|
this folder. If the permissions are not correct, use a shell provisioner
|
||||||
prior to this to configure it properly.
|
prior to this to configure it properly.
|
||||||
|
|
||||||
|
## Chef Configuration
|
||||||
|
|
||||||
|
By default, Packer uses a simple Chef configuration file in order to set
|
||||||
|
the options specified for the provisioner. But Chef is a complex tool that
|
||||||
|
supports many configuration options. Packer allows you to specify a custom
|
||||||
|
configuration template if you'd like to set custom configurations.
|
||||||
|
|
||||||
|
The default value for the configuration template is:
|
||||||
|
|
||||||
|
```
|
||||||
|
cookbook_path [{{.CookbookPaths}}]
|
||||||
|
```
|
||||||
|
|
||||||
|
This template is a [configuration template](/docs/templates/configuration-templates.html)
|
||||||
|
and has a set of variables available to use:
|
||||||
|
|
||||||
|
* `CookbookPaths` is the set of cookbook paths ready to embedded directly
|
||||||
|
into a Ruby array to configure Chef.
|
||||||
|
|
||||||
## Execute Command
|
## Execute Command
|
||||||
|
|
||||||
By default, Packer uses the following command (broken across multiple lines
|
By default, Packer uses the following command (broken across multiple lines
|
||||||
|
|
Loading…
Reference in New Issue