Added manifest post-processor, which creates a manifest of build artifacts

This commit is contained in:
Chris Bednarski 2016-06-09 22:26:22 -07:00
parent 73d376633d
commit db593a517d
3 changed files with 139 additions and 0 deletions

View File

@ -39,6 +39,7 @@ import (
dockerpushpostprocessor "github.com/mitchellh/packer/post-processor/docker-push"
dockersavepostprocessor "github.com/mitchellh/packer/post-processor/docker-save"
dockertagpostprocessor "github.com/mitchellh/packer/post-processor/docker-tag"
manifestpostprocessor "github.com/mitchellh/packer/post-processor/manifest"
shelllocalpostprocessor "github.com/mitchellh/packer/post-processor/shell-local"
vagrantpostprocessor "github.com/mitchellh/packer/post-processor/vagrant"
vagrantcloudpostprocessor "github.com/mitchellh/packer/post-processor/vagrant-cloud"
@ -108,6 +109,7 @@ var PostProcessors = map[string]packer.PostProcessor{
"docker-push": new(dockerpushpostprocessor.PostProcessor),
"docker-save": new(dockersavepostprocessor.PostProcessor),
"docker-tag": new(dockertagpostprocessor.PostProcessor),
"manifest": new(manifestpostprocessor.PostProcessor),
"shell-local": new(shelllocalpostprocessor.PostProcessor),
"vagrant": new(vagrantpostprocessor.PostProcessor),
"vagrant-cloud": new(vagrantcloudpostprocessor.PostProcessor),

View File

@ -0,0 +1,37 @@
package manifest
import "fmt"
const BuilderId = "packer.post-processor.manifest"
type Artifact struct {
BuildName string `json:"build_name"`
BuildTime int64 `json:"build_time"`
Description string `json:"description"`
BuildFiles []string `json:"files"`
BuildId string `json:"artifact_id"`
}
func (a *Artifact) BuilderId() string {
return BuilderId
}
func (a *Artifact) Files() []string {
return a.BuildFiles
}
func (a *Artifact) Id() string {
return a.BuildId
}
func (a *Artifact) String() string {
return fmt.Sprintf("%s-%s", a.BuildName, a.BuildId)
}
func (a *Artifact) State(name string) interface{} {
return nil
}
func (a *Artifact) Destroy() error {
return nil
}

View File

@ -0,0 +1,100 @@
package manifest
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
)
// The artifact-override post-processor allows you to specify arbitrary files as
// artifacts. These will override any other artifacts created by the builder.
// This allows you to use a builder and provisioner to create some file, such as
// a compiled binary or tarball, extract it from the builder (VM or container)
// and then save that binary or tarball and throw away the builder.
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Filename string `mapstructure:"filename"`
ctx interpolate.Context
}
type PostProcessor struct {
config Config
}
type ManifestFile struct {
Builds []Artifact `json:"builds"`
}
func (p *PostProcessor) Configure(raws ...interface{}) error {
err := config.Decode(&p.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &p.config.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{},
},
}, raws...)
if err != nil {
return err
}
if p.config.Filename == "" {
p.config.Filename = "packer-manifest.json"
}
return nil
}
func (p *PostProcessor) PostProcess(ui packer.Ui, source packer.Artifact) (packer.Artifact, bool, error) {
artifact := &Artifact{}
// Create the current artifact.
artifact.BuildFiles = source.Files()
artifact.BuildId = source.Id()
artifact.BuildName = source.BuilderId()
artifact.BuildTime = time.Now().Unix()
artifact.Description = source.String()
// Create a lock file with exclusive access. If this fails we will retry
// after a delay
lockFilename := p.config.Filename + ".lock"
_, err := os.OpenFile(lockFilename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
defer os.Remove(lockFilename)
// Read the current manifest file from disk
contents := []byte{}
if contents, err = ioutil.ReadFile(p.config.Filename); err != nil && !os.IsNotExist(err) {
return nil, true, fmt.Errorf("Unable to open %s for reading: %s", p.config.Filename, err)
}
// Parse the manifest file JSON, if we have some
manifestFile := &ManifestFile{}
if len(contents) > 0 {
if err = json.Unmarshal(contents, manifestFile); err != nil {
return nil, true, fmt.Errorf("Unable to parse content from %s: %s", p.config.Filename, err)
}
}
// Add the current artifact to the manifest file
manifestFile.Builds = append(manifestFile.Builds, *artifact)
// Write JSON to disk
if out, err := json.Marshal(manifestFile); err == nil {
if err := ioutil.WriteFile(p.config.Filename, out, 0664); err != nil {
return nil, true, fmt.Errorf("Unable to write %s: %s", p.config.Filename, err)
}
} else {
return nil, true, fmt.Errorf("Unable to marshal JSON %s", err)
}
return artifact, true, err
}