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
7ff549ec
Commit
7ff549ec
authored
Dec 19, 2013
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #733 from mitchellh/f-vagrant-pp-revamp
Vagrant Post-Processor Refactor + "Include" feature
parents
930b844b
99cbe1fc
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
579 additions
and
751 deletions
+579
-751
command/fix/command.go
command/fix/command.go
+1
-8
command/fix/fixer.go
command/fix/fixer.go
+11
-0
command/fix/fixer_pp_vagrant_override.go
command/fix/fixer_pp_vagrant_override.go
+75
-0
command/fix/fixer_pp_vagrant_override_test.go
command/fix/fixer_pp_vagrant_override_test.go
+79
-0
command/fix/help.go
command/fix/help.go
+6
-1
packer/artifact_mock.go
packer/artifact_mock.go
+16
-6
post-processor/vagrant/aws.go
post-processor/vagrant/aws.go
+21
-133
post-processor/vagrant/aws_test.go
post-processor/vagrant/aws_test.go
+2
-7
post-processor/vagrant/digitalocean.go
post-processor/vagrant/digitalocean.go
+16
-131
post-processor/vagrant/digitalocean_test.go
post-processor/vagrant/digitalocean_test.go
+2
-7
post-processor/vagrant/post-processor.go
post-processor/vagrant/post-processor.go
+171
-87
post-processor/vagrant/post-processor_test.go
post-processor/vagrant/post-processor_test.go
+93
-7
post-processor/vagrant/provider.go
post-processor/vagrant/provider.go
+18
-0
post-processor/vagrant/util.go
post-processor/vagrant/util.go
+0
-8
post-processor/vagrant/virtualbox.go
post-processor/vagrant/virtualbox.go
+22
-158
post-processor/vagrant/virtualbox_test.go
post-processor/vagrant/virtualbox_test.go
+2
-7
post-processor/vagrant/vmware.go
post-processor/vagrant/vmware.go
+7
-120
post-processor/vagrant/vmware_test.go
post-processor/vagrant/vmware_test.go
+2
-7
website/source/docs/post-processors/vagrant.html.markdown
website/source/docs/post-processors/vagrant.html.markdown
+35
-64
No files found.
command/fix/command.go
View file @
7ff549ec
...
...
@@ -49,15 +49,8 @@ func (c Command) Run(env packer.Environment, args []string) int {
// Close the file since we're done with that
tplF
.
Close
()
// Run the template through the various fixers
fixers
:=
[]
string
{
"iso-md5"
,
"createtime"
,
"virtualbox-gaattach"
,
}
input
:=
templateData
for
_
,
name
:=
range
fixers
{
for
_
,
name
:=
range
FixerOrder
{
var
err
error
fixer
,
ok
:=
Fixers
[
name
]
if
!
ok
{
...
...
command/fix/fixer.go
View file @
7ff549ec
...
...
@@ -15,10 +15,21 @@ type Fixer interface {
// Fixers is the map of all available fixers, by name.
var
Fixers
map
[
string
]
Fixer
// FixerOrder is the default order the fixers should be run.
var
FixerOrder
[]
string
func
init
()
{
Fixers
=
map
[
string
]
Fixer
{
"iso-md5"
:
new
(
FixerISOMD5
),
"createtime"
:
new
(
FixerCreateTime
),
"pp-vagrant-override"
:
new
(
FixerVagrantPPOverride
),
"virtualbox-gaattach"
:
new
(
FixerVirtualBoxGAAttach
),
}
FixerOrder
=
[]
string
{
"iso-md5"
,
"createtime"
,
"virtualbox-gaattach"
,
"pp-vagrant-override"
,
}
}
command/fix/fixer_pp_vagrant_override.go
0 → 100644
View file @
7ff549ec
package
fix
import
(
"github.com/mitchellh/mapstructure"
)
// FixerVagrantPPOvveride is a Fixer that replaces the provider-specific
// overrides for the Vagrant post-processor with the new style introduced
// as part of Packer 0.5.0.
type
FixerVagrantPPOverride
struct
{}
func
(
FixerVagrantPPOverride
)
Fix
(
input
map
[
string
]
interface
{})
(
map
[
string
]
interface
{},
error
)
{
// Our template type we'll use for this fixer only
type
template
struct
{
PostProcessors
[]
interface
{}
`mapstructure:"post-processors"`
}
// Decode the input into our structure, if we can
var
tpl
template
if
err
:=
mapstructure
.
Decode
(
input
,
&
tpl
);
err
!=
nil
{
return
nil
,
err
}
// Go through each post-processor and get out all the complex configs
pps
:=
make
([]
map
[
string
]
interface
{},
0
,
len
(
tpl
.
PostProcessors
))
for
_
,
rawPP
:=
range
tpl
.
PostProcessors
{
switch
pp
:=
rawPP
.
(
type
)
{
case
string
:
case
map
[
string
]
interface
{}
:
pps
=
append
(
pps
,
pp
)
case
[]
interface
{}
:
for
_
,
innerRawPP
:=
range
pp
{
if
innerPP
,
ok
:=
innerRawPP
.
(
map
[
string
]
interface
{});
ok
{
pps
=
append
(
pps
,
innerPP
)
}
}
}
}
// Go through each post-processor and make the fix if necessary
possible
:=
[]
string
{
"aws"
,
"digitalocean"
,
"virtualbox"
,
"vmware"
}
for
_
,
pp
:=
range
pps
{
typeRaw
,
ok
:=
pp
[
"type"
]
if
!
ok
{
continue
}
if
typeName
,
ok
:=
typeRaw
.
(
string
);
!
ok
{
continue
}
else
if
typeName
!=
"vagrant"
{
continue
}
overrides
:=
make
(
map
[
string
]
interface
{})
for
_
,
name
:=
range
possible
{
if
_
,
ok
:=
pp
[
name
];
!
ok
{
continue
}
overrides
[
name
]
=
pp
[
name
]
delete
(
pp
,
name
)
}
if
len
(
overrides
)
>
0
{
pp
[
"override"
]
=
overrides
}
}
input
[
"post-processors"
]
=
tpl
.
PostProcessors
return
input
,
nil
}
func
(
FixerVagrantPPOverride
)
Synopsis
()
string
{
return
`Fixes provider-specific overrides for Vagrant post-processor`
}
command/fix/fixer_pp_vagrant_override_test.go
0 → 100644
View file @
7ff549ec
package
fix
import
(
"reflect"
"testing"
)
func
TestFixerVagrantPPOverride_Impl
(
t
*
testing
.
T
)
{
var
_
Fixer
=
new
(
FixerVagrantPPOverride
)
}
func
TestFixerVagrantPPOverride_Fix
(
t
*
testing
.
T
)
{
var
f
FixerVagrantPPOverride
input
:=
map
[
string
]
interface
{}{
"post-processors"
:
[]
interface
{}{
"foo"
,
map
[
string
]
interface
{}{
"type"
:
"vagrant"
,
"aws"
:
map
[
string
]
interface
{}{
"foo"
:
"bar"
,
},
},
map
[
string
]
interface
{}{
"type"
:
"vsphere"
,
},
[]
interface
{}{
map
[
string
]
interface
{}{
"type"
:
"vagrant"
,
"vmware"
:
map
[
string
]
interface
{}{
"foo"
:
"bar"
,
},
},
},
},
}
expected
:=
map
[
string
]
interface
{}{
"post-processors"
:
[]
interface
{}{
"foo"
,
map
[
string
]
interface
{}{
"type"
:
"vagrant"
,
"override"
:
map
[
string
]
interface
{}{
"aws"
:
map
[
string
]
interface
{}{
"foo"
:
"bar"
,
},
},
},
map
[
string
]
interface
{}{
"type"
:
"vsphere"
,
},
[]
interface
{}{
map
[
string
]
interface
{}{
"type"
:
"vagrant"
,
"override"
:
map
[
string
]
interface
{}{
"vmware"
:
map
[
string
]
interface
{}{
"foo"
:
"bar"
,
},
},
},
},
},
}
output
,
err
:=
f
.
Fix
(
input
)
if
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
!
reflect
.
DeepEqual
(
output
,
expected
)
{
t
.
Fatalf
(
"unexpected: %#v
\n
expected: %#v
\n
"
,
output
,
expected
)
}
}
command/fix/help.go
View file @
7ff549ec
...
...
@@ -11,6 +11,11 @@ Usage: packer fix [options] TEMPLATE
Fixes that are run:
iso-md5 Replaces "iso_md5" in builders with newer "iso_checksum"
iso-md5 Replaces "iso_md5" in builders with newer "iso_checksum"
createtime Replaces ".CreateTime" in builder configs with "{{timestamp}}"
virtualbox-gaattach Updates VirtualBox builders using "guest_additions_attach"
to use "guest_additions_mode"
pp-vagrant-override Replaces old-style provider overrides for the Vagrant
post-processor to new-style as of Packer 0.5.0.
`
packer/artifact_mock.go
View file @
7ff549ec
...
...
@@ -2,16 +2,26 @@ package packer
// MockArtifact is an implementation of Artifact that can be used for tests.
type
MockArtifact
struct
{
IdValue
string
DestroyCalled
bool
BuilderIdValue
string
FilesValue
[]
string
IdValue
string
DestroyCalled
bool
}
func
(
*
MockArtifact
)
BuilderId
()
string
{
return
"bid"
func
(
a
*
MockArtifact
)
BuilderId
()
string
{
if
a
.
BuilderIdValue
==
""
{
return
"bid"
}
return
a
.
BuilderIdValue
}
func
(
*
MockArtifact
)
Files
()
[]
string
{
return
[]
string
{
"a"
,
"b"
}
func
(
a
*
MockArtifact
)
Files
()
[]
string
{
if
a
.
FilesValue
==
nil
{
return
[]
string
{
"a"
,
"b"
}
}
return
a
.
FilesValue
}
func
(
a
*
MockArtifact
)
Id
()
string
{
...
...
post-processor/vagrant/aws.go
View file @
7ff549ec
package
vagrant
import
(
"
compress/flate
"
"
bytes
"
"fmt"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"
)
type
AWSBoxConfig
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
OutputPath
string
`mapstructure:"output"`
VagrantfileTemplate
string
`mapstructure:"vagrantfile_template"`
CompressionLevel
string
`mapstructure:"compression_level"`
tpl
*
packer
.
ConfigTemplate
}
type
AWSVagrantfileTemplate
struct
{
Images
map
[
string
]
string
}
type
AWSBoxPostProcessor
struct
{
config
AWSBoxConfig
}
func
(
p
*
AWSBoxPostProcessor
)
Configure
(
raws
...
interface
{})
error
{
md
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
raws
...
)
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
// Accumulate any errors
errs
:=
common
.
CheckUnusedConfig
(
md
)
validates
:=
map
[
string
]
*
string
{
"output"
:
&
p
.
config
.
OutputPath
,
"vagrantfile_template"
:
&
p
.
config
.
VagrantfileTemplate
,
"compression_level"
:
&
p
.
config
.
CompressionLevel
,
}
"text/template"
for
n
,
ptr
:=
range
validates
{
if
err
:=
p
.
config
.
tpl
.
Validate
(
*
ptr
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing %s: %s"
,
n
,
err
))
}
}
"github.com/mitchellh/packer/packer"
)
if
errs
!=
nil
&&
len
(
errs
.
Errors
)
>
0
{
return
errs
}
type
AWSProvider
struct
{}
return
nil
}
func
(
p
*
AWSProvider
)
Process
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
,
dir
string
)
(
vagrantfile
string
,
metadata
map
[
string
]
interface
{},
err
error
)
{
// Create the metadata
metadata
=
map
[
string
]
interface
{}{
"provider"
:
"aws"
}
func
(
p
*
AWSBoxPostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
// Determine the regions...
tplData
:=
&
AWSVagrantfileTemplate
{
// Build up the template data to build our Vagrantfile
tplData
:=
&
awsVagrantfileTemplate
{
Images
:
make
(
map
[
string
]
string
),
}
for
_
,
regions
:=
range
strings
.
Split
(
artifact
.
Id
(),
","
)
{
parts
:=
strings
.
Split
(
regions
,
":"
)
if
len
(
parts
)
!=
2
{
return
nil
,
false
,
fmt
.
Errorf
(
"Poorly formatted artifact ID: %s"
,
artifact
.
Id
())
err
=
fmt
.
Errorf
(
"Poorly formatted artifact ID: %s"
,
artifact
.
Id
())
return
}
tplData
.
Images
[
parts
[
0
]]
=
parts
[
1
]
}
// Compile the output path
outputPath
,
err
:=
p
.
config
.
tpl
.
Process
(
p
.
config
.
OutputPath
,
&
OutputPathTemplate
{
ArtifactId
:
artifact
.
Id
(),
BuildName
:
p
.
config
.
PackerBuildName
,
Provider
:
"aws"
,
})
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Create a temporary directory for us to build the contents of the box in
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"packer"
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
os
.
RemoveAll
(
dir
)
// Create the Vagrantfile from the template
vf
,
err
:=
os
.
Create
(
filepath
.
Join
(
dir
,
"Vagrantfile"
))
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
vf
.
Close
()
vagrantfileContents
:=
defaultAWSVagrantfile
if
p
.
config
.
VagrantfileTemplate
!=
""
{
log
.
Printf
(
"Using vagrantfile template: %s"
,
p
.
config
.
VagrantfileTemplate
)
f
,
err
:=
os
.
Open
(
p
.
config
.
VagrantfileTemplate
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"error opening vagrantfile template: %s"
,
err
)
return
nil
,
false
,
err
}
defer
f
.
Close
()
contents
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"error reading vagrantfile template: %s"
,
err
)
return
nil
,
false
,
err
}
vagrantfileContents
=
string
(
contents
)
}
vagrantfileContents
,
err
=
p
.
config
.
tpl
.
Process
(
vagrantfileContents
,
tplData
)
if
err
!=
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"Error writing Vagrantfile: %s"
,
err
)
}
vf
.
Write
([]
byte
(
vagrantfileContents
))
vf
.
Close
()
var
level
int
=
flate
.
DefaultCompression
if
p
.
config
.
CompressionLevel
!=
""
{
level
,
err
=
strconv
.
Atoi
(
p
.
config
.
CompressionLevel
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
}
// Create the metadata
metadata
:=
map
[
string
]
string
{
"provider"
:
"aws"
}
if
err
:=
WriteMetadata
(
dir
,
metadata
);
err
!=
nil
{
return
nil
,
false
,
err
}
// Compress the directory to the given output path
if
err
:=
DirToBox
(
outputPath
,
dir
,
ui
,
level
);
err
!=
nil
{
err
=
fmt
.
Errorf
(
"error creating box: %s"
,
err
)
return
nil
,
false
,
err
}
// Build up the contents
var
contents
bytes
.
Buffer
t
:=
template
.
Must
(
template
.
New
(
"vf"
)
.
Parse
(
defaultAWSVagrantfile
))
err
=
t
.
Execute
(
&
contents
,
tplData
)
vagrantfile
=
contents
.
String
()
return
}
return
NewArtifact
(
"aws"
,
outputPath
),
true
,
nil
type
awsVagrantfileTemplate
struct
{
Images
map
[
string
]
string
}
var
defaultAWSVagrantfile
=
`
...
...
post-processor/vagrant/aws_test.go
View file @
7ff549ec
package
vagrant
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
TestAWSBoxPostProcessor_ImplementsPostProcessor
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
AWSBoxPostProcessor
{}
if
_
,
ok
:=
raw
.
(
packer
.
PostProcessor
);
!
ok
{
t
.
Fatalf
(
"AWS PostProcessor should be a PostProcessor"
)
}
func
TestAWSProvider_impl
(
t
*
testing
.
T
)
{
var
_
Provider
=
new
(
AWSProvider
)
}
post-processor/vagrant/digitalocean.go
View file @
7ff549ec
package
vagrant
import
(
"
compress/flate
"
"
bytes
"
"fmt"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"text/template"
)
type
DigitalOceanBoxConfig
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
OutputPath
string
`mapstructure:"output"`
VagrantfileTemplate
string
`mapstructure:"vagrantfile_template"`
CompressionLevel
string
`mapstructure:"compression_level"`
tpl
*
packer
.
ConfigTemplate
}
type
DigitalOceanVagrantfileTemplate
struct
{
type
digitalOceanVagrantfileTemplate
struct
{
Image
string
""
Region
string
""
}
type
DigitalOceanBoxPostProcessor
struct
{
config
DigitalOceanBoxConfig
}
func
(
p
*
DigitalOceanBoxPostProcessor
)
Configure
(
rDigitalOcean
...
interface
{})
error
{
md
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
rDigitalOcean
...
)
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
// Accumulate any errors
errs
:=
common
.
CheckUnusedConfig
(
md
)
type
DigitalOceanProvider
struct
{}
validates
:=
map
[
string
]
*
string
{
"output"
:
&
p
.
config
.
OutputPath
,
"vagrantfile_template"
:
&
p
.
config
.
VagrantfileTemplate
,
"compression_level"
:
&
p
.
config
.
CompressionLevel
,
}
for
n
,
ptr
:=
range
validates
{
if
err
:=
p
.
config
.
tpl
.
Validate
(
*
ptr
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing %s: %s"
,
n
,
err
))
}
}
if
errs
!=
nil
&&
len
(
errs
.
Errors
)
>
0
{
return
errs
}
return
nil
}
func
(
p
*
DigitalOceanProvider
)
Process
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
,
dir
string
)
(
vagrantfile
string
,
metadata
map
[
string
]
interface
{},
err
error
)
{
// Create the metadata
metadata
=
map
[
string
]
interface
{}{
"provider"
:
"digital_ocean"
}
func
(
p
*
DigitalOceanBoxPostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
// Determine the image and region...
tplData
:=
&
D
igitalOceanVagrantfileTemplate
{}
tplData
:=
&
d
igitalOceanVagrantfileTemplate
{}
parts
:=
strings
.
Split
(
artifact
.
Id
(),
":"
)
if
len
(
parts
)
!=
2
{
return
nil
,
false
,
fmt
.
Errorf
(
"Poorly formatted artifact ID: %s"
,
artifact
.
Id
())
err
=
fmt
.
Errorf
(
"Poorly formatted artifact ID: %s"
,
artifact
.
Id
())
return
}
tplData
.
Region
=
parts
[
0
]
tplData
.
Image
=
parts
[
1
]
// Compile the output path
outputPath
,
err
:=
p
.
config
.
tpl
.
Process
(
p
.
config
.
OutputPath
,
&
OutputPathTemplate
{
ArtifactId
:
artifact
.
Id
(),
BuildName
:
p
.
config
.
PackerBuildName
,
Provider
:
"digitalocean"
,
})
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Create a temporary directory for us to build the contents of the box in
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"packer"
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
os
.
RemoveAll
(
dir
)
// Create the Vagrantfile from the template
vf
,
err
:=
os
.
Create
(
filepath
.
Join
(
dir
,
"Vagrantfile"
))
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
vf
.
Close
()
vagrantfileContents
:=
defaultDigitalOceanVagrantfile
if
p
.
config
.
VagrantfileTemplate
!=
""
{
log
.
Printf
(
"Using vagrantfile template: %s"
,
p
.
config
.
VagrantfileTemplate
)
f
,
err
:=
os
.
Open
(
p
.
config
.
VagrantfileTemplate
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"error opening vagrantfile template: %s"
,
err
)
return
nil
,
false
,
err
}
defer
f
.
Close
()
contents
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"error reading vagrantfile template: %s"
,
err
)
return
nil
,
false
,
err
}
vagrantfileContents
=
string
(
contents
)
}
vagrantfileContents
,
err
=
p
.
config
.
tpl
.
Process
(
vagrantfileContents
,
tplData
)
if
err
!=
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"Error writing Vagrantfile: %s"
,
err
)
}
vf
.
Write
([]
byte
(
vagrantfileContents
))
vf
.
Close
()
// Create the metadata
metadata
:=
map
[
string
]
string
{
"provider"
:
"digital_ocean"
}
if
err
:=
WriteMetadata
(
dir
,
metadata
);
err
!=
nil
{
return
nil
,
false
,
err
}
// Compress the directory to the given output path
var
level
int
=
flate
.
DefaultCompression
if
p
.
config
.
CompressionLevel
!=
""
{
level
,
err
=
strconv
.
Atoi
(
p
.
config
.
CompressionLevel
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
}
if
err
:=
DirToBox
(
outputPath
,
dir
,
ui
,
level
);
err
!=
nil
{
err
=
fmt
.
Errorf
(
"error creating box: %s"
,
err
)
return
nil
,
false
,
err
}
return
NewArtifact
(
"DigitalOcean"
,
outputPath
),
true
,
nil
// Build up the Vagrantfile
var
contents
bytes
.
Buffer
t
:=
template
.
Must
(
template
.
New
(
"vf"
)
.
Parse
(
defaultDigitalOceanVagrantfile
))
err
=
t
.
Execute
(
&
contents
,
tplData
)
vagrantfile
=
contents
.
String
()
return
}
var
defaultDigitalOceanVagrantfile
=
`
...
...
@@ -159,5 +45,4 @@ Vagrant.configure("2") do |config|
digital_ocean.region = "{{ .Region }}"
end
end
`
post-processor/vagrant/digitalocean_test.go
View file @
7ff549ec
package
vagrant
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
TestDigitalOceanBoxPostProcessor_ImplementsPostProcessor
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
DigitalOceanBoxPostProcessor
{}
if
_
,
ok
:=
raw
.
(
packer
.
PostProcessor
);
!
ok
{
t
.
Fatalf
(
"Digitalocean PostProcessor should be a PostProcessor"
)
}
func
TestDigitalOceanProvider_impl
(
t
*
testing
.
T
)
{
var
_
Provider
=
new
(
DigitalOceanProvider
)
}
post-processor/vagrant/post-processor.go
View file @
7ff549ec
...
...
@@ -4,11 +4,15 @@
package
vagrant
import
(
"compress/flate"
"fmt"
"github.com/mitchellh/mapstructure"
"io/ioutil"
"os"
"path/filepath"
"text/template"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"log"
)
var
builtins
=
map
[
string
]
string
{
...
...
@@ -22,133 +26,213 @@ var builtins = map[string]string{
type
Config
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
OutputPath
string
`mapstructure:"output"`
CompressionLevel
int
`mapstructure:"compression_level"`
Include
[]
string
`mapstructure:"include"`
OutputPath
string
`mapstructure:"output"`
Override
map
[
string
]
interface
{}
VagrantfileTemplate
string
`mapstructure:"vagrantfile_template"`
tpl
*
packer
.
ConfigTemplate
}
type
PostProcessor
struct
{
config
Config
premade
map
[
string
]
packer
.
PostProcessor
extraConfig
map
[
string
]
interface
{}
configs
map
[
string
]
*
Config
}
func
(
p
*
PostProcessor
)
Configure
(
raws
...
interface
{})
error
{
_
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
raws
...
)
if
err
!=
nil
{
p
.
configs
=
make
(
map
[
string
]
*
Config
)
p
.
configs
[
""
]
=
new
(
Config
)
if
err
:=
p
.
configureSingle
(
p
.
configs
[
""
],
raws
...
);
err
!=
nil
{
return
err
}
tpl
,
err
:=
packer
.
NewConfigTemplate
()
// Go over any of the provider-specific overrides and load those up.
for
name
,
override
:=
range
p
.
configs
[
""
]
.
Override
{
subRaws
:=
make
([]
interface
{},
len
(
raws
)
+
1
)
copy
(
subRaws
,
raws
)
subRaws
[
len
(
raws
)]
=
override
config
:=
new
(
Config
)
p
.
configs
[
name
]
=
config
if
err
:=
p
.
configureSingle
(
config
,
subRaws
...
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Error configuring %s: %s"
,
name
,
err
)
}
}
return
nil
}
func
(
p
*
PostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
name
,
ok
:=
builtins
[
artifact
.
BuilderId
()]
if
!
ok
{
return
nil
,
false
,
fmt
.
Errorf
(
"Unknown artifact type, can't build box: %s"
,
artifact
.
BuilderId
())
}
provider
:=
providerForName
(
name
)
if
provider
==
nil
{
// This shouldn't happen since we hard code all of these ourselves
panic
(
fmt
.
Sprintf
(
"bad provider name: %s"
,
name
))
}
config
:=
p
.
configs
[
""
]
if
specificConfig
,
ok
:=
p
.
configs
[
name
];
ok
{
config
=
specificConfig
}
ui
.
Say
(
fmt
.
Sprintf
(
"Creating Vagrant box for '%s' provider"
,
name
))
outputPath
,
err
:=
config
.
tpl
.
Process
(
config
.
OutputPath
,
&
outputPathTemplate
{
ArtifactId
:
artifact
.
Id
(),
BuildName
:
config
.
PackerBuildName
,
Provider
:
name
,
})
if
err
!=
nil
{
return
err
return
nil
,
false
,
err
}
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
// Defaults
if
p
.
config
.
OutputPath
==
""
{
p
.
config
.
OutputPath
=
"packer_{{ .BuildName }}_{{.Provider}}.box"
// Create a temporary directory for us to build the contents of the box in
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"packer"
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
os
.
RemoveAll
(
dir
)
// Copy all of the includes files into the temporary directory
for
_
,
src
:=
range
config
.
Include
{
ui
.
Message
(
fmt
.
Sprintf
(
"Copying from include: %s"
,
src
))
dst
:=
filepath
.
Join
(
dir
,
filepath
.
Base
(
src
))
if
err
:=
CopyContents
(
dst
,
src
);
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error copying include file: %s
\n\n
%s"
,
src
,
err
)
return
nil
,
false
,
err
}
}
// Accumulate any errors
errs
:=
new
(
packer
.
MultiError
)
if
err
:=
tpl
.
Validate
(
p
.
config
.
OutputPath
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing output template: %s"
,
err
))
}
// Store extra configuration we'll send to each post-processor type
p
.
extraConfig
=
make
(
map
[
string
]
interface
{})
p
.
extraConfig
[
"output"
]
=
p
.
config
.
OutputPath
p
.
extraConfig
[
"packer_build_name"
]
=
p
.
config
.
PackerBuildName
p
.
extraConfig
[
"packer_builder_type"
]
=
p
.
config
.
PackerBuilderType
p
.
extraConfig
[
"packer_debug"
]
=
p
.
config
.
PackerDebug
p
.
extraConfig
[
"packer_force"
]
=
p
.
config
.
PackerForce
p
.
extraConfig
[
"packer_user_variables"
]
=
p
.
config
.
PackerUserVars
// TODO(mitchellh): Properly handle multiple raw configs. This isn't
// very pressing at the moment because at the time of this comment
// only the first member of raws can contain the actual type-overrides.
var
mapConfig
map
[
string
]
interface
{}
if
err
:=
mapstructure
.
Decode
(
raws
[
0
],
&
mapConfig
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Failed to decode config: %s"
,
err
))
return
errs
// Run the provider processing step
vagrantfile
,
metadata
,
err
:=
provider
.
Process
(
ui
,
artifact
,
dir
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Write the metadata we got
if
err
:=
WriteMetadata
(
dir
,
metadata
);
err
!=
nil
{
return
nil
,
false
,
err
}
p
.
premade
=
make
(
map
[
string
]
packer
.
PostProcessor
)
for
k
,
raw
:=
range
mapConfig
{
pp
,
err
:=
p
.
subPostProcessor
(
k
,
raw
,
p
.
extraConfig
)
// Write our Vagrantfile
var
customVagrantfile
string
if
config
.
VagrantfileTemplate
!=
""
{
ui
.
Message
(
fmt
.
Sprintf
(
"Using custom Vagrantfile: %s"
,
config
.
VagrantfileTemplate
))
customBytes
,
err
:=
ioutil
.
ReadFile
(
config
.
VagrantfileTemplate
)
if
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
err
)
continue
return
nil
,
false
,
err
}
if
pp
==
nil
{
continue
}
customVagrantfile
=
string
(
customBytes
)
}
p
.
premade
[
k
]
=
pp
f
,
err
:=
os
.
Create
(
filepath
.
Join
(
dir
,
"Vagrantfile"
))
if
err
!=
nil
{
return
nil
,
false
,
err
}
if
len
(
errs
.
Errors
)
>
0
{
return
errs
t
:=
template
.
Must
(
template
.
New
(
"root"
)
.
Parse
(
boxVagrantfileContents
))
err
=
t
.
Execute
(
f
,
&
vagrantfileTemplate
{
ProviderVagrantfile
:
vagrantfile
,
CustomVagrantfile
:
customVagrantfile
,
})
f
.
Close
()
if
err
!=
nil
{
return
nil
,
false
,
err
}
return
nil
// Create the box
if
err
:=
DirToBox
(
outputPath
,
dir
,
ui
,
config
.
CompressionLevel
);
err
!=
nil
{
return
nil
,
false
,
err
}
return
nil
,
false
,
nil
}
func
(
p
*
PostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
ppName
,
ok
:=
builtins
[
artifact
.
BuilderId
()]
if
!
ok
{
return
nil
,
false
,
fmt
.
Errorf
(
"Unknown artifact type, can't build box: %s"
,
artifact
.
BuilderId
())
func
(
p
*
PostProcessor
)
configureSingle
(
config
*
Config
,
raws
...
interface
{})
error
{
md
,
err
:=
common
.
DecodeConfig
(
config
,
raws
...
)
if
err
!=
nil
{
return
err
}
// Use the premade PostProcessor if we have one. Otherwise, we
// create it and configure it here.
pp
,
ok
:=
p
.
premade
[
ppName
]
if
!
ok
{
log
.
Printf
(
"Premade post-processor for '%s' not found. Creating."
,
ppName
)
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
config
.
tpl
.
UserVars
=
config
.
PackerUserVars
var
err
error
pp
,
err
=
p
.
subPostProcessor
(
ppName
,
nil
,
p
.
extraConfig
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Defaults
if
config
.
OutputPath
==
""
{
config
.
OutputPath
=
"packer_{{ .BuildName }}_{{.Provider}}.box"
}
if
pp
==
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"Vagrant box post-processor not found: %s"
,
ppName
)
found
:=
false
for
_
,
k
:=
range
md
.
Keys
{
if
k
==
"compression_level"
{
found
=
true
break
}
}
ui
.
Say
(
fmt
.
Sprintf
(
"Creating Vagrant box for '%s' provider"
,
ppName
))
return
pp
.
PostProcess
(
ui
,
artifact
)
}
if
!
found
{
config
.
CompressionLevel
=
flate
.
DefaultCompression
}
// Accumulate any errors
errs
:=
common
.
CheckUnusedConfig
(
md
)
validates
:=
map
[
string
]
*
string
{
"output"
:
&
config
.
OutputPath
,
"vagrantfile_template"
:
&
config
.
VagrantfileTemplate
,
}
func
(
p
*
PostProcessor
)
subPostProcessor
(
key
string
,
specific
interface
{},
extra
map
[
string
]
interface
{})
(
packer
.
PostProcessor
,
error
)
{
pp
:=
keyToPostProcessor
(
key
)
if
pp
==
nil
{
return
nil
,
nil
for
n
,
ptr
:=
range
validates
{
if
err
:=
config
.
tpl
.
Validate
(
*
ptr
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing %s: %s"
,
n
,
err
))
}
}
if
err
:=
pp
.
Configure
(
extra
,
specific
);
err
!=
nil
{
return
nil
,
err
if
err
s
!=
nil
&&
len
(
errs
.
Errors
)
>
0
{
return
errs
}
return
pp
,
nil
return
nil
}
// keyToPostProcessor maps a configuration key to the actual post-processor
// it will be configuring. This returns a new instance of that post-processor.
func
keyToPostProcessor
(
key
string
)
packer
.
PostProcessor
{
switch
key
{
case
"aws"
:
return
new
(
AWSBoxPostProcessor
)
case
"digitalocean"
:
return
new
(
DigitalOceanBoxPostProcessor
)
func
providerForName
(
name
string
)
Provider
{
switch
name
{
case
"virtualbox"
:
return
new
(
VBoxBoxPostProcessor
)
case
"vmware"
:
return
new
(
VMwareBoxPostProcessor
)
return
new
(
VBoxProvider
)
default
:
return
nil
}
}
// OutputPathTemplate is the structure that is availalable within the
// OutputPath variables.
type
outputPathTemplate
struct
{
ArtifactId
string
BuildName
string
Provider
string
}
type
vagrantfileTemplate
struct
{
ProviderVagrantfile
string
CustomVagrantfile
string
}
const
boxVagrantfileContents
string
=
`
# The contents below were provided by the Packer Vagrant post-processor
{{ .ProviderVagrantfile }}
# The contents below (if any) are custom contents provided by the
# Packer template during image build.
{{ .CustomVagrantfile }}
`
post-processor/vagrant/post-processor_test.go
View file @
7ff549ec
package
vagrant
import
(
"bytes"
"compress/flate"
"github.com/mitchellh/packer/packer"
"strings"
"testing"
)
...
...
@@ -9,15 +12,55 @@ func testConfig() map[string]interface{} {
return
map
[
string
]
interface
{}{}
}
func
testPP
(
t
*
testing
.
T
)
*
PostProcessor
{
var
p
PostProcessor
if
err
:=
p
.
Configure
(
testConfig
());
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
return
&
p
}
func
testUi
()
*
packer
.
BasicUi
{
return
&
packer
.
BasicUi
{
Reader
:
new
(
bytes
.
Buffer
),
Writer
:
new
(
bytes
.
Buffer
),
}
}
func
TestPostProcessor_ImplementsPostProcessor
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
PostProcessor
{}
if
_
,
ok
:=
raw
.
(
packer
.
PostProcessor
);
!
ok
{
t
.
Fatalf
(
"AWS PostProcessor should be a PostProcessor"
)
var
_
packer
.
PostProcessor
=
new
(
PostProcessor
)
}
func
TestPostProcessorPrepare_compressionLevel
(
t
*
testing
.
T
)
{
var
p
PostProcessor
// Default
c
:=
testConfig
()
delete
(
c
,
"compression_level"
)
if
err
:=
p
.
Configure
(
c
);
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
config
:=
p
.
configs
[
""
]
if
config
.
CompressionLevel
!=
flate
.
DefaultCompression
{
t
.
Fatalf
(
"bad: %#v"
,
config
.
CompressionLevel
)
}
// Set
c
=
testConfig
()
c
[
"compression_level"
]
=
7
if
err
:=
p
.
Configure
(
c
);
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
config
=
p
.
configs
[
""
]
if
config
.
CompressionLevel
!=
7
{
t
.
Fatalf
(
"bad: %#v"
,
config
.
CompressionLevel
)
}
}
func
Test
BuilderPrepare_O
utputPath
(
t
*
testing
.
T
)
{
func
Test
PostProcessorPrepare_o
utputPath
(
t
*
testing
.
T
)
{
var
p
PostProcessor
// Default
...
...
@@ -36,14 +79,57 @@ func TestBuilderPrepare_OutputPath(t *testing.T) {
}
}
func
Test
BuilderPrepare_PPConfig
(
t
*
testing
.
T
)
{
func
Test
PostProcessorPrepare_subConfigs
(
t
*
testing
.
T
)
{
var
p
PostProcessor
// Default
c
:=
testConfig
()
c
[
"aws"
]
=
map
[
string
]
interface
{}{}
c
[
"compression_level"
]
=
42
c
[
"vagrantfile_template"
]
=
"foo"
c
[
"override"
]
=
map
[
string
]
interface
{}{
"aws"
:
map
[
string
]
interface
{}{
"compression_level"
:
7
,
},
}
err
:=
p
.
Configure
(
c
)
if
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
p
.
configs
[
""
]
.
CompressionLevel
!=
42
{
t
.
Fatalf
(
"bad: %#v"
,
p
.
configs
[
""
]
.
CompressionLevel
)
}
if
p
.
configs
[
""
]
.
VagrantfileTemplate
!=
"foo"
{
t
.
Fatalf
(
"bad: %#v"
,
p
.
configs
[
""
]
.
VagrantfileTemplate
)
}
if
p
.
configs
[
"aws"
]
.
CompressionLevel
!=
7
{
t
.
Fatalf
(
"bad: %#v"
,
p
.
configs
[
"aws"
]
.
CompressionLevel
)
}
if
p
.
configs
[
"aws"
]
.
VagrantfileTemplate
!=
"foo"
{
t
.
Fatalf
(
"bad: %#v"
,
p
.
configs
[
"aws"
]
.
VagrantfileTemplate
)
}
}
func
TestPostProcessorPostProcess_badId
(
t
*
testing
.
T
)
{
artifact
:=
&
packer
.
MockArtifact
{
BuilderIdValue
:
"invalid.packer"
,
}
_
,
_
,
err
:=
testPP
(
t
)
.
PostProcess
(
testUi
(),
artifact
)
if
!
strings
.
Contains
(
err
.
Error
(),
"artifact type"
)
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
func
TestProviderForName
(
t
*
testing
.
T
)
{
if
v
,
ok
:=
providerForName
(
"virtualbox"
)
.
(
*
VBoxProvider
);
!
ok
{
t
.
Fatalf
(
"bad: %#v"
,
v
)
}
if
providerForName
(
"nope"
)
!=
nil
{
t
.
Fatal
(
"should be nil if bad provider"
)
}
}
post-processor/vagrant/provider.go
0 → 100644
View file @
7ff549ec
package
vagrant
import
(
"github.com/mitchellh/packer/packer"
)
// Provider is the interface that each provider must implement in order
// to package the artifacts into a Vagrant-compatible box.
type
Provider
interface
{
// Process is called to process an artifact into a Vagrant box. The
// artifact is given as well as the temporary directory path to
// put things.
//
// The Provider should return the contents for the Vagrantfile,
// any metadata (including the provider type in that), and an error
// if any.
Process
(
packer
.
Ui
,
packer
.
Artifact
,
string
)
(
vagrantfile
string
,
metadata
map
[
string
]
interface
{},
err
error
)
}
post-processor/vagrant/util.go
View file @
7ff549ec
...
...
@@ -13,14 +13,6 @@ import (
"path/filepath"
)
// OutputPathTemplate is the structure that is availalable within the
// OutputPath variables.
type
OutputPathTemplate
struct
{
ArtifactId
string
BuildName
string
Provider
string
}
// Copies a file by copying the contents of the file to another place.
func
CopyContents
(
dst
,
src
string
)
error
{
srcF
,
err
:=
os
.
Open
(
src
)
...
...
post-processor/vagrant/virtualbox.go
View file @
7ff549ec
...
...
@@ -2,10 +2,8 @@ package vagrant
import
(
"archive/tar"
"compress/flate"
"errors"
"fmt"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"io"
"io/ioutil"
...
...
@@ -15,183 +13,49 @@ import (
"regexp"
)
type
VBoxBoxConfig
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
type
VBoxProvider
struct
{}
Include
[]
string
`mapstructure:"include"`
OutputPath
string
`mapstructure:"output"`
VagrantfileTemplate
string
`mapstructure:"vagrantfile_template"`
CompressionLevel
int
`mapstructure:"compression_level"`
tpl
*
packer
.
ConfigTemplate
}
type
VBoxVagrantfileTemplate
struct
{
BaseMacAddress
string
}
type
VBoxBoxPostProcessor
struct
{
config
VBoxBoxConfig
}
func
(
p
*
VBoxBoxPostProcessor
)
Configure
(
raws
...
interface
{})
error
{
md
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
raws
...
)
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
// Defaults
found
:=
false
for
_
,
k
:=
range
md
.
Keys
{
println
(
k
)
if
k
==
"compression_level"
{
found
=
true
break
}
}
if
!
found
{
p
.
config
.
CompressionLevel
=
flate
.
DefaultCompression
}
// Accumulate any errors
errs
:=
common
.
CheckUnusedConfig
(
md
)
validates
:=
map
[
string
]
*
string
{
"output"
:
&
p
.
config
.
OutputPath
,
"vagrantfile_template"
:
&
p
.
config
.
VagrantfileTemplate
,
}
for
n
,
ptr
:=
range
validates
{
if
err
:=
p
.
config
.
tpl
.
Validate
(
*
ptr
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing %s: %s"
,
n
,
err
))
}
}
if
errs
!=
nil
&&
len
(
errs
.
Errors
)
>
0
{
return
errs
}
return
nil
}
func
(
p
*
VBoxBoxPostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
var
err
error
// Compile the output path
outputPath
,
err
:=
p
.
config
.
tpl
.
Process
(
p
.
config
.
OutputPath
,
&
OutputPathTemplate
{
ArtifactId
:
artifact
.
Id
(),
BuildName
:
p
.
config
.
PackerBuildName
,
Provider
:
"virtualbox"
,
})
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Create a temporary directory for us to build the contents of the box in
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"packer"
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
os
.
RemoveAll
(
dir
)
// Copy all of the includes files into the temporary directory
for
_
,
src
:=
range
p
.
config
.
Include
{
ui
.
Message
(
fmt
.
Sprintf
(
"Copying from include: %s"
,
src
))
dst
:=
filepath
.
Join
(
dir
,
filepath
.
Base
(
src
))
if
err
:=
CopyContents
(
dst
,
src
);
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error copying include file: %s
\n\n
%s"
,
src
,
err
)
return
nil
,
false
,
err
}
}
func
(
p
*
VBoxProvider
)
Process
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
,
dir
string
)
(
vagrantfile
string
,
metadata
map
[
string
]
interface
{},
err
error
)
{
// Create the metadata
metadata
=
map
[
string
]
interface
{}{
"provider"
:
"virtualbox"
}
// Copy all of the original contents into the temporary directory
for
_
,
path
:=
range
artifact
.
Files
()
{
// We treat OVA files specially, we unpack those into the temporary
// directory so we can get the resulting disk and OVF.
if
extension
:=
filepath
.
Ext
(
path
);
extension
==
".ova"
{
ui
.
Message
(
fmt
.
Sprintf
(
"Unpacking OVA: %s"
,
path
))
if
err
:
=
DecompressOva
(
dir
,
path
);
err
!=
nil
{
return
nil
,
false
,
err
if
err
=
DecompressOva
(
dir
,
path
);
err
!=
nil
{
return
}
}
else
{
ui
.
Message
(
fmt
.
Sprintf
(
"Copying from artifact: %s"
,
path
))
dstPath
:=
filepath
.
Join
(
dir
,
filepath
.
Base
(
path
))
if
err
:
=
CopyContents
(
dstPath
,
path
);
err
!=
nil
{
return
nil
,
false
,
err
if
err
=
CopyContents
(
dstPath
,
path
);
err
!=
nil
{
return
}
}
}
// Create the Vagrantfile from the template
tplData
:=
&
VBoxVagrantfileTemplate
{}
tplData
.
BaseMacAddress
,
err
=
p
.
findBaseMacAddress
(
dir
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
vf
,
err
:=
os
.
Create
(
filepath
.
Join
(
dir
,
"Vagrantfile"
))
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
vf
.
Close
()
vagrantfileContents
:=
defaultVBoxVagrantfile
if
p
.
config
.
VagrantfileTemplate
!=
""
{
ui
.
Message
(
fmt
.
Sprintf
(
"Using Vagrantfile template: %s"
,
p
.
config
.
VagrantfileTemplate
))
f
,
err
:=
os
.
Open
(
p
.
config
.
VagrantfileTemplate
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
f
.
Close
()
contents
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
vagrantfileContents
=
string
(
contents
)
}
vagrantfileContents
,
err
=
p
.
config
.
tpl
.
Process
(
vagrantfileContents
,
tplData
)
if
err
!=
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"Error writing Vagrantfile: %s"
,
err
)
}
vf
.
Write
([]
byte
(
vagrantfileContents
))
vf
.
Close
()
// Create the metadata
metadata
:=
map
[
string
]
string
{
"provider"
:
"virtualbox"
}
if
err
:=
WriteMetadata
(
dir
,
metadata
);
err
!=
nil
{
return
nil
,
false
,
err
}
// Rename the OVF file to box.ovf, as required by Vagrant
ui
.
Message
(
"Renaming the OVF to box.ovf..."
)
if
err
:
=
p
.
renameOVF
(
dir
);
err
!=
nil
{
return
nil
,
false
,
err
if
err
=
p
.
renameOVF
(
dir
);
err
!=
nil
{
return
}
// Compress the directory to the given output path
ui
.
Message
(
fmt
.
Sprintf
(
"Compressing box..."
))
if
err
:=
DirToBox
(
outputPath
,
dir
,
ui
,
p
.
config
.
CompressionLevel
);
err
!=
nil
{
return
nil
,
false
,
err
// Create the Vagrantfile from the template
var
baseMacAddress
string
baseMacAddress
,
err
=
p
.
findBaseMacAddress
(
dir
)
if
err
!=
nil
{
return
}
return
NewArtifact
(
"virtualbox"
,
outputPath
),
false
,
nil
vagrantfile
=
fmt
.
Sprintf
(
vboxVagrantfile
,
baseMacAddress
)
return
}
func
(
p
*
VBox
BoxPostProcesso
r
)
findOvf
(
dir
string
)
(
string
,
error
)
{
func
(
p
*
VBox
Provide
r
)
findOvf
(
dir
string
)
(
string
,
error
)
{
log
.
Println
(
"Looking for OVF in artifact..."
)
file_matches
,
err
:=
filepath
.
Glob
(
filepath
.
Join
(
dir
,
"*.ovf"
))
if
err
!=
nil
{
...
...
@@ -209,7 +73,7 @@ func (p *VBoxBoxPostProcessor) findOvf(dir string) (string, error) {
return
file_matches
[
0
],
err
}
func
(
p
*
VBox
BoxPostProcesso
r
)
renameOVF
(
dir
string
)
error
{
func
(
p
*
VBox
Provide
r
)
renameOVF
(
dir
string
)
error
{
log
.
Println
(
"Looking for OVF to rename..."
)
ovf
,
err
:=
p
.
findOvf
(
dir
)
if
err
!=
nil
{
...
...
@@ -220,7 +84,7 @@ func (p *VBoxBoxPostProcessor) renameOVF(dir string) error {
return
os
.
Rename
(
ovf
,
filepath
.
Join
(
dir
,
"box.ovf"
))
}
func
(
p
*
VBox
BoxPostProcesso
r
)
findBaseMacAddress
(
dir
string
)
(
string
,
error
)
{
func
(
p
*
VBox
Provide
r
)
findBaseMacAddress
(
dir
string
)
(
string
,
error
)
{
log
.
Println
(
"Looking for OVF for base mac address..."
)
ovf
,
err
:=
p
.
findOvf
(
dir
)
if
err
!=
nil
{
...
...
@@ -295,8 +159,8 @@ func DecompressOva(dir, src string) error {
return
nil
}
var
defaultVB
oxVagrantfile
=
`
var
vb
oxVagrantfile
=
`
Vagrant.configure("2") do |config|
config.vm.base_mac = "{{ .BaseMacAddress }}
"
config.vm.base_mac = "%s
"
end
`
post-processor/vagrant/virtualbox_test.go
View file @
7ff549ec
package
vagrant
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
TestVBoxBoxPostProcessor_ImplementsPostProcessor
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
VBoxBoxPostProcessor
{}
if
_
,
ok
:=
raw
.
(
packer
.
PostProcessor
);
!
ok
{
t
.
Fatalf
(
"VBox PostProcessor should be a PostProcessor"
)
}
func
TestVBoxProvider_impl
(
t
*
testing
.
T
)
{
var
_
Provider
=
new
(
VBoxProvider
)
}
post-processor/vagrant/vmware.go
View file @
7ff549ec
package
vagrant
import
(
"compress/flate"
"fmt"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)
type
VMwareBoxConfig
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
type
VMwareProvider
struct
{}
OutputPath
string
`mapstructure:"output"`
VagrantfileTemplate
string
`mapstructure:"vagrantfile_template"`
CompressionLevel
string
`mapstructure:"compression_level"`
tpl
*
packer
.
ConfigTemplate
}
type
VMwareBoxPostProcessor
struct
{
config
VMwareBoxConfig
}
func
(
p
*
VMwareBoxPostProcessor
)
Configure
(
raws
...
interface
{})
error
{
md
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
raws
...
)
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
// Accumulate any errors
errs
:=
common
.
CheckUnusedConfig
(
md
)
validates
:=
map
[
string
]
*
string
{
"output"
:
&
p
.
config
.
OutputPath
,
"vagrantfile_template"
:
&
p
.
config
.
VagrantfileTemplate
,
"compression_level"
:
&
p
.
config
.
CompressionLevel
,
}
for
n
,
ptr
:=
range
validates
{
if
err
:=
p
.
config
.
tpl
.
Validate
(
*
ptr
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error parsing %s: %s"
,
n
,
err
))
}
}
if
errs
!=
nil
&&
len
(
errs
.
Errors
)
>
0
{
return
errs
}
return
nil
}
func
(
p
*
VMwareBoxPostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
// Compile the output path
outputPath
,
err
:=
p
.
config
.
tpl
.
Process
(
p
.
config
.
OutputPath
,
&
OutputPathTemplate
{
ArtifactId
:
artifact
.
Id
(),
BuildName
:
p
.
config
.
PackerBuildName
,
Provider
:
"vmware"
,
})
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Create a temporary directory for us to build the contents of the box in
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"packer"
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
os
.
RemoveAll
(
dir
)
func
(
p
*
VMwareProvider
)
Process
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
,
dir
string
)
(
vagrantfile
string
,
metadata
map
[
string
]
interface
{},
err
error
)
{
// Create the metadata
metadata
=
map
[
string
]
interface
{}{
"provider"
:
"vmware_desktop"
}
// Copy all of the original contents into the temporary directory
for
_
,
path
:=
range
artifact
.
Files
()
{
ui
.
Message
(
fmt
.
Sprintf
(
"Copying: %s"
,
path
))
dstPath
:=
filepath
.
Join
(
dir
,
filepath
.
Base
(
path
))
if
err
:=
CopyContents
(
dstPath
,
path
);
err
!=
nil
{
return
nil
,
false
,
err
}
}
if
p
.
config
.
VagrantfileTemplate
!=
""
{
f
,
err
:=
os
.
Open
(
p
.
config
.
VagrantfileTemplate
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
defer
f
.
Close
()
contents
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
// Create the Vagrantfile from the template
vf
,
err
:=
os
.
Create
(
filepath
.
Join
(
dir
,
"Vagrantfile"
))
if
err
!=
nil
{
return
nil
,
false
,
err
if
err
=
CopyContents
(
dstPath
,
path
);
err
!=
nil
{
return
}
defer
vf
.
Close
()
vagrantfileContents
,
err
:=
p
.
config
.
tpl
.
Process
(
string
(
contents
),
nil
)
if
err
!=
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"Error writing Vagrantfile: %s"
,
err
)
}
vf
.
Write
([]
byte
(
vagrantfileContents
))
vf
.
Close
()
}
var
level
int
=
flate
.
DefaultCompression
if
p
.
config
.
CompressionLevel
!=
""
{
level
,
err
=
strconv
.
Atoi
(
p
.
config
.
CompressionLevel
)
if
err
!=
nil
{
return
nil
,
false
,
err
}
}
// Create the metadata
metadata
:=
map
[
string
]
string
{
"provider"
:
"vmware_desktop"
}
if
err
:=
WriteMetadata
(
dir
,
metadata
);
err
!=
nil
{
return
nil
,
false
,
err
}
// Compress the directory to the given output path
ui
.
Message
(
fmt
.
Sprintf
(
"Compressing box..."
))
if
err
:=
DirToBox
(
outputPath
,
dir
,
ui
,
level
);
err
!=
nil
{
return
nil
,
false
,
err
}
return
NewArtifact
(
"vmware"
,
outputPath
),
false
,
nil
return
}
post-processor/vagrant/vmware_test.go
View file @
7ff549ec
package
vagrant
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
TestVMwareBoxPostProcessor_ImplementsPostProcessor
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
VMwareBoxPostProcessor
{}
if
_
,
ok
:=
raw
.
(
packer
.
PostProcessor
);
!
ok
{
t
.
Fatalf
(
"VMware PostProcessor should be a PostProcessor"
)
}
func
TestVMwareProvider_impl
(
t
*
testing
.
T
)
{
var
_
Provider
=
new
(
VMwareProvider
)
}
website/source/docs/post-processors/vagrant.html.markdown
View file @
7ff549ec
...
...
@@ -18,7 +18,7 @@ documentation on [using post-processors](/docs/templates/post-processors.html)
in templates. This knowledge will be expected for the remainder of
this document.
Because Vagrant boxes are
[
provider-specific
](
#
)
,
Because Vagrant boxes are
[
provider-specific
](
http://docs.vagrantup.com/v2/boxes/format.html
)
,
the Vagrant post-processor is hardcoded to understand how to convert
the artifacts of certain builders into proper boxes for their
respective providers.
...
...
@@ -27,6 +27,7 @@ Currently, the Vagrant post-processor can create boxes for the following
providers.
*
AWS
*
DigitalOcean
*
VirtualBox
*
VMware
...
...
@@ -47,82 +48,52 @@ However, if you want to configure things a bit more, the post-processor
does expose some configuration options. The available options are listed
below, with more details about certain options in following sections.
*
`compression_level`
(integer) - An integer repesenting the
compression level to use when creating the Vagrant box. Valid
values range from 0 to 9, with 0 being no compression and 9 being
the best compression. By default, compression is enabled at level 1.
*
`include`
(array of strings) - Paths to files to include in the
Vagrant box. These files will each be copied into the top level directory
of the Vagrant box (regardless of their paths). They can then be used
from the Vagrantfile.
*
`output`
(string) - The full path to the box file that will be created
by this post-processor. This is a
[
configuration template
](
/docs/templates/configuration-templates.html
)
.
The variable
`Provider`
is replaced by the Vagrant provider the box is for.
The variable
`ArtifactId`
is replaced by the ID of the input artifact.
The variable
`BuildName`
is replaced with the name of the build.
By default, the value of this config is
`packer_{{.BuildName}}_{{.Provider}}.box`
.
*
`aws`
,
`virtualbox`
, or
`vmware`
(objects) - These are used to configure
the specific options for certain providers. A reference of available
configuration parameters for each is in the section below.
### AWS Provider
The AWS provider itself can be configured with specific options:
*
`vagrantfile_template`
(string) - Path to a template to use for the
Vagrantfile that is packaged with the box. The contents of the file must be a valid Go
[
text template
](
http://golang.org/pkg/text/template
)
. By default
this is a template that simply sets the AMIs for the various regions
of the AWS build.
*
`compression_level`
(integer) - An integer repesenting the
compression level to use when creating the Vagrant box. Valid
values range from 0 to 9, with 0 being no compression and 9 being
the best compression.
The
`vagrantfile_template`
has the
`Images`
variable which is a map
of region (string) to AMI ID (string). An example Vagrantfile template for
AWS is shown below. The example simply sets the AMI for each region.
```
Vagrant.configure("2") do |config|
config.vm.provider "aws" do |aws|
{{ range $region, $ami := .Images }}
aws.region_config "{{ $region }}", ami: "{{ $ami }}"
{{ end }}
end
end
```
Vagrantfile that is packaged with the box.
##
# VirtualBox Provider
##
Provider-Specific Overrides
The VirtualBox provider itself can be configured with specific options:
*
`vagrantfile_template`
(string) - Path to a template to use for the
Vagrantfile that is packaged with the box. The contents of the file must be a valid Go
[
text template
](
http://golang.org/pkg/text/template
)
. By default this is
a template that just sets the base MAC address so that networking works.
If you have a Packer template with multiple builder types within it,
you may want to configure the box creation for each type a little differently.
For example, the contents of the Vagrantfile for a Vagrant box for AWS might
be different from the contents of the Vagrantfile you want for VMware.
The post-processor lets you do this.
*
`compression_level`
(integer) - An integer repesenting the
compression level to use when creating the Vagrant box. Valid
values range from 0 to 9, with 0 being no compression and 9 being
the best compression.
Specify overrides within the
`override`
configuration by provider name:
The
`vagrantfile_template`
has the
`BaseMACAddress`
variable which is a string
containing the MAC address of the first network interface. This must be set
in the Vagrantfile for networking to work properly with Vagrant. An example
Vagrantfile template is shown below:
```
json
{
"type"
:
"vagrant"
,
"compression_level"
:
1
,
"override"
:
{
"vmware"
:
{
"compression_level"
:
0
}
}
}
```
Vagrant.configure("2") do |config|
config.vm.base_mac = "{{ .BaseMacAddress }}"
end
```
### VMware Provider
The VMware provider itself can be configured with specific options:
*
`vagrantfile_template`
(string) - Path to a template to use for the
Vagrantfile that is packaged with the box. The contents of the file must be a valid Go
[
text template
](
http://golang.org/pkg/text/template
)
. By default no
Vagrantfile is packaged with the box. Note that currently no variables
are available in the template, but this may change in the future.
In the example above, the compression level will be set to 1 except for
VMware, where it will be set to 0.
*
`compression_level`
(integer) - An integer repesenting the
compression level to use when creating the Vagrant box. Valid
values range from 0 to 9, with 0 being no compression and 9 being
the best compression.
The available provider names are:
`aws`
,
`digitalocean`
,
`virtualbox`
,
and
`vmware`
.
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