Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
packer
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kristopher Ruzic
packer
Commits
d854b086
Commit
d854b086
authored
Sep 07, 2013
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
provisioner/puppet-masterless: rework internals, use SCP
parent
7684ee94
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
148 additions
and
168 deletions
+148
-168
provisioner/puppet-masterless/provisioner.go
provisioner/puppet-masterless/provisioner.go
+148
-168
No files found.
provisioner/puppet-masterless/provisioner.go
View file @
d854b086
// This package implements a provisioner for Packer that executes
// This package implements a provisioner for Packer that executes
// Puppet within the remote machine
// Puppet on the remote machine, configured to apply a local manifest
// versus connecting to a Puppet master.
package
puppetmasterless
package
puppetmasterless
import
(
import
(
"bytes"
"fmt"
"fmt"
"github.com/mitchellh/iochan"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/mapstructure"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/packer"
"io"
"log"
"os"
"os"
"path/filepath"
"path/filepath"
"strings"
"strings"
"text/template"
)
)
const
(
type
Config
struct
{
RemoteStagingPath
=
"/tmp/provision/puppet"
common
.
PackerConfig
`mapstructure:",squash"`
DefaultModulePath
=
"modules"
tpl
*
packer
.
ConfigTemplate
DefaultManifestPath
=
"manifests"
DefaultManifestFile
=
"site.pp"
)
var
Ui
packer
.
Ui
// The command used to execute Puppet.
ExecuteCommand
string
`mapstructure:"execute_command"`
type
config
struct
{
// An array of local paths of modules to upload.
// An array of local paths of modules to upload.
ModulePath
string
`mapstructure:"module_path"`
ModulePaths
[]
string
`mapstructure:"module_paths"`
// Path to the manifests
ManifestPath
string
`mapstructure:"manifest_path"`
//
Manifest file
//
The main manifest file to apply to kick off the entire thing.
ManifestFile
string
`mapstructure:"manifest_file"`
ManifestFile
string
`mapstructure:"manifest_file"`
//
Option to avoid sudo use when executing commands. Defaults to false
.
//
If true, `sudo` will NOT be used to execute Puppet
.
PreventSudo
bool
`mapstructure:"prevent_sudo"`
PreventSudo
bool
`mapstructure:"prevent_sudo"`
// The directory where files will be uploaded. Packer requires write
// permissions in this directory.
StagingDir
string
`mapstructure:"staging_directory"`
}
}
type
Provisioner
struct
{
type
Provisioner
struct
{
config
c
onfig
config
C
onfig
}
}
type
ExecuteManifestTemplate
struct
{
type
ExecuteTemplate
struct
{
ModulePath
string
ManifestFile
string
Sudo
bool
Sudo
bool
Modulepath
string
Manifest
string
}
}
func
(
p
*
Provisioner
)
Prepare
(
raws
...
interface
{})
error
{
func
(
p
*
Provisioner
)
Prepare
(
raws
...
interface
{})
error
{
errs
:=
make
([]
error
,
0
)
md
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
raws
...
)
for
_
,
raw
:=
range
raws
{
if
err
!=
nil
{
if
err
:=
mapstructure
.
Decode
(
raw
,
&
p
.
config
);
err
!=
nil
{
return
err
return
err
}
}
p
.
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
}
p
.
config
.
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
if
p
.
config
.
ModulePath
==
""
{
// Accumulate any errors
p
.
config
.
ModulePath
=
DefaultModulePath
errs
:=
common
.
CheckUnusedConfig
(
md
)
// Set some defaults
if
p
.
config
.
ExecuteCommand
==
""
{
p
.
config
.
ExecuteCommand
=
"{{if .Sudo}}sudo {{end}}puppet apply --verbose --modulepath='{{.ModulePath}}' {{.ManifestFile}}"
}
}
if
p
.
config
.
ManifestPath
==
""
{
if
p
.
config
.
StagingDir
==
""
{
p
.
config
.
ManifestPath
=
DefaultManifestPath
p
.
config
.
StagingDir
=
"/tmp/packer-puppet-masterless"
}
}
if
p
.
config
.
ManifestFile
==
""
{
// Templates
p
.
config
.
ManifestFile
=
DefaultManifestFile
templates
:=
map
[
string
]
*
string
{
"staging_dir"
:
&
p
.
config
.
StagingDir
,
}
}
if
p
.
config
.
ModulePath
!=
""
{
for
n
,
ptr
:=
range
templates
{
pFileInfo
,
err
:=
os
.
Stat
(
p
.
config
.
ModulePath
)
var
err
error
*
ptr
,
err
=
p
.
config
.
tpl
.
Process
(
*
ptr
,
nil
)
if
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error processing %s: %s"
,
n
,
err
))
}
}
if
err
!=
nil
||
!
pFileInfo
.
IsDir
()
{
sliceTemplates
:=
map
[
string
][]
string
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"Bad module path '%s': %s"
,
p
.
config
.
ModulePath
,
err
))
"module_paths"
:
p
.
config
.
ModulePaths
,
}
for
n
,
slice
:=
range
sliceTemplates
{
for
i
,
elem
:=
range
slice
{
var
err
error
slice
[
i
],
err
=
p
.
config
.
tpl
.
Process
(
elem
,
nil
)
if
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error processing %s[%d]: %s"
,
n
,
i
,
err
))
}
}
}
}
}
if
p
.
config
.
ManifestPath
!=
""
{
validates
:=
map
[
string
]
*
string
{
pFileInfo
,
err
:=
os
.
Stat
(
p
.
config
.
ManifestPath
)
"execute_command"
:
&
p
.
config
.
ExecuteCommand
,
}
if
err
!=
nil
||
!
pFileInfo
.
IsDir
()
{
for
n
,
ptr
:=
range
validates
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"Bad manifest path '%s': %s"
,
p
.
config
.
ManifestPath
,
err
))
if
err
:=
p
.
config
.
tpl
.
Validate
(
*
ptr
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing %s: %s"
,
n
,
err
))
}
}
}
}
if
p
.
config
.
ManifestFile
!=
""
{
// Validation
path
:=
filepath
.
Join
(
p
.
config
.
ManifestPath
,
p
.
config
.
ManifestFile
)
if
p
.
config
.
ManifestFile
==
""
{
if
_
,
err
:=
os
.
Stat
(
path
);
os
.
IsNotExist
(
err
)
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errs
=
append
(
errs
,
fmt
.
Errorf
(
"No manifest file '%s': %s"
,
path
,
err
))
fmt
.
Errorf
(
"A manifest_file must be specified."
))
}
else
{
info
,
err
:=
os
.
Stat
(
p
.
config
.
ManifestFile
)
if
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"manifest_file is invalid: %s"
,
err
))
}
else
if
info
.
IsDir
()
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"manifest_file must point to a file"
))
}
}
}
}
if
len
(
er
rs
)
>
0
{
if
errs
!=
nil
&&
len
(
errs
.
Erro
rs
)
>
0
{
return
&
packer
.
MultiError
{
errs
}
return
errs
}
}
return
nil
return
nil
}
}
func
(
p
*
Provisioner
)
Provision
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
)
error
{
func
(
p
*
Provisioner
)
Provision
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
)
error
{
var
err
error
ui
.
Message
(
"Creating Puppet staging directory..."
)
Ui
=
ui
if
err
:=
p
.
createDir
(
ui
,
comm
,
p
.
config
.
StagingDir
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Error creating staging directory: %s"
,
err
)
err
=
CreateRemoteDirectory
(
RemoteStagingPath
,
comm
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error creating remote staging directory: %s"
,
err
)
}
}
// Upload all modules
// Upload all modules
ui
.
Say
(
fmt
.
Sprintf
(
"Copying module path: %s"
,
p
.
config
.
ModulePath
))
modulePaths
:=
make
([]
string
,
0
,
len
(
p
.
config
.
ModulePaths
))
err
=
UploadLocalDirectory
(
p
.
config
.
ModulePath
,
comm
)
for
i
,
path
:=
range
p
.
config
.
ModulePaths
{
if
err
!=
nil
{
ui
.
Message
(
fmt
.
Sprintf
(
"Upload local modules from: %s"
,
path
))
targetPath
:=
fmt
.
Sprintf
(
"%s/module-%d"
,
p
.
config
.
StagingDir
,
i
)
if
err
:=
p
.
uploadDirectory
(
ui
,
comm
,
targetPath
,
path
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Error uploading modules: %s"
,
err
)
return
fmt
.
Errorf
(
"Error uploading modules: %s"
,
err
)
}
}
modulePaths
=
append
(
modulePaths
,
targetPath
)
}
// Upload manifests
// Upload manifests
ui
.
Say
(
fmt
.
Sprintf
(
"Copying manifests: %s"
,
p
.
config
.
ManifestPath
)
)
ui
.
Message
(
"Uploading manifests..."
)
err
=
UploadLocalDirectory
(
p
.
config
.
ManifestPath
,
comm
)
remoteManifestFile
,
err
:=
p
.
uploadManifests
(
ui
,
comm
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error uploading manifests: %s"
,
err
)
return
fmt
.
Errorf
(
"Error uploading manifests: %s"
,
err
)
}
}
// Execute Puppet
// Execute Puppet
ui
.
Say
(
"Beginning Puppet run"
)
command
,
err
:=
p
.
config
.
tpl
.
Process
(
p
.
config
.
ExecuteCommand
,
&
ExecuteTemplate
{
ManifestFile
:
remoteManifestFile
,
ModulePath
:
strings
.
Join
(
modulePaths
,
":"
),
Sudo
:
!
p
.
config
.
PreventSudo
,
})
if
err
!=
nil
{
return
err
}
// Compile the command
cmd
:=
&
packer
.
RemoteCmd
{
var
command
bytes
.
Buffer
Command
:
command
,
mpath
:=
filepath
.
Join
(
RemoteStagingPath
,
p
.
config
.
ManifestPath
)
}
manifest
:=
filepath
.
Join
(
mpath
,
p
.
config
.
ManifestFile
)
modulepath
:=
filepath
.
Join
(
RemoteStagingPath
,
p
.
config
.
ModulePath
)
t
:=
template
.
Must
(
template
.
New
(
"puppet-run"
)
.
Parse
(
"{{if .Sudo}}sudo {{end}}puppet apply --verbose --modulepath={{.Modulepath}} {{.Manifest}}"
))
t
.
Execute
(
&
command
,
&
ExecuteManifestTemplate
{
!
p
.
config
.
PreventSudo
,
modulepath
,
manifest
})
err
=
executeCommand
(
command
.
String
(),
comm
)
ui
.
Message
(
"Running Puppet..."
)
if
err
!=
nil
{
if
err
:=
cmd
.
StartWithUi
(
comm
,
ui
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Error running Puppet: %s"
,
err
)
return
err
}
if
cmd
.
ExitStatus
!=
0
{
return
fmt
.
Errorf
(
"Puppet exited with a non-zero exit status: %d"
,
cmd
.
ExitStatus
)
}
}
return
nil
return
nil
...
@@ -147,116 +186,57 @@ func (p *Provisioner) Cancel() {
...
@@ -147,116 +186,57 @@ func (p *Provisioner) Cancel() {
os
.
Exit
(
0
)
os
.
Exit
(
0
)
}
}
func
UploadLocalDirectory
(
localDir
string
,
comm
packer
.
Communicator
)
(
err
error
)
{
func
(
p
*
Provisioner
)
uploadManifests
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
)
(
string
,
error
)
{
visitPath
:=
func
(
path
string
,
f
os
.
FileInfo
,
err
error
)
(
err2
error
)
{
// Create the remote manifests directory...
var
remotePath
=
RemoteStagingPath
+
"/"
+
path
ui
.
Message
(
"Uploading manifests..."
)
if
f
.
IsDir
()
{
remoteManifestsPath
:=
fmt
.
Sprintf
(
"%s/manifests"
,
p
.
config
.
StagingDir
)
// Make remote directory
if
err
:=
p
.
createDir
(
ui
,
comm
,
remoteManifestsPath
);
err
!=
nil
{
err
=
CreateRemoteDirectory
(
remotePath
,
comm
)
return
""
,
fmt
.
Errorf
(
"Error creating manifests directory: %s"
,
err
)
if
err
!=
nil
{
return
err
}
}
else
{
// Upload file to existing directory
file
,
err
:=
os
.
Open
(
path
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error opening file: %s"
,
err
)
}
}
err
=
comm
.
Upload
(
remotePath
,
file
)
// Upload the main manifest
f
,
err
:=
os
.
Open
(
p
.
config
.
ManifestFile
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error uploading file: %s"
,
err
)
return
""
,
err
}
}
return
}
}
defer
f
.
Close
()
log
.
Printf
(
"Uploading directory %s"
,
localDir
)
manifestFilename
:=
filepath
.
Base
(
p
.
config
.
ManifestFile
)
err
=
filepath
.
Walk
(
localDir
,
visitPath
)
remoteManifestFile
:=
fmt
.
Sprintf
(
"%s/%s"
,
remoteManifestsPath
,
manifestFilename
)
if
err
!=
nil
{
if
err
:=
comm
.
Upload
(
remoteManifestFile
,
f
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Error uploading modules %s: %s"
,
localDir
,
err
)
return
""
,
err
}
}
return
nil
return
remoteManifestFile
,
nil
}
}
func
CreateRemoteDirectory
(
path
string
,
comm
packer
.
Communicator
)
(
err
error
)
{
func
(
p
*
Provisioner
)
createDir
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
,
dir
string
)
error
{
log
.
Printf
(
"Creating remote directory: %s "
,
path
)
ui
.
Message
(
fmt
.
Sprintf
(
"Creating directory: %s"
,
dir
))
cmd
:=
&
packer
.
RemoteCmd
{
var
copyCommand
=
[]
string
{
"mkdir -p"
,
path
}
Command
:
fmt
.
Sprintf
(
"mkdir -p '%s'"
,
dir
),
var
cmd
packer
.
RemoteCmd
cmd
.
Command
=
strings
.
Join
(
copyCommand
,
" "
)
var
stdout
bytes
.
Buffer
cmd
.
Stdout
=
&
stdout
// Start the command
if
err
:=
comm
.
Start
(
&
cmd
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Unable to create remote directory %s: %d"
,
path
,
err
)
}
}
// Wait for it to complete
if
err
:=
cmd
.
StartWithUi
(
comm
,
ui
);
err
!=
nil
{
cmd
.
Wait
()
return
err
return
}
func
executeCommand
(
command
string
,
comm
packer
.
Communicator
)
(
err
error
)
{
// Setup the remote command
stdout_r
,
stdout_w
:=
io
.
Pipe
()
stderr_r
,
stderr_w
:=
io
.
Pipe
()
var
cmd
packer
.
RemoteCmd
cmd
.
Command
=
command
cmd
.
Stdout
=
stdout_w
cmd
.
Stderr
=
stderr_w
log
.
Printf
(
"Executing command: %s"
,
cmd
.
Command
)
err
=
comm
.
Start
(
&
cmd
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed executing command: %s"
,
err
)
}
}
exitChan
:=
make
(
chan
int
,
1
)
if
cmd
.
ExitStatus
!=
0
{
stdoutChan
:=
iochan
.
DelimReader
(
stdout_r
,
'\n'
)
return
fmt
.
Errorf
(
"Non-zero exit status."
)
stderrChan
:=
iochan
.
DelimReader
(
stderr_r
,
'\n'
)
go
func
()
{
defer
stdout_w
.
Close
()
defer
stderr_w
.
Close
()
cmd
.
Wait
()
exitChan
<-
cmd
.
ExitStatus
}()
OutputLoop
:
for
{
select
{
case
output
:=
<-
stderrChan
:
Ui
.
Message
(
strings
.
TrimSpace
(
output
))
case
output
:=
<-
stdoutChan
:
Ui
.
Message
(
strings
.
TrimSpace
(
output
))
case
exitStatus
:=
<-
exitChan
:
log
.
Printf
(
"Puppet provisioner exited with status %d"
,
exitStatus
)
if
exitStatus
!=
0
{
return
fmt
.
Errorf
(
"Command exited with non-zero exit status: %d"
,
exitStatus
)
}
}
break
OutputLoop
return
nil
}
}
}
// Make sure we finish off stdout/stderr because we may have gotten
func
(
p
*
Provisioner
)
uploadDirectory
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
,
dst
string
,
src
string
)
error
{
// a message from the exit channel first.
if
err
:=
p
.
createDir
(
ui
,
comm
,
dst
);
err
!=
nil
{
for
output
:=
range
stdoutChan
{
return
err
Ui
.
Message
(
output
)
}
}
for
output
:=
range
stderrChan
{
// Make sure there is a trailing "/" so that the directory isn't
Ui
.
Message
(
output
)
// created on the other side.
if
src
[
len
(
src
)
-
1
]
!=
'/'
{
src
=
src
+
"/"
}
}
return
nil
return
comm
.
UploadDir
(
dst
,
src
,
nil
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment