Merge pull request #411 from jerryclinesmith/issue_348
provisioners/chef-solo: add support for roles and data_bags
This commit is contained in:
commit
129f1290c1
|
@ -20,6 +20,8 @@ type Config struct {
|
||||||
|
|
||||||
ConfigTemplate string `mapstructure:"config_template"`
|
ConfigTemplate string `mapstructure:"config_template"`
|
||||||
CookbookPaths []string `mapstructure:"cookbook_paths"`
|
CookbookPaths []string `mapstructure:"cookbook_paths"`
|
||||||
|
RolesPath string `mapstructure:"roles_path"`
|
||||||
|
DataBagsPath string `mapstructure:"data_bags_path"`
|
||||||
ExecuteCommand string `mapstructure:"execute_command"`
|
ExecuteCommand string `mapstructure:"execute_command"`
|
||||||
InstallCommand string `mapstructure:"install_command"`
|
InstallCommand string `mapstructure:"install_command"`
|
||||||
RemoteCookbookPaths []string `mapstructure:"remote_cookbook_paths"`
|
RemoteCookbookPaths []string `mapstructure:"remote_cookbook_paths"`
|
||||||
|
@ -38,6 +40,8 @@ type Provisioner struct {
|
||||||
|
|
||||||
type ConfigTemplate struct {
|
type ConfigTemplate struct {
|
||||||
CookbookPaths string
|
CookbookPaths string
|
||||||
|
RolesPath string
|
||||||
|
DataBagsPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecuteTemplate struct {
|
type ExecuteTemplate struct {
|
||||||
|
@ -144,6 +148,24 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.RolesPath != "" {
|
||||||
|
pFileInfo, err := os.Stat(p.config.RolesPath)
|
||||||
|
|
||||||
|
if err != nil || !pFileInfo.IsDir() {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, fmt.Errorf("Bad roles path '%s': %s", p.config.RolesPath, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.config.DataBagsPath != "" {
|
||||||
|
pFileInfo, err := os.Stat(p.config.DataBagsPath)
|
||||||
|
|
||||||
|
if err != nil || !pFileInfo.IsDir() {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, fmt.Errorf("Bad data bags path '%s': %s", p.config.DataBagsPath, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process the user variables within the JSON and set the JSON.
|
// Process the user variables within the JSON and set the JSON.
|
||||||
// Do this early so that we can validate and show errors.
|
// Do this early so that we can validate and show errors.
|
||||||
p.config.Json, err = p.processJsonUserVars()
|
p.config.Json, err = p.processJsonUserVars()
|
||||||
|
@ -180,7 +202,23 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||||
cookbookPaths = append(cookbookPaths, targetPath)
|
cookbookPaths = append(cookbookPaths, targetPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
configPath, err := p.createConfig(ui, comm, cookbookPaths)
|
rolesPath := ""
|
||||||
|
if p.config.RolesPath != "" {
|
||||||
|
rolesPath := fmt.Sprintf("%s/roles", p.config.StagingDir)
|
||||||
|
if err := p.uploadDirectory(ui, comm, rolesPath, p.config.RolesPath); err != nil {
|
||||||
|
return fmt.Errorf("Error uploading roles: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBagsPath := ""
|
||||||
|
if p.config.DataBagsPath != "" {
|
||||||
|
dataBagsPath := fmt.Sprintf("%s/data_bags", p.config.StagingDir)
|
||||||
|
if err := p.uploadDirectory(ui, comm, dataBagsPath, p.config.DataBagsPath); err != nil {
|
||||||
|
return fmt.Errorf("Error uploading data bags: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configPath, err := p.createConfig(ui, comm, cookbookPaths, rolesPath, dataBagsPath)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -217,7 +255,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, localCookbooks []string) (string, error) {
|
func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, localCookbooks []string, rolesPath string, dataBagsPath string) (string, error) {
|
||||||
ui.Message("Creating configuration file 'solo.rb'")
|
ui.Message("Creating configuration file 'solo.rb'")
|
||||||
|
|
||||||
cookbook_paths := make([]string, len(p.config.RemoteCookbookPaths)+len(localCookbooks))
|
cookbook_paths := make([]string, len(p.config.RemoteCookbookPaths)+len(localCookbooks))
|
||||||
|
@ -230,6 +268,16 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roles_path := ""
|
||||||
|
if rolesPath != "" {
|
||||||
|
roles_path = fmt.Sprintf(`"%s"`, rolesPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
data_bags_path := ""
|
||||||
|
if dataBagsPath != "" {
|
||||||
|
data_bags_path = fmt.Sprintf(`"%s"`, dataBagsPath)
|
||||||
|
}
|
||||||
|
|
||||||
// Read the template
|
// Read the template
|
||||||
tpl := DefaultConfigTemplate
|
tpl := DefaultConfigTemplate
|
||||||
if p.config.ConfigTemplate != "" {
|
if p.config.ConfigTemplate != "" {
|
||||||
|
@ -249,6 +297,8 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, local
|
||||||
|
|
||||||
configString, err := p.config.tpl.Process(tpl, &ConfigTemplate{
|
configString, err := p.config.tpl.Process(tpl, &ConfigTemplate{
|
||||||
CookbookPaths: strings.Join(cookbook_paths, ","),
|
CookbookPaths: strings.Join(cookbook_paths, ","),
|
||||||
|
RolesPath: roles_path,
|
||||||
|
DataBagsPath: data_bags_path,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -400,4 +450,10 @@ func (p *Provisioner) processJsonUserVars() (map[string]interface{}, error) {
|
||||||
|
|
||||||
var DefaultConfigTemplate = `
|
var DefaultConfigTemplate = `
|
||||||
cookbook_path [{{.CookbookPaths}}]
|
cookbook_path [{{.CookbookPaths}}]
|
||||||
|
{{if .RolesPath != ""}}
|
||||||
|
role_path {{.RolesPath}}
|
||||||
|
{{end}}
|
||||||
|
{{if .DataBagsPath != ""}}
|
||||||
|
data_bag_path {{.DataBagsPath}}
|
||||||
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
|
@ -75,11 +75,25 @@ func TestProvisionerPrepare_cookbookPaths(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rolesPath, err := ioutil.TempDir("", "roles")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBagsPath, err := ioutil.TempDir("", "data_bags")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
defer os.Remove(path1)
|
defer os.Remove(path1)
|
||||||
defer os.Remove(path2)
|
defer os.Remove(path2)
|
||||||
|
defer os.Remove(rolesPath)
|
||||||
|
defer os.Remove(dataBagsPath)
|
||||||
|
|
||||||
config := testConfig()
|
config := testConfig()
|
||||||
config["cookbook_paths"] = []string{path1, path2}
|
config["cookbook_paths"] = []string{path1, path2}
|
||||||
|
config["roles_path"] = rolesPath
|
||||||
|
config["data_bags_path"] = dataBagsPath
|
||||||
|
|
||||||
err = p.Prepare(config)
|
err = p.Prepare(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -93,6 +107,14 @@ func TestProvisionerPrepare_cookbookPaths(t *testing.T) {
|
||||||
if p.config.CookbookPaths[0] != path1 || p.config.CookbookPaths[1] != path2 {
|
if p.config.CookbookPaths[0] != path1 || p.config.CookbookPaths[1] != path2 {
|
||||||
t.Fatalf("unexpected: %#v", p.config.CookbookPaths)
|
t.Fatalf("unexpected: %#v", p.config.CookbookPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.RolesPath != rolesPath {
|
||||||
|
t.Fatalf("unexpected: %#v", p.config.RolesPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.config.DataBagsPath != dataBagsPath {
|
||||||
|
t.Fatalf("unexpected: %#v", p.config.DataBagsPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvisionerPrepare_json(t *testing.T) {
|
func TestProvisionerPrepare_json(t *testing.T) {
|
||||||
|
|
|
@ -44,6 +44,14 @@ configuration is actually required, but at least `run_list` is recommended.
|
||||||
to the remote machine in the directory specified by the `staging_directory`.
|
to the remote machine in the directory specified by the `staging_directory`.
|
||||||
By default, this is empty.
|
By default, this is empty.
|
||||||
|
|
||||||
|
* `roles_path` (string) - The path to the "roles" directory on your local filesystem.
|
||||||
|
These will be uploaded to the remote machine in the directory specified by the
|
||||||
|
`staging_directory`. By default, this is empty.
|
||||||
|
|
||||||
|
* `data_bags_path` (string) - The path to the "data_bags" directory on your local filesystem.
|
||||||
|
These will be uploaded to the remote machine in the directory specified by the
|
||||||
|
`staging_directory`. By default, this is empty.
|
||||||
|
|
||||||
* `execute_command` (string) - The command used to execute Chef. This has
|
* `execute_command` (string) - The command used to execute Chef. This has
|
||||||
various [configuration template variables](/docs/templates/configuration-templates.html)
|
various [configuration template variables](/docs/templates/configuration-templates.html)
|
||||||
available. See below for more information.
|
available. See below for more information.
|
||||||
|
|
Loading…
Reference in New Issue