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(
io.Reader, *uploadOpts) (<-chan struct{}, <-chan error, error)
func (c *PushCommand) Run(args []string) int {
var create bool
var token string
var message string
var create bool
f := flag.NewFlagSet("push", flag.ContinueOnError)
f.Usage = func() { c.Ui.Error(c.Help()) }
f.BoolVar(&create, "create", false, "create")
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 {
return 1
}
......@@ -49,6 +52,12 @@ func (c *PushCommand) Run(args []string) int {
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
tpl, err := packer.ParseTemplateFile(args[0], nil)
if err != nil {
......@@ -149,6 +158,15 @@ func (c *PushCommand) Run(args []string) int {
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.
var badBuilds []string
for name, b := range uploadOpts.Builds {
......@@ -169,12 +187,6 @@ func (c *PushCommand) Run(args []string) int {
"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
r, err := archive.CreateArchive(path, &opts)
if err != nil {
......@@ -217,59 +229,30 @@ func (*PushCommand) Help() string {
helpText := `
Usage: packer push [options] TEMPLATE
Push the template and the files it needs to a Packer build service.
This will not initiate any builds, it will only update the templates
used for builds.
Push the given template and supporting files to a Packer build service such as
Atlas.
The configuration about what is pushed is configured within the
template's "push" section.
If a build configuration for the given template does not exist, it will be
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:
-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
ATLAS_TOKEN environmental variable will be used.
-token=<token> The access token to use to when uploading
`
return strings.TrimSpace(helpText)
}
func (*PushCommand) Synopsis() string {
return "push template 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
return "push a template and supporting files to a Packer build service"
}
func (c *PushCommand) upload(
......@@ -284,11 +267,18 @@ func (c *PushCommand) upload(
return nil, nil, fmt.Errorf("upload: %s", err)
}
// Get the app
// Get the build configuration
bc, err := c.client.BuildConfig(user, name)
if err != nil {
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
version := atlas.BuildConfigVersion{
......@@ -307,7 +297,7 @@ func (c *PushCommand) upload(
// Start the upload
doneCh, errCh := make(chan struct{}), make(chan error)
go func() {
err := c.client.UploadBuildConfigVersion(&version, r, r.Size)
err := c.client.UploadBuildConfigVersion(&version, opts.Metadata, r, r.Size)
if err != nil {
errCh <- err
return
......@@ -323,6 +313,7 @@ type uploadOpts struct {
URL string
Slug string
Builds map[string]*uploadBuildInfo
Metadata map[string]interface{}
}
type uploadBuildInfo struct {
......
......@@ -3,15 +3,16 @@ package packer
import (
"bytes"
"fmt"
"github.com/hashicorp/go-version"
"github.com/mitchellh/mapstructure"
jsonutil "github.com/mitchellh/packer/common/json"
"io"
"io/ioutil"
"os"
"sort"
"text/template"
"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
......@@ -33,6 +34,7 @@ type rawTemplate struct {
// The Template struct represents a parsed template, parsed into the most
// completed form it can be without additional processing by the caller.
type Template struct {
RawContents []byte
Description string
Variables map[string]RawVariable
Builders map[string]RawBuilderConfig
......@@ -163,6 +165,7 @@ func ParseTemplate(data []byte, vars map[string]string) (t *Template, err error)
}
t = &Template{}
t.RawContents = data
t.Description = rawTpl.Description
t.Variables = make(map[string]RawVariable)
t.Builders = make(map[string]RawBuilderConfig)
......
......@@ -58,6 +58,10 @@ func TestParseTemplateFile_basic(t *testing.T) {
if len(result.Builders) != 1 {
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) {
......
......@@ -9,6 +9,10 @@ import (
)
func TestPostProcessorConfigure(t *testing.T) {
currentEnv := os.Getenv("ATLAS_TOKEN")
os.Setenv("ATLAS_TOKEN", "")
defer os.Setenv("ATLAS_TOKEN", currentEnv)
var p PostProcessor
if err := p.Configure(validDefaults()); err != nil {
t.Fatalf("err: %s", err)
......
......@@ -7,27 +7,42 @@ description: |-
# Command-Line: Push
The `packer push` Packer command takes a template and pushes it to a build
service. The build service will automatically build your Packer template and
expose the artifacts.
The `packer push` Packer command takes a template and pushes it to a Packer
build service such as [HashiCorp's Atlas](https://atlas.hashicorp.com). The
build service will automatically build your Packer template and expose the
artifacts.
This command currently only sends templates to
[Atlas](https://atlas.hashicorp.com) by HashiCorp, but the command will
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
External build services such as HashiCorp's Atlas make it easy to iterate on
Packer templates, especially when the builder you are running may not be easily
accessable (such as developing `qemu` builders on Mac or Windows).
For the `push` command to work, the
[push configuration](/docs/templates/push.html)
!> The Packer build service will receive the raw copy of your Packer template
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.
## Options
* `-create=true` - If the build configuration matching the name of the push
doesn't exist, it will be created if this is true. This defaults to true.
* `-message` - A message to identify the purpose or changes in this Packer
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
be specified within the push configuration in the template. By setting this
in the template, you can take advantage of user variables.
```shell
$ packer push -token ABCD1234 template.json
```
......@@ -46,8 +46,8 @@ each category, the available configuration keys are alphabetized.
this is `https://atlas.hashicorp.com`.
* `base_dir` (string) - The base directory of the files to upload. This
will be the CWD when the build service executes your template. This
path is relative to the template.
will be the current working directory when the build service executes your
template. This path is relative to the template.
* `include` (array of strings) - Glob patterns to include relative to
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.
the `base_dir`.
* `token` (string) - An access token to use to authenticate to the build
service. For Atlas, you can retrieve this access token in your account
section by clicking your account name in the upper right corner.
service.
* `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
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