Merge pull request #625 from matheeeny/encrypted-data-bags

provisioner/chef-solo: add support for chef-solo encrypted data bags
This commit is contained in:
Mitchell Hashimoto 2013-11-18 15:44:55 -08:00
commit 41ff27f4aa
1 changed files with 74 additions and 38 deletions

View File

@ -18,20 +18,21 @@ import (
type Config struct { type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
ChefEnvironment string `mapstructure:"chef_environment"` ChefEnvironment string `mapstructure:"chef_environment"`
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"` RolesPath string `mapstructure:"roles_path"`
DataBagsPath string `mapstructure:"data_bags_path"` DataBagsPath string `mapstructure:"data_bags_path"`
EnvironmentsPath string `mapstructure:"environments_path"` EncryptedDataBagSecret string `mapstructure:"encrypted_data_bag_secret"`
ExecuteCommand string `mapstructure:"execute_command"` EnvironmentsPath string `mapstructure:"environments_path"`
InstallCommand string `mapstructure:"install_command"` ExecuteCommand string `mapstructure:"execute_command"`
RemoteCookbookPaths []string `mapstructure:"remote_cookbook_paths"` InstallCommand string `mapstructure:"install_command"`
Json map[string]interface{} RemoteCookbookPaths []string `mapstructure:"remote_cookbook_paths"`
PreventSudo bool `mapstructure:"prevent_sudo"` Json map[string]interface{}
RunList []string `mapstructure:"run_list"` PreventSudo bool `mapstructure:"prevent_sudo"`
SkipInstall bool `mapstructure:"skip_install"` RunList []string `mapstructure:"run_list"`
StagingDir string `mapstructure:"staging_directory"` SkipInstall bool `mapstructure:"skip_install"`
StagingDir string `mapstructure:"staging_directory"`
tpl *packer.ConfigTemplate tpl *packer.ConfigTemplate
} }
@ -41,18 +42,20 @@ type Provisioner struct {
} }
type ConfigTemplate struct { type ConfigTemplate struct {
CookbookPaths string CookbookPaths string
DataBagsPath string DataBagsPath string
RolesPath string EncryptedDataBagSecret string
EnvironmentsPath string RolesPath string
ChefEnvironment string EnvironmentsPath string
ChefEnvironment string
// Templates don't support boolean statements until Go 1.2. In the // Templates don't support boolean statements until Go 1.2. In the
// mean time, we do this. // mean time, we do this.
// TODO(mitchellh): Remove when Go 1.2 is released // TODO(mitchellh): Remove when Go 1.2 is released
HasDataBagsPath bool HasDataBagsPath bool
HasRolesPath bool HasEncryptedDataBagSecret bool
HasEnvironmentsPath bool HasRolesPath bool
HasEnvironmentsPath bool
} }
type ExecuteTemplate struct { type ExecuteTemplate struct {
@ -97,12 +100,13 @@ 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, "config_template": &p.config.ConfigTemplate,
"data_bags_path": &p.config.DataBagsPath, "data_bags_path": &p.config.DataBagsPath,
"roles_path": &p.config.RolesPath, "encrypted_data_bag_secret": &p.config.EncryptedDataBagSecret,
"staging_dir": &p.config.StagingDir, "roles_path": &p.config.RolesPath,
"environments_path": &p.config.EnvironmentsPath, "staging_dir": &p.config.StagingDir,
"chef_environment": &p.config.ChefEnvironment, "environments_path": &p.config.EnvironmentsPath,
"chef_environment": &p.config.ChefEnvironment,
} }
for n, ptr := range templates { for n, ptr := range templates {
@ -181,6 +185,15 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
} }
} }
if p.config.EncryptedDataBagSecret != "" {
pFileInfo, err := os.Stat(p.config.EncryptedDataBagSecret)
if err != nil || pFileInfo.IsDir() {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Bad encrypted data bag secret '%s': %s", p.config.EncryptedDataBagSecret, err))
}
}
if p.config.EnvironmentsPath != "" { if p.config.EnvironmentsPath != "" {
pFileInfo, err := os.Stat(p.config.EnvironmentsPath) pFileInfo, err := os.Stat(p.config.EnvironmentsPath)
@ -244,6 +257,14 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
} }
} }
encryptedDataBagSecret := ""
if p.config.EncryptedDataBagSecret != "" {
encryptedDataBagSecret = fmt.Sprintf("%s/encrypted_data_bag_secret", p.config.StagingDir)
if err := p.uploadFile(ui, comm, encryptedDataBagSecret, p.config.EncryptedDataBagSecret); err != nil {
return fmt.Errorf("Error uploading encrypted data bag secret: %s", err)
}
}
environmentsPath := "" environmentsPath := ""
if p.config.EnvironmentsPath != "" { if p.config.EnvironmentsPath != "" {
environmentsPath = fmt.Sprintf("%s/environments", p.config.StagingDir) environmentsPath = fmt.Sprintf("%s/environments", p.config.StagingDir)
@ -252,7 +273,7 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
} }
} }
configPath, err := p.createConfig(ui, comm, cookbookPaths, rolesPath, dataBagsPath, environmentsPath, p.config.ChefEnvironment) configPath, err := p.createConfig(ui, comm, cookbookPaths, rolesPath, dataBagsPath, encryptedDataBagSecret, environmentsPath, p.config.ChefEnvironment)
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)
} }
@ -289,7 +310,17 @@ 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, rolesPath string, dataBagsPath string, environmentsPath string, chefEnvironment string) (string, error) { func (p *Provisioner) uploadFile(ui packer.Ui, comm packer.Communicator, dst string, src string) error {
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
return comm.Upload(dst, f)
}
func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, localCookbooks []string, rolesPath string, dataBagsPath string, encryptedDataBagSecret string, environmentsPath string, chefEnvironment 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))
@ -320,14 +351,16 @@ 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: rolesPath, RolesPath: rolesPath,
DataBagsPath: dataBagsPath, DataBagsPath: dataBagsPath,
EnvironmentsPath: environmentsPath, EncryptedDataBagSecret: encryptedDataBagSecret,
HasRolesPath: rolesPath != "", EnvironmentsPath: environmentsPath,
HasDataBagsPath: dataBagsPath != "", HasRolesPath: rolesPath != "",
HasEnvironmentsPath: environmentsPath != "", HasDataBagsPath: dataBagsPath != "",
ChefEnvironment: chefEnvironment, HasEncryptedDataBagSecret: encryptedDataBagSecret != "",
HasEnvironmentsPath: environmentsPath != "",
ChefEnvironment: chefEnvironment,
}) })
if err != nil { if err != nil {
return "", err return "", err
@ -485,6 +518,9 @@ role_path "{{.RolesPath}}"
{{if .HasDataBagsPath}} {{if .HasDataBagsPath}}
data_bag_path "{{.DataBagsPath}}" data_bag_path "{{.DataBagsPath}}"
{{end}} {{end}}
{{if .HasEncryptedDataBagSecret}}
encrypted_data_bag_secret "{{.EncryptedDataBagSecret}}"
{{end}}
{{if .HasEnvironmentsPath}} {{if .HasEnvironmentsPath}}
environments_path "{{.EnvironmentsPath}}" environments_path "{{.EnvironmentsPath}}"
chef_environment "{{.ChefEnvironment}}" chef_environment "{{.ChefEnvironment}}"