Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e61157c5c | |||
| 7c4bd4f2d6 | |||
| 9c6cc829fa | |||
| 53b0223e20 | |||
| 15e80316fe | |||
| 485d5b86d0 | |||
| b0d5bff98f | |||
| 8c51316897 | |||
| 3bcfeafa15 | |||
| 3d461195e3 | |||
| e6a1fc448a | |||
| d1aefb38bb | |||
| e0a66fbe30 | |||
| 80db9efef5 | |||
| 8853e7a17e | |||
| ad38604390 | |||
| 64f4ee380d | |||
| 3bf88e2dd7 | |||
| c8508ade17 | |||
| 4e8db89403 | |||
| 1b8551d843 | |||
| 46ec8f758b | |||
| 46e49b745e | |||
| 4b29fab843 | |||
| 82e21622ef | |||
| e4dda36a1d | |||
| 1216fc1cbb | |||
| 2b4735e825 | |||
| 422e05d8b9 | |||
| 4c273e33c5 | |||
| b24fcbc800 | |||
| 852c10264b | |||
| ef59ee41a8 | |||
| da7febbfb9 |
@@ -1,3 +1,16 @@
|
||||
## 0.2.3 (August 7, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* builder/amazon/all: Added Amazon AMI tag support [GH-233]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: Absolute/relative filepaths on Windows now work for iso_url
|
||||
and other settings. [GH-240]
|
||||
* builder/amazon/all: instance info is refreshed while waiting for SSH,
|
||||
allowing Packer to see updated IP/DNS info. [GH-243]
|
||||
|
||||
## 0.2.2 (August 1, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
@@ -9,15 +9,30 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// StateRefreshFunc is a function type used for StateChangeConf that is
|
||||
// responsible for refreshing the item being watched for a state change.
|
||||
//
|
||||
// It returns three results. `result` is any object that will be returned
|
||||
// as the final object after waiting for state change. This allows you to
|
||||
// return the final updated object, for example an EC2 instance after refreshing
|
||||
// it.
|
||||
//
|
||||
// `state` is the latest state of that object. And `err` is any error that
|
||||
// may have happened while refreshing the state.
|
||||
type StateRefreshFunc func() (result interface{}, state string, err error)
|
||||
|
||||
// StateChangeConf is the configuration struct used for `WaitForState`.
|
||||
type StateChangeConf struct {
|
||||
Conn *ec2.EC2
|
||||
Pending []string
|
||||
Refresh func() (interface{}, string, error)
|
||||
Refresh StateRefreshFunc
|
||||
StepState map[string]interface{}
|
||||
Target string
|
||||
}
|
||||
|
||||
func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) func() (interface{}, string, error) {
|
||||
// InstanceStateRefreshFunc returns a StateRefreshFunc that is used to watch
|
||||
// an EC2 instance.
|
||||
func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := conn.Instances([]string{i.InstanceId}, ec2.NewFilter())
|
||||
if err != nil {
|
||||
@@ -29,6 +44,8 @@ func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) func() (interface{
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForState watches an object and waits for it to achieve a certain
|
||||
// state.
|
||||
func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
|
||||
log.Printf("Waiting for state to become: %s", conf.Target)
|
||||
|
||||
|
||||
@@ -6,23 +6,40 @@ import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/packer/communicator/ssh"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSHAddress returns a function that can be given to the SSH communicator
|
||||
// for determining the SSH address based on the instance DNS name.
|
||||
func SSHAddress(port int) func(map[string]interface{}) (string, error) {
|
||||
func SSHAddress(e *ec2.EC2, port int) func(map[string]interface{}) (string, error) {
|
||||
return func(state map[string]interface{}) (string, error) {
|
||||
var host string
|
||||
instance := state["instance"].(*ec2.Instance)
|
||||
if instance.DNSName != "" {
|
||||
host = instance.DNSName
|
||||
} else if instance.VpcId == "" {
|
||||
host = instance.PrivateIpAddress
|
||||
} else {
|
||||
return "", errors.New("couldn't determine IP address for instance")
|
||||
for j := 0; j < 2; j++ {
|
||||
var host string
|
||||
i := state["instance"].(*ec2.Instance)
|
||||
if i.DNSName != "" {
|
||||
host = i.DNSName
|
||||
} else if i.VpcId != "" {
|
||||
host = i.PrivateIpAddress
|
||||
}
|
||||
|
||||
if host != "" {
|
||||
return fmt.Sprintf("%s:%d", host, port), nil
|
||||
}
|
||||
|
||||
r, err := e.Instances([]string{i.InstanceId}, ec2.NewFilter())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 {
|
||||
return "", fmt.Errorf("instance not found: %s", i.InstanceId)
|
||||
}
|
||||
|
||||
state["instance"] = &r.Reservations[0].Instances[0]
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s:%d", host, port), nil
|
||||
return "", errors.New("couldn't determine IP address for instance")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type StepCreateTags struct {
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
func (s *StepCreateTags) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
amis := state["amis"].(map[string]string)
|
||||
ami := amis[ec2conn.Region.Name]
|
||||
|
||||
if len(s.Tags) > 0 {
|
||||
ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", ami))
|
||||
|
||||
var ec2Tags []ec2.Tag
|
||||
for key, value := range s.Tags {
|
||||
ec2Tags = append(ec2Tags, ec2.Tag{key, value})
|
||||
}
|
||||
|
||||
_, err := ec2conn.CreateTags([]string{ami}, ec2Tags)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error adding tags to AMI (%s): %s", ami, err)
|
||||
state["error"] = err
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCreateTags) Cleanup(state map[string]interface{}) {
|
||||
// No cleanup...
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"text/template"
|
||||
@@ -27,6 +27,9 @@ type config struct {
|
||||
|
||||
// Configuration of the resulting AMI
|
||||
AMIName string `mapstructure:"ami_name"`
|
||||
|
||||
// Tags for the AMI
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
@@ -101,13 +104,14 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SubnetId: b.config.SubnetId,
|
||||
},
|
||||
&common.StepConnectSSH{
|
||||
SSHAddress: awscommon.SSHAddress(b.config.SSHPort),
|
||||
SSHAddress: awscommon.SSHAddress(ec2conn, b.config.SSHPort),
|
||||
SSHConfig: awscommon.SSHConfig(b.config.SSHUsername),
|
||||
SSHWaitTimeout: b.config.SSHTimeout(),
|
||||
},
|
||||
&common.StepProvision{},
|
||||
&stepStopInstance{},
|
||||
&stepCreateAMI{},
|
||||
&awscommon.StepCreateTags{b.config.Tags},
|
||||
}
|
||||
|
||||
// Run!
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os"
|
||||
@@ -33,6 +33,7 @@ type Config struct {
|
||||
BundleUploadCommand string `mapstructure:"bundle_upload_command"`
|
||||
BundleVolCommand string `mapstructure:"bundle_vol_command"`
|
||||
S3Bucket string `mapstructure:"s3_bucket"`
|
||||
Tags map[string]string
|
||||
X509CertPath string `mapstructure:"x509_cert_path"`
|
||||
X509KeyPath string `mapstructure:"x509_key_path"`
|
||||
X509UploadPath string `mapstructure:"x509_upload_path"`
|
||||
@@ -167,7 +168,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SubnetId: b.config.SubnetId,
|
||||
},
|
||||
&common.StepConnectSSH{
|
||||
SSHAddress: awscommon.SSHAddress(b.config.SSHPort),
|
||||
SSHAddress: awscommon.SSHAddress(ec2conn, b.config.SSHPort),
|
||||
SSHConfig: awscommon.SSHConfig(b.config.SSHUsername),
|
||||
SSHWaitTimeout: b.config.SSHTimeout(),
|
||||
},
|
||||
@@ -176,6 +177,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
&StepBundleVolume{},
|
||||
&StepUploadBundle{},
|
||||
&StepRegisterAMI{},
|
||||
&awscommon.StepCreateTags{b.config.Tags},
|
||||
}
|
||||
|
||||
// Run!
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"math/rand"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -73,6 +74,17 @@ func DownloadableURL(original string) (string, error) {
|
||||
}
|
||||
|
||||
if url.Scheme == "file" {
|
||||
// For Windows absolute file paths, remove leading / prior to processing
|
||||
// since net/url turns "C:/" into "/C:/"
|
||||
if runtime.GOOS == "windows" && url.Path[0] == '/' {
|
||||
url.Path = url.Path[1:len(url.Path)]
|
||||
|
||||
// Also replace all backslashes with forwardslashes since Windows
|
||||
// users are likely to do this but the URL should actually only
|
||||
// contain forward slashes.
|
||||
url.Path = strings.Replace(url.Path, `\`, `/`, -1)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(url.Path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// DownloadConfig is the configuration given to instantiate a new
|
||||
@@ -107,6 +108,11 @@ func (d *DownloadClient) Get() (string, error) {
|
||||
var finalPath string
|
||||
if url.Scheme == "file" && !d.config.CopyFile {
|
||||
finalPath = url.Path
|
||||
|
||||
// Remove forward slash on absolute Windows file URLs before processing
|
||||
if runtime.GOOS == "windows" && finalPath[0] == '/' {
|
||||
finalPath = finalPath[1:len(finalPath)]
|
||||
}
|
||||
} else {
|
||||
finalPath = d.config.TargetPath
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
var GitCommit string
|
||||
|
||||
// The version of packer.
|
||||
const Version = "0.2.2"
|
||||
const Version = "0.2.3"
|
||||
|
||||
// Any pre-release marker for the version. If this is "" (empty string),
|
||||
// then it means that it is a final release. Otherwise, this is the
|
||||
|
||||
@@ -3,11 +3,9 @@ package file
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
@@ -23,49 +21,26 @@ type Provisioner struct {
|
||||
}
|
||||
|
||||
func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
var md mapstructure.Metadata
|
||||
decoderConfig := &mapstructure.DecoderConfig{
|
||||
Metadata: &md,
|
||||
Result: &p.config,
|
||||
}
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(decoderConfig)
|
||||
md, err := common.DecodeConfig(&p.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, raw := range raws {
|
||||
err := decoder.Decode(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate any errors
|
||||
errs := make([]error, 0)
|
||||
|
||||
// Unused keys are errors
|
||||
if len(md.Unused) > 0 {
|
||||
sort.Strings(md.Unused)
|
||||
for _, unused := range md.Unused {
|
||||
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
|
||||
errs = append(
|
||||
errs, fmt.Errorf("Unknown configuration key: %s", unused))
|
||||
}
|
||||
}
|
||||
}
|
||||
errs := common.CheckUnusedConfig(md)
|
||||
|
||||
if _, err := os.Stat(p.config.Source); err != nil {
|
||||
errs = append(errs,
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Bad source '%s': %s", p.config.Source, err))
|
||||
}
|
||||
|
||||
if p.config.Destination == "" {
|
||||
errs = append(errs, errors.New("Destination must be specified."))
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Destination must be specified."))
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return &packer.MultiError{errs}
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -5,7 +5,7 @@ package saltmasterless
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/builder/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -7,12 +7,11 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
@@ -61,37 +60,13 @@ type ExecuteCommandTemplate struct {
|
||||
}
|
||||
|
||||
func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
var md mapstructure.Metadata
|
||||
decoderConfig := &mapstructure.DecoderConfig{
|
||||
Metadata: &md,
|
||||
Result: &p.config,
|
||||
}
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(decoderConfig)
|
||||
md, err := common.DecodeConfig(&p.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, raw := range raws {
|
||||
err := decoder.Decode(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate any errors
|
||||
errs := make([]error, 0)
|
||||
|
||||
// Unused keys are errors
|
||||
if len(md.Unused) > 0 {
|
||||
sort.Strings(md.Unused)
|
||||
for _, unused := range md.Unused {
|
||||
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
|
||||
errs = append(
|
||||
errs, fmt.Errorf("Unknown configuration key: %s", unused))
|
||||
}
|
||||
}
|
||||
}
|
||||
errs := common.CheckUnusedConfig(md)
|
||||
|
||||
if p.config.ExecuteCommand == "" {
|
||||
p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
|
||||
@@ -118,7 +93,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
}
|
||||
|
||||
if p.config.Script != "" && len(p.config.Scripts) > 0 {
|
||||
errs = append(errs, errors.New("Only one of script or scripts can be specified."))
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Only one of script or scripts can be specified."))
|
||||
}
|
||||
|
||||
if p.config.Script != "" {
|
||||
@@ -126,14 +102,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
}
|
||||
|
||||
if len(p.config.Scripts) == 0 && p.config.Inline == nil {
|
||||
errs = append(errs, errors.New("Either a script file or inline script must be specified."))
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Either a script file or inline script must be specified."))
|
||||
} else if len(p.config.Scripts) > 0 && p.config.Inline != nil {
|
||||
errs = append(errs, errors.New("Only a script file or an inline script can be specified, not both."))
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("Only a script file or an inline script can be specified, not both."))
|
||||
}
|
||||
|
||||
for _, path := range p.config.Scripts {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Bad script '%s': %s", path, err))
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Bad script '%s': %s", path, err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,14 +120,13 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
for _, kv := range p.config.Vars {
|
||||
vs := strings.Split(kv, "=")
|
||||
if len(vs) != 2 || vs[0] == "" {
|
||||
errs = append(
|
||||
errs,
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Environment variable not in format 'key=value': %s", kv))
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return &packer.MultiError{errs}
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -78,6 +78,8 @@ Optional:
|
||||
* `subnet_id` (string) - If using VPC, the ID of the subnet, such as
|
||||
"subnet-12345def", where Packer will launch the EC2 instance.
|
||||
|
||||
* `tags` (object of key/value strings) - Tags applied to the AMI.
|
||||
|
||||
* `vpc_id` (string) - If launching into a VPC subnet, Packer needs the
|
||||
VPC ID in order to create a temporary security group within the VPC.
|
||||
|
||||
@@ -94,7 +96,7 @@ Here is a basic example. It is completely valid except for the access keys:
|
||||
"source_ami": "ami-de0d9eb7",
|
||||
"instance_type": "t1.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-quick-start {{.CreateTime}}"
|
||||
"ami_name": "packer-quick-start {{.CreateTime}}",
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -105,6 +107,28 @@ the section above for more information on what environmental variables Packer
|
||||
will look for.
|
||||
</div>
|
||||
|
||||
## Tag Example
|
||||
|
||||
Here is an example using the optional AMI tags. This will add the tags
|
||||
"OS_Version" and "Release" to the finished AMI.
|
||||
|
||||
<pre class="prettyprint">
|
||||
{
|
||||
"type": "amazon-ebs",
|
||||
"access_key": "YOUR KEY HERE",
|
||||
"secret_key": "YOUR SECRET KEY HERE",
|
||||
"region": "us-east-1",
|
||||
"source_ami": "ami-de0d9eb7",
|
||||
"instance_type": "t1.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-quick-start {{.CreateTime}}",
|
||||
"tags": {
|
||||
"OS_Version": "Ubuntu",
|
||||
"Release": "Latest"
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
## AMI Name Variables
|
||||
|
||||
The AMI name specified by the `ami_name` configuration variable is actually
|
||||
|
||||
@@ -109,6 +109,8 @@ Optional:
|
||||
* `subnet_id` (string) - If using VPC, the ID of the subnet, such as
|
||||
"subnet-12345def", where Packer will launch the EC2 instance.
|
||||
|
||||
* `tags` (object of key/value strings) - Tags applied to the AMI.
|
||||
|
||||
* `vpc_id` (string) - If launching into a VPC subnet, Packer needs the
|
||||
VPC ID in order to create a temporary security group within the VPC.
|
||||
|
||||
|
||||
@@ -50,3 +50,22 @@ environmental variable was not setup properly. Please go back and ensure
|
||||
that your PATH variable contains the directory which has Packer installed.
|
||||
|
||||
Otherwise, Packer is installed and you're ready to go!
|
||||
|
||||
## Alternative Installation Methods
|
||||
|
||||
Installation from binary packages is currently the only officially supported
|
||||
installation method. The binary packages are guaranteed to be the latest
|
||||
available version and match the proper checksums. However, in addition to
|
||||
the official binaries, there are other unofficial 3rd party methods of
|
||||
installation managed by the Packer community:
|
||||
|
||||
### Homebrew
|
||||
|
||||
If you're using OS X and [Homebrew](http://brew.sh), you can install Packer by
|
||||
adding the `binary` tap. Remember that this is updated by a 3rd party, so
|
||||
it may not be the latest available version.
|
||||
|
||||
```
|
||||
$ brew tap homebrew/binary
|
||||
$ brew install packer
|
||||
```
|
||||
|
||||
@@ -78,11 +78,13 @@ and has the password "packer" for sudo usage, then you'll likely want to
|
||||
change `execute_command` to be:
|
||||
|
||||
```
|
||||
"echo 'packer' | sudo -S sh '{{ .Path }}'"
|
||||
"echo 'packer' | {{ .Vars }} sudo -E -S sh '{{ .Path }}'"
|
||||
```
|
||||
|
||||
The `-S` flag tells `sudo` to read the password from stdin, which in this
|
||||
case is being piped in with the value of "packer".
|
||||
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.
|
||||
|
||||
@@ -53,3 +53,18 @@ environment variable was not setup properly. Please go back and ensure
|
||||
that your PATH variable contains the directory which has Packer installed.
|
||||
|
||||
Otherwise, Packer is installed and you're ready to go!
|
||||
|
||||
## Alternative Installation Methods
|
||||
|
||||
While the binary packages is the only official method of installation, there
|
||||
are alternatives available.
|
||||
|
||||
### Homebrew
|
||||
|
||||
If you're using OS X and [Homebrew](http://brew.sh), you can install Packer by
|
||||
adding the `binary` tap:
|
||||
|
||||
```
|
||||
$ brew tap homebrew/binary
|
||||
$ brew install packer
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user