Commit 26241c8a authored by Seth Vargo's avatar Seth Vargo

Merge pull request #1895 from mitchellh/sethvargo/push_updates

Update Push APIs
parents 7cb3bb64 cd0d3269
...@@ -32,13 +32,16 @@ type pushUploadFn func( ...@@ -32,13 +32,16 @@ type pushUploadFn func(
io.Reader, *uploadOpts) (<-chan struct{}, <-chan error, error) io.Reader, *uploadOpts) (<-chan struct{}, <-chan error, error)
func (c *PushCommand) Run(args []string) int { func (c *PushCommand) Run(args []string) int {
var create bool
var token string var token string
var message string
var create bool
f := flag.NewFlagSet("push", flag.ContinueOnError) f := flag.NewFlagSet("push", flag.ContinueOnError)
f.Usage = func() { c.Ui.Error(c.Help()) } f.Usage = func() { c.Ui.Error(c.Help()) }
f.BoolVar(&create, "create", false, "create")
f.StringVar(&token, "token", "", "token") f.StringVar(&token, "token", "", "token")
f.StringVar(&message, "m", "", "message")
f.StringVar(&message, "message", "", "message")
f.BoolVar(&create, "create", false, "create (deprecated)")
if err := f.Parse(args); err != nil { if err := f.Parse(args); err != nil {
return 1 return 1
} }
...@@ -49,6 +52,12 @@ func (c *PushCommand) Run(args []string) int { ...@@ -49,6 +52,12 @@ func (c *PushCommand) Run(args []string) int {
return 1 return 1
} }
// Print deprecations
if create {
c.Ui.Error(fmt.Sprintf("The '-create' option is now the default and is\n" +
"longer used. It will be removed in the next version."))
}
// Read the template // Read the template
tpl, err := packer.ParseTemplateFile(args[0], nil) tpl, err := packer.ParseTemplateFile(args[0], nil)
if err != nil { if err != nil {
...@@ -149,6 +158,15 @@ func (c *PushCommand) Run(args []string) int { ...@@ -149,6 +158,15 @@ func (c *PushCommand) Run(args []string) int {
uploadOpts.Builds[b.Name] = info uploadOpts.Builds[b.Name] = info
} }
// Add the upload metadata
metadata := make(map[string]interface{})
if message != "" {
metadata["message"] = message
}
metadata["template"] = tpl.RawContents
metadata["template_name"] = filepath.Base(args[0])
uploadOpts.Metadata = metadata
// Warn about builds not having post-processors. // Warn about builds not having post-processors.
var badBuilds []string var badBuilds []string
for name, b := range uploadOpts.Builds { for name, b := range uploadOpts.Builds {
...@@ -169,12 +187,6 @@ func (c *PushCommand) Run(args []string) int { ...@@ -169,12 +187,6 @@ func (c *PushCommand) Run(args []string) int {
"Builds: %s\n\n", strings.Join(badBuilds, ", "))) "Builds: %s\n\n", strings.Join(badBuilds, ", ")))
} }
// Create the build config if it doesn't currently exist.
if err := c.create(uploadOpts.Slug, create); err != nil {
c.Ui.Error(err.Error())
return 1
}
// Start the archiving process // Start the archiving process
r, err := archive.CreateArchive(path, &opts) r, err := archive.CreateArchive(path, &opts)
if err != nil { if err != nil {
...@@ -217,59 +229,30 @@ func (*PushCommand) Help() string { ...@@ -217,59 +229,30 @@ func (*PushCommand) Help() string {
helpText := ` helpText := `
Usage: packer push [options] TEMPLATE Usage: packer push [options] TEMPLATE
Push the template and the files it needs to a Packer build service. Push the given template and supporting files to a Packer build service such as
This will not initiate any builds, it will only update the templates Atlas.
used for builds.
The configuration about what is pushed is configured within the If a build configuration for the given template does not exist, it will be
template's "push" section. created automatically. If the build configuration already exists, a new
version will be created with this template and the supporting files.
Additional configuration options (such as the Atlas server URL and files to
include) may be specified in the "push" section of the Packer template. Please
see the online documentation for more information about these configurables.
Options: Options:
-create Create the build configuration if it doesn't exist. -m, -message=<detail> A message to identify the purpose or changes in this
Packer template much like a VCS commit message
-token=<token> Access token to use to upload. If blank, the -token=<token> The access token to use to when uploading
ATLAS_TOKEN environmental variable will be used.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }
func (*PushCommand) Synopsis() string { func (*PushCommand) Synopsis() string {
return "push template files to a Packer build service" return "push a template and supporting files to a Packer build service"
}
func (c *PushCommand) create(name string, create bool) error {
if c.uploadFn != nil {
return nil
}
// Separate the slug into the user and name components
user, name, err := atlas.ParseSlug(name)
if err != nil {
return fmt.Errorf("Malformed push name: %s", err)
}
// Check if it exists. If so, we're done.
if _, err := c.client.BuildConfig(user, name); err == nil {
return nil
} else if err != atlas.ErrNotFound {
return err
}
// Otherwise, show an error if we're not creating.
if !create {
return fmt.Errorf(
"Push target doesn't exist: %s. Either create this online via\n"+
"the website or pass the -create flag.", name)
}
// Create it
if err := c.client.CreateBuildConfig(user, name); err != nil {
return err
}
return nil
} }
func (c *PushCommand) upload( func (c *PushCommand) upload(
...@@ -284,10 +267,17 @@ func (c *PushCommand) upload( ...@@ -284,10 +267,17 @@ func (c *PushCommand) upload(
return nil, nil, fmt.Errorf("upload: %s", err) return nil, nil, fmt.Errorf("upload: %s", err)
} }
// Get the app // Get the build configuration
bc, err := c.client.BuildConfig(user, name) bc, err := c.client.BuildConfig(user, name)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("upload: %s", err) if err == atlas.ErrNotFound {
// Build configuration doesn't exist, attempt to create it
bc, err = c.client.CreateBuildConfig(user, name)
}
if err != nil {
return nil, nil, fmt.Errorf("upload: %s", err)
}
} }
// Build the version to send up // Build the version to send up
...@@ -307,7 +297,7 @@ func (c *PushCommand) upload( ...@@ -307,7 +297,7 @@ func (c *PushCommand) upload(
// Start the upload // Start the upload
doneCh, errCh := make(chan struct{}), make(chan error) doneCh, errCh := make(chan struct{}), make(chan error)
go func() { go func() {
err := c.client.UploadBuildConfigVersion(&version, r, r.Size) err := c.client.UploadBuildConfigVersion(&version, opts.Metadata, r, r.Size)
if err != nil { if err != nil {
errCh <- err errCh <- err
return return
...@@ -320,9 +310,10 @@ func (c *PushCommand) upload( ...@@ -320,9 +310,10 @@ func (c *PushCommand) upload(
} }
type uploadOpts struct { type uploadOpts struct {
URL string URL string
Slug string Slug string
Builds map[string]*uploadBuildInfo Builds map[string]*uploadBuildInfo
Metadata map[string]interface{}
} }
type uploadBuildInfo struct { type uploadBuildInfo struct {
......
...@@ -3,15 +3,16 @@ package packer ...@@ -3,15 +3,16 @@ package packer
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/hashicorp/go-version"
"github.com/mitchellh/mapstructure"
jsonutil "github.com/mitchellh/packer/common/json"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"sort" "sort"
"text/template" "text/template"
"time" "time"
"github.com/hashicorp/go-version"
"github.com/mitchellh/mapstructure"
jsonutil "github.com/mitchellh/packer/common/json"
) )
// The rawTemplate struct represents the structure of a template read // The rawTemplate struct represents the structure of a template read
...@@ -33,6 +34,7 @@ type rawTemplate struct { ...@@ -33,6 +34,7 @@ type rawTemplate struct {
// The Template struct represents a parsed template, parsed into the most // The Template struct represents a parsed template, parsed into the most
// completed form it can be without additional processing by the caller. // completed form it can be without additional processing by the caller.
type Template struct { type Template struct {
RawContents []byte
Description string Description string
Variables map[string]RawVariable Variables map[string]RawVariable
Builders map[string]RawBuilderConfig Builders map[string]RawBuilderConfig
...@@ -163,6 +165,7 @@ func ParseTemplate(data []byte, vars map[string]string) (t *Template, err error) ...@@ -163,6 +165,7 @@ func ParseTemplate(data []byte, vars map[string]string) (t *Template, err error)
} }
t = &Template{} t = &Template{}
t.RawContents = data
t.Description = rawTpl.Description t.Description = rawTpl.Description
t.Variables = make(map[string]RawVariable) t.Variables = make(map[string]RawVariable)
t.Builders = make(map[string]RawBuilderConfig) t.Builders = make(map[string]RawBuilderConfig)
......
...@@ -58,6 +58,10 @@ func TestParseTemplateFile_basic(t *testing.T) { ...@@ -58,6 +58,10 @@ func TestParseTemplateFile_basic(t *testing.T) {
if len(result.Builders) != 1 { if len(result.Builders) != 1 {
t.Fatalf("bad: %#v", result.Builders) t.Fatalf("bad: %#v", result.Builders)
} }
if string(result.RawContents) != data {
t.Fatalf("expected %q to be %q", result.RawContents, data)
}
} }
func TestParseTemplateFile_minPackerVersionBad(t *testing.T) { func TestParseTemplateFile_minPackerVersionBad(t *testing.T) {
......
...@@ -9,6 +9,10 @@ import ( ...@@ -9,6 +9,10 @@ import (
) )
func TestPostProcessorConfigure(t *testing.T) { func TestPostProcessorConfigure(t *testing.T) {
currentEnv := os.Getenv("ATLAS_TOKEN")
os.Setenv("ATLAS_TOKEN", "")
defer os.Setenv("ATLAS_TOKEN", currentEnv)
var p PostProcessor var p PostProcessor
if err := p.Configure(validDefaults()); err != nil { if err := p.Configure(validDefaults()); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
......
...@@ -7,27 +7,42 @@ description: |- ...@@ -7,27 +7,42 @@ description: |-
# Command-Line: Push # Command-Line: Push
The `packer push` Packer command takes a template and pushes it to a build The `packer push` Packer command takes a template and pushes it to a Packer
service. The build service will automatically build your Packer template and build service such as [HashiCorp's Atlas](https://atlas.hashicorp.com). The
expose the artifacts. build service will automatically build your Packer template and expose the
artifacts.
This command currently only sends templates to External build services such as HashiCorp's Atlas make it easy to iterate on
[Atlas](https://atlas.hashicorp.com) by HashiCorp, but the command will Packer templates, especially when the builder you are running may not be easily
be pluggable in the future with alternate implementations.
External build services such as Atlas make it easy to iterate on Packer
templates, especially when the builder you're running may not be easily
accessable (such as developing `qemu` builders on Mac or Windows). accessable (such as developing `qemu` builders on Mac or Windows).
For the `push` command to work, the !> The Packer build service will receive the raw copy of your Packer template
[push configuration](/docs/templates/push.html) when you push. **If you have sensitive data in your Packer template, you should
move that data into Packer variables or environment variables!**
For the `push` command to work, the [push configuration](/docs/templates/push.html)
must be completed within the template. must be completed within the template.
## Options ## Options
* `-create=true` - If the build configuration matching the name of the push * `-message` - A message to identify the purpose or changes in this Packer
doesn't exist, it will be created if this is true. This defaults to true. template much like a VCS commit message. This message will be passed to the
Packer build service. This option is also available as a short option `-m`.
* `-token` - An access token for authenticating the push to the Packer build
service such as Atlas. This can also be specified within the push
configuration in the template.
## Examples
Push a Packer template:
```shell
$ packer push -m "Updating the apache version" template.json
```
Push a Packer template with a custom token:
* `-token=FOO` - An access token for authenticating the push. This can also ```shell
be specified within the push configuration in the template. By setting this $ packer push -token ABCD1234 template.json
in the template, you can take advantage of user variables. ```
...@@ -46,8 +46,8 @@ each category, the available configuration keys are alphabetized. ...@@ -46,8 +46,8 @@ each category, the available configuration keys are alphabetized.
this is `https://atlas.hashicorp.com`. this is `https://atlas.hashicorp.com`.
* `base_dir` (string) - The base directory of the files to upload. This * `base_dir` (string) - The base directory of the files to upload. This
will be the CWD when the build service executes your template. This will be the current working directory when the build service executes your
path is relative to the template. template. This path is relative to the template.
* `include` (array of strings) - Glob patterns to include relative to * `include` (array of strings) - Glob patterns to include relative to
the `base_dir`. If this is specified, only files that match the include the `base_dir`. If this is specified, only files that match the include
...@@ -57,9 +57,38 @@ each category, the available configuration keys are alphabetized. ...@@ -57,9 +57,38 @@ each category, the available configuration keys are alphabetized.
the `base_dir`. the `base_dir`.
* `token` (string) - An access token to use to authenticate to the build * `token` (string) - An access token to use to authenticate to the build
service. For Atlas, you can retrieve this access token in your account service.
section by clicking your account name in the upper right corner.
* `vcs` (bool) - If true, Packer will detect your VCS (if there is one) * `vcs` (bool) - 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 and only upload the files that are tracked by the VCS. This is useful
for automatically excluding ignored files. This defaults to true. for automatically excluding ignored files. This defaults to false.
## Examples
A push configuration section with minimal options:
```javascript
{
"push": {
"name": "hashicorp/precise64"
}
}
```
A push configuration specifying Packer to inspect the VCS and list individual
files to include:
```javascript
{
"push": {
"name": "hashicorp/precise64",
"vcs": true,
"include": [
"other_file/outside_of.vcs"
]
}
}
```
~> **Variable interpolation** is not currently possible in Packer push
configurations. This will be fixed in an upcoming release.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment