Compare commits
166 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28c80a648c | |||
| 9c72861438 | |||
| ac75d5329e | |||
| 37c20e2bf0 | |||
| dec1b65a20 | |||
| bb6db46962 | |||
| d8cde46e76 | |||
| f3f3d1fe73 | |||
| 2f5f6c159b | |||
| 56745e14f5 | |||
| bf0c326cd5 | |||
| b2811a8252 | |||
| d00271aab3 | |||
| 4da4150abe | |||
| 3a681d0c0c | |||
| 518ad704b7 | |||
| fb39fa2cc6 | |||
| e3ab74e09f | |||
| 39a8ba1365 | |||
| 241903d0b0 | |||
| c615539929 | |||
| 9365a43179 | |||
| ae064207d5 | |||
| 224bb78175 | |||
| f27505626f | |||
| 9b97726621 | |||
| a49f263e90 | |||
| 618d2f3158 | |||
| 4dccc54191 | |||
| e7092ff5c5 | |||
| 29e6194e49 | |||
| 8e3559c3b1 | |||
| c614bb703d | |||
| 733376fa54 | |||
| 985cd94952 | |||
| 6343d8f16a | |||
| a3bf467378 | |||
| b3eacc5c2b | |||
| 78174dae4e | |||
| da20c36454 | |||
| 28a13111b8 | |||
| d2339b7ccc | |||
| 4128a49f7a | |||
| 7e64e90670 | |||
| 034040d2a7 | |||
| ff2e07771e | |||
| 1de5171857 | |||
| 683d6a73ec | |||
| 0c0ff5a25b | |||
| d99a1fab86 | |||
| 183beedb12 | |||
| 132b289b0e | |||
| a6269671ec | |||
| 1c71eaaa91 | |||
| 775450f46a | |||
| bd6c31c2d9 | |||
| da749e2470 | |||
| fcb7967bf5 | |||
| 750e09d51d | |||
| eaf8550e50 | |||
| 6d6b3e1ac2 | |||
| db10f7c0ce | |||
| cc9549eac8 | |||
| 0cee01261c | |||
| 98e7f2a341 | |||
| ed463bccda | |||
| c416f6e14b | |||
| 872e78d5b0 | |||
| 7ca5984128 | |||
| 0ca03f09c1 | |||
| 67a1703768 | |||
| 61c083c0fd | |||
| 0869c9fe64 | |||
| 5dd8ae45c7 | |||
| 03850cafc6 | |||
| 6ca48fa3c8 | |||
| ebd4cb761d | |||
| 3239d157c1 | |||
| 548f2ced1c | |||
| 3abec94936 | |||
| 5ff86ae15f | |||
| ac444accb1 | |||
| fd2d44c212 | |||
| 8fd673ff9f | |||
| d1961e782b | |||
| 31357df126 | |||
| 6c2e6c41d9 | |||
| caa518b294 | |||
| 51804e9132 | |||
| 61753d37cb | |||
| 2ee2850c1a | |||
| 95f9391fd6 | |||
| 6dd36075b2 | |||
| 782d693075 | |||
| d3ed169175 | |||
| 5c82ac2835 | |||
| aa3a336e72 | |||
| 2498ad02c8 | |||
| 8657b1e9d8 | |||
| 0904f4ed56 | |||
| bfcd004497 | |||
| 9e6207f5bc | |||
| eef260a11b | |||
| c1ad38155c | |||
| 6c7a7b6068 | |||
| 98db68e36c | |||
| b315e470c8 | |||
| 0a2e54feaf | |||
| 1aef60ff76 | |||
| 062b2270dd | |||
| 1b9d0dcddd | |||
| 4a60e469e9 | |||
| 677498a55c | |||
| 95dd79740f | |||
| 79de517e04 | |||
| 7b64723a11 | |||
| 21d50916b6 | |||
| 69777d8ad2 | |||
| 41e160ccda | |||
| aab5ca7059 | |||
| 60fabe64e1 | |||
| a3fa7cdce3 | |||
| 3eaf7f38b0 | |||
| 5c64f7f7cf | |||
| 94e1f83070 | |||
| eee066371a | |||
| aa84f9eeb5 | |||
| 355364ce4c | |||
| 18e29e0f2b | |||
| 6644d76982 | |||
| 016d916d83 | |||
| d8b6c94012 | |||
| daf563e210 | |||
| e112d9b288 | |||
| d740bad640 | |||
| 4d003aa5a3 | |||
| 586cab11ee | |||
| 88fac0b49c | |||
| 5896d96bdb | |||
| fe0fde195d | |||
| 9805c10c87 | |||
| 8ae0cfc759 | |||
| dd1fdc722a | |||
| 7b9d48799e | |||
| d5c17734b8 | |||
| dd97a60c9b | |||
| c537623bc6 | |||
| 6bb480e2f7 | |||
| eba28519db | |||
| 1831a09055 | |||
| f765d57009 | |||
| a2c9b2da8f | |||
| 7af5d5419a | |||
| fbf7db0418 | |||
| def6f8aefc | |||
| 18438cf291 | |||
| 8f0e28fae1 | |||
| 49664ca9c6 | |||
| 67fed8e802 | |||
| a019575026 | |||
| 32f469dc9a | |||
| c0bc74990b | |||
| 3cc90768a2 | |||
| 4244a6ce8d | |||
| 0ed15e039a | |||
| b06158aeea |
@@ -1,3 +1,51 @@
|
||||
## 0.8.2 (July 17, 2015)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* builder/docker: Add option to use a Pty [GH-2425]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: Fix crash when `min_packer_version` is specified in a template. [GH-2385]
|
||||
* builder/amazon: Fix EC2 devices being included in EBS mappings [GH-2459]
|
||||
* builder/googlecompute: Fix default name for GCE images [GH-2400]
|
||||
* builder/null: Fix error message with missing ssh_host [GH-2407]
|
||||
* builder/virtualbox: Use --portcount on VirtualBox 5.x [GH-2438]
|
||||
* provisioner/puppet: Packer now correctly handles a directory for manifest_file [GH-2463]
|
||||
* provisioner/winrm: Fix potential crash with WinRM [GH-2416]
|
||||
|
||||
## 0.8.1 (July 2, 2015)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* builder/amazon: When debug mode is enabled, the Windows administrator
|
||||
password for Windows instances will be shown [GH-2351]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: `min_packer_version` field in configs work [GH-2356]
|
||||
* core: The `build_name` and `build_type` functions work in provisioners [GH-2367]
|
||||
* core: Handle timeout in SSH handshake [GH-2333]
|
||||
* command/build: Fix reading configuration from stdin [GH-2366]
|
||||
* builder/amazon: Fix issue with sharing AMIs when using `ami_users` [GH-2308]
|
||||
* builder/amazon: Fix issue when using multiple Security Groups [GH-2381]
|
||||
* builder/amazon: Fix for tag creation when creating new ec2 instance [GH-2317]
|
||||
* builder/amazon: Fix issue with creating AMIs with multiple device mappings [GH-2320]
|
||||
* builder/amazon: Fix failing AMI snapshot tagging when copying to other
|
||||
regions [GH-2316]
|
||||
* builder/amazon: Fix setting AMI launch permissions [GH-2348]
|
||||
* builder/amazon: Fix spot instance cleanup to remove the correct request [GH-2327]
|
||||
* builder/amazon: Fix `bundle_prefix` not interpolating `timestamp` [GH-2352]
|
||||
* builder/amazon-instance: Fix issue with creating AMIs without specifying a
|
||||
virtualization type [GH-2330]
|
||||
* builder/digitalocean: Fix builder using private IP instead of public IP [GH-2339]
|
||||
* builder/google: Set default communicator settings properly [GH-2353]
|
||||
* builder/vmware-iso: Setting `checksum_type` to `none` for ESX builds
|
||||
now works [GH-2323]
|
||||
* provisioner/chef: Use knife config file vs command-line params to
|
||||
clean up nodes so full set of features can be used [GH-2306]
|
||||
* post-processor/compress: Fixed crash in compress post-processor plugin [GH-2311]
|
||||
|
||||
## 0.8.0 (June 23, 2015)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
+2
-2
@@ -53,8 +53,8 @@ it raises the chances we can quickly merge or address your contributions.
|
||||
If you have never worked with Go before, you will have to complete the
|
||||
following steps in order to be able to compile and test Packer.
|
||||
|
||||
1. Install Go. Make sure the Go version is at least Go 1.2. Packer will not work with anything less than
|
||||
Go 1.2. On a Mac, you can `brew install go` to install Go 1.2.
|
||||
1. Install Go. Make sure the Go version is at least Go 1.4. Packer will not work with anything less than
|
||||
Go 1.4. On a Mac, you can `brew install go` to install Go 1.4.
|
||||
|
||||
2. Set and export the `GOPATH` environment variable and update your `PATH`.
|
||||
For example, you can add to your `.bash_profile`.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Packer
|
||||
|
||||
[](https://travis-ci.org/mitchellh/packer)
|
||||
[](https://ci.appveyor.com/project/hashicorp/packer)
|
||||
|
||||
* Website: http://www.packer.io
|
||||
* IRC: `#packer-tool` on Freenode
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# appveyor.yml reference : http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
version: "{build}"
|
||||
|
||||
skip_tags: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
matrix:
|
||||
- GOARCH: 386
|
||||
GOVERSION: 1.4.2
|
||||
- GOARCH: amd64
|
||||
GOVERSION: 1.4.2
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\mitchellh\packer
|
||||
|
||||
install:
|
||||
- set Path=c:\go\bin;%Path%
|
||||
- echo %Path%
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-%GOARCH%.msi
|
||||
- msiexec /i go%GOVERSION%.windows-%GOARCH%.msi /q
|
||||
- go version
|
||||
- go env
|
||||
- go get -d -v -t ./...
|
||||
|
||||
build_script:
|
||||
- go test -v ./...
|
||||
|
||||
test: off
|
||||
|
||||
deploy: off
|
||||
@@ -1,6 +1,8 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
@@ -29,27 +31,30 @@ func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
|
||||
|
||||
for _, blockDevice := range b {
|
||||
ebsBlockDevice := &ec2.EBSBlockDevice{
|
||||
VolumeType: &blockDevice.VolumeType,
|
||||
VolumeSize: &blockDevice.VolumeSize,
|
||||
DeleteOnTermination: &blockDevice.DeleteOnTermination,
|
||||
VolumeType: aws.String(blockDevice.VolumeType),
|
||||
VolumeSize: aws.Long(blockDevice.VolumeSize),
|
||||
DeleteOnTermination: aws.Boolean(blockDevice.DeleteOnTermination),
|
||||
}
|
||||
|
||||
// IOPS is only valid for SSD Volumes
|
||||
if blockDevice.VolumeType != "" && blockDevice.VolumeType != "standard" && blockDevice.VolumeType != "gp2" {
|
||||
ebsBlockDevice.IOPS = &blockDevice.IOPS
|
||||
ebsBlockDevice.IOPS = aws.Long(blockDevice.IOPS)
|
||||
}
|
||||
|
||||
// You cannot specify Encrypted if you specify a Snapshot ID
|
||||
if blockDevice.SnapshotId != "" {
|
||||
ebsBlockDevice.SnapshotID = &blockDevice.SnapshotId
|
||||
ebsBlockDevice.SnapshotID = aws.String(blockDevice.SnapshotId)
|
||||
} else if blockDevice.Encrypted {
|
||||
ebsBlockDevice.Encrypted = &blockDevice.Encrypted
|
||||
ebsBlockDevice.Encrypted = aws.Boolean(blockDevice.Encrypted)
|
||||
}
|
||||
|
||||
mapping := &ec2.BlockDeviceMapping{
|
||||
EBS: ebsBlockDevice,
|
||||
DeviceName: &blockDevice.DeviceName,
|
||||
VirtualName: &blockDevice.VirtualName,
|
||||
DeviceName: aws.String(blockDevice.DeviceName),
|
||||
VirtualName: aws.String(blockDevice.VirtualName),
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
|
||||
mapping.EBS = ebsBlockDevice
|
||||
}
|
||||
|
||||
if blockDevice.NoDevice {
|
||||
|
||||
@@ -17,17 +17,15 @@ func TestBlockDevice(t *testing.T) {
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VirtualName: "ephemeral0",
|
||||
SnapshotId: "snap-1234",
|
||||
VolumeType: "standard",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
IOPS: 1000,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
VirtualName: aws.String("ephemeral0"),
|
||||
VirtualName: aws.String(""),
|
||||
EBS: &ec2.EBSBlockDevice{
|
||||
SnapshotID: aws.String("snap-1234"),
|
||||
VolumeType: aws.String("standard"),
|
||||
@@ -55,7 +53,6 @@ func TestBlockDevice(t *testing.T) {
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VirtualName: "ephemeral0",
|
||||
VolumeType: "io1",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
@@ -64,7 +61,7 @@ func TestBlockDevice(t *testing.T) {
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
VirtualName: aws.String("ephemeral0"),
|
||||
VirtualName: aws.String(""),
|
||||
EBS: &ec2.EBSBlockDevice{
|
||||
VolumeType: aws.String("io1"),
|
||||
VolumeSize: aws.Long(8),
|
||||
@@ -73,6 +70,17 @@ func TestBlockDevice(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VirtualName: "ephemeral0",
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
VirtualName: aws.String("ephemeral0"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -84,11 +92,14 @@ func TestBlockDevice(t *testing.T) {
|
||||
expected := []*ec2.BlockDeviceMapping{tc.Result}
|
||||
got := blockDevices.BuildAMIDevices()
|
||||
if !reflect.DeepEqual(expected, got) {
|
||||
t.Fatalf("Bad block device, \nexpected: %s\n\ngot: %s", awsutil.StringValue(expected), awsutil.StringValue(got))
|
||||
t.Fatalf("Bad block device, \nexpected: %s\n\ngot: %s",
|
||||
awsutil.StringValue(expected), awsutil.StringValue(got))
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, blockDevices.BuildLaunchDevices()) {
|
||||
t.Fatalf("Bad block device, \nexpected: %s\n\ngot: %s", awsutil.StringValue(expected), awsutil.StringValue(blockDevices.BuildLaunchDevices()))
|
||||
t.Fatalf("Bad block device, \nexpected: %s\n\ngot: %s",
|
||||
awsutil.StringValue(expected),
|
||||
awsutil.StringValue(blockDevices.BuildLaunchDevices()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,13 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||
// Declare list of resources to tag
|
||||
resourceIds := []*string{&ami}
|
||||
|
||||
regionconn := ec2.New(&aws.Config{
|
||||
Credentials: ec2conn.Config.Credentials,
|
||||
Region: region,
|
||||
})
|
||||
|
||||
// Retrieve image list for given AMI
|
||||
imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{
|
||||
imageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{
|
||||
ImageIDs: resourceIds,
|
||||
})
|
||||
|
||||
@@ -63,11 +68,6 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||
}
|
||||
}
|
||||
|
||||
regionconn := ec2.New(&aws.Config{
|
||||
Credentials: ec2conn.Config.Credentials,
|
||||
Region: region,
|
||||
})
|
||||
|
||||
_, err = regionconn.CreateTags(&ec2.CreateTagsInput{
|
||||
Resources: resourceIds,
|
||||
Tags: ec2Tags,
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
// StepGetPassword reads the password from a Windows server and sets it
|
||||
// on the WinRM config.
|
||||
type StepGetPassword struct {
|
||||
Debug bool
|
||||
Comm *communicator.Config
|
||||
Timeout time.Duration
|
||||
}
|
||||
@@ -85,6 +86,13 @@ WaitLoop:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In debug-mode, we output the password
|
||||
if s.Debug {
|
||||
ui.Message(fmt.Sprintf(
|
||||
"Password (since debug is enabled): %s", s.Comm.WinRMPassword))
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
||||
@@ -44,21 +44,35 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
|
||||
|
||||
if len(s.Groups) > 0 {
|
||||
groups := make([]*string, len(s.Groups))
|
||||
adds := make([]*ec2.LaunchPermission, len(s.Groups))
|
||||
addGroups := &ec2.ModifyImageAttributeInput{
|
||||
LaunchPermission: &ec2.LaunchPermissionModifications{},
|
||||
}
|
||||
|
||||
for i, g := range s.Groups {
|
||||
groups[i] = &g
|
||||
}
|
||||
options["groups"] = &ec2.ModifyImageAttributeInput{
|
||||
UserGroups: groups,
|
||||
groups[i] = aws.String(g)
|
||||
adds[i] = &ec2.LaunchPermission{
|
||||
Group: aws.String(g),
|
||||
}
|
||||
}
|
||||
addGroups.UserGroups = groups
|
||||
addGroups.LaunchPermission.Add = adds
|
||||
|
||||
options["groups"] = addGroups
|
||||
}
|
||||
|
||||
if len(s.Users) > 0 {
|
||||
users := make([]*string, len(s.Users))
|
||||
adds := make([]*ec2.LaunchPermission, len(s.Users))
|
||||
for i, u := range s.Users {
|
||||
users[i] = &u
|
||||
users[i] = aws.String(u)
|
||||
adds[i] = &ec2.LaunchPermission{UserID: aws.String(u)}
|
||||
}
|
||||
options["users"] = &ec2.ModifyImageAttributeInput{
|
||||
UserIDs: users,
|
||||
LaunchPermission: &ec2.LaunchPermissionModifications{
|
||||
Add: adds,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
|
||||
securityGroupIds := make([]*string, len(tempSecurityGroupIds))
|
||||
for i, sg := range tempSecurityGroupIds {
|
||||
securityGroupIds[i] = &sg
|
||||
securityGroupIds[i] = aws.String(sg)
|
||||
}
|
||||
|
||||
userData := s.UserData
|
||||
@@ -256,7 +256,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
ec2Tags := make([]*ec2.Tag, 1, len(s.Tags)+1)
|
||||
ec2Tags[0] = &ec2.Tag{Key: aws.String("Name"), Value: aws.String("Packer Builder")}
|
||||
for k, v := range s.Tags {
|
||||
ec2Tags = append(ec2Tags, &ec2.Tag{Key: &k, Value: &v})
|
||||
ec2Tags = append(ec2Tags, &ec2.Tag{Key: aws.String(k), Value: aws.String(v)})
|
||||
}
|
||||
|
||||
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
@@ -296,7 +296,7 @@ func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) {
|
||||
if s.spotRequest != nil {
|
||||
ui.Say("Cancelling the spot request...")
|
||||
input := &ec2.CancelSpotInstanceRequestsInput{
|
||||
SpotInstanceRequestIDs: []*string{s.spotRequest.InstanceID},
|
||||
SpotInstanceRequestIDs: []*string{s.spotRequest.SpotInstanceRequestID},
|
||||
}
|
||||
if _, err := ec2conn.CancelSpotInstanceRequests(input); err != nil {
|
||||
ui.Error(fmt.Sprintf("Error cancelling the spot request, may still be around: %s", err))
|
||||
|
||||
@@ -119,6 +119,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Tags: b.config.RunTags,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/packer/builder/amazon/common"
|
||||
builderT "github.com/mitchellh/packer/helper/builder/testing"
|
||||
@@ -44,6 +45,71 @@ func TestBuilderAcc_forceDeregister(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_amiSharing(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccSharing,
|
||||
Check: checkAMISharing(2, "932021504756", "all"),
|
||||
})
|
||||
}
|
||||
|
||||
func checkAMISharing(count int, uid, group string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packer.Artifact) error {
|
||||
if len(artifacts) > 1 {
|
||||
return fmt.Errorf("more than 1 artifact")
|
||||
}
|
||||
|
||||
// Get the actual *Artifact pointer so we can access the AMIs directly
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, ok := artifactRaw.(*common.Artifact)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown artifact: %#v", artifactRaw)
|
||||
}
|
||||
|
||||
// describe the image, get block devices with a snapshot
|
||||
ec2conn, _ := testEC2Conn()
|
||||
imageResp, err := ec2conn.DescribeImageAttribute(&ec2.DescribeImageAttributeInput{
|
||||
Attribute: aws.String("launchPermission"),
|
||||
ImageID: aws.String(artifact.Amis["us-east-1"]),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving Image Attributes for AMI Artifact (%#v) in AMI Sharing Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
// Launch Permissions are in addition to the userid that created it, so if
|
||||
// you add 3 additional ami_users, you expect 2 Launch Permissions here
|
||||
if len(imageResp.LaunchPermissions) != count {
|
||||
return fmt.Errorf("Error in Image Attributes, expected (%d) Launch Permissions, got (%d)", count, len(imageResp.LaunchPermissions))
|
||||
}
|
||||
|
||||
userFound := false
|
||||
for _, lp := range imageResp.LaunchPermissions {
|
||||
if lp.UserID != nil && uid == *lp.UserID {
|
||||
userFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !userFound {
|
||||
return fmt.Errorf("Error in Image Attributes, expected User ID (%s) to have Launch Permissions, but was not found", uid)
|
||||
}
|
||||
|
||||
groupFound := false
|
||||
for _, lp := range imageResp.LaunchPermissions {
|
||||
if lp.Group != nil && group == *lp.Group {
|
||||
groupFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !groupFound {
|
||||
return fmt.Errorf("Error in Image Attributes, expected Group ID (%s) to have Launch Permissions, but was not found", group)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func checkRegionCopy(regions []string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packer.Artifact) error {
|
||||
if len(artifacts) > 1 {
|
||||
@@ -138,6 +204,22 @@ const testBuilderAccForceDeregister = `
|
||||
}
|
||||
`
|
||||
|
||||
// share with catsby
|
||||
const testBuilderAccSharing = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami": "ami-76b2a71e",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-test {{timestamp}}",
|
||||
"ami_users":["932021504756"],
|
||||
"ami_groups":["all"]
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
func buildForceDeregisterConfig(name, flag string) string {
|
||||
return fmt.Sprintf(testBuilderAccForceDeregister, name, flag)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,12 @@ type Builder struct {
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
configs := make([]interface{}, len(raws)+1)
|
||||
configs[0] = map[string]interface{}{
|
||||
"bundle_prefix": "image-{{timestamp}}",
|
||||
}
|
||||
copy(configs[1:], raws)
|
||||
|
||||
b.config.ctx.Funcs = awscommon.TemplateFuncs
|
||||
err := config.Decode(&b.config, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
@@ -60,7 +66,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
"bundle_vol_command",
|
||||
},
|
||||
},
|
||||
}, raws...)
|
||||
}, configs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,10 +75,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
b.config.BundleDestination = "/tmp"
|
||||
}
|
||||
|
||||
if b.config.BundlePrefix == "" {
|
||||
b.config.BundlePrefix = "image-{{timestamp}}"
|
||||
}
|
||||
|
||||
if b.config.BundleUploadCommand == "" {
|
||||
if b.config.IamInstanceProfile != "" {
|
||||
b.config.BundleUploadCommand = "sudo -i -n ec2-upload-bundle " +
|
||||
@@ -204,6 +206,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Tags: b.config.RunTags,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
|
||||
@@ -130,7 +130,6 @@ func TestBuilderPrepare_BundlePrefix(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
config["bundle_prefix"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
|
||||
@@ -3,6 +3,7 @@ package instance
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
@@ -20,15 +21,17 @@ func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Say("Registering the AMI...")
|
||||
registerOpts := &ec2.RegisterImageInput{
|
||||
ImageLocation: &manifestPath,
|
||||
Name: &config.AMIName,
|
||||
Name: aws.String(config.AMIName),
|
||||
BlockDeviceMappings: config.BlockDevices.BuildAMIDevices(),
|
||||
VirtualizationType: &config.AMIVirtType,
|
||||
}
|
||||
|
||||
if config.AMIVirtType != "" {
|
||||
registerOpts.VirtualizationType = aws.String(config.AMIVirtType)
|
||||
}
|
||||
|
||||
// Set SriovNetSupport to "simple". See http://goo.gl/icuXh5
|
||||
if config.AMIEnhancedNetworking {
|
||||
simple := "simple"
|
||||
registerOpts.SRIOVNetSupport = &simple
|
||||
registerOpts.SRIOVNetSupport = aws.String("simple")
|
||||
}
|
||||
|
||||
registerResp, err := ec2conn.RegisterImage(registerOpts)
|
||||
|
||||
@@ -14,11 +14,11 @@ func (s *stepDropletInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*godo.Client)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(Config)
|
||||
dropletId := state.Get("droplet_id").(int)
|
||||
dropletID := state.Get("droplet_id").(int)
|
||||
|
||||
ui.Say("Waiting for droplet to become active...")
|
||||
|
||||
err := waitForDropletState("active", dropletId, client, c.StateTimeout)
|
||||
err := waitForDropletState("active", dropletID, client, c.StateTimeout)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for droplet to become active: %s", err)
|
||||
state.Put("error", err)
|
||||
@@ -27,7 +27,7 @@ func (s *stepDropletInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
}
|
||||
|
||||
// Set the IP on the state for later
|
||||
droplet, _, err := client.Droplets.Get(dropletId)
|
||||
droplet, _, err := client.Droplets.Get(dropletID)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error retrieving droplet: %s", err)
|
||||
state.Put("error", err)
|
||||
@@ -39,13 +39,28 @@ func (s *stepDropletInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
invalid := droplet.Networks == nil ||
|
||||
len(droplet.Networks.V4) == 0
|
||||
if invalid {
|
||||
err := fmt.Errorf("IPv4 address not found for droplet!")
|
||||
err := fmt.Errorf("IPv4 address not found for droplet")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Find a public IPv4 network
|
||||
foundNetwork := false
|
||||
for _, network := range droplet.Networks.V4 {
|
||||
if network.Type == "public" {
|
||||
state.Put("droplet_ip", network.IPAddress)
|
||||
foundNetwork = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundNetwork {
|
||||
err := fmt.Errorf("Count not find a public IPv4 address for this droplet")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("droplet_ip", droplet.Networks.V4[0].IPAddress)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ type Communicator struct {
|
||||
HostDir string
|
||||
ContainerDir string
|
||||
Version *version.Version
|
||||
|
||||
Config *Config
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
@@ -45,7 +45,11 @@ func (c *Communicator) Start(remote *packer.RemoteCmd) error {
|
||||
|
||||
var cmd *exec.Cmd
|
||||
if c.canExec() {
|
||||
cmd = exec.Command("docker", "exec", "-i", c.ContainerId, "/bin/sh")
|
||||
if c.Config.Pty {
|
||||
cmd = exec.Command("docker", "exec", "-i", "-t", c.ContainerId, "/bin/sh")
|
||||
} else {
|
||||
cmd = exec.Command("docker", "exec", "-i", c.ContainerId, "/bin/sh")
|
||||
}
|
||||
} else {
|
||||
cmd = exec.Command("docker", "attach", c.ContainerId)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ type Config struct {
|
||||
LoginUsername string `mapstructure:"login_username"`
|
||||
LoginPassword string `mapstructure:"login_password"`
|
||||
LoginServer string `mapstructure:"login_server"`
|
||||
Pty bool
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
type StepConnectDocker struct{}
|
||||
|
||||
func (s *StepConnectDocker) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
containerId := state.Get("container_id").(string)
|
||||
driver := state.Get("driver").(Driver)
|
||||
tempDir := state.Get("temp_dir").(string)
|
||||
@@ -25,6 +26,7 @@ func (s *StepConnectDocker) Run(state multistep.StateBag) multistep.StepAction {
|
||||
HostDir: tempDir,
|
||||
ContainerDir: "/packer-files",
|
||||
Version: version,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
state.Put("communicator", comm)
|
||||
|
||||
@@ -59,6 +59,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var errs *packer.MultiError
|
||||
|
||||
// Set defaults.
|
||||
if c.Network == "" {
|
||||
c.Network = "default"
|
||||
@@ -73,7 +75,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
}
|
||||
|
||||
if c.ImageName == "" {
|
||||
c.ImageName = "packer-{{timestamp}}"
|
||||
img, err := interpolate.Render("packer-{{timestamp}}", nil)
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Unable to parse image name: %s ", err))
|
||||
c.ImageName = img
|
||||
}
|
||||
}
|
||||
|
||||
if c.InstanceName == "" {
|
||||
@@ -96,7 +103,9 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
c.Comm.SSHUsername = "root"
|
||||
}
|
||||
|
||||
var errs *packer.MultiError
|
||||
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
|
||||
errs = packer.MultiErrorAppend(errs, es...)
|
||||
}
|
||||
|
||||
// Process required parameters.
|
||||
if c.ProjectId == "" {
|
||||
|
||||
@@ -2,48 +2,10 @@ package googlecompute
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testConfig(t *testing.T) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"account_file": testAccountFile(t),
|
||||
"project_id": "hashicorp",
|
||||
"source_image": "foo",
|
||||
"zone": "us-east-1a",
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigStruct(t *testing.T) *Config {
|
||||
c, warns, errs := NewConfig(testConfig(t))
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", len(warns))
|
||||
}
|
||||
if errs != nil {
|
||||
t.Fatalf("bad: %#v", errs)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func testConfigErr(t *testing.T, warns []string, err error, extra string) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("should error: %s", extra)
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigOk(t *testing.T, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigPrepare(t *testing.T) {
|
||||
cases := []struct {
|
||||
Key string
|
||||
@@ -152,6 +114,83 @@ func TestConfigPrepare(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigDefaults(t *testing.T) {
|
||||
cases := []struct {
|
||||
Read func(c *Config) interface{}
|
||||
Value interface{}
|
||||
}{
|
||||
{
|
||||
func(c *Config) interface{} { return c.Comm.Type },
|
||||
"ssh",
|
||||
},
|
||||
|
||||
{
|
||||
func(c *Config) interface{} { return c.Comm.SSHPort },
|
||||
22,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw := testConfig(t)
|
||||
|
||||
c, warns, errs := NewConfig(raw)
|
||||
testConfigOk(t, warns, errs)
|
||||
|
||||
actual := tc.Read(c)
|
||||
if actual != tc.Value {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageName(t *testing.T) {
|
||||
c, _, _ := NewConfig(testConfig(t))
|
||||
if strings.Contains(c.ImageName, "{{timestamp}}") {
|
||||
t.Errorf("ImageName should be interpolated; found %s", c.ImageName)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper stuff below
|
||||
|
||||
func testConfig(t *testing.T) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"account_file": testAccountFile(t),
|
||||
"project_id": "hashicorp",
|
||||
"source_image": "foo",
|
||||
"zone": "us-east-1a",
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigStruct(t *testing.T) *Config {
|
||||
c, warns, errs := NewConfig(testConfig(t))
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", len(warns))
|
||||
}
|
||||
if errs != nil {
|
||||
t.Fatalf("bad: %#v", errs)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func testConfigErr(t *testing.T, warns []string, err error, extra string) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("should error: %s", extra)
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigOk(t *testing.T, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccountFile(t *testing.T) string {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
|
||||
@@ -33,7 +33,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
}
|
||||
if c.CommConfig.SSHHost == "" {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("host must be specified"))
|
||||
fmt.Errorf("ssh_host must be specified"))
|
||||
}
|
||||
|
||||
if c.CommConfig.SSHUsername == "" {
|
||||
|
||||
@@ -22,7 +22,7 @@ func (d *VBox42Driver) CreateSATAController(vmName string, name string) error {
|
||||
}
|
||||
|
||||
portCountArg := "--sataportcount"
|
||||
if strings.HasPrefix(version, "4.3") {
|
||||
if strings.HasPrefix(version, "4.3") || strings.HasPrefix(version, "5.") {
|
||||
portCountArg = "--portcount"
|
||||
}
|
||||
|
||||
|
||||
@@ -396,11 +396,18 @@ func (d *ESX5Driver) upload(dst, src string) error {
|
||||
}
|
||||
|
||||
func (d *ESX5Driver) verifyChecksum(ctype string, hash string, file string) bool {
|
||||
stdin := bytes.NewBufferString(fmt.Sprintf("%s %s", hash, file))
|
||||
_, err := d.run(stdin, fmt.Sprintf("%ssum", ctype), "-c")
|
||||
if err != nil {
|
||||
return false
|
||||
if ctype == "none" {
|
||||
if err := d.sh("stat", file); err != nil {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
stdin := bytes.NewBufferString(fmt.Sprintf("%s %s", hash, file))
|
||||
_, err := d.run(stdin, fmt.Sprintf("%ssum", ctype), "-c")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -37,7 +37,13 @@ func (c BuildCommand) Run(args []string) int {
|
||||
}
|
||||
|
||||
// Parse the template
|
||||
tpl, err := template.ParseFile(args[0])
|
||||
var tpl *template.Template
|
||||
var err error
|
||||
if args[0] == "-" {
|
||||
tpl, err = template.Parse(os.Stdin)
|
||||
} else {
|
||||
tpl, err = template.ParseFile(args[0])
|
||||
}
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err))
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/builder/file"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
func TestBuildOnlyFileCommaFlags(t *testing.T) {
|
||||
c := &BuildCommand{
|
||||
Meta: testMetaFile(t),
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-only=chocolate,vanilla",
|
||||
filepath.Join(testFixture("build-only"), "template.json"),
|
||||
}
|
||||
|
||||
defer cleanup()
|
||||
|
||||
if code := c.Run(args); code != 0 {
|
||||
fatalCommand(t, c.Meta)
|
||||
}
|
||||
|
||||
if !fileExists("chocolate.txt") {
|
||||
t.Error("Expected to find chocolate.txt")
|
||||
}
|
||||
if !fileExists("vanilla.txt") {
|
||||
t.Error("Expected to find vanilla.txt")
|
||||
}
|
||||
if fileExists("cherry.txt") {
|
||||
t.Error("Expected NOT to find cherry.txt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildStdin(t *testing.T) {
|
||||
c := &BuildCommand{
|
||||
Meta: testMetaFile(t),
|
||||
}
|
||||
f, err := os.Open(filepath.Join(testFixture("build-only"), "template.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
stdin := os.Stdin
|
||||
os.Stdin = f
|
||||
defer func() { os.Stdin = stdin }()
|
||||
|
||||
defer cleanup()
|
||||
if code := c.Run([]string{"-"}); code != 0 {
|
||||
fatalCommand(t, c.Meta)
|
||||
}
|
||||
|
||||
if !fileExists("chocolate.txt") {
|
||||
t.Error("Expected to find chocolate.txt")
|
||||
}
|
||||
if !fileExists("vanilla.txt") {
|
||||
t.Error("Expected to find vanilla.txt")
|
||||
}
|
||||
if !fileExists("cherry.txt") {
|
||||
t.Error("Expected to find cherry.txt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildOnlyFileMultipleFlags(t *testing.T) {
|
||||
c := &BuildCommand{
|
||||
Meta: testMetaFile(t),
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-only=chocolate",
|
||||
"-only=cherry",
|
||||
filepath.Join(testFixture("build-only"), "template.json"),
|
||||
}
|
||||
|
||||
defer cleanup()
|
||||
|
||||
if code := c.Run(args); code != 0 {
|
||||
fatalCommand(t, c.Meta)
|
||||
}
|
||||
|
||||
if !fileExists("chocolate.txt") {
|
||||
t.Error("Expected to find chocolate.txt")
|
||||
}
|
||||
if fileExists("vanilla.txt") {
|
||||
t.Error("Expected NOT to find vanilla.txt")
|
||||
}
|
||||
if !fileExists("cherry.txt") {
|
||||
t.Error("Expected to find cherry.txt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildExceptFileCommaFlags(t *testing.T) {
|
||||
c := &BuildCommand{
|
||||
Meta: testMetaFile(t),
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-except=chocolate",
|
||||
filepath.Join(testFixture("build-only"), "template.json"),
|
||||
}
|
||||
|
||||
defer cleanup()
|
||||
|
||||
if code := c.Run(args); code != 0 {
|
||||
fatalCommand(t, c.Meta)
|
||||
}
|
||||
|
||||
if fileExists("chocolate.txt") {
|
||||
t.Error("Expected NOT to find chocolate.txt")
|
||||
}
|
||||
if !fileExists("vanilla.txt") {
|
||||
t.Error("Expected to find vanilla.txt")
|
||||
}
|
||||
if !fileExists("cherry.txt") {
|
||||
t.Error("Expected to find cherry.txt")
|
||||
}
|
||||
}
|
||||
|
||||
// fileExists returns true if the filename is found
|
||||
func fileExists(filename string) bool {
|
||||
if _, err := os.Stat(filename); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// testCoreConfigBuilder creates a packer CoreConfig that has a file builder
|
||||
// available. This allows us to test a builder that writes files to disk.
|
||||
func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig {
|
||||
components := packer.ComponentFinder{
|
||||
Builder: func(n string) (packer.Builder, error) {
|
||||
return &file.Builder{}, nil
|
||||
},
|
||||
}
|
||||
return &packer.CoreConfig{
|
||||
Components: components,
|
||||
}
|
||||
}
|
||||
|
||||
// testMetaFile creates a Meta object that includes a file builder
|
||||
func testMetaFile(t *testing.T) Meta {
|
||||
var out, err bytes.Buffer
|
||||
return Meta{
|
||||
CoreConfig: testCoreConfigBuilder(t),
|
||||
Ui: &packer.BasicUi{
|
||||
Writer: &out,
|
||||
ErrorWriter: &err,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
os.RemoveAll("chocolate.txt")
|
||||
os.RemoveAll("vanilla.txt")
|
||||
os.RemoveAll("cherry.txt")
|
||||
}
|
||||
@@ -20,6 +20,13 @@ func fatalCommand(t *testing.T, m Meta) {
|
||||
err.String())
|
||||
}
|
||||
|
||||
func outputCommand(t *testing.T, m Meta) (string, string) {
|
||||
ui := m.Ui.(*packer.BasicUi)
|
||||
out := ui.Writer.(*bytes.Buffer)
|
||||
err := ui.ErrorWriter.(*bytes.Buffer)
|
||||
return out.String(), err.String()
|
||||
}
|
||||
|
||||
func testFixture(n string) string {
|
||||
return filepath.Join(fixturesDir, n)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ type Meta struct {
|
||||
CoreConfig *packer.CoreConfig
|
||||
Cache packer.Cache
|
||||
Ui packer.Ui
|
||||
Version string
|
||||
|
||||
// These are set by command-line flags
|
||||
flagBuildExcept []string
|
||||
|
||||
@@ -122,10 +122,8 @@ func TestPush_noName(t *testing.T) {
|
||||
|
||||
func TestPush_cliName(t *testing.T) {
|
||||
var actual []string
|
||||
var actualOpts *uploadOpts
|
||||
uploadFn := func(r io.Reader, opts *uploadOpts) (<-chan struct{}, <-chan error, error) {
|
||||
actual = testArchive(t, r)
|
||||
actualOpts = opts
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
close(doneCh)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"builders": [
|
||||
{
|
||||
"name":"chocolate",
|
||||
"type":"file",
|
||||
"content":"chocolate",
|
||||
"target":"chocolate.txt"
|
||||
},
|
||||
{
|
||||
"name":"vanilla",
|
||||
"type":"file",
|
||||
"content":"vanilla",
|
||||
"target":"vanilla.txt"
|
||||
},
|
||||
{
|
||||
"name":"cherry",
|
||||
"type":"file",
|
||||
"content":"cherry",
|
||||
"target":"cherry.txt"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"builders":[
|
||||
{
|
||||
"type":"file",
|
||||
"target":"chocolate.txt",
|
||||
"content":"chocolate"
|
||||
}
|
||||
],
|
||||
"min_packer_version":"101.0.0"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateCommandOKVersion(t *testing.T) {
|
||||
c := &ValidateCommand{
|
||||
Meta: testMetaFile(t),
|
||||
}
|
||||
args := []string{
|
||||
filepath.Join(testFixture("validate"), "template.json"),
|
||||
}
|
||||
|
||||
// This should pass with a valid configuration version
|
||||
c.CoreConfig.Version = "102.0.0"
|
||||
if code := c.Run(args); code != 0 {
|
||||
fatalCommand(t, c.Meta)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCommandBadVersion(t *testing.T) {
|
||||
c := &ValidateCommand{
|
||||
Meta: testMetaFile(t),
|
||||
}
|
||||
args := []string{
|
||||
filepath.Join(testFixture("validate"), "template.json"),
|
||||
}
|
||||
|
||||
// This should fail with an invalid configuration version
|
||||
c.CoreConfig.Version = "100.0.0"
|
||||
if code := c.Run(args); code != 1 {
|
||||
t.Errorf("Expected exit code 1")
|
||||
}
|
||||
|
||||
stdout, stderr := outputCommand(t, c.Meta)
|
||||
expected := `Error initializing core: This template requires Packer version 101.0.0 or higher; using 100.0.0
|
||||
`
|
||||
if stderr != expected {
|
||||
t.Fatalf("Expected:\n%s\nFound:\n%s\n", expected, stderr)
|
||||
}
|
||||
t.Log(stdout)
|
||||
}
|
||||
@@ -5,9 +5,6 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@@ -16,8 +13,18 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
)
|
||||
|
||||
// ErrHandshakeTimeout is returned from New() whenever we're unable to establish
|
||||
// an ssh connection within a certain timeframe. By default the handshake time-
|
||||
// out period is 1 minute. You can change it with Config.HandshakeTimeout.
|
||||
var ErrHandshakeTimeout = fmt.Errorf("Timeout during SSH handshake")
|
||||
|
||||
type comm struct {
|
||||
client *ssh.Client
|
||||
config *Config
|
||||
@@ -37,6 +44,13 @@ type Config struct {
|
||||
|
||||
// Pty, if true, will request a pty from the remote end.
|
||||
Pty bool
|
||||
|
||||
// DisableAgent, if true, will not forward the SSH agent.
|
||||
DisableAgent bool
|
||||
|
||||
// HandshakeTimeout limits the amount of time we'll wait to handshake before
|
||||
// saying the connection failed.
|
||||
HandshakeTimeout time.Duration
|
||||
}
|
||||
|
||||
// Creates a new packer.Communicator implementation over SSH. This takes
|
||||
@@ -270,10 +284,46 @@ func (c *comm) reconnect() (err error) {
|
||||
}
|
||||
|
||||
log.Printf("handshaking with SSH")
|
||||
sshConn, sshChan, req, err := ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
|
||||
|
||||
// Default timeout to 1 minute if it wasn't specified (zero value). For
|
||||
// when you need to handshake from low orbit.
|
||||
var duration time.Duration
|
||||
if c.config.HandshakeTimeout == 0 {
|
||||
duration = 1 * time.Minute
|
||||
} else {
|
||||
duration = c.config.HandshakeTimeout
|
||||
}
|
||||
|
||||
connectionEstablished := make(chan struct{}, 1)
|
||||
|
||||
var sshConn ssh.Conn
|
||||
var sshChan <-chan ssh.NewChannel
|
||||
var req <-chan *ssh.Request
|
||||
|
||||
go func() {
|
||||
sshConn, sshChan, req, err = ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
|
||||
close(connectionEstablished)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-connectionEstablished:
|
||||
// We don't need to do anything here. We just want select to block until
|
||||
// we connect or timeout.
|
||||
case <-time.After(duration):
|
||||
if c.conn != nil {
|
||||
c.conn.Close()
|
||||
}
|
||||
if sshConn != nil {
|
||||
sshConn.Close()
|
||||
}
|
||||
return ErrHandshakeTimeout
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("handshake error: %s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("handshake complete!")
|
||||
if sshConn != nil {
|
||||
c.client = ssh.NewClient(sshConn, sshChan, req)
|
||||
}
|
||||
@@ -287,6 +337,11 @@ func (c *comm) connectToAgent() {
|
||||
return
|
||||
}
|
||||
|
||||
if c.config.DisableAgent {
|
||||
log.Printf("[INFO] SSH agent forwarding is disabled.")
|
||||
return
|
||||
}
|
||||
|
||||
// open connection to the local agent
|
||||
socketLocation := os.Getenv("SSH_AUTH_SOCK")
|
||||
if socketLocation == "" {
|
||||
|
||||
@@ -5,10 +5,12 @@ package ssh
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// private key for mock server
|
||||
@@ -94,6 +96,28 @@ func newMockLineServer(t *testing.T) string {
|
||||
return l.Addr().String()
|
||||
}
|
||||
|
||||
func newMockBrokenServer(t *testing.T) string {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable tp listen for connection: %s", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer l.Close()
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to accept incoming connection: %s", err)
|
||||
}
|
||||
defer c.Close()
|
||||
// This should block for a period of time longer than our timeout in
|
||||
// the test case. That way we invoke a failure scenario.
|
||||
t.Log("Block on handshaking for SSH connection")
|
||||
time.Sleep(5 * time.Second)
|
||||
}()
|
||||
|
||||
return l.Addr().String()
|
||||
}
|
||||
|
||||
func TestCommIsCommunicator(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &comm{}
|
||||
@@ -157,10 +181,44 @@ func TestStart(t *testing.T) {
|
||||
t.Fatalf("error connecting to SSH: %s", err)
|
||||
}
|
||||
|
||||
var cmd packer.RemoteCmd
|
||||
stdout := new(bytes.Buffer)
|
||||
cmd.Command = "echo foo"
|
||||
cmd.Stdout = stdout
|
||||
cmd := &packer.RemoteCmd{
|
||||
Command: "echo foo",
|
||||
Stdout: new(bytes.Buffer),
|
||||
}
|
||||
|
||||
client.Start(&cmd)
|
||||
client.Start(cmd)
|
||||
}
|
||||
|
||||
func TestHandshakeTimeout(t *testing.T) {
|
||||
clientConfig := &ssh.ClientConfig{
|
||||
User: "user",
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.Password("pass"),
|
||||
},
|
||||
}
|
||||
|
||||
address := newMockBrokenServer(t)
|
||||
conn := func() (net.Conn, error) {
|
||||
conn, err := net.Dial("tcp", address)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to dial to remote side: %s", err)
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
Connection: conn,
|
||||
SSHConfig: clientConfig,
|
||||
HandshakeTimeout: 50 * time.Millisecond,
|
||||
}
|
||||
|
||||
_, err := New(address, config)
|
||||
if err != ErrHandshakeTimeout {
|
||||
// Note: there's another error that can come back from this call:
|
||||
// ssh: handshake failed: EOF
|
||||
// This should appear in cases where the handshake fails because of
|
||||
// malformed (or no) data sent back by the server, but should not happen
|
||||
// in a timeout scenario.
|
||||
t.Fatalf("Expected handshake timeout, got: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +85,17 @@ func (c *Communicator) Start(rc *packer.RemoteCmd) error {
|
||||
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) {
|
||||
defer shell.Close()
|
||||
|
||||
go io.Copy(rc.Stdout, cmd.Stdout)
|
||||
go io.Copy(rc.Stderr, cmd.Stderr)
|
||||
if rc.Stdout != nil && cmd.Stdout != nil {
|
||||
go io.Copy(rc.Stdout, cmd.Stdout)
|
||||
} else {
|
||||
log.Printf("[WARN] Failed to read stdout for command '%s'", rc.Command)
|
||||
}
|
||||
|
||||
if rc.Stderr != nil && cmd.Stderr != nil {
|
||||
go io.Copy(rc.Stderr, cmd.Stderr)
|
||||
} else {
|
||||
log.Printf("[WARN] Failed to read stderr for command '%s'", rc.Command)
|
||||
}
|
||||
|
||||
cmd.Wait()
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ type Config struct {
|
||||
SSHPrivateKey string `mapstructure:"ssh_private_key_file"`
|
||||
SSHPty bool `mapstructure:"ssh_pty"`
|
||||
SSHTimeout time.Duration `mapstructure:"ssh_timeout"`
|
||||
SSHDisableAgent bool `mapstructure:"ssh_disable_agent"`
|
||||
SSHHandshakeAttempts int `mapstructure:"ssh_handshake_attempts"`
|
||||
SSHBastionHost string `mapstructure:"ssh_bastion_host"`
|
||||
SSHBastionPort int `mapstructure:"ssh_bastion_port"`
|
||||
|
||||
@@ -158,9 +158,10 @@ func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, cancel <-chan stru
|
||||
|
||||
// Then we attempt to connect via SSH
|
||||
config := &ssh.Config{
|
||||
Connection: connFunc,
|
||||
SSHConfig: sshConfig,
|
||||
Pty: s.Config.SSHPty,
|
||||
Connection: connFunc,
|
||||
SSHConfig: sshConfig,
|
||||
Pty: s.Config.SSHPty,
|
||||
DisableAgent: s.Config.SSHDisableAgent,
|
||||
}
|
||||
|
||||
log.Println("[INFO] Attempting SSH connection...")
|
||||
|
||||
@@ -42,6 +42,8 @@ func Decode(target interface{}, config *DecodeOpts, raws ...interface{}) error {
|
||||
if config.InterpolateContext == nil {
|
||||
config.InterpolateContext = ctx
|
||||
} else {
|
||||
config.InterpolateContext.BuildName = ctx.BuildName
|
||||
config.InterpolateContext.BuildType = ctx.BuildType
|
||||
config.InterpolateContext.TemplatePath = ctx.TemplatePath
|
||||
config.InterpolateContext.UserVariables = ctx.UserVariables
|
||||
}
|
||||
|
||||
@@ -74,6 +74,36 @@ func TestDecode(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"build name": {
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "{{build_name}}",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"packer_build_name": "foo",
|
||||
},
|
||||
},
|
||||
&Target{
|
||||
Name: "foo",
|
||||
},
|
||||
nil,
|
||||
},
|
||||
|
||||
"build type": {
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "{{build_type}}",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"packer_builder_type": "foo",
|
||||
},
|
||||
},
|
||||
&Target{
|
||||
Name: "foo",
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range cases {
|
||||
|
||||
@@ -11,6 +11,6 @@ func (s *StringFlag) String() string {
|
||||
}
|
||||
|
||||
func (s *StringFlag) Set(value string) error {
|
||||
*s = append(*s, value)
|
||||
*s = append(*s, strings.Split(value, ",")...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ func TestStringFlag_implements(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStringFlagSet tests for setting the same flag more than once on the CLI
|
||||
// like: blah -flag foo -flag bar
|
||||
func TestStringFlagSet(t *testing.T) {
|
||||
sv := new(StringFlag)
|
||||
err := sv.Set("foo")
|
||||
@@ -31,3 +33,18 @@ func TestStringFlagSet(t *testing.T) {
|
||||
t.Fatalf("Bad: %#v", sv)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMultiStringFlag tests for setting the same flag using a comma-separated
|
||||
// list of items like: blah -flag=foo,bar
|
||||
func TestMultiStringFlag(t *testing.T) {
|
||||
sv := new(StringFlag)
|
||||
err := sv.Set("chocolate,vanilla")
|
||||
if err != nil {
|
||||
t.Fatalf("err :%s", err)
|
||||
}
|
||||
|
||||
expected := []string{"chocolate", "vanilla"}
|
||||
if !reflect.DeepEqual([]string(*sv), expected) {
|
||||
t.Fatalf("Expected: %#v, found: %#v", expected, sv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ func wrappedMain() int {
|
||||
PostProcessor: config.LoadPostProcessor,
|
||||
Provisioner: config.LoadProvisioner,
|
||||
},
|
||||
Version: Version,
|
||||
},
|
||||
Cache: cache,
|
||||
Ui: ui,
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/mitchellh/packer/template"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
@@ -17,6 +18,7 @@ type Core struct {
|
||||
components ComponentFinder
|
||||
variables map[string]string
|
||||
builds map[string]*template.Builder
|
||||
version string
|
||||
}
|
||||
|
||||
// CoreConfig is the structure for initializing a new Core. Once a CoreConfig
|
||||
@@ -25,6 +27,7 @@ type CoreConfig struct {
|
||||
Components ComponentFinder
|
||||
Template *template.Template
|
||||
Variables map[string]string
|
||||
Version string
|
||||
}
|
||||
|
||||
// The function type used to lookup Builder implementations.
|
||||
@@ -55,6 +58,7 @@ func NewCore(c *CoreConfig) (*Core, error) {
|
||||
Template: c.Template,
|
||||
components: c.Components,
|
||||
variables: c.Variables,
|
||||
version: c.Version,
|
||||
}
|
||||
if err := result.validate(); err != nil {
|
||||
return nil, err
|
||||
@@ -226,6 +230,28 @@ func (c *Core) validate() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate the minimum version is satisfied
|
||||
if c.Template.MinVersion != "" {
|
||||
versionActual, err := version.NewVersion(c.version)
|
||||
if err != nil {
|
||||
// This shouldn't happen since we set it via the compiler
|
||||
panic(err)
|
||||
}
|
||||
|
||||
versionMin, err := version.NewVersion(c.Template.MinVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"min_version is invalid: %s", err)
|
||||
}
|
||||
|
||||
if versionActual.LessThan(versionMin) {
|
||||
return fmt.Errorf(
|
||||
"This template requires Packer version %s or higher; using %s",
|
||||
versionMin,
|
||||
versionActual)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate variables are set
|
||||
var err error
|
||||
for n, v := range c.Template.Variables {
|
||||
|
||||
@@ -484,6 +484,19 @@ func TestCoreValidate(t *testing.T) {
|
||||
map[string]string{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
|
||||
// Min version good
|
||||
{
|
||||
"validate-min-version.json",
|
||||
map[string]string{"foo": "bar"},
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"validate-min-version-high.json",
|
||||
map[string]string{"foo": "bar"},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -501,6 +514,7 @@ func TestCoreValidate(t *testing.T) {
|
||||
_, err = NewCore(&CoreConfig{
|
||||
Template: tpl,
|
||||
Variables: tc.Vars,
|
||||
Version: "1.0.0",
|
||||
})
|
||||
if (err != nil) != tc.Err {
|
||||
t.Fatalf("err: %s\n\n%s", tc.File, err)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"min_packer_version": "2.1.0",
|
||||
|
||||
"builders": [
|
||||
{"type": "foo"}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"min_packer_version": "0.1.0",
|
||||
|
||||
"builders": [
|
||||
{"type": "foo"}
|
||||
]
|
||||
}
|
||||
@@ -19,6 +19,18 @@ import (
|
||||
"github.com/pierrec/lz4"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidCompressionLevel is returned when the compression level passed
|
||||
// to gzip is not in the expected range. See compress/flate for details.
|
||||
ErrInvalidCompressionLevel = fmt.Errorf(
|
||||
"Invalid compression level. Expected an integer from -1 to 9.")
|
||||
|
||||
ErrWrongInputCount = fmt.Errorf(
|
||||
"Can only have 1 input file when not using tar/zip")
|
||||
|
||||
filenamePattern = regexp.MustCompile(`(?:\.([a-z0-9]+))`)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
|
||||
@@ -35,21 +47,9 @@ type Config struct {
|
||||
}
|
||||
|
||||
type PostProcessor struct {
|
||||
config *Config
|
||||
config Config
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrInvalidCompressionLevel is returned when the compression level passed
|
||||
// to gzip is not in the expected range. See compress/flate for details.
|
||||
ErrInvalidCompressionLevel = fmt.Errorf(
|
||||
"Invalid compression level. Expected an integer from -1 to 9.")
|
||||
|
||||
ErrWrongInputCount = fmt.Errorf(
|
||||
"Can only have 1 input file when not using tar/zip")
|
||||
|
||||
filenamePattern = regexp.MustCompile(`(?:\.([a-z0-9]+))`)
|
||||
)
|
||||
|
||||
func (p *PostProcessor) Configure(raws ...interface{}) error {
|
||||
err := config.Decode(&p.config, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
@@ -109,7 +109,6 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/builder/file"
|
||||
env "github.com/mitchellh/packer/helper/builder/testing"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template"
|
||||
)
|
||||
@@ -187,11 +186,6 @@ func setup(t *testing.T) (packer.Ui, packer.Artifact, error) {
|
||||
}
|
||||
|
||||
func testArchive(t *testing.T, config string) packer.Artifact {
|
||||
if os.Getenv(env.TestEnvVar) == "" {
|
||||
t.Skip(fmt.Sprintf(
|
||||
"Acceptance tests skipped unless env '%s' set", env.TestEnvVar))
|
||||
}
|
||||
|
||||
ui, artifact, err := setup(t)
|
||||
if err != nil {
|
||||
t.Fatalf("Error bootstrapping test: %s", err)
|
||||
|
||||
@@ -187,14 +187,20 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||
}
|
||||
|
||||
err = p.executeChef(ui, comm, configPath, jsonPath)
|
||||
|
||||
knifeConfigPath, err2 := p.createKnifeConfig(
|
||||
ui, comm, nodeName, serverUrl, p.config.ClientKey, p.config.SslVerifyMode)
|
||||
if err2 != nil {
|
||||
return fmt.Errorf("Error creating knife config on node: %s", err2)
|
||||
}
|
||||
if !p.config.SkipCleanNode {
|
||||
if err2 := p.cleanNode(ui, comm, nodeName); err2 != nil {
|
||||
if err2 := p.cleanNode(ui, comm, nodeName, knifeConfigPath); err2 != nil {
|
||||
return fmt.Errorf("Error cleaning up chef node: %s", err2)
|
||||
}
|
||||
}
|
||||
|
||||
if !p.config.SkipCleanClient {
|
||||
if err2 := p.cleanClient(ui, comm, nodeName); err2 != nil {
|
||||
if err2 := p.cleanClient(ui, comm, nodeName, knifeConfigPath); err2 != nil {
|
||||
return fmt.Errorf("Error cleaning up chef client: %s", err2)
|
||||
}
|
||||
}
|
||||
@@ -273,6 +279,32 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, nodeN
|
||||
return remotePath, nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) createKnifeConfig(ui packer.Ui, comm packer.Communicator, nodeName string, serverUrl string, clientKey string, sslVerifyMode string) (string, error) {
|
||||
ui.Message("Creating configuration file 'knife.rb'")
|
||||
|
||||
// Read the template
|
||||
tpl := DefaultKnifeTemplate
|
||||
|
||||
ctx := p.config.ctx
|
||||
ctx.Data = &ConfigTemplate{
|
||||
NodeName: nodeName,
|
||||
ServerUrl: serverUrl,
|
||||
ClientKey: clientKey,
|
||||
SslVerifyMode: sslVerifyMode,
|
||||
}
|
||||
configString, err := interpolate.Render(tpl, &ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
remotePath := filepath.ToSlash(filepath.Join(p.config.StagingDir, "knife.rb"))
|
||||
if err := comm.Upload(remotePath, bytes.NewReader([]byte(configString)), nil); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return remotePath, nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) createJson(ui packer.Ui, comm packer.Communicator) (string, error) {
|
||||
ui.Message("Creating JSON attribute file")
|
||||
|
||||
@@ -334,32 +366,30 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) cleanNode(ui packer.Ui, comm packer.Communicator, node string) error {
|
||||
func (p *Provisioner) cleanNode(ui packer.Ui, comm packer.Communicator, node string, knifeConfigPath string) error {
|
||||
ui.Say("Cleaning up chef node...")
|
||||
args := []string{"node", "delete", node}
|
||||
if err := p.knifeExec(ui, comm, node, args); err != nil {
|
||||
if err := p.knifeExec(ui, comm, node, knifeConfigPath, args); err != nil {
|
||||
return fmt.Errorf("Failed to cleanup node: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) cleanClient(ui packer.Ui, comm packer.Communicator, node string) error {
|
||||
func (p *Provisioner) cleanClient(ui packer.Ui, comm packer.Communicator, node string, knifeConfigPath string) error {
|
||||
ui.Say("Cleaning up chef client...")
|
||||
args := []string{"client", "delete", node}
|
||||
if err := p.knifeExec(ui, comm, node, args); err != nil {
|
||||
if err := p.knifeExec(ui, comm, node, knifeConfigPath, args); err != nil {
|
||||
return fmt.Errorf("Failed to cleanup client: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) knifeExec(ui packer.Ui, comm packer.Communicator, node string, args []string) error {
|
||||
func (p *Provisioner) knifeExec(ui packer.Ui, comm packer.Communicator, node string, knifeConfigPath string, args []string) error {
|
||||
flags := []string{
|
||||
"-y",
|
||||
"-s", fmt.Sprintf("'%s'", p.config.ServerUrl),
|
||||
"-k", fmt.Sprintf("'%s'", p.config.ClientKey),
|
||||
"-u", fmt.Sprintf("'%s'", node),
|
||||
"-c", knifeConfigPath,
|
||||
}
|
||||
|
||||
cmdText := fmt.Sprintf(
|
||||
@@ -573,3 +603,14 @@ environment "{{.ChefEnvironment}}"
|
||||
ssl_verify_mode :{{.SslVerifyMode}}
|
||||
{{end}}
|
||||
`
|
||||
|
||||
var DefaultKnifeTemplate = `
|
||||
log_level :info
|
||||
log_location STDOUT
|
||||
chef_server_url "{{.ServerUrl}}"
|
||||
client_key "{{.ClientKey}}"
|
||||
node_name "{{.NodeName}}"
|
||||
{{if ne .SslVerifyMode ""}}
|
||||
ssl_verify_mode :{{.SslVerifyMode}}
|
||||
{{end}}
|
||||
`
|
||||
|
||||
@@ -270,28 +270,43 @@ func (p *Provisioner) uploadManifests(ui packer.Ui, comm packer.Communicator) (s
|
||||
return "", fmt.Errorf("Error creating manifests directory: %s", err)
|
||||
}
|
||||
|
||||
// Upload the main manifest
|
||||
f, err := os.Open(p.config.ManifestFile)
|
||||
// NOTE! manifest_file may either be a directory or a file, as puppet apply
|
||||
// now accepts either one.
|
||||
|
||||
fi, err := os.Stat(p.config.ManifestFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
manifestFilename := p.config.ManifestFile
|
||||
if fi, err := os.Stat(p.config.ManifestFile); err != nil {
|
||||
return "", fmt.Errorf("Error inspecting manifest file: %s", err)
|
||||
} else if !fi.IsDir() {
|
||||
manifestFilename = filepath.Base(manifestFilename)
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
// If manifest_file is a directory we'll upload the whole thing
|
||||
ui.Message(fmt.Sprintf(
|
||||
"Uploading manifest directory from: %s", p.config.ManifestFile))
|
||||
|
||||
remoteManifestDir := fmt.Sprintf("%s/manifests", p.config.StagingDir)
|
||||
err := p.uploadDirectory(ui, comm, remoteManifestDir, p.config.ManifestFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error uploading manifest dir: %s", err)
|
||||
}
|
||||
return remoteManifestDir, nil
|
||||
} else {
|
||||
ui.Say("WARNING: manifest_file should be a file. Use manifest_dir for directories")
|
||||
}
|
||||
// Otherwise manifest_file is a file and we'll upload it
|
||||
ui.Message(fmt.Sprintf(
|
||||
"Uploading manifest file from: %s", p.config.ManifestFile))
|
||||
|
||||
remoteManifestFile := fmt.Sprintf("%s/%s", remoteManifestsPath, manifestFilename)
|
||||
if err := comm.Upload(remoteManifestFile, f, nil); err != nil {
|
||||
return "", err
|
||||
}
|
||||
f, err := os.Open(p.config.ManifestFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return remoteManifestFile, nil
|
||||
manifestFilename := filepath.Base(p.config.ManifestFile)
|
||||
remoteManifestFile := fmt.Sprintf("%s/%s", remoteManifestsPath, manifestFilename)
|
||||
if err := comm.Upload(remoteManifestFile, f, nil); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return remoteManifestFile, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||
|
||||
@@ -71,7 +71,7 @@ func funcGenBuildName(ctx *Context) interface{} {
|
||||
func funcGenBuildType(ctx *Context) interface{} {
|
||||
return func() (string, error) {
|
||||
if ctx == nil || ctx.BuildType == "" {
|
||||
return "", errors.New("build_name not available")
|
||||
return "", errors.New("build_type not available")
|
||||
}
|
||||
|
||||
return ctx.BuildType, nil
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ package main
|
||||
var GitCommit string
|
||||
|
||||
// The main version number that is being run at the moment.
|
||||
const Version = "0.8.0"
|
||||
const Version = "0.8.2"
|
||||
|
||||
// A pre-release marker for the version. If this is "" (empty string)
|
||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||
|
||||
+31
-29
@@ -1,6 +1,6 @@
|
||||
GIT
|
||||
remote: git://github.com/hashicorp/middleman-hashicorp.git
|
||||
revision: 7796ba44d303ac8e1b566e855e2766e6d0f695fc
|
||||
revision: 76f0f284ad44cea0457484ea83467192f02daf87
|
||||
specs:
|
||||
middleman-hashicorp (0.1.0)
|
||||
bootstrap-sass (~> 3.3)
|
||||
@@ -11,6 +11,7 @@ GIT
|
||||
middleman-minify-html (~> 3.4)
|
||||
middleman-syntax (~> 2.0)
|
||||
rack-contrib (~> 1.2)
|
||||
rack-protection (~> 1.5)
|
||||
rack-rewrite (~> 1.5)
|
||||
rack-ssl-enforcer (~> 0.2)
|
||||
redcarpet (~> 3.2)
|
||||
@@ -20,18 +21,18 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (4.1.10)
|
||||
activesupport (4.1.12)
|
||||
i18n (~> 0.6, >= 0.6.9)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 1.1)
|
||||
autoprefixer-rails (5.1.11)
|
||||
autoprefixer-rails (5.2.1)
|
||||
execjs
|
||||
json
|
||||
bootstrap-sass (3.3.4.1)
|
||||
bootstrap-sass (3.3.5.1)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
sass (>= 3.3.0)
|
||||
builder (3.2.2)
|
||||
celluloid (0.16.0)
|
||||
timers (~> 4.0.0)
|
||||
@@ -53,29 +54,30 @@ GEM
|
||||
sass (>= 3.3.0, < 3.5)
|
||||
compass-import-once (1.0.5)
|
||||
sass (>= 3.2, < 3.5)
|
||||
daemons (1.2.2)
|
||||
daemons (1.2.3)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.7)
|
||||
execjs (2.5.2)
|
||||
ffi (1.9.8)
|
||||
ffi (1.9.10)
|
||||
git-version-bump (0.15.1)
|
||||
haml (4.0.6)
|
||||
tilt
|
||||
hike (1.2.3)
|
||||
hitimes (1.2.2)
|
||||
hooks (0.4.0)
|
||||
uber (~> 0.0.4)
|
||||
htmlcompressor (0.1.2)
|
||||
htmlcompressor (0.2.0)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (0.7.0)
|
||||
json (1.8.2)
|
||||
kramdown (1.7.0)
|
||||
json (1.8.3)
|
||||
kramdown (1.8.0)
|
||||
less (2.6.0)
|
||||
commonjs (~> 0.2.7)
|
||||
libv8 (3.16.14.7)
|
||||
listen (2.10.0)
|
||||
libv8 (3.16.14.11)
|
||||
listen (2.10.1)
|
||||
celluloid (~> 0.16.0)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
@@ -106,8 +108,8 @@ GEM
|
||||
em-websocket (~> 0.5.1)
|
||||
middleman-core (>= 3.3)
|
||||
rack-livereload (~> 0.3.15)
|
||||
middleman-minify-html (3.4.0)
|
||||
htmlcompressor (~> 0.1.0)
|
||||
middleman-minify-html (3.4.1)
|
||||
htmlcompressor (~> 0.2.0)
|
||||
middleman-core (>= 3.2)
|
||||
middleman-sprockets (3.4.2)
|
||||
middleman-core (>= 3.3)
|
||||
@@ -117,31 +119,34 @@ GEM
|
||||
middleman-syntax (2.0.0)
|
||||
middleman-core (~> 3.2)
|
||||
rouge (~> 1.0)
|
||||
minitest (5.6.1)
|
||||
multi_json (1.11.0)
|
||||
minitest (5.7.0)
|
||||
multi_json (1.11.2)
|
||||
padrino-helpers (0.12.5)
|
||||
i18n (~> 0.6, >= 0.6.7)
|
||||
padrino-support (= 0.12.5)
|
||||
tilt (~> 1.4.1)
|
||||
padrino-support (0.12.5)
|
||||
activesupport (>= 3.1)
|
||||
rack (1.6.1)
|
||||
rack-contrib (1.2.0)
|
||||
rack (>= 0.9.1)
|
||||
rack-livereload (0.3.15)
|
||||
rack (1.6.4)
|
||||
rack-contrib (1.3.0)
|
||||
git-version-bump (~> 0.15)
|
||||
rack (~> 1.4)
|
||||
rack-livereload (0.3.16)
|
||||
rack
|
||||
rack-protection (1.5.3)
|
||||
rack
|
||||
rack-rewrite (1.5.1)
|
||||
rack-ssl-enforcer (0.2.8)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rb-fsevent (0.9.4)
|
||||
rb-fsevent (0.9.5)
|
||||
rb-inotify (0.9.5)
|
||||
ffi (>= 0.5.0)
|
||||
redcarpet (3.2.3)
|
||||
ref (1.0.5)
|
||||
rouge (1.8.0)
|
||||
sass (3.4.13)
|
||||
sprockets (2.12.3)
|
||||
redcarpet (3.3.2)
|
||||
ref (2.0.0)
|
||||
rouge (1.9.1)
|
||||
sass (3.4.16)
|
||||
sprockets (2.12.4)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
@@ -175,6 +180,3 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
middleman-hashicorp!
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.2
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
all: build
|
||||
|
||||
init:
|
||||
bundle
|
||||
|
||||
dev: init
|
||||
PACKER_DISABLE_DOWNLOAD_FETCH=true PACKER_VERSION=1.0 bundle exec middleman server
|
||||
|
||||
build: init
|
||||
PACKER_DISABLE_DOWNLOAD_FETCH=true PACKER_VERSION=1.0 bundle exec middleman build
|
||||
+1
-2
@@ -16,8 +16,7 @@ Running the site locally is simple. Clone this repo and run the following
|
||||
commands:
|
||||
|
||||
```
|
||||
$ bundle
|
||||
$ PACKER_DISABLE_DOWNLOAD_FETCH=true PACKER_VERSION=1.0 bundle exec middleman server
|
||||
make dev
|
||||
```
|
||||
|
||||
Then open up `localhost:4567`. Note that some URLs you may need to append
|
||||
|
||||
@@ -3,6 +3,17 @@ require "rack/contrib/not_found"
|
||||
require "rack/contrib/response_headers"
|
||||
require "rack/contrib/static_cache"
|
||||
require "rack/contrib/try_static"
|
||||
require "rack/protection"
|
||||
|
||||
# Protect against various bad things
|
||||
use Rack::Protection::JsonCsrf
|
||||
use Rack::Protection::RemoteReferrer
|
||||
use Rack::Protection::HttpOrigin
|
||||
use Rack::Protection::EscapedParams
|
||||
use Rack::Protection::XSSHeader
|
||||
use Rack::Protection::FrameOptions
|
||||
use Rack::Protection::PathTraversal
|
||||
use Rack::Protection::IPSpoofing
|
||||
|
||||
# Properly compress the output if the client can handle it.
|
||||
use Rack::Deflater
|
||||
|
||||
@@ -321,6 +321,10 @@ header .header {
|
||||
.person {
|
||||
margin-bottom: 30px;
|
||||
|
||||
img {
|
||||
width: 125px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,10 @@ There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `access_key` (string) - The access key used to communicate with AWS.
|
||||
@@ -124,7 +128,7 @@ each category, the available configuration keys are alphabetized.
|
||||
* `enhanced_networking` (boolean) - Enable enhanced networking (SriovNetSupport) on
|
||||
HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your AWS IAM policy.
|
||||
|
||||
* `force_deregister` (boolean) – Force Packer to first deregister an existing
|
||||
* `force_deregister` (boolean) - Force Packer to first deregister an existing
|
||||
AMI if one with the same name already exists. Default `false`.
|
||||
|
||||
* `mount_path` (string) - The path where the volume will be mounted. This is
|
||||
@@ -133,13 +137,13 @@ AMI if one with the same name already exists. Default `false`.
|
||||
template where the `.Device` variable is replaced with the name of the
|
||||
device where the volume is attached.
|
||||
|
||||
* `mount_options` (array of strings) – Options to supply the `mount` command
|
||||
* `mount_options` (array of strings) - Options to supply the `mount` command
|
||||
when mounting devices. Each option will be prefixed with `-o ` and supplied to
|
||||
the `mount` command ran by Packer. Because this command is ran in a shell, user
|
||||
discrestion is advised. See [this manual page for the mount command][1] for valid
|
||||
file system specific options
|
||||
|
||||
* `root_volume_size` (integer) – The size of the root volume for the chroot
|
||||
* `root_volume_size` (integer) - The size of the root volume for the chroot
|
||||
environment, and the resulting AMI
|
||||
|
||||
* `tags` (object of key/value strings) - Tags applied to the AMI.
|
||||
|
||||
@@ -31,6 +31,10 @@ There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `access_key` (string) - The access key used to communicate with AWS.
|
||||
@@ -63,22 +67,22 @@ each category, the available configuration keys are alphabetized.
|
||||
* `ami_block_device_mappings` (array of block device mappings) - Add the block
|
||||
device mappings to the AMI. The block device mappings allow for keys:
|
||||
|
||||
- `device_name` (string) – The device name exposed to the instance (for
|
||||
- `device_name` (string) - The device name exposed to the instance (for
|
||||
example, "/dev/sdh" or "xvdh")
|
||||
- `virtual_name` (string) – The virtual device name. See the documentation on
|
||||
- `virtual_name` (string) - The virtual device name. See the documentation on
|
||||
[Block Device Mapping][1] for more information
|
||||
- `snapshot_id` (string) – The ID of the snapshot
|
||||
- `volume_type` (string) – The volume type. gp2 for General Purpose (SSD)
|
||||
- `snapshot_id` (string) - The ID of the snapshot
|
||||
- `volume_type` (string) - The volume type. gp2 for General Purpose (SSD)
|
||||
volumes, io1 for Provisioned IOPS (SSD) volumes, and standard for Magnetic
|
||||
volumes
|
||||
- `volume_size` (integer) – The size of the volume, in GiB. Required if not
|
||||
- `volume_size` (integer) - The size of the volume, in GiB. Required if not
|
||||
specifying a `snapshot_id`
|
||||
- `delete_on_termination` (boolean) – Indicates whether the EBS volume is
|
||||
- `delete_on_termination` (boolean) - Indicates whether the EBS volume is
|
||||
deleted on instance termination
|
||||
- `encrypted` (boolean) – Indicates whether to encrypt the volume or not
|
||||
- `no_device` (boolean) – Suppresses the specified device included in the
|
||||
- `encrypted` (boolean) - Indicates whether to encrypt the volume or not
|
||||
- `no_device` (boolean) - Suppresses the specified device included in the
|
||||
block device mapping of the AMI
|
||||
- `iops` (integer) – The number of I/O operations per second (IOPS) that the
|
||||
- `iops` (integer) - The number of I/O operations per second (IOPS) that the
|
||||
volume supports. See the documentation on [IOPs][2] for more information
|
||||
|
||||
|
||||
@@ -112,7 +116,7 @@ each category, the available configuration keys are alphabetized.
|
||||
* `enhanced_networking` (boolean) - Enable enhanced networking (SriovNetSupport) on
|
||||
HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your AWS IAM policy.
|
||||
|
||||
* `force_deregister` (boolean) – Force Packer to first deregister an existing
|
||||
* `force_deregister` (boolean) - Force Packer to first deregister an existing
|
||||
AMI if one with the same name already exists. Default `false`.
|
||||
|
||||
* `iam_instance_profile` (string) - The name of an
|
||||
@@ -154,20 +158,9 @@ AMI if one with the same name already exists. Default `false`.
|
||||
generate a temporary keypair. `ssh_private_key_file` must be specified
|
||||
with this.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be available on. This defaults
|
||||
to port 22.
|
||||
|
||||
* `ssh_private_key_file` (string) - Use this ssh private key file instead of
|
||||
a generated ssh key pair for connecting to the instance. This key file must
|
||||
already exist on the `source_ami`
|
||||
|
||||
* `ssh_private_ip` (bool) - If true, then SSH will always use the private
|
||||
* `ssh_private_ip` (boolean) - If true, then SSH will always use the private
|
||||
IP if available.
|
||||
|
||||
* `ssh_timeout` (string) - The time to wait for SSH to become available
|
||||
before timing out. The format of this value is a duration such as "5s"
|
||||
or "5m". The default SSH timeout is "5m", or five minutes.
|
||||
|
||||
* `subnet_id` (string) - If using VPC, the ID of the subnet, such as
|
||||
"subnet-12345def", where Packer will launch the EC2 instance. This field is
|
||||
required if you are using an non-default VPC.
|
||||
@@ -279,11 +272,11 @@ 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.
|
||||
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
|
||||
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 setting by specifying `delete_on_termination=false` in the
|
||||
termination setting by specifying `delete_on_termination=false` in the
|
||||
`launch_device_mappings` block for the device.
|
||||
|
||||
[1]: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_BlockDeviceMapping.html
|
||||
|
||||
@@ -36,6 +36,10 @@ There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `access_key` (string) - The access key used to communicate with AWS.
|
||||
@@ -83,22 +87,22 @@ each category, the available configuration keys are alphabetized.
|
||||
* `ami_block_device_mappings` (array of block device mappings) - Add the block
|
||||
device mappings to the AMI. The block device mappings allow for keys:
|
||||
|
||||
- `device_name` (string) – The device name exposed to the instance (for
|
||||
- `device_name` (string) - The device name exposed to the instance (for
|
||||
example, "/dev/sdh" or "xvdh")
|
||||
- `virtual_name` (string) – The virtual device name. See the documentation on
|
||||
- `virtual_name` (string) - The virtual device name. See the documentation on
|
||||
[Block Device Mapping][1] for more information
|
||||
- `snapshot_id` (string) – The ID of the snapshot
|
||||
- `volume_type` (string) – The volume type. gp2 for General Purpose (SSD)
|
||||
- `snapshot_id` (string) - The ID of the snapshot
|
||||
- `volume_type` (string) - The volume type. gp2 for General Purpose (SSD)
|
||||
volumes, io1 for Provisioned IOPS (SSD) volumes, and standard for Magnetic
|
||||
volumes
|
||||
- `volume_size` (integer) – The size of the volume, in GiB. Required if not
|
||||
- `volume_size` (integer) - The size of the volume, in GiB. Required if not
|
||||
specifying a `snapshot_id`
|
||||
- `delete_on_termination` (boolean) – Indicates whether the EBS volume is
|
||||
- `delete_on_termination` (boolean) - Indicates whether the EBS volume is
|
||||
deleted on instance termination
|
||||
- `encrypted` (boolean) – Indicates whether to encrypt the volume or not
|
||||
- `no_device` (boolean) – Suppresses the specified device included in the
|
||||
- `encrypted` (boolean) - Indicates whether to encrypt the volume or not
|
||||
- `no_device` (boolean) - Suppresses the specified device included in the
|
||||
block device mapping of the AMI
|
||||
- `iops` (integer) – The number of I/O operations per second (IOPS) that the
|
||||
- `iops` (integer) - The number of I/O operations per second (IOPS) that the
|
||||
volume supports. See the documentation on [IOPs][2] for more information
|
||||
|
||||
* `ami_description` (string) - The description to set for the resulting
|
||||
@@ -151,7 +155,7 @@ each category, the available configuration keys are alphabetized.
|
||||
* `enhanced_networking` (boolean) - Enable enhanced networking (SriovNetSupport) on
|
||||
HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your AWS IAM policy.
|
||||
|
||||
* `force_deregister` (boolean) – Force Packer to first deregister an existing
|
||||
* `force_deregister` (boolean) - Force Packer to first deregister an existing
|
||||
AMI if one with the same name already exists. Default `false`.
|
||||
|
||||
* `iam_instance_profile` (string) - The name of an
|
||||
@@ -193,20 +197,9 @@ AMI if one with the same name already exists. Default `false`.
|
||||
generate a temporary keypair. `ssh_private_key_file` must be specified
|
||||
with this.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be available on. This defaults
|
||||
to port 22.
|
||||
|
||||
* `ssh_private_key_file` (string) - Use this ssh private key file instead of
|
||||
a generated ssh key pair for connecting to the instance. This key file must
|
||||
already exist on the `source_ami`
|
||||
|
||||
* `ssh_private_ip` (bool) - If true, then SSH will always use the private
|
||||
* `ssh_private_ip` (boolean) - If true, then SSH will always use the private
|
||||
IP if available.
|
||||
|
||||
* `ssh_timeout` (string) - The time to wait for SSH to become available
|
||||
before timing out. The format of this value is a duration such as "5s"
|
||||
or "5m". The default SSH timeout is "5m", or five minutes.
|
||||
|
||||
* `subnet_id` (string) - If using VPC, the ID of the subnet, such as
|
||||
"subnet-12345def", where Packer will launch the EC2 instance. This field is
|
||||
required if you are using an non-default VPC.
|
||||
|
||||
@@ -24,6 +24,10 @@ There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `api_token` (string) - The client TOKEN to use to access your account.
|
||||
@@ -53,16 +57,6 @@ each category, the available configuration keys are alphabetized.
|
||||
To help make this unique, use a function like `timestamp` (see
|
||||
[configuration templates](/docs/templates/configuration-templates.html) for more info)
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be available on. Defaults to port
|
||||
22.
|
||||
|
||||
* `ssh_timeout` (string) - The time to wait for SSH to become available
|
||||
before timing out. The format of this value is a duration such as "5s"
|
||||
or "5m". The default SSH timeout is "1m".
|
||||
|
||||
* `ssh_username` (string) - The username to use in order to communicate
|
||||
over SSH to the running droplet. Default is "root".
|
||||
|
||||
* `state_timeout` (string) - The time to wait, as a duration string,
|
||||
for a droplet to enter a desired state (such as "active") before
|
||||
timing out. The default state timeout is "6m".
|
||||
|
||||
@@ -62,6 +62,10 @@ Configuration options are organized below into two categories: required and
|
||||
optional. Within each category, the available options are alphabetized and
|
||||
described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `commit` (boolean) - If true, the container will be committed to an
|
||||
@@ -113,7 +117,10 @@ _exported_. More specifically, if you set `export_path` in your configuration.
|
||||
If you set `commit`, see the next section.
|
||||
|
||||
The example below shows a full configuration that would import and push
|
||||
the created image:
|
||||
the created image. This is accomplished using a sequence definition (a
|
||||
collection of post-processors that are treated as as single pipeline, see
|
||||
[Post-Processors](/docs/templates/post-processors.html)
|
||||
for more information):
|
||||
|
||||
```javascript
|
||||
{
|
||||
@@ -130,6 +137,12 @@ the created image:
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the result of each builder is passed through the defined
|
||||
sequence of post-processors starting first with the `docker-import`
|
||||
post-processor which will import the artifact as a docker image. The resulting
|
||||
docker image is then passed on to the `docker-push` post-processor which handles
|
||||
pushing the image to a container repository.
|
||||
|
||||
If you want to do this manually, however, perhaps from a script, you can
|
||||
import the image using the process below:
|
||||
|
||||
@@ -142,9 +155,12 @@ and `docker push`, respectively.
|
||||
|
||||
## Using the Artifact: Committed
|
||||
|
||||
If you committed your container to an image, you probably want to tag,
|
||||
save, push, etc. Packer can do this automatically for you. An example is
|
||||
shown below which tags and pushes the image:
|
||||
If you committed your container to an image, you probably want to tag, save,
|
||||
push, etc. Packer can do this automatically for you. An example is shown below
|
||||
which tags and pushes an image. This is accomplished using a sequence
|
||||
definition (a collection of post-processors that are treated as as single
|
||||
pipeline, see [Post-Processors](/docs/templates/post-processors.html) for more
|
||||
information):
|
||||
|
||||
```javascript
|
||||
{
|
||||
@@ -161,6 +177,39 @@ shown below which tags and pushes the image:
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the result of each builder is passed through the defined
|
||||
sequence of post-processors starting first with the `docker-tag` post-processor
|
||||
which tags the committed image with the supplied repository and tag information.
|
||||
Once tagged, the resulting artifact is then passed on to the `docker-push`
|
||||
post-processor which handles pushing the image to a container repository.
|
||||
|
||||
Going a step further, if you wanted to tag and push an image to multiple
|
||||
container repositories, this could be accomplished by defining two,
|
||||
nearly-identical sequence definitions, as demonstrated by the example below:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"post-processors": [
|
||||
[
|
||||
{
|
||||
"type": "docker-tag",
|
||||
"repository": "mitchellh/packer",
|
||||
"tag": "0.7"
|
||||
},
|
||||
"docker-push"
|
||||
],
|
||||
[
|
||||
{
|
||||
"type": "docker-tag",
|
||||
"repository": "hashicorp/packer",
|
||||
"tag": "0.7"
|
||||
},
|
||||
"docker-push"
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Dockerfiles
|
||||
|
||||
This builder allows you to build Docker images _without_ Dockerfiles.
|
||||
|
||||
@@ -15,7 +15,7 @@ Compute Engine doesn't allow the creation of images from scratch.
|
||||
|
||||
## Authentication
|
||||
|
||||
Authenticating with Google Cloud services requires at most one JSON file,
|
||||
Authenticating with Google Cloud services requires at most one JSON file,
|
||||
called the _account file_. The _account file_ is **not** required if you are running
|
||||
the `googlecompute` Packer builder from a GCE instance with a properly-configured
|
||||
[Compute Engine Service Account](https://cloud.google.com/compute/docs/authentication).
|
||||
@@ -23,7 +23,7 @@ the `googlecompute` Packer builder from a GCE instance with a properly-configure
|
||||
### Running With a Compute Engine Service Account
|
||||
If you run the `googlecompute` Packer builder from a GCE instance, you can configure that
|
||||
instance to use a [Compute Engine Service Account](https://cloud.google.com/compute/docs/authentication). This will allow Packer to authenticate
|
||||
to Google Cloud without having to bake in a separate credential/authentication file.
|
||||
to Google Cloud without having to bake in a separate credential/authentication file.
|
||||
|
||||
To create a GCE instance that uses a service account, provide the required scopes when
|
||||
launching the instance.
|
||||
@@ -85,6 +85,10 @@ existing GCE image. The account file is obtained in the previous section.
|
||||
Configuration options are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `project_id` (string) - The project ID that will be used to launch instances
|
||||
@@ -120,13 +124,6 @@ each category, the available options are alphabetized and described.
|
||||
* `network` (string) - The Google Compute network to use for the launched
|
||||
instance. Defaults to `"default"`.
|
||||
|
||||
* `ssh_port` (integer) - The SSH port. Defaults to `22`.
|
||||
|
||||
* `ssh_timeout` (string) - The time to wait for SSH to become available.
|
||||
Defaults to `"1m"`.
|
||||
|
||||
* `ssh_username` (string) - The SSH username. Defaults to `"root"`.
|
||||
|
||||
* `state_timeout` (string) - The time to wait for instance state changes.
|
||||
Defaults to `"5m"`.
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ no provisioners are defined, but it will connect to the specified host via ssh.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"type": "null",
|
||||
"host": "127.0.0.1",
|
||||
"type": "null",
|
||||
"ssh_host": "127.0.0.1",
|
||||
"ssh_username": "foo",
|
||||
"ssh_password": "bar"
|
||||
}
|
||||
@@ -29,23 +29,6 @@ no provisioners are defined, but it will connect to the specified host via ssh.
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
Configuration options are organized into two categories: required and
|
||||
optional. Within each category, the available options are alphabetized and
|
||||
described.
|
||||
|
||||
### Required:
|
||||
|
||||
* `host` (string) - The hostname or IP address to connect to.
|
||||
|
||||
* `ssh_password` (string) - The password to be used for the ssh connection.
|
||||
Cannot be combined with ssh_private_key_file.
|
||||
|
||||
* `ssh_private_key_file` (string) - The filename of the ssh private key to be
|
||||
used for the ssh connection. E.g. /home/user/.ssh/identity_rsa.
|
||||
|
||||
* `ssh_username` (string) - The username to be used for the ssh connection.
|
||||
|
||||
### Optional:
|
||||
|
||||
* `port` (integer) - ssh port to connect to, defaults to 22.
|
||||
The null builder has no configuration parameters other than the
|
||||
[communicator](/docs/templates/communicator.html) settings.
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `flavor` (string) - The ID, name, or full URL for the desired flavor for the
|
||||
@@ -82,16 +86,6 @@ each category, the available configuration keys are alphabetized.
|
||||
If not specified, Packer will use the environment variable
|
||||
`OS_REGION_NAME`, if set.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be available on. Defaults to port
|
||||
22.
|
||||
|
||||
* `ssh_timeout` (string) - The time to wait for SSH to become available
|
||||
before timing out. The format of this value is a duration such as "5s"
|
||||
or "1m". The default SSH timeout is "5m".
|
||||
|
||||
* `ssh_username` (string) - The username to use in order to communicate
|
||||
over SSH to the running server. The default is "root".
|
||||
|
||||
* `ssh_interface` (string) - The type of interface to connect via SSH. Values
|
||||
useful for Rackspace are "public" or "private", and the default behavior is
|
||||
to connect via whichever is returned first from the OpenStack API.
|
||||
|
||||
@@ -50,6 +50,10 @@ There are many configuration options available for the Parallels builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
||||
@@ -190,21 +194,6 @@ each category, the available options are alphabetized and described.
|
||||
If it doesn't shut down in this time, it is an error. By default, the timeout
|
||||
is "5m", or five minutes.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be listening on in the guest
|
||||
virtual machine. By default this is 22.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `vm_name` (string) - This is the name of the PVM directory for the new
|
||||
virtual machine, without the file extension. By default this is
|
||||
"packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
|
||||
@@ -46,6 +46,10 @@ There are many configuration options available for the Parallels builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `source_path` (string) - The path to a PVM directory that acts as
|
||||
@@ -133,21 +137,6 @@ each category, the available options are alphabetized and described.
|
||||
If it doesn't shut down in this time, it is an error. By default, the timeout
|
||||
is "5m", or five minutes.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be listening on in the guest
|
||||
virtual machine. By default this is 22.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `vm_name` (string) - This is the name of the virtual machine when it is
|
||||
imported as well as the name of the PVM directory when the virtual machine is
|
||||
exported. By default this is "packer-BUILDNAME", where "BUILDNAME" is
|
||||
|
||||
@@ -73,6 +73,10 @@ There are many configuration options available for the Qemu builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
||||
@@ -112,11 +116,11 @@ each category, the available options are alphabetized and described.
|
||||
the default is 10 seconds.
|
||||
|
||||
* `disk_cache` (string) - The cache mode to use for disk. Allowed values
|
||||
values include any of "writethrough", "writeback", "none", "unsafe" or
|
||||
"directsync".
|
||||
include any of "writethrough", "writeback", "none", "unsafe" or
|
||||
"directsync". By default, this is set to "writeback".
|
||||
|
||||
* `disk_discard` (string) - The discard mode to use for disk. Allowed values
|
||||
include any of "unmap" or "ignore".
|
||||
include any of "unmap" or "ignore". By default, this is set to "ignore".
|
||||
|
||||
* `disk_image` (boolean) - Packer defaults to building from an ISO file,
|
||||
this parameter controls whether the ISO URL supplied is actually a bootable
|
||||
@@ -144,7 +148,7 @@ each category, the available options are alphabetized and described.
|
||||
* `format` (string) - Either "qcow2" or "raw", this specifies the output
|
||||
format of the virtual machine image. This defaults to "qcow2".
|
||||
|
||||
* `headless` (boolean) - Packer defaults to building virtual machines by
|
||||
* `headless` (boolean) - Packer defaults to building QEMU virtual machines by
|
||||
launching a GUI that shows the console of the machine being built.
|
||||
When this value is set to true, the machine will start without a console.
|
||||
|
||||
@@ -184,6 +188,11 @@ each category, the available options are alphabetized and described.
|
||||
By default this is "output-BUILDNAME" where "BUILDNAME" is the name
|
||||
of the build.
|
||||
|
||||
* `qemu_binary` (string) - The name of the Qemu binary to look for. This
|
||||
defaults to "qemu-system-x86_64", but may need to be changed for some
|
||||
platforms. For example "qemu-kvm", or "qemu-system-i386" may be a better
|
||||
choice for some systems.
|
||||
|
||||
* `qemuargs` (array of array of strings) - Allows complete control over
|
||||
the qemu command line (though not, at this time, qemu-img). Each array
|
||||
of strings makes up a command line switch that overrides matching default
|
||||
@@ -221,11 +230,6 @@ qemu-system-x86 command. The arguments are all printed for review.
|
||||
qemu-system-x86 -m 1024m --no-acpi -netdev user,id=mynet0,hostfwd=hostip:hostport-guestip:guestport -device virtio-net,netdev=mynet0"
|
||||
</pre>
|
||||
|
||||
* `qemu_binary` (string) - The name of the Qemu binary to look for. This
|
||||
defaults to "qemu-system-x86_64", but may need to be changed for some
|
||||
platforms. For example "qemu-kvm", or "qemu-system-i386" may be a better
|
||||
choice for some systems.
|
||||
|
||||
* `shutdown_command` (string) - The command to use to gracefully shut down
|
||||
the machine once all the provisioning is done. By default this is an empty
|
||||
string, which tells Packer to just forcefully shut down the machine.
|
||||
@@ -241,23 +245,6 @@ qemu-system-x86 command. The arguments are all printed for review.
|
||||
Packer will choose a randomly available port in this range to use as the
|
||||
host port.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be listening on in the guest
|
||||
virtual machine. By default this is 22. The Qemu builder will map, via
|
||||
port forward, a port on the host machine to the port listed here so
|
||||
machines outside the installing VM can access the VM.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `vm_name` (string) - This is the name of the image (QCOW2 or IMG) file for
|
||||
the new virtual machine, without the file extension. By default this is
|
||||
"packer-BUILDNAME", where "BUILDNAME" is the name of the build.
|
||||
|
||||
@@ -33,7 +33,6 @@ Ubuntu to self-install. Still, the example serves to show the basic configuratio
|
||||
"iso_checksum_type": "md5",
|
||||
"ssh_username": "packer",
|
||||
"ssh_password": "packer",
|
||||
"ssh_wait_timeout": "30s",
|
||||
"shutdown_command": "echo 'packer' | sudo -S shutdown -P now"
|
||||
}
|
||||
```
|
||||
@@ -48,6 +47,10 @@ There are many configuration options available for the VirtualBox builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
||||
@@ -196,22 +199,7 @@ each category, the available options are alphabetized and described.
|
||||
Packer will choose a randomly available port in this range to use as the
|
||||
host port.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be listening on in the guest
|
||||
virtual machine. By default this is 22.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `ssh_skip_nat_mapping` (bool) - Defaults to false. When enabled, Packer does
|
||||
* `ssh_skip_nat_mapping` (boolean) - Defaults to false. When enabled, Packer does
|
||||
not setup forwarded port mapping for SSH requests and uses `ssh_port` on the
|
||||
host to communicate to the virtual machine
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ the settings here.
|
||||
"source_path": "source.ovf",
|
||||
"ssh_username": "packer",
|
||||
"ssh_password": "packer",
|
||||
"ssh_wait_timeout": "30s",
|
||||
"shutdown_command": "echo 'packer' | sudo -S shutdown -P now"
|
||||
}
|
||||
```
|
||||
@@ -54,6 +53,10 @@ There are many configuration options available for the VirtualBox builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `source_path` (string) - The path to an OVF or OVA file that acts as
|
||||
@@ -171,22 +174,7 @@ each category, the available options are alphabetized and described.
|
||||
Packer will choose a randomly available port in this range to use as the
|
||||
host port.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be listening on in the guest
|
||||
virtual machine. By default this is 22.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `ssh_skip_nat_mapping` (bool) - Defaults to false. When enabled, Packer does
|
||||
* `ssh_skip_nat_mapping` (boolean) - Defaults to false. When enabled, Packer does
|
||||
not setup forwarded port mapping for SSH requests and uses `ssh_port` on the
|
||||
host to communicate to the virtual machine
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ Ubuntu to self-install. Still, the example serves to show the basic configuratio
|
||||
"iso_checksum": "af5f788aee1b32c4b2634734309cc9e9",
|
||||
"iso_checksum_type": "md5",
|
||||
"ssh_username": "packer",
|
||||
"ssh_wait_timeout": "30s",
|
||||
"shutdown_command": "shutdown -P now"
|
||||
}
|
||||
```
|
||||
@@ -49,6 +48,10 @@ There are many configuration options available for the VMware builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
||||
@@ -201,28 +204,6 @@ each category, the available options are alphabetized and described.
|
||||
slightly larger. If you find this to be the case, you can disable compaction
|
||||
using this configuration value.
|
||||
|
||||
* `ssh_host` (string) - Hostname or IP address of the host. By default, DHCP
|
||||
is used to connect to the host and this field is not used.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will listen on within the virtual
|
||||
machine. By default this is 22.
|
||||
|
||||
* `ssh_skip_request_pty` (boolean) - If true, a pty will not be requested as
|
||||
part of the SSH connection. By default, this is "false", so a pty
|
||||
_will_ be requested.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `tools_upload_flavor` (string) - The flavor of the VMware Tools ISO to
|
||||
upload into the VM. Valid values are "darwin", "linux", and "windows".
|
||||
By default, this is empty, which means VMware tools won't be uploaded.
|
||||
|
||||
@@ -44,6 +44,10 @@ There are many configuration options available for the VMware builder.
|
||||
They are organized below into two categories: required and optional. Within
|
||||
each category, the available options are alphabetized and described.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
* `source_path` (string) - Path to the source VMX file to clone.
|
||||
@@ -126,25 +130,6 @@ each category, the available options are alphabetized and described.
|
||||
slightly larger. If you find this to be the case, you can disable compaction
|
||||
using this configuration value.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will listen on within the virtual
|
||||
machine. By default this is 22.
|
||||
|
||||
* `ssh_skip_request_pty` (boolean) - If true, a pty will not be requested as
|
||||
part of the SSH connection. By default, this is "false", so a pty
|
||||
_will_ be requested.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `vm_name` (string) - This is the name of the VMX file for the new virtual
|
||||
machine, without the file extension. By default this is "packer-BUILDNAME",
|
||||
where "BUILDNAME" is the name of the build.
|
||||
|
||||
@@ -5,18 +5,41 @@ description: |-
|
||||
Packer strives to be stable and bug-free, but issues inevitably arise where certain things may not work entirely correctly, or may not appear to work correctly. In these cases, it is sometimes helpful to see more details about what Packer is actually doing.
|
||||
---
|
||||
|
||||
# Debugging Packer
|
||||
# Debugging Packer Builds
|
||||
|
||||
Packer strives to be stable and bug-free, but issues inevitably arise where
|
||||
certain things may not work entirely correctly, or may not appear to work
|
||||
correctly. In these cases, it is sometimes helpful to see more details about
|
||||
what Packer is actually doing.
|
||||
For remote builds with cloud providers like Amazon Web Services AMIs, debugging
|
||||
a Packer build can be eased greatly with `packer build -debug`. This disables
|
||||
parallelization and enables debug mode.
|
||||
|
||||
Debug mode informs the builders that they should output debugging information.
|
||||
The exact behavior of debug mode is left to the builder. In general, builders
|
||||
usually will stop between each step, waiting for keyboard input before
|
||||
continuing. This will allow you to inspect state and so on.
|
||||
|
||||
In debug mode once the remote instance is instantiated, Packer will emit to the
|
||||
current directory an emphemeral private ssh key as a .pem file. Using that you
|
||||
can `ssh -i <key.pem>` into the remote build instance and see what is going on
|
||||
for debugging. The emphemeral key will be deleted at the end of the packer run
|
||||
during cleanup.
|
||||
|
||||
### Windows
|
||||
As of Packer 0.8.1 the default WinRM communicator will emit the password for a
|
||||
Remote Desktop Connection into your instance. This happens following the several
|
||||
minute pause as the instance is booted. Note a .pem key is still created for
|
||||
securely transmitting the password. Packer automatically decrypts the password
|
||||
for you in debug mode.
|
||||
|
||||
## Debugging Packer
|
||||
|
||||
Issues occasionally arise where certain things may not work entirely correctly,
|
||||
or may not appear to work correctly. In these cases, it is sometimes helpful to
|
||||
see more details about what Packer is actually doing.
|
||||
|
||||
Packer has detailed logs which can be enabled by setting the `PACKER_LOG`
|
||||
environmental variable to any value. This will cause detailed logs to appear
|
||||
on stderr. The logs contain log messages from Packer as well as any plugins
|
||||
that are being used. Log messages from plugins are prefixed by their application
|
||||
name.
|
||||
environmental variable to any value like this `PACKER_LOG=1 packer build
|
||||
<config.json>`. This will cause detailed logs to appear on stderr. The logs
|
||||
contain log messages from Packer as well as any plugins that are being used. Log
|
||||
messages from plugins are prefixed by their application name.
|
||||
|
||||
Note that because Packer is highly parallelized, log messages sometimes
|
||||
appear out of order, especially with respect to plugins. In this case,
|
||||
|
||||
@@ -37,10 +37,10 @@ The configuration allows you to specify and access the artifact in Atlas.
|
||||
have access to the organization, hashicorp in this example, in order to add an artifact to
|
||||
the organization in Atlas.
|
||||
|
||||
* `artifact_type` (string) - For uploading AMIs to Atlas, `artifact_type` will always be `aws.ami`.
|
||||
* `artifact_type` (string) - For uploading AMIs to Atlas, `artifact_type` will always be `amazon.ami`.
|
||||
This field must be defined because Atlas can host other artifact types, such as Vagrant boxes.
|
||||
|
||||
-> **Note:** If you want to upload Vagrant boxes to Atlas, for now use the [Vagrant Cloud post-processor](/docs/post-processors/vagrant-cloud.html).
|
||||
-> **Note:** If you want to upload Vagrant boxes to Atlas, use the [Atlas post-processor](/docs/post-processors/atlas.html).
|
||||
|
||||
### Optional:
|
||||
|
||||
@@ -85,7 +85,7 @@ to `https://atlas.hashicorp.com/api/v1`.
|
||||
"type": "atlas",
|
||||
"token": "{{user `atlas_token`}}",
|
||||
"artifact": "hashicorp/foobar",
|
||||
"artifact_type": "aws.ami",
|
||||
"artifact_type": "amazon.ami",
|
||||
"metadata": {
|
||||
"created_at": "{{timestamp}}"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ If you want more control over how the archive is created you can specify the fol
|
||||
that support it, from 1 through 9 inclusive. Typically higher compression
|
||||
levels take longer but produce smaller files. Defaults to `6`
|
||||
|
||||
* `keep_input_artifact` (bool) - Keep source files; defaults to `false`
|
||||
* `keep_input_artifact` (boolean) - Keep source files; defaults to `false`
|
||||
|
||||
### Supported Formats
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ description: |-
|
||||
|
||||
# Vagrant Cloud Post-Processor
|
||||
|
||||
~> Vagrant Cloud has been superseded by Atlas. Please use the [Atlas post-processor](/docs/post-processors/atlas.html) instead. Learn more about [Atlas](https://atlas.hashicorp.com/).
|
||||
|
||||
Type: `vagrant-cloud`
|
||||
|
||||
The Packer Vagrant Cloud post-processor receives a Vagrant box from the `vagrant`
|
||||
|
||||
@@ -41,15 +41,16 @@ Optional:
|
||||
* `extra_arguments` (array of strings) - An array of extra arguments to pass to the
|
||||
ansible command. By default, this is empty.
|
||||
|
||||
* `inventory_groups` (string) - You can let Packer generate a temporary inventory
|
||||
for you. It will contains only `127.0.0.1`. Thanks to `inventory_groups`,
|
||||
packer will set the current machine into different groups and will
|
||||
generate an inventory like:
|
||||
* `inventory_groups` (string) - A comma-separated list of groups to which
|
||||
packer will assign the host `127.0.0.1`. A value of `my_group_1,my_group_2`
|
||||
will generate an Ansible inventory like:
|
||||
|
||||
```text
|
||||
[my_group_1]
|
||||
127.0.0.1
|
||||
[my_group_2]
|
||||
127.0.0.1
|
||||
```
|
||||
|
||||
* `inventory_file` (string) - The inventory file to be used by ansible.
|
||||
This file must exist on your local system and will be uploaded to the
|
||||
|
||||
@@ -113,11 +113,17 @@ The default value for the configuration template is:
|
||||
log_level :info
|
||||
log_location STDOUT
|
||||
chef_server_url "{{.ServerUrl}}"
|
||||
{{if ne .ValidationClientName ""}}
|
||||
validation_client_name "{{.ValidationClientName}}"
|
||||
{{else}}
|
||||
validation_client_name "chef-validator"
|
||||
{{end}}
|
||||
{{if ne .ValidationKeyPath ""}}
|
||||
validation_key "{{.ValidationKeyPath}}"
|
||||
{{end}}
|
||||
{{if ne .NodeName ""}}
|
||||
node_name "{{.NodeName}}"
|
||||
{{end}}
|
||||
```
|
||||
|
||||
This template is a [configuration template](/docs/templates/configuration-templates.html)
|
||||
|
||||
@@ -40,9 +40,12 @@ The reference of available configuration options is listed below.
|
||||
|
||||
Required parameters:
|
||||
|
||||
* `manifest_file` (string) - The manifest file for Puppet to use in order
|
||||
to compile and run a catalog. This file must exist on your local system
|
||||
and will be uploaded to the remote machine.
|
||||
* `manifest_file` (string) - This is either a path to a puppet manifest (`.pp`
|
||||
file) _or_ a directory containing multiple manifests that puppet will apply
|
||||
(the ["main manifest"][1]). These file(s) must exist on your local system and
|
||||
will be uploaded to the remote machine.
|
||||
|
||||
[1]: https://docs.puppetlabs.com/puppet/latest/reference/dirs_manifest.html
|
||||
|
||||
Optional parameters:
|
||||
|
||||
@@ -64,6 +67,10 @@ Optional parameters:
|
||||
the `manifest_file`. It is a separate directory that will be set as
|
||||
the "manifestdir" setting on Puppet.
|
||||
|
||||
~> `manifest_dir` is passed to `puppet apply` as the `--manifestdir` option.
|
||||
This option was deprecated in puppet 3.6, and removed in puppet 4.0. If you
|
||||
have multiple manifests you should use `manifest_file` instead.
|
||||
|
||||
* `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.
|
||||
|
||||
@@ -51,7 +51,7 @@ required. They are listed below:
|
||||
* `facter` (object of key/value strings) - Additional Facter facts to make available to the
|
||||
Puppet run.
|
||||
|
||||
* `ignore_exit_codes` (bool) - If true, Packer will never consider the
|
||||
* `ignore_exit_codes` (boolean) - If true, Packer will never consider the
|
||||
provisioner a failure.
|
||||
|
||||
* `options` (string) - Additional command line options to pass
|
||||
|
||||
@@ -89,10 +89,14 @@ Optional parameters:
|
||||
|
||||
To many new users, the `execute_command` is puzzling. However, it provides
|
||||
an important function: customization of how the command is executed. The
|
||||
most common use case for this is dealing with **sudo password prompts**.
|
||||
most common use case for this is dealing with **sudo password prompts**. You may
|
||||
also need to customize this if you use a non-POSIX shell, such as `tcsh` on
|
||||
FreeBSD.
|
||||
|
||||
For example, if the default user of an installed operating system is "packer"
|
||||
and has the password "packer" for sudo usage, then you'll likely want to
|
||||
### Sudo Example
|
||||
|
||||
Some operating systems default to a non-root user. For example if you login
|
||||
as `ubuntu` and can sudo using the password `packer`, then you'll want to
|
||||
change `execute_command` to be:
|
||||
|
||||
```text
|
||||
@@ -100,13 +104,23 @@ change `execute_command` to be:
|
||||
```
|
||||
|
||||
The `-S` flag tells `sudo` to read the password from stdin, which in this
|
||||
case is being piped in with the value of "packer". The `-E` flag tells `sudo`
|
||||
case is being piped in with the value of `packer`. The `-E` flag tells `sudo`
|
||||
to preserve the environment, allowing our environmental variables to work
|
||||
within the script.
|
||||
|
||||
By setting the `execute_command` to this, your script(s) can run with
|
||||
root privileges without worrying about password prompts.
|
||||
|
||||
### FreeBSD Example
|
||||
|
||||
FreeBSD's default shell is `tcsh`, which deviates from POSIX sematics. In order
|
||||
for packer to pass environment variables you will need to change the
|
||||
`execute_command` to:
|
||||
|
||||
chmod +x {{ .Path }}; env {{ .Vars }} {{ .Path }}
|
||||
|
||||
Note the addition of `env` before `{{ .Vars }}`.
|
||||
|
||||
## Default Environmental Variables
|
||||
|
||||
In addition to being able to specify custom environmental variables using
|
||||
|
||||
@@ -61,3 +61,15 @@ you can specify a custom name using the `name` key within the builder definition
|
||||
This is particularly useful if you have multiple builds defined that use
|
||||
the same underlying builder. In this case, you must specify a name for at least
|
||||
one of them since the names must be unique.
|
||||
|
||||
## Communicators
|
||||
|
||||
Every build is associated with a single
|
||||
[communicator](/docs/templates/communicator.html). Communicators are
|
||||
used to establish a connection for provisioning a remote machine (such
|
||||
as an AWS instance or local virtual machine).
|
||||
|
||||
All the examples for the various builders show some communicator (usually
|
||||
SSH), but the communicators are highly customizable so we recommend
|
||||
reading the
|
||||
[communicator documentation](/docs/templates/communicator.html).
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
---
|
||||
layout: "docs"
|
||||
page_title: "Templates: Communicators"
|
||||
description: |-
|
||||
Communicators are the mechanism Packer uses to upload files, execute scripts, etc. with the machine being created.
|
||||
---
|
||||
|
||||
# Templates: Communicators
|
||||
|
||||
Communicators are the mechanism Packer uses to upload files, execute
|
||||
scripts, etc. with the machine being created.
|
||||
|
||||
Communicators are configured within the [builder](/docs/templates/builders.html)
|
||||
section. Packer currently supports three kinds of communicators:
|
||||
|
||||
* `none` - No communicator will be used. If this is set, most provisioners
|
||||
also can't be used.
|
||||
|
||||
* `ssh` - An SSH connection will be established to the machine. This is
|
||||
usually the default.
|
||||
|
||||
* `winrm` - A WinRM connection will be established.
|
||||
|
||||
In addition to the above, some builders have custom communicators they can
|
||||
use. For example, the Docker builder has a "docker" communicator that uses
|
||||
`docker exec` and `docker cp` to execute scripts and copy files.
|
||||
|
||||
## Using a Communicator
|
||||
|
||||
By default, the SSH communicator is usually used. Additional configuration
|
||||
may not even be necessary, since some builders such as Amazon automatically
|
||||
configure everything.
|
||||
|
||||
However, to specify a communicator, you set the `communicator` key within
|
||||
a build. Multiple builds can have different communicators. Example:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"builders": [{
|
||||
"type": "amazon-ebs",
|
||||
"communicator": "ssh"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
After specifying the `communicator`, you can specify a number of other
|
||||
configuration parameters for that communicator. These are documented below.
|
||||
|
||||
## SSH Communicator
|
||||
|
||||
The SSH communicator connects to the host via SSH. If you have an SSH
|
||||
agent enabled on the machine running Packer, it will automatically forward
|
||||
the SSH agent to the remote host.
|
||||
|
||||
The SSH communicator has the following options:
|
||||
|
||||
* `ssh_host` (string) - The address to SSH to. This usually is automatically
|
||||
configured by the builder.
|
||||
|
||||
* `ssh_port` (int) - The port to connect to SSH. This defaults to 22.
|
||||
|
||||
* `ssh_username` (string) - The username to connect to SSH with.
|
||||
|
||||
* `ssh_password` (string) - A plaintext password to use to authenticate
|
||||
with SSH.
|
||||
|
||||
* `ssh_private_key_file` (string) - Path to a PEM encoded private key
|
||||
file to use to authentiate with SSH.
|
||||
|
||||
* `ssh_pty` (boolean) - If true, a PTY will be requested for the SSH connection.
|
||||
This defaults to false.
|
||||
|
||||
* `ssh_timeout` (string) - The time to wait for SSH to become available.
|
||||
Packer uses this to determine when the machine has booted so this is usually
|
||||
quite long. Example value: "10m"
|
||||
|
||||
* `ssh_handshake_attempts` (int) - The number of handshakes to attempt with
|
||||
SSH once it can connect. This defaults to 10.
|
||||
|
||||
* `ssh_disable_agent` (boolean) - If true, SSH agent forwarding will be disabled.
|
||||
|
||||
* `ssh_bastion_host` (string) - A bastion host to use for the actual
|
||||
SSH connection.
|
||||
|
||||
* `ssh_bastion_port` (int) - The port of the bastion host. Defaults to 22.
|
||||
|
||||
* `ssh_bastion_username` (string) - The username to connect to the bastion host.
|
||||
|
||||
* `ssh_bastion_password` (string) - The password to use to authenticate
|
||||
with the bastion host.
|
||||
|
||||
* `ssh_bastion_private_key_file` (string) - A private key file to use
|
||||
to authenticate with the bastion host.
|
||||
|
||||
## WinRM Communicator
|
||||
|
||||
The WinRM communicator has the following options.
|
||||
|
||||
* `winrm_host` (string) - The address for WinRM to connect to.
|
||||
|
||||
* `winrm_port` (int) - The WinRM port to connect to. This defaults to 5985.
|
||||
|
||||
* `winrm_username` (string) - The username to use to connect to WinRM.
|
||||
|
||||
* `winrm_password` (string) - The password to use to connect to WinRM.
|
||||
|
||||
* `winrm_timeout` (string) - The amount of time to wait for WinRM to
|
||||
become available. This defaults to "30m" since setting up a Windows
|
||||
machine generally takes a long time.
|
||||
+1
-1
@@ -59,7 +59,7 @@ each category, the available configuration keys are alphabetized.
|
||||
* `token` (string) - An access token to use to authenticate to the build
|
||||
service.
|
||||
|
||||
* `vcs` (bool) - If true, Packer will detect your VCS (if there is one)
|
||||
* `vcs` (boolean) - If true, Packer will detect your VCS (if there is one)
|
||||
and only upload the files that are tracked by the VCS. This is useful
|
||||
for automatically excluding ignored files. This defaults to false.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ description: |-
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-1">
|
||||
<h2>
|
||||
<span class="text-green">Packer</span> is a tool for creating identical machine images for multiple platforms from a single source configuration.
|
||||
<span class="text-green">Packer</span> is a tool for creating machine and container images for multiple platforms from a single source configuration.
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,7 +58,7 @@ description: |-
|
||||
<h2 class="text-green text-center">Works Great With</h2>
|
||||
<p>
|
||||
Out of the box Packer comes with support to build images for
|
||||
Amazon EC2, DigitalOcean, Google Compute Engine, QEMU,
|
||||
Amazon EC2, DigitalOcean, Docker, Google Compute Engine, QEMU,
|
||||
VirtualBox, VMware, and more. Support for
|
||||
more platforms is on the way, and anyone can add new platforms
|
||||
via plugins.
|
||||
|
||||
@@ -54,7 +54,7 @@ briefly. Create a file `example.json` and fill it with the following contents:
|
||||
"access_key": "{{user `aws_access_key`}}",
|
||||
"secret_key": "{{user `aws_secret_key`}}",
|
||||
"region": "us-east-1",
|
||||
"source_ami": "ami-c65be9ae",
|
||||
"source_ami": "ami-de0d9eb7",
|
||||
"instance_type": "t1.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-example {{timestamp}}"
|
||||
|
||||
@@ -17,7 +17,7 @@ the [documentation](/docs). The documentation is less of a guide and
|
||||
more of a reference of all the overall features and options of Packer.
|
||||
|
||||
If you're interested in learning more about how Packer fits into the
|
||||
HashiCorp ecosystem of tools, read our [Atlas getting started overview](https://atlas.hashicorp.com/help/getting-started/getting-started-overview).
|
||||
HashiCorp ecosystem of tools, read our [Atlas getting started overview](https://atlas.hashicorp.com/help/intro/getting-started).
|
||||
|
||||
As you use Packer more, please voice your comments and concerns on
|
||||
the [mailing list or IRC](/community). Additionally, Packer is
|
||||
|
||||
@@ -49,9 +49,9 @@ you're not okay with this, just follow along.
|
||||
!> **Warning!** You _will_ be charged $0.01 by DigitalOcean per image
|
||||
created with Packer because of the time the "droplet" is running.
|
||||
|
||||
Once you sign up for an account, grab your client ID and API key from
|
||||
the [DigitalOcean API access page](https://www.digitalocean.com/api_access).
|
||||
Save these values somewhere, you'll need them in a second.
|
||||
Once you sign up for an account, grab your API token from
|
||||
the [DigitalOcean API access page](https://cloud.digitalocean.com/settings/applications).
|
||||
Save these values somewhere; you'll need them in a second.
|
||||
|
||||
## Modifying the Template
|
||||
|
||||
@@ -62,8 +62,10 @@ array.
|
||||
```javascript
|
||||
{
|
||||
"type": "digitalocean",
|
||||
"api_key": "{{user `do_api_key`}}",
|
||||
"client_id": "{{user `do_client_id`}}"
|
||||
"api_token": "{{user `do_api_token`}}",
|
||||
"image": "ubuntu-14-04-x64",
|
||||
"region": "nyc3",
|
||||
"size": "512mb",
|
||||
}
|
||||
```
|
||||
|
||||
@@ -72,13 +74,46 @@ to include the access keys for DigitalOcean.
|
||||
|
||||
```javascript
|
||||
"variables": {
|
||||
"do_api_key": "",
|
||||
"do_client_id": ""
|
||||
"do_api_token": "",
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The entire template should now [look like this](https://gist.github.com/pearkes/cc5f8505eee5403a43a6).
|
||||
The entire template should now look like this:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"variables": {
|
||||
"aws_access_key": "",
|
||||
"aws_secret_key": "",
|
||||
"do_api_token": ""
|
||||
},
|
||||
"builders": [{
|
||||
"type": "amazon-ebs",
|
||||
"access_key": "{{user `aws_access_key`}}",
|
||||
"secret_key": "{{user `aws_secret_key`}}",
|
||||
"region": "us-east-1",
|
||||
"source_ami": "ami-de0d9eb7",
|
||||
"instance_type": "t1.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-example {{timestamp}}"
|
||||
},{
|
||||
"type": "digitalocean",
|
||||
"api_token": "{{user `do_api_token`}}",
|
||||
"image": "ubuntu-14-04-x64",
|
||||
"region": "nyc3",
|
||||
"size": "512mb"
|
||||
}],
|
||||
"provisioners": [{
|
||||
"type": "shell",
|
||||
"inline": [
|
||||
"sleep 30",
|
||||
"sudo apt-get update",
|
||||
"sudo apt-get install -y redis-server"
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
Additional builders are simply added to the `builders` array in the template.
|
||||
This tells Packer to build multiple images. The builder `type` values don't
|
||||
@@ -104,8 +139,7 @@ same.
|
||||
$ packer build \
|
||||
-var 'aws_access_key=YOUR ACCESS KEY' \
|
||||
-var 'aws_secret_key=YOUR SECRET KEY' \
|
||||
-var 'do_api_key=YOUR API KEY' \
|
||||
-var 'do_client_id=YOUR CLIENT ID' \
|
||||
-var 'do_api_token=YOUR API TOKEN' \
|
||||
example.json
|
||||
==> amazon-ebs: amazon-ebs output will be in this color.
|
||||
==> digitalocean: digitalocean output will be in this color.
|
||||
|
||||
@@ -66,7 +66,7 @@ Now we have Atlas building an AMI with Redis pre-configured. This is great, but
|
||||
{
|
||||
"type": "atlas",
|
||||
"artifact": "ATLAS_USERNAME/packer-tutorial",
|
||||
"artifact_type": "aws.ami"
|
||||
"artifact_type": "amazon.ami"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ description: |-
|
||||
|
||||
HashiCorp is the creator of the open source projects Vagrant, Packer, Terraform, Serf, and Consul, and the commercial product Atlas. Packer is just one piece of the ecosystem HashiCorp has built to make application delivery a versioned, auditable, repeatable, and collaborative process. To learn more about our beliefs on the qualities of the modern datacenter and responsible application delivery, read [The Atlas Mindset: Version Control for Infrastructure](https://hashicorp.com/blog/atlas-mindset.html/?utm_source=packer&utm_campaign=HashicorpEcosystem).
|
||||
|
||||
If you are using Packer to build machine images and deployable artifacts, it’s likely that you need a solution for deploying those artifacts. Terraform is our tool for creating, combining, and modifying infrastructure.
|
||||
If you are using Packer to build machine images and deployable artifacts, it's likely that you need a solution for deploying those artifacts. Terraform is our tool for creating, combining, and modifying infrastructure.
|
||||
|
||||
Below are summaries of HashiCorp’s open source projects and a graphic showing how Atlas connects them to create a full application delivery workflow.
|
||||
Below are summaries of HashiCorp's open source projects and a graphic showing how Atlas connects them to create a full application delivery workflow.
|
||||
|
||||
# HashiCorp Ecosystem
|
||||

|
||||
@@ -27,6 +27,6 @@ Below are summaries of HashiCorp’s open source projects and a graphic showing
|
||||
|
||||
[Consul](https://consul.io/?utm_source=packer&utm_campaign=HashicorpEcosystem) is a HashiCorp tool for service discovery, service registry, and health checks. In the Atlas workflow Consul is configured at the Packer build stage and identifies the service(s) contained in each artifact. Since Consul is configured at the build phase with Packer, when the artifact is deployed with Terraform, it is fully configured with dependencies and service discovery pre-baked. This greatly reduces the risk of an unhealthy node in production due to configuration failure at runtime.
|
||||
|
||||
[Serf](https://serfdom.io/?utm_source=packer&utm_campaign=HashicorpEcosystem) is a HashiCorp tool for cluster membership and failure detection. Consul uses Serf’s gossip protocol as the foundation for service discovery.
|
||||
[Serf](https://serfdom.io/?utm_source=packer&utm_campaign=HashicorpEcosystem) is a HashiCorp tool for cluster membership and failure detection. Consul uses Serf's gossip protocol as the foundation for service discovery.
|
||||
|
||||
[Vagrant](https://www.vagrantup.com/?utm_source=packer&utm_campaign=HashicorpEcosystem) is a HashiCorp tool for managing development environments that mirror production. Vagrant environments reduce the friction of developing a project and reduce the risk of unexpected behavior appearing after deployment. Vagrant boxes can be built in parallel with production artifacts with Packer to maintain parity between development and production.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<li><a href="/docs/templates/provisioners.html">Provisioners</a></li>
|
||||
<li><a href="/docs/templates/post-processors.html">Post-Processors</a></li>
|
||||
<li><a href="/docs/templates/push.html">Push</a></li>
|
||||
<li><a href="/docs/templates/communicator.html">Communicators</a></li>
|
||||
<li><a href="/docs/templates/configuration-templates.html">Configuration Templates</a></li>
|
||||
<li><a href="/docs/templates/user-variables.html">User Variables</a></li>
|
||||
<li><a href="/docs/templates/veewee-to-packer.html">Veewee-to-Packer</a></li>
|
||||
|
||||
@@ -51,12 +51,15 @@
|
||||
<div class="col-md-12">
|
||||
<ul>
|
||||
<li class="packer"><a href="/">Packer</a></li>
|
||||
<li>
|
||||
A <a href="http://www.hashicorp.com/">HashiCorp</a> project.
|
||||
</li>
|
||||
<a href="http://www.hashicorp.com">
|
||||
<li class="pull-right hashi-logo">&nbps;</li>
|
||||
</a>
|
||||
<li>
|
||||
A <a href="http://www.hashicorp.com/">HashiCorp</a> project.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/mitchellh/packer/blob/master/website/source/<%= current_page.path %>.markdown">Edit this page</a>
|
||||
</li>
|
||||
<a href="http://www.hashicorp.com">
|
||||
<li class="pull-right hashi-logo">&nbps;</li>
|
||||
</a>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user