This commit is contained in:
Chris Bednarski 2015-11-04 17:11:50 -08:00
commit 935fa3a590
25 changed files with 289 additions and 20 deletions

View File

@ -9,6 +9,7 @@ import (
"log" "log"
"runtime" "runtime"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
awscommon "github.com/mitchellh/packer/builder/amazon/common" awscommon "github.com/mitchellh/packer/builder/amazon/common"
@ -131,7 +132,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
return nil, err return nil, err
} }
ec2conn := ec2.New(config) session := session.New(config)
ec2conn := ec2.New(session)
wrappedCommand := func(command string) (string, error) { wrappedCommand := func(command string) (string, error) {
ctx := b.config.ctx ctx := b.config.ctx

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
) )
@ -72,7 +73,8 @@ func (a *Artifact) Destroy() error {
Credentials: a.Conn.Config.Credentials, Credentials: a.Conn.Config.Credentials,
Region: aws.String(region), Region: aws.String(region),
} }
regionConn := ec2.New(regionConfig) sess := session.New(regionConfig)
regionConn := ec2.New(sess)
input := &ec2.DeregisterImageInput{ input := &ec2.DeregisterImageInput{
ImageId: &imageId, ImageId: &imageId,

View File

@ -6,6 +6,7 @@ import (
"sync" "sync"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
@ -87,7 +88,9 @@ func amiRegionCopy(state multistep.StateBag, config *AccessConfig, name string,
} }
awsConfig.Region = aws.String(target) awsConfig.Region = aws.String(target)
regionconn := ec2.New(awsConfig) sess := session.New(awsConfig)
regionconn := ec2.New(sess)
resp, err := regionconn.CopyImage(&ec2.CopyImageInput{ resp, err := regionconn.CopyImage(&ec2.CopyImageInput{
SourceRegion: &source, SourceRegion: &source,
SourceImageId: &imageId, SourceImageId: &imageId,

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
@ -33,11 +34,13 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
// Declare list of resources to tag // Declare list of resources to tag
resourceIds := []*string{&ami} resourceIds := []*string{&ami}
awsConfig := aws.Config{
regionconn := ec2.New(&aws.Config{
Credentials: ec2conn.Config.Credentials, Credentials: ec2conn.Config.Credentials,
Region: aws.String(region), Region: aws.String(region),
}) }
session := session.New(&awsConfig)
regionconn := ec2.New(session)
// Retrieve image list for given AMI // Retrieve image list for given AMI
imageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{ imageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
@ -88,10 +89,12 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
for region, ami := range amis { for region, ami := range amis {
ui.Say(fmt.Sprintf("Modifying attributes on AMI (%s)...", ami)) ui.Say(fmt.Sprintf("Modifying attributes on AMI (%s)...", ami))
regionconn := ec2.New(&aws.Config{ awsConfig := aws.Config{
Credentials: ec2conn.Config.Credentials, Credentials: ec2conn.Config.Credentials,
Region: aws.String(region), Region: aws.String(region),
}) }
session := session.New(&awsConfig)
regionconn := ec2.New(session)
for name, input := range options { for name, input := range options {
ui.Message(fmt.Sprintf("Modifying: %s", name)) ui.Message(fmt.Sprintf("Modifying: %s", name))
input.ImageId = &ami input.ImageId = &ami

View File

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
awscommon "github.com/mitchellh/packer/builder/amazon/common" awscommon "github.com/mitchellh/packer/builder/amazon/common"
@ -68,7 +69,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
return nil, err return nil, err
} }
ec2conn := ec2.New(config) session := session.New(config)
ec2conn := ec2.New(session)
// Setup the state bag and initial state for the steps // Setup the state bag and initial state for the steps
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/packer/builder/amazon/common" "github.com/mitchellh/packer/builder/amazon/common"
builderT "github.com/mitchellh/packer/helper/builder/testing" builderT "github.com/mitchellh/packer/helper/builder/testing"
@ -160,7 +161,8 @@ func testEC2Conn() (*ec2.EC2, error) {
return nil, err return nil, err
} }
return ec2.New(config), nil session := session.New(config)
return ec2.New(session), nil
} }
const testBuilderAccBasic = ` const testBuilderAccBasic = `

View File

@ -9,6 +9,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
awscommon "github.com/mitchellh/packer/builder/amazon/common" awscommon "github.com/mitchellh/packer/builder/amazon/common"
@ -159,7 +160,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
return nil, err return nil, err
} }
ec2conn := ec2.New(config) session := session.New(config)
ec2conn := ec2.New(session)
// Setup the state bag and initial state for the steps // Setup the state bag and initial state for the steps
state := new(multistep.BasicStateBag) state := new(multistep.BasicStateBag)

View File

@ -88,6 +88,8 @@ type Config struct {
DiskSize uint `mapstructure:"disk_size"` DiskSize uint `mapstructure:"disk_size"`
DiskCache string `mapstructure:"disk_cache"` DiskCache string `mapstructure:"disk_cache"`
DiskDiscard string `mapstructure:"disk_discard"` DiskDiscard string `mapstructure:"disk_discard"`
SkipCompaction bool `mapstructure:"skip_compaction"`
DiskCompression bool `mapstructure:"disk_compression"`
FloppyFiles []string `mapstructure:"floppy_files"` FloppyFiles []string `mapstructure:"floppy_files"`
Format string `mapstructure:"format"` Format string `mapstructure:"format"`
Headless bool `mapstructure:"headless"` Headless bool `mapstructure:"headless"`
@ -242,6 +244,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs, errors.New("invalid format, only 'qcow2' or 'raw' are allowed")) errs, errors.New("invalid format, only 'qcow2' or 'raw' are allowed"))
} }
if b.config.Format != "qcow2" {
b.config.SkipCompaction = true
b.config.DiskCompression = false
}
if _, ok := accels[b.config.Accelerator]; !ok { if _, ok := accels[b.config.Accelerator]; !ok {
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, errors.New("invalid accelerator, only 'kvm', 'tcg', 'xen', or 'none' are allowed")) errs, errors.New("invalid accelerator, only 'kvm', 'tcg', 'xen', or 'none' are allowed"))
@ -364,6 +371,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
}, },
new(common.StepProvision), new(common.StepProvision),
new(stepShutdown), new(stepShutdown),
new(stepConvertDisk),
} }
// Setup the state bag // Setup the state bag

View File

@ -132,6 +132,48 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
} }
} }
func TestBuilderPrepare_DiskCompaction(t *testing.T) {
var b Builder
config := testConfig()
// Bad
config["skip_compaction"] = false
config["disk_compression"] = true
config["format"] = "img"
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
if b.config.SkipCompaction != true {
t.Fatalf("SkipCompaction should be true")
}
if b.config.DiskCompression != false {
t.Fatalf("DiskCompression should be false")
}
// Good
config["skip_compaction"] = false
config["disk_compression"] = true
config["format"] = "qcow2"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.SkipCompaction != false {
t.Fatalf("SkipCompaction should be false")
}
if b.config.DiskCompression != true {
t.Fatalf("DiskCompression should be true")
}
}
func TestBuilderPrepare_DiskSize(t *testing.T) { func TestBuilderPrepare_DiskSize(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()

View File

@ -0,0 +1,67 @@
package qemu
import (
"fmt"
"path/filepath"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"os"
)
// This step converts the virtual disk that was used as the
// hard drive for the virtual machine.
type stepConvertDisk struct{}
func (s *stepConvertDisk) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
diskName := state.Get("disk_filename").(string)
ui := state.Get("ui").(packer.Ui)
if config.SkipCompaction && !config.DiskCompression {
return multistep.ActionContinue
}
name := diskName + ".convert"
sourcePath := filepath.Join(config.OutputDir, diskName)
targetPath := filepath.Join(config.OutputDir, name)
command := []string{
"convert",
"-q",
}
if config.DiskCompression {
command = append(command, "-c")
}
command = append(command, []string{
"-f", config.Format,
"-O", config.Format,
sourcePath,
targetPath,
}...,
)
ui.Say("Converting hard drive...")
if err := driver.QemuImg(command...); err != nil {
err := fmt.Errorf("Error converting hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if err := os.Rename(targetPath, sourcePath); err != nil {
err := fmt.Errorf("Error moving converted hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepConvertDisk) Cleanup(state multistep.StateBag) {}

View File

@ -40,7 +40,7 @@ type Config struct {
DiskSize uint `mapstructure:"disk_size"` DiskSize uint `mapstructure:"disk_size"`
DiskTypeId string `mapstructure:"disk_type_id"` DiskTypeId string `mapstructure:"disk_type_id"`
FloppyFiles []string `mapstructure:"floppy_files"` FloppyFiles []string `mapstructure:"floppy_files"`
Format string `mapstruture:"format"` Format string `mapstructure:"format"`
GuestOSType string `mapstructure:"guest_os_type"` GuestOSType string `mapstructure:"guest_os_type"`
Version string `mapstructure:"version"` Version string `mapstructure:"version"`
VMName string `mapstructure:"vm_name"` VMName string `mapstructure:"vm_name"`

View File

@ -10,7 +10,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/mitchellh/osext" "github.com/kardianos/osext"
"github.com/mitchellh/packer/command" "github.com/mitchellh/packer/command"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/packer/plugin" "github.com/mitchellh/packer/packer/plugin"

View File

@ -22,6 +22,9 @@ type Config struct {
// The command used to execute Puppet. // The command used to execute Puppet.
ExecuteCommand string `mapstructure:"execute_command"` ExecuteCommand string `mapstructure:"execute_command"`
// Additional arguments to pass when executing Puppet
ExtraArguments []string `mapstructure:"extra_arguments"`
// Additional facts to set when executing Puppet // Additional facts to set when executing Puppet
Facter map[string]string Facter map[string]string
@ -62,6 +65,7 @@ type ExecuteTemplate struct {
ManifestFile string ManifestFile string
ManifestDir string ManifestDir string
Sudo bool Sudo bool
ExtraArguments string
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
@ -86,6 +90,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
"{{if ne .HieraConfigPath \"\"}}--hiera_config='{{.HieraConfigPath}}' {{end}}" + "{{if ne .HieraConfigPath \"\"}}--hiera_config='{{.HieraConfigPath}}' {{end}}" +
"{{if ne .ManifestDir \"\"}}--manifestdir='{{.ManifestDir}}' {{end}}" + "{{if ne .ManifestDir \"\"}}--manifestdir='{{.ManifestDir}}' {{end}}" +
"--detailed-exitcodes " + "--detailed-exitcodes " +
"{{if ne .ExtraArguments \"\"}}{{.ExtraArguments}} {{end}}" +
"{{.ManifestFile}}" "{{.ManifestFile}}"
} }
@ -218,6 +223,7 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
ModulePath: strings.Join(modulePaths, ":"), ModulePath: strings.Join(modulePaths, ":"),
Sudo: !p.config.PreventSudo, Sudo: !p.config.PreventSudo,
WorkingDir: p.config.WorkingDir, WorkingDir: p.config.WorkingDir,
ExtraArguments: strings.Join(p.config.ExtraArguments, " "),
} }
command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
if err != nil { if err != nil {

View File

@ -1,10 +1,12 @@
package puppetmasterless package puppetmasterless
import ( import (
"github.com/mitchellh/packer/packer"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"testing" "testing"
"github.com/mitchellh/packer/packer"
) )
func testConfig() map[string]interface{} { func testConfig() map[string]interface{} {
@ -177,3 +179,86 @@ func TestProvisionerPrepare_facterFacts(t *testing.T) {
t.Fatalf("err: Default facts are not set in the Puppet provisioner!") t.Fatalf("err: Default facts are not set in the Puppet provisioner!")
} }
} }
func TestProvisionerPrepare_extraArguments(t *testing.T) {
config := testConfig()
// Test with missing parameter
delete(config, "extra_arguments")
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
// Test with malformed value
config["extra_arguments"] = "{{}}"
p = new(Provisioner)
err = p.Prepare(config)
if err == nil {
t.Fatal("should be an error")
}
// Test with valid values
config["extra_arguments"] = []string{
"arg",
}
p = new(Provisioner)
err = p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
func TestProvisionerProvision_extraArguments(t *testing.T) {
config := testConfig()
ui := &packer.MachineReadableUi{
Writer: ioutil.Discard,
}
comm := new(packer.MockCommunicator)
extraArguments := []string{
"--some-arg=yup",
"--some-other-arg",
}
config["extra_arguments"] = extraArguments
// Test with valid values
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
err = p.Provision(ui, comm)
if err != nil {
t.Fatalf("err: %s", err)
}
expectedArgs := strings.Join(extraArguments, " ")
if !strings.Contains(comm.StartCmd.Command, expectedArgs) {
t.Fatalf("Command %q doesn't contain the expected arguments %q", comm.StartCmd.Command, expectedArgs)
}
// Test with missing parameter
delete(config, "extra_arguments")
p = new(Provisioner)
err = p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
err = p.Provision(ui, comm)
if err != nil {
t.Fatalf("err: %s", err)
}
// Check the expected `extra_arguments` position for an empty value
splitCommand := strings.Split(comm.StartCmd.Command, " ")
if "" == splitCommand[len(splitCommand)-2] {
t.Fatalf("Command %q contains an extra-space which may cause arg parsing issues", comm.StartCmd.Command)
}
}

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# #
# This script builds the application from source for multiple platforms. # This script builds the application from source for multiple platforms.
set -e set -e

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
# Get the parent directory of where this script is. # Get the parent directory of where this script is.

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
# Get the parent directory of where this script is. # Get the parent directory of where this script is.

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# Set the tmpdir # Set the tmpdir
if [ -z "$TMPDIR" ]; then if [ -z "$TMPDIR" ]; then

View File

@ -278,7 +278,7 @@ Here is an example using the optional AMI tags. This will add the tags
-> **Note:** Packer uses pre-built AMIs as the source for building images. -> **Note:** Packer uses pre-built AMIs as the source for building images.
These source AMIs may include volumes that are not flagged to be destroyed on These source AMIs may include volumes that are not flagged to be destroyed on
termiation of the instance building the new image. Packer will attempt to clean termination of the instance building the new image. Packer will attempt to clean
up all residual volumes that are not designated by the user to remain after up all residual volumes that are not designated by the user to remain after
termination. If you need to preserve those source volumes, you can overwrite the termination. If you need to preserve those source volumes, you can overwrite the
termination setting by specifying `delete_on_termination=false` in the termination setting by specifying `delete_on_termination=false` in the

View File

@ -101,6 +101,7 @@ Packer to work:
"ec2:DeleteSecurityGroup", "ec2:DeleteSecurityGroup",
"ec2:AuthorizeSecurityGroupIngress", "ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateImage", "ec2:CreateImage",
"ec2:CopyImage",
"ec2:RunInstances", "ec2:RunInstances",
"ec2:TerminateInstances", "ec2:TerminateInstances",
"ec2:StopInstances", "ec2:StopInstances",

View File

@ -136,6 +136,12 @@ builder.
- `disk_size` (integer) - The size, in megabytes, of the hard disk to create - `disk_size` (integer) - The size, in megabytes, of the hard disk to create
for the VM. By default, this is 40000 (about 40 GB). for the VM. By default, this is 40000 (about 40 GB).
- `skip_compaction` (boolean) - Packer compacts the QCOW2 image using `qemu-img convert`.
Set this option to `true` to disable compacting. Defaults to `false`.
- `disk_compression` (boolean) - Apply compression to the QCOW2 disk file
using `qemu-img convert`. Defaults to `false`.
- `floppy_files` (array of strings) - A list of files to place onto a floppy - `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that is attached when the VM is booted. This is most useful for disk that is attached when the VM is booted. This is most useful for
unattended Windows installs, which look for an `Autounattend.xml` file on unattended Windows installs, which look for an `Autounattend.xml` file on

View File

@ -58,10 +58,36 @@ any logging to be enabled.
### Debugging Packer in Powershell/Windows ### Debugging Packer in Powershell/Windows
In Windows you can set the detailed logs environmental variable `PACKER_LOG` or In Windows you can set the detailed logs environmental variable `PACKER_LOG` or
the log variable `PACKER_LOG_PATH` using powershell environment variables. For example: the log variable `PACKER_LOG_PATH` using powershell environment variables. For
example:
$env:PACKER_LOG=1 $env:PACKER_LOG=1
$env:PACKER_LOG_PATH="packerlog.txt" $env:PACKER_LOG_PATH="packerlog.txt"
If you find a bug with Packer, please include the detailed log by using a If you find a bug with Packer, please include the detailed log by using a
service such as [gist](http://gist.github.com). service such as [gist](http://gist.github.com).
## Issues Installing Ubuntu Packages
Issues may arise using and building Ubuntu AMIs where common packages that
*should* be installed from Ubuntu's Main repository are not found during a
provisioner step:
amazon-ebs: No candidate version found for build-essential
amazon-ebs: No candidate version found for build-essential
This, obviously can cause problems where a build is unable to finish
successfully as the proper packages cannot be provisioned correctly. The problem
arises when cloud-init has not finished fully running on the source AMI by the
time that packer starts any provisioning steps.
Adding the following provisioner to the packer template, allows for the
cloud-init process to fully finish before packer starts provisioning the source
AMI.
{
"type": "shell",
"inline": [
"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done"
]
}

View File

@ -59,6 +59,12 @@ Optional parameters:
variables](/docs/templates/configuration-templates.html) available. See variables](/docs/templates/configuration-templates.html) available. See
below for more information. below for more information.
- `extra_arguments` (array of strings) - This is an array of additional options to
pass to the puppet command when executing puppet. This allows for
customization of the `execute_command` without having to completely replace
or include it's contents, making forward-compatible customizations much
easier.
- `facter` (object of key/value strings) - Additional - `facter` (object of key/value strings) - Additional
[facts](http://puppetlabs.com/puppet/related-projects/facter) to make [facts](http://puppetlabs.com/puppet/related-projects/facter) to make
available when Puppet is running. available when Puppet is running.

View File

@ -38,6 +38,9 @@ Optional:
has more detailed usage instructions. By default, no arguments are sent to has more detailed usage instructions. By default, no arguments are sent to
the script. the script.
- `disable_sudo` (boolean) - By default, the bootstrap install command is prefixed with `sudo`. When using a
Docker builder, you will likely want to pass `true` since `sudo` is often not pre-installed.
- `remote_pillar_roots` (string) - The path to your remote [pillar - `remote_pillar_roots` (string) - The path to your remote [pillar
roots](http://docs.saltstack.com/ref/configuration/master.html#pillar-configuration). roots](http://docs.saltstack.com/ref/configuration/master.html#pillar-configuration).
default: `/srv/pillar`. default: `/srv/pillar`.