From fd0df9ff587247dacfe2c5491e8f8b32b2af9fd7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 9 Sep 2013 13:24:17 -0700 Subject: [PATCH] provisioners/puppet-masterless: support hiera configs --- provisioner/puppet-masterless/provisioner.go | 65 ++++++++++++++++--- .../puppet-masterless/provisioner_test.go | 25 +++++++ .../puppet-masterless.html.markdown | 7 ++ 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/provisioner/puppet-masterless/provisioner.go b/provisioner/puppet-masterless/provisioner.go index c6a475a3d..c9ce901a4 100644 --- a/provisioner/puppet-masterless/provisioner.go +++ b/provisioner/puppet-masterless/provisioner.go @@ -22,6 +22,9 @@ type Config struct { // Additional facts to set when executing Puppet Facter map[string]string + // Path to a hiera configuration file to upload and use. + HieraConfigPath string `mapstructure:"hiera_config_path"` + // An array of local paths of modules to upload. ModulePaths []string `mapstructure:"module_paths"` @@ -41,10 +44,12 @@ type Provisioner struct { } type ExecuteTemplate struct { - FacterVars string - ModulePath string - ManifestFile string - Sudo bool + FacterVars string + HasHieraConfigPath bool + HieraConfigPath string + ModulePath string + ManifestFile string + Sudo bool } func (p *Provisioner) Prepare(raws ...interface{}) error { @@ -64,7 +69,10 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { // Set some defaults if p.config.ExecuteCommand == "" { - p.config.ExecuteCommand = "{{.FacterVars}}{{if .Sudo}} sudo -E {{end}}puppet apply --verbose --modulepath='{{.ModulePath}}' {{.ManifestFile}}" + p.config.ExecuteCommand = "{{.FacterVars}}{{if .Sudo}} sudo -E {{end}}" + + "puppet apply --verbose --modulepath='{{.ModulePath}}' " + + "{{if .HasHieraConfigPath}}--hiera_config='{{.HieraConfigPath}}' {{end}}" + + "{{.ManifestFile}}" } if p.config.StagingDir == "" { @@ -133,6 +141,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.Facter = newFacts // Validation + if p.config.HieraConfigPath != "" { + info, err := os.Stat(p.config.ManifestFile) + if err != nil { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("hiera_config_path is invalid: %s", err)) + } else if info.IsDir() { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("hiera_config_path must point to a file")) + } + } + if p.config.ManifestFile == "" { errs = packer.MultiErrorAppend(errs, fmt.Errorf("A manifest_file must be specified.")) @@ -171,6 +190,16 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { return fmt.Errorf("Error creating staging directory: %s", err) } + // Upload hiera config if set + remoteHieraConfigPath := "" + if p.config.HieraConfigPath != "" { + var err error + remoteHieraConfigPath, err = p.uploadHieraConfig(ui, comm) + if err != nil { + return fmt.Errorf("Error uploading hiera config: %s", err) + } + } + // Upload all modules modulePaths := make([]string, 0, len(p.config.ModulePaths)) for i, path := range p.config.ModulePaths { @@ -198,10 +227,12 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { // Execute Puppet command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteTemplate{ - FacterVars: strings.Join(facterVars, " "), - ManifestFile: remoteManifestFile, - ModulePath: strings.Join(modulePaths, ":"), - Sudo: !p.config.PreventSudo, + FacterVars: strings.Join(facterVars, " "), + HasHieraConfigPath: remoteHieraConfigPath != "", + HieraConfigPath: remoteHieraConfigPath, + ManifestFile: remoteManifestFile, + ModulePath: strings.Join(modulePaths, ":"), + Sudo: !p.config.PreventSudo, }) if err != nil { return err @@ -229,6 +260,22 @@ func (p *Provisioner) Cancel() { os.Exit(0) } +func (p *Provisioner) uploadHieraConfig(ui packer.Ui, comm packer.Communicator) (string, error) { + ui.Message("Uploading hiera configuration...") + f, err := os.Open(p.config.HieraConfigPath) + if err != nil { + return "", err + } + defer f.Close() + + path := fmt.Sprintf("%s/hiera.yaml", p.config.StagingDir) + if err := comm.Upload(path, f); err != nil { + return "", err + } + + return path, nil +} + func (p *Provisioner) uploadManifests(ui packer.Ui, comm packer.Communicator) (string, error) { // Create the remote manifests directory... ui.Message("Uploading manifests...") diff --git a/provisioner/puppet-masterless/provisioner_test.go b/provisioner/puppet-masterless/provisioner_test.go index 88dea6029..b19757f23 100644 --- a/provisioner/puppet-masterless/provisioner_test.go +++ b/provisioner/puppet-masterless/provisioner_test.go @@ -26,6 +26,31 @@ func TestProvisioner_Impl(t *testing.T) { } } +func TestProvisionerPrepare_hieraConfigPath(t *testing.T) { + config := testConfig() + + delete(config, "hiera_config_path") + p := new(Provisioner) + err := p.Prepare(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + // Test with a good one + tf, err := ioutil.TempFile("", "packer") + if err != nil { + t.Fatalf("error tempfile: %s", err) + } + defer os.Remove(tf.Name()) + + config["hiera_config_path"] = tf.Name() + p = new(Provisioner) + err = p.Prepare(config) + if err != nil { + t.Fatalf("err: %s", err) + } +} + func TestProvisionerPrepare_manifestFile(t *testing.T) { config := testConfig() diff --git a/website/source/docs/provisioners/puppet-masterless.html.markdown b/website/source/docs/provisioners/puppet-masterless.html.markdown index ee284c52e..11dbc6a85 100644 --- a/website/source/docs/provisioners/puppet-masterless.html.markdown +++ b/website/source/docs/provisioners/puppet-masterless.html.markdown @@ -54,6 +54,10 @@ Optional parameters: [facts](http://puppetlabs.com/puppet/related-projects/facter) to make available when Puppet is running. +* `hiera_config_path` (string) - The path to a local file with hiera + configuration to be uploaded to the remote machine. Hiera data directories + must be uploaded using the file provisioner separately. + * `module_paths` (array of strings) - This is an array of paths to module directories on your local filesystem. These will be uploaded to the remote machine. By default, this is empty. @@ -78,6 +82,7 @@ for readability) to execute Puppet: {{.FacterVars}}{{if .Sudo} sudo -E {{end}}puppet apply \ --verbose \ --modulepath='{{.ModulePath}}' \ + {{if .HasHieraConfigPath}}--hiera_config='{{.HieraConfigPath}}' {{end}} \ {{.ManifestFile}} ``` @@ -87,6 +92,8 @@ can contain various template variables, defined below: * `FacterVars` - Shell-friendly string of environmental variables used to set custom facts configured for this provisioner. +* `HasHieraConfigPath` - Boolean true if there is a hiera config path set. +* `HieraConfigPath` - The path to a hiera configuration file. * `ManifestFile` - The path on the remote machine to the manifest file for Puppet to use. * `ModulePath` - The paths to the module directories.