func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only import from docker-import artifacts.", artifact.BuilderId()) return nil, false, err } driver := p.Driver if driver == nil { // If no driver is set, then we use the real driver driver = &docker.DockerDriver{Tpl: p.config.tpl, Ui: ui} } // Get the name. We strip off any tags from the name because the // push doesn't use those. name := artifact.Id() if i := strings.Index(name, "/"); i >= 0 { // This should always be true because the / is required. But we have // to get the index to this so we don't accidentally strip off the port if j := strings.Index(name[i:], ":"); j >= 0 { name = name[:i+j] } } ui.Message("Pushing: " + name) if err := driver.Push(name); err != nil { return nil, false, err } return nil, false, nil }
func (p *AWSProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) { // Create the metadata metadata = map[string]interface{}{"provider": "aws"} // Build up the template data to build our Vagrantfile tplData := &awsVagrantfileTemplate{ Images: make(map[string]string), } for _, regions := range strings.Split(artifact.Id(), ",") { parts := strings.Split(regions, ":") if len(parts) != 2 { err = fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id()) return } tplData.Images[parts[0]] = parts[1] } // Build up the contents var contents bytes.Buffer t := template.Must(template.New("vf").Parse(defaultAWSVagrantfile)) err = t.Execute(&contents, tplData) vagrantfile = contents.String() return }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only tag from Docker builder artifacts.", artifact.BuilderId()) return nil, false, err } driver := p.Driver if driver == nil { // If no driver is set, then we use the real driver driver = &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui} } importRepo := p.config.Repository if p.config.Tag != "" { importRepo += ":" + p.config.Tag } ui.Message("Tagging image: " + artifact.Id()) ui.Message("Repository: " + importRepo) err := driver.TagImage(artifact.Id(), importRepo, p.config.Force) if err != nil { return nil, false, err } // Build the artifact artifact = &docker.ImportArtifact{ BuilderIdValue: BuilderId, Driver: driver, IdValue: importRepo, } return artifact, true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != docker.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only import from Docker builder artifacts.", artifact.BuilderId()) return nil, false, err } importRepo := p.config.Repository if p.config.Tag != "" { importRepo += ":" + p.config.Tag } driver := &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui} ui.Message("Importing image: " + artifact.Id()) ui.Message("Repository: " + importRepo) id, err := driver.Import(artifact.Files()[0], importRepo) if err != nil { return nil, false, err } ui.Message("Imported ID: " + id) // Build the artifact artifact = &docker.ImportArtifact{ BuilderIdValue: BuilderId, Driver: driver, IdValue: importRepo, } return artifact, false, nil }
func (pp *TestPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) { pp.ppCalled = true pp.ppArtifact = a pp.ppArtifactId = a.Id() pp.ppUi = ui return testPostProcessorArtifact, false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only tag from Docker builder artifacts.", artifact.BuilderId()) return nil, false, err } dockerfile, template_err := p.render_template(trim_artifact_id(artifact.Id())) if template_err != nil { // could not render template return nil, false, template_err } log.Printf("[DEBUG] Dockerfile: %s\n", dockerfile.String()) if image_id, err := p.docker_build_fn(dockerfile); err != nil { // docker build command failed ui.Error("docker build command failed: " + err.Error()) return nil, false, err } else { ui.Message("Built image: " + image_id) new_artifact := &docker.ImportArtifact{ BuilderIdValue: dockerimport.BuilderId, Driver: &docker.DockerDriver{Ui: ui, Tpl: nil}, IdValue: image_id, } log.Printf("[DEBUG] artifact: %#v\n", new_artifact) return new_artifact, true, nil } }
func NewArtifact(artifact packer.Artifact) *Artifact { return &Artifact{ builderId: artifact.BuilderId(), files: artifact.Files(), id: artifact.Id(), str: artifact.String(), } }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Only accepts input from the vagrant post-processor if artifact.BuilderId() != "mitchellh.post-processor.vagrant" { return nil, false, fmt.Errorf( "Unknown artifact type, requires box from vagrant post-processor: %s", artifact.BuilderId()) } // We assume that there is only one .box file to upload if !strings.HasSuffix(artifact.Files()[0], ".box") { return nil, false, fmt.Errorf( "Unknown files in artifact from vagrant post-processor: %s", artifact.Files()) } // create the HTTP client p.client = VagrantCloudClient{}.New(p.config.VagrantCloudUrl, p.config.AccessToken) // The name of the provider for vagrant cloud, and vagrant providerName := providerFromBuilderName(artifact.Id()) // Set up the state state := new(multistep.BasicStateBag) state.Put("config", p.config) state.Put("client", p.client) state.Put("artifact", artifact) state.Put("artifactFilePath", artifact.Files()[0]) state.Put("ui", ui) state.Put("providerName", providerName) // Build the steps steps := []multistep.Step{ new(stepVerifyBox), new(stepCreateVersion), new(stepCreateProvider), new(stepPrepareUpload), new(stepUpload), new(stepVerifyUpload), new(stepReleaseVersion), } // Run the steps if p.config.PackerDebug { p.runner = &multistep.DebugRunner{ Steps: steps, PauseFn: common.MultistepDebugFn(ui), } } else { p.runner = &multistep.BasicRunner{Steps: steps} } p.runner.Run(state) // If there was an error, return that if rawErr, ok := state.GetOk("error"); ok { return nil, false, rawErr.(error) } return NewArtifact(providerName, p.config.Tag), true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId && artifact.BuilderId() != dockertag.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only import from docker-import and docker-tag artifacts.", artifact.BuilderId()) return nil, false, err } driver := p.Driver if driver == nil { // If no driver is set, then we use the real driver driver = &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui} } if p.config.EcrLogin { ui.Message("Fetching ECR credentials...") username, password, err := p.config.EcrGetLogin(p.config.LoginServer) if err != nil { return nil, false, err } p.config.LoginUsername = username p.config.LoginPassword = password } if p.config.Login || p.config.EcrLogin { ui.Message("Logging in...") err := driver.Login( p.config.LoginServer, p.config.LoginEmail, p.config.LoginUsername, p.config.LoginPassword) if err != nil { return nil, false, fmt.Errorf( "Error logging in to Docker: %s", err) } defer func() { ui.Message("Logging out...") if err := driver.Logout(p.config.LoginServer); err != nil { ui.Error(fmt.Sprintf("Error logging out: %s", err)) } }() } // Get the name. name := artifact.Id() ui.Message("Pushing: " + name) if err := driver.Push(name); err != nil { return nil, false, err } return nil, false, nil }
func (p *OVFPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != "mitchellh.vmware" { return nil, false, fmt.Errorf("ovftool post-processor can only be used on VMware boxes: %s", artifact.BuilderId()) } vmx := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".vmx") { vmx = path } } if vmx == "" { return nil, false, fmt.Errorf("VMX file could not be located.") } // Strip DVD and floppy drives from the VMX if err := p.stripDrives(vmx); err != nil { return nil, false, fmt.Errorf("Couldn't strip floppy/DVD drives from VMX") } p.cfg.ctx.Data = &OutputPathTemplate{ ArtifactId: artifact.Id(), BuildName: p.cfg.BuildName, Provider: "vmware", } targetPath, err := interpolate.Render(p.cfg.TargetPath, &p.cfg.ctx) if err != nil { return nil, false, err } // build the arguments args := []string{ "--targetType=" + p.cfg.TargetType, "--acceptAllEulas", } // append --compression, if it is set if p.cfg.Compression > 0 { args = append(args, fmt.Sprintf("--compress=%d", p.cfg.Compression)) } // add the source/target args = append(args, vmx, targetPath) ui.Message(fmt.Sprintf("Executing ovftool with arguments: %+v", args)) cmd := exec.Command(executable, args...) var buffer bytes.Buffer cmd.Stdout = &buffer cmd.Stderr = &buffer err = cmd.Run() if err != nil { return nil, false, fmt.Errorf("Unable to execute ovftool: %s", buffer.String()) } ui.Message(fmt.Sprintf("%s", buffer.String())) return artifact, false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != "mitchellh.post-processor.vagrant" { return nil, false, fmt.Errorf( "Unknown artifact type, requires box from vagrant post-processor: %s", artifact.BuilderId()) } box := artifact.Files()[0] if !strings.HasSuffix(box, ".box") { return nil, false, fmt.Errorf( "Unknown files in artifact from vagrant post-processor: %s", artifact.Files()) } provider := providerFromBuilderName(artifact.Id()) file, err := os.Open(box) if err != nil { return nil, false, err } defer file.Close() info, err := file.Stat() if err != nil { return nil, false, err } size := info.Size() ui.Message(fmt.Sprintf("Box size: %s (%d bytes)", box, size)) metadata, err := p.getMetadata() if err != nil { return nil, false, err } ui.Message("Generating checksum") checksum, err := sum256(file) if err != nil { return nil, false, err } ui.Message(fmt.Sprintf("Checksum is %s", checksum)) ui.Message(fmt.Sprintf("Adding %s %s box to metadata", provider, p.config.Version)) if err := metadata.Add(p.config.Version, &Provider{ Name: provider, Url: fmt.Sprintf("%s/%s/%s", p.config.UrlPrefix, p.config.BoxDir, path.Base(box)), ChecksumType: "sha256", Checksum: checksum, }); err != nil { return nil, false, err } ui.Message(fmt.Sprintf("Saving the metadata: %s", p.config.MetadataPath)) if err := p.putMetadata(metadata); err != nil { return nil, false, err } return &Artifact{fmt.Sprintf("%s/%s", p.config.UrlPrefix, p.config.MetadataPath)}, true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { r, _ := regexp.Compile("ami-[a-z0-9]+") amiId := r.FindString(artifact.Id()) if err := ioutil.WriteFile(p.config.OutputPath, []byte(amiId), 0644); err != nil { return artifact, false, err } return artifact, true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId && artifact.BuilderId() != dockertag.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only import from docker-import and docker-tag artifacts.", artifact.BuilderId()) return nil, false, err } driver := p.Driver if driver == nil { // If no driver is set, then we use the real driver driver = &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui} } if p.config.Login { ui.Message("Logging in...") err := driver.Login( p.config.LoginServer, p.config.LoginEmail, p.config.LoginUsername, p.config.LoginPassword) if err != nil { return nil, false, fmt.Errorf( "Error logging in to Docker: %s", err) } defer func() { ui.Message("Logging out...") if err := driver.Logout(p.config.LoginServer); err != nil { ui.Error(fmt.Sprintf("Error logging out: %s", err)) } }() } // Get the name. We strip off any tags from the name because the // push doesn't use those. name := artifact.Id() if i := strings.Index(name, "/"); i >= 0 { // This should always be true because the / is required. But we have // to get the index to this so we don't accidentally strip off the port if j := strings.Index(name[i:], ":"); j >= 0 { name = name[:i+j] } } ui.Message("Pushing: " + name) if err := driver.Push(name); err != nil { return nil, false, err } return nil, false, nil }
func makeAmiList(a packer.Artifact) (map[string]string, error) { type Amis map[string]string amis := make(Amis) // converting from Artifact interface via Id() regionAmiList := strings.Split(a.Id(), ",") for _, regionAmi := range regionAmiList { // region:ami-id amiInfo := strings.Split(regionAmi, ":") amis[amiInfo[0]] = amiInfo[1] } return amis, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if p.config.AmiId != nil { r, _ := regexp.Compile("ami-[a-z0-9]+") amiId := r.FindString(artifact.Id()) for file, properties := range p.config.AmiId { err := UpdateJsonFile(file, properties, amiId, ui) if err != nil { return artifact, false, err } } } return artifact, true, nil }
// ProcessOutputPath takes an output path template and executes it, // replacing variables with their respective values. func ProcessOutputPath(path string, provider string, artifact packer.Artifact) (string, error) { var buf bytes.Buffer tplData := &OutputPathTemplate{ ArtifactId: artifact.Id(), Provider: provider, } t, err := template.New("output").Parse(path) if err != nil { return "", err } err = t.Execute(&buf, tplData) return buf.String(), err }
// PostProcess is the main entry point. It calls a Provider's Convert() method // to delegate conversion to that Provider's command-line tool. func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { provider, err := providerForBuilderId(artifact.BuilderId()) if err != nil { return nil, false, err } ui.Say(fmt.Sprintf("Converting %s image to VHD file...", provider)) // Render output path. p.config.ctx.Data = &outputPathTemplate{ ArtifactId: artifact.Id(), BuildName: p.config.PackerBuildName, Provider: provider.Name(), } outputPath, err := interpolate.Render(p.config.OutputPath, &p.config.ctx) if err != nil { return nil, false, err } // Check if VHD file exists. Remove if the user specified `force` in the // template or `--force` on the command-line. // This differs from the Vagrant post-processor because the the VHD can be // used (and written to) immediately. It is comparable to a Builder // end-product. if _, err = os.Stat(outputPath); err == nil { if p.config.PackerForce || p.config.Force { ui.Message(fmt.Sprintf("Removing existing VHD file at %s", outputPath)) os.Remove(outputPath) } else { return nil, false, fmt.Errorf("VHD file exists: %s\nUse the force flag to delete it.", outputPath) } } err = provider.Convert(ui, artifact, outputPath) if err != nil { return nil, false, err } ui.Say(fmt.Sprintf("Converted VHD: %s", outputPath)) artifact = NewArtifact(provider.String(), outputPath) keep := p.config.KeepInputArtifact return artifact, keep, nil }
func (p *DigitalOceanProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) { // Create the metadata metadata = map[string]interface{}{"provider": "digital_ocean"} // Determine the image and region... tplData := &digitalOceanVagrantfileTemplate{} parts := strings.Split(artifact.Id(), ":") if len(parts) != 2 { err = fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id()) return } tplData.Region = parts[0] tplData.Image = parts[1] // Build up the Vagrantfile var contents bytes.Buffer t := template.Must(template.New("vf").Parse(defaultDigitalOceanVagrantfile)) err = t.Execute(&contents, tplData) vagrantfile = contents.String() return }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId && artifact.BuilderId() != dockertag.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only save Docker builder artifacts.", artifact.BuilderId()) return nil, false, err } path := p.config.Path // Open the file that we're going to write to f, err := os.Create(path) if err != nil { err := fmt.Errorf("Error creating output file: %s", err) return nil, false, err } driver := p.Driver if driver == nil { // If no driver is set, then we use the real driver driver = &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui} } ui.Message("Saving image: " + artifact.Id()) if err := driver.SaveImage(artifact.Id(), f); err != nil { f.Close() os.Remove(f.Name()) return nil, false, err } f.Close() ui.Message("Saved to: " + path) return artifact, true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockerimport.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only import from docker-import artifacts.", artifact.BuilderId()) return nil, false, err } driver := &docker.DockerDriver{Tpl: p.config.tpl, Ui: ui} // Get the name. We strip off any tags from the name because the // push doesn't use those. name := artifact.Id() if i := strings.Index(name, ":"); i >= 0 { name = name[:i] } ui.Message("Pushing: " + name) if err := driver.Push(name); err != nil { return nil, false, err } return nil, false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Only accept input from the vagrant post-processor if artifact.BuilderId() != "mitchellh.post-processor.vagrant" { return nil, false, fmt.Errorf("Unknown artifact type, requires box from vagrant post-processor: %s", artifact.BuilderId()) } // Assume there is only one .box file to upload box := artifact.Files()[0] if !strings.HasSuffix(box, ".box") { return nil, false, fmt.Errorf("Unknown files in artifact from vagrant post-processor: %s", artifact.Files()) } provider := providerFromBuilderName(artifact.Id()) ui.Say(fmt.Sprintf("Preparing to copy box for '%s' provider to path '%s'", provider, p.config.Path)) // open the box so we can copy to path and calculate checksum for the manifest file, err := os.Open(box) if err != nil { return nil, false, err } defer file.Close() // get the file's size info, err := file.Stat() if err != nil { return nil, false, err } size := info.Size() ui.Message(fmt.Sprintf("Box to copy: %s (%d bytes)", box, size)) // get the latest manifest so we can add to it ui.Message("Fetching latest manifest") manifest, err := p.getManifest() if err != nil { return nil, false, err } // generate the path to copy the box to the path boxPath := fmt.Sprintf("%s/%s/%s/%s", p.config.Path, p.config.BoxDir, p.config.Version, path.Base(box)) ui.Message("Generating checksum") checksum, err := sum256(file) if err != nil { return nil, false, err } ui.Message(fmt.Sprintf("Checksum is %s", checksum)) ui.Message(fmt.Sprintf("Adding %s %s box to manifest", provider, p.config.Version)) if err := manifest.add(p.config.Version, &Provider{ Name: provider, Url: boxPath, ChecksumType: "sha256", Checksum: checksum, }); err != nil { return nil, false, err } // upload the box to S3 (rewinding as we already read the file to generate the checksum) ui.Message(fmt.Sprintf("Copying box to path: %s", boxPath)) if _, err := file.Seek(0, 0); err != nil { return nil, false, err } ui.Message(fmt.Sprintf("Opening box")) in, err := os.Open(box) if err != nil { return nil, false, err } defer in.Close() ui.Message(fmt.Sprintf("Creating directories")) err = os.MkdirAll(path.Dir(boxPath), 0777) if err != nil { return nil, false, err } ui.Message(fmt.Sprintf("Creating box copy")) out, err := os.Create(boxPath) if err != nil { return nil, false, err } defer out.Close() ui.Message(fmt.Sprintf("Copying box")) _, err = io.Copy(out, in) cerr := out.Close() if err != nil { return nil, false, err } if cerr != nil { return nil, false, cerr } ui.Message(fmt.Sprintf("Uploading the manifest: %s", p.config.ManifestPath)) if err := p.putManifest(manifest); err != nil { return nil, false, err } return &Artifact{p.config.ManifestPath}, true, nil }
func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { var err error // Compile the output path outputPath, err := p.config.tpl.Process(p.config.OutputPath, &OutputPathTemplate{ ArtifactId: artifact.Id(), BuildName: p.config.PackerBuildName, Provider: "virtualbox", }) if err != nil { return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { return nil, false, err } defer os.RemoveAll(dir) // Copy all of the original contents into the temporary directory for _, path := range artifact.Files() { // We treat OVA files specially, we unpack those into the temporary // directory so we can get the resulting disk and OVF. if extension := filepath.Ext(path); extension == ".ova" { ui.Message(fmt.Sprintf("Unpacking OVA: %s", path)) if err := DecompressOva(dir, filepath.Base(path)); err != nil { return nil, false, err } } else { ui.Message(fmt.Sprintf("Copying: %s", path)) dstPath := filepath.Join(dir, filepath.Base(path)) if err := CopyContents(dstPath, path); err != nil { return nil, false, err } } } // Create the Vagrantfile from the template tplData := &VBoxVagrantfileTemplate{} tplData.BaseMacAddress, err = p.findBaseMacAddress(dir) if err != nil { return nil, false, err } vf, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { return nil, false, err } defer vf.Close() vagrantfileContents := defaultVBoxVagrantfile if p.config.VagrantfileTemplate != "" { f, err := os.Open(p.config.VagrantfileTemplate) if err != nil { return nil, false, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { return nil, false, err } vagrantfileContents = string(contents) } vagrantfileContents, err = p.config.tpl.Process(vagrantfileContents, tplData) if err != nil { return nil, false, fmt.Errorf("Error writing Vagrantfile: %s", err) } vf.Write([]byte(vagrantfileContents)) vf.Close() // Create the metadata metadata := map[string]string{"provider": "virtualbox"} if err := WriteMetadata(dir, metadata); err != nil { return nil, false, err } // Rename the OVF file to box.ovf, as required by Vagrant ui.Message("Renaming the OVF to box.ovf...") if err := p.renameOVF(dir); err != nil { return nil, false, err } // Compress the directory to the given output path ui.Message(fmt.Sprintf("Compressing box...")) if err := DirToBox(outputPath, dir, ui); err != nil { return nil, false, err } return NewArtifact("virtualbox", outputPath), false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, err := p.client.Artifact(p.config.user, p.config.name); err != nil { if err != atlas.ErrNotFound { return nil, false, fmt.Errorf( "Error finding artifact: %s", err) } // Artifact doesn't exist, create it ui.Message(fmt.Sprintf("Creating artifact: %s", p.config.Artifact)) _, err = p.client.CreateArtifact(p.config.user, p.config.name) if err != nil { return nil, false, fmt.Errorf( "Error creating artifact: %s", err) } } opts := &atlas.UploadArtifactOpts{ User: p.config.user, Name: p.config.name, Type: p.config.Type, ID: artifact.Id(), Metadata: p.metadata(artifact), BuildId: p.config.buildId, } if fs := artifact.Files(); len(fs) > 0 { var archiveOpts archive.ArchiveOpts // We have files. We want to compress/upload them. If we have just // one file, then we use it as-is. Otherwise, we compress all of // them into a single file. var path string if len(fs) == 1 { path = fs[0] } else { path = longestCommonPrefix(fs) if path == "" { return nil, false, fmt.Errorf( "No common prefix for achiving files: %v", fs) } // Modify the archive options to only include the files // that are in our file list. include := make([]string, 0, len(fs)) for i, f := range fs { include[i] = strings.Replace(f, path, "", 1) } archiveOpts.Include = include } r, err := archive.CreateArchive(path, &archiveOpts) if err != nil { return nil, false, fmt.Errorf( "Error archiving artifact: %s", err) } defer r.Close() opts.File = r opts.FileSize = r.Size } ui.Message("Uploading artifact version...") var av *atlas.ArtifactVersion doneCh := make(chan struct{}) errCh := make(chan error, 1) go func() { var err error av, err = p.client.UploadArtifact(opts) if err != nil { errCh <- err return } close(doneCh) }() select { case err := <-errCh: return nil, false, fmt.Errorf("Error uploading: %s", err) case <-doneCh: } return &Artifact{ Name: p.config.Artifact, Type: p.config.Type, Version: av.Version, }, true, nil }
func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Determine the regions... tplData := &AWSVagrantfileTemplate{ Images: make(map[string]string), } for _, regions := range strings.Split(artifact.Id(), ",") { parts := strings.Split(regions, ":") if len(parts) != 2 { return nil, false, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id()) } tplData.Images[parts[0]] = parts[1] } // Compile the output path outputPath, err := p.config.tpl.Process(p.config.OutputPath, &OutputPathTemplate{ ArtifactId: artifact.Id(), BuildName: p.config.PackerBuildName, Provider: "aws", }) if err != nil { return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { return nil, false, err } defer os.RemoveAll(dir) // Create the Vagrantfile from the template vf, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { return nil, false, err } defer vf.Close() vagrantfileContents := defaultAWSVagrantfile if p.config.VagrantfileTemplate != "" { log.Printf("Using vagrantfile template: %s", p.config.VagrantfileTemplate) f, err := os.Open(p.config.VagrantfileTemplate) if err != nil { err = fmt.Errorf("error opening vagrantfile template: %s", err) return nil, false, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { err = fmt.Errorf("error reading vagrantfile template: %s", err) return nil, false, err } vagrantfileContents = string(contents) } vagrantfileContents, err = p.config.tpl.Process(vagrantfileContents, tplData) if err != nil { return nil, false, fmt.Errorf("Error writing Vagrantfile: %s", err) } vf.Write([]byte(vagrantfileContents)) vf.Close() // Create the metadata metadata := map[string]string{"provider": "aws"} if err := WriteMetadata(dir, metadata); err != nil { return nil, false, err } // Compress the directory to the given output path if err := DirToBox(outputPath, dir, ui); err != nil { err = fmt.Errorf("error creating box: %s", err) return nil, false, err } return NewArtifact("aws", outputPath), true, nil }
func (p *PostProcessor) PostProcessProvider(name string, provider Provider, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { config := p.configs[""] if specificConfig, ok := p.configs[name]; ok { config = specificConfig } ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", name)) config.ctx.Data = &outputPathTemplate{ ArtifactId: artifact.Id(), BuildName: config.PackerBuildName, Provider: name, } outputPath, err := interpolate.Render(config.OutputPath, &config.ctx) if err != nil { return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { return nil, false, err } defer os.RemoveAll(dir) // Copy all of the includes files into the temporary directory for _, src := range config.Include { ui.Message(fmt.Sprintf("Copying from include: %s", src)) dst := filepath.Join(dir, filepath.Base(src)) if err := CopyContents(dst, src); err != nil { err = fmt.Errorf("Error copying include file: %s\n\n%s", src, err) return nil, false, err } } // Run the provider processing step vagrantfile, metadata, err := provider.Process(ui, artifact, dir) if err != nil { return nil, false, err } // Write the metadata we got if err := WriteMetadata(dir, metadata); err != nil { return nil, false, err } // Write our Vagrantfile var customVagrantfile string if config.VagrantfileTemplate != "" { ui.Message(fmt.Sprintf("Using custom Vagrantfile: %s", config.VagrantfileTemplate)) customBytes, err := ioutil.ReadFile(config.VagrantfileTemplate) if err != nil { return nil, false, err } customVagrantfile = string(customBytes) } f, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { return nil, false, err } t := template.Must(template.New("root").Parse(boxVagrantfileContents)) err = t.Execute(f, &vagrantfileTemplate{ ProviderVagrantfile: vagrantfile, CustomVagrantfile: customVagrantfile, }) f.Close() if err != nil { return nil, false, err } // Create the box if err := DirToBox(outputPath, dir, ui, config.CompressionLevel); err != nil { return nil, false, err } return NewArtifact(name, outputPath), provider.KeepInputArtifact(), nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if artifact.BuilderId() != dockertag.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only build with Dockerfile from Docker tag artifacts.", artifact.BuilderId()) return nil, false, err } p.config.From = artifact.Id() template_str := `FROM {{ .From }} {{ if .Maintainer }}MAINTAINER {{ .Maintainer }} {{ end }}{{ if .Cmd }}CMD {{ process .Cmd }} {{ end }}{{ if .Label }}{{ range $k, $v := .Label }}LABEL "{{ $k }}"="{{ $v }}" {{ end }}{{ end }}{{ if .Expose }}EXPOSE {{ join .Expose " " }} {{ end }}{{ if .Env }}{{ range $k, $v := .Env }}ENV {{ $k }} {{ $v }} {{ end }}{{ end }}{{ if .Entrypoint }}ENTRYPOINT {{ process .Entrypoint }} {{ end }}{{ if .Volume }}VOLUME {{ process .Volume }} {{ end }}{{ if .User }}USER {{ .User }} {{ end }}{{ if .WorkDir }}WORKDIR {{ .WorkDir }}{{ end }}` dockerfile := new(bytes.Buffer) template_writer := bufio.NewWriter(dockerfile) tmpl, err := template.New("Dockerfile").Funcs(template.FuncMap{ "process": p.processVar, "join": strings.Join, }).Parse(template_str) if err != nil { return nil, false, err } err = tmpl.Execute(template_writer, p.config) if err != nil { return nil, false, err } template_writer.Flush() log.Printf("Dockerfile:\n%s", dockerfile.String()) driver := p.Driver if driver == nil { // If no driver is set, then we use the real driver driver = &DockerDriver{&docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui}} } ui.Message("Building image from Dockerfile") id, err := driver.BuildImage(dockerfile) if err != nil { return nil, false, err } ui.Message("Destroying previously tagged image: " + p.config.From) err = artifact.Destroy() if err != nil { return nil, false, err } ui.Message("Tagging new image, " + id + ", as " + p.config.From) err = driver.TagImage(id, p.config.From, true) if err != nil { return nil, false, err } // Build the artifact artifact = &docker.ImportArtifact{ BuilderIdValue: dockertag.BuilderId, Driver: driver, IdValue: p.config.From, } return artifact, true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, source packer.Artifact) (packer.Artifact, bool, error) { artifact := &Artifact{} var err error var fi os.FileInfo // Create the current artifact. for _, name := range source.Files() { af := ArtifactFile{} if fi, err = os.Stat(name); err == nil { af.Size = fi.Size() } if p.config.StripPath { af.Name = filepath.Base(name) } else { af.Name = name } artifact.ArtifactFiles = append(artifact.ArtifactFiles, af) } artifact.ArtifactId = source.Id() artifact.BuilderType = p.config.PackerBuilderType artifact.BuildName = p.config.PackerBuildName artifact.BuildTime = time.Now().Unix() // Since each post-processor runs in a different process we need a way to // coordinate between various post-processors in a single packer run. We do // this by setting a UUID per run and tracking this in the manifest file. // When we detect that the UUID in the file is the same, we know that we are // part of the same run and we simply add our data to the list. If the UUID // is different we will check the -force flag and decide whether to truncate // the file before we proceed. artifact.PackerRunUUID = os.Getenv("PACKER_RUN_UUID") // Create a lock file with exclusive access. If this fails we will retry // after a delay. lockFilename := p.config.Filename + ".lock" for i := 0; i < 3; i++ { // The file should not be locked for very long so we'll keep this short. time.Sleep((time.Duration(i) * 200 * time.Millisecond)) _, err = os.OpenFile(lockFilename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) if err == nil { break } log.Printf("Error locking manifest file for reading and writing. Will sleep and retry. %s", err) } defer os.Remove(lockFilename) // TODO fix error on first run: // * Post-processor failed: open packer-manifest.json: no such file or directory // // Read the current manifest file from disk contents := []byte{} if contents, err = ioutil.ReadFile(p.config.Filename); err != nil && !os.IsNotExist(err) { return source, true, fmt.Errorf("Unable to open %s for reading: %s", p.config.Filename, err) } // Parse the manifest file JSON, if we have one manifestFile := &ManifestFile{} if len(contents) > 0 { if err = json.Unmarshal(contents, manifestFile); err != nil { return source, true, fmt.Errorf("Unable to parse content from %s: %s", p.config.Filename, err) } } // If -force is set and we are not on same run, truncate the file. Otherwise // we will continue to add new builds to the existing manifest file. if p.config.PackerForce && os.Getenv("PACKER_RUN_UUID") != manifestFile.LastRunUUID { manifestFile = &ManifestFile{} } // Add the current artifact to the manifest file manifestFile.Builds = append(manifestFile.Builds, *artifact) manifestFile.LastRunUUID = os.Getenv("PACKER_RUN_UUID") // Write JSON to disk if out, err := json.MarshalIndent(manifestFile, "", " "); err == nil { if err = ioutil.WriteFile(p.config.Filename, out, 0664); err != nil { return source, true, fmt.Errorf("Unable to write %s: %s", p.config.Filename, err) } } else { return source, true, fmt.Errorf("Unable to marshal JSON %s", err) } return source, true, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { name, ok := builtins[artifact.BuilderId()] if !ok { return nil, false, fmt.Errorf( "Unknown artifact type, can't build box: %s", artifact.BuilderId()) } provider := providerForName(name) if provider == nil { // This shouldn't happen since we hard code all of these ourselves panic(fmt.Sprintf("bad provider name: %s", name)) } config := p.configs[""] if specificConfig, ok := p.configs[name]; ok { config = specificConfig } ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", name)) outputPath, err := config.tpl.Process(config.OutputPath, &outputPathTemplate{ ArtifactId: artifact.Id(), BuildName: config.PackerBuildName, Provider: name, }) if err != nil { return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { return nil, false, err } defer os.RemoveAll(dir) // Copy all of the includes files into the temporary directory for _, src := range config.Include { ui.Message(fmt.Sprintf("Copying from include: %s", src)) dst := filepath.Join(dir, filepath.Base(src)) if err := CopyContents(dst, src); err != nil { err = fmt.Errorf("Error copying include file: %s\n\n%s", src, err) return nil, false, err } } // Run the provider processing step vagrantfile, metadata, err := provider.Process(ui, artifact, dir) if err != nil { return nil, false, err } // Write the metadata we got if err := WriteMetadata(dir, metadata); err != nil { return nil, false, err } // Write our Vagrantfile var customVagrantfile string if config.VagrantfileTemplate != "" { ui.Message(fmt.Sprintf( "Using custom Vagrantfile: %s", config.VagrantfileTemplate)) customBytes, err := ioutil.ReadFile(config.VagrantfileTemplate) if err != nil { return nil, false, err } customVagrantfile = string(customBytes) } f, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { return nil, false, err } t := template.Must(template.New("root").Parse(boxVagrantfileContents)) err = t.Execute(f, &vagrantfileTemplate{ ProviderVagrantfile: vagrantfile, CustomVagrantfile: customVagrantfile, }) f.Close() if err != nil { return nil, false, err } // Create the box if err := DirToBox(outputPath, dir, ui, config.CompressionLevel); err != nil { return nil, false, err } return NewArtifact(name, outputPath), false, nil }
func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Compile the output path outputPath, err := p.config.tpl.Process(p.config.OutputPath, &OutputPathTemplate{ ArtifactId: artifact.Id(), BuildName: p.config.PackerBuildName, Provider: "vmware", }) if err != nil { return nil, false, err } // Create a temporary directory for us to build the contents of the box in dir, err := ioutil.TempDir("", "packer") if err != nil { return nil, false, err } defer os.RemoveAll(dir) // Copy all of the original contents into the temporary directory for _, path := range artifact.Files() { ui.Message(fmt.Sprintf("Copying: %s", path)) dstPath := filepath.Join(dir, filepath.Base(path)) if err := CopyContents(dstPath, path); err != nil { return nil, false, err } } if p.config.VagrantfileTemplate != "" { f, err := os.Open(p.config.VagrantfileTemplate) if err != nil { return nil, false, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { return nil, false, err } // Create the Vagrantfile from the template vf, err := os.Create(filepath.Join(dir, "Vagrantfile")) if err != nil { return nil, false, err } defer vf.Close() vagrantfileContents, err := p.config.tpl.Process(string(contents), nil) if err != nil { return nil, false, fmt.Errorf("Error writing Vagrantfile: %s", err) } vf.Write([]byte(vagrantfileContents)) vf.Close() } var level int = flate.DefaultCompression if p.config.CompressionLevel != "" { level, err = strconv.Atoi(p.config.CompressionLevel) if err != nil { return nil, false, err } } // Create the metadata metadata := map[string]string{"provider": "vmware_desktop"} if err := WriteMetadata(dir, metadata); err != nil { return nil, false, err } // Compress the directory to the given output path ui.Message(fmt.Sprintf("Compressing box...")) if err := DirToBox(outputPath, dir, ui, level); err != nil { return nil, false, err } return NewArtifact("vmware", outputPath), false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // Only accept input from the vagrant post-processor if artifact.BuilderId() != "mitchellh.post-processor.vagrant" { return nil, false, fmt.Errorf("Unknown artifact type, requires box from vagrant post-processor: %s", artifact.BuilderId()) } // Assume there is only one .box file to upload box := artifact.Files()[0] if !strings.HasSuffix(box, ".box") { return nil, false, fmt.Errorf("Unknown files in artifact from vagrant post-processor: %s", artifact.Files()) } provider := providerFromBuilderName(artifact.Id()) ui.Say(fmt.Sprintf("Preparing to upload box for '%s' provider to S3 bucket '%s'", provider, p.config.Bucket)) // open the box so we can upload to S3 and calculate checksum for the manifest file, err := os.Open(box) if err != nil { return nil, false, err } defer file.Close() // get the file's size info, err := file.Stat() if err != nil { return nil, false, err } size := info.Size() ui.Message(fmt.Sprintf("Box to upload: %s (%d bytes)", box, size)) // get the latest manifest so we can add to it ui.Message("Fetching latest manifest") manifest, err := p.getManifest() if err != nil { return nil, false, err } // generate the path to store the box in S3 boxPath := fmt.Sprintf("%s/%s/%s", p.config.BoxDir, p.config.Version, path.Base(box)) ui.Message("Generating checksum") checksum, err := sum256(file) if err != nil { return nil, false, err } ui.Message(fmt.Sprintf("Checksum is %s", checksum)) ui.Message(fmt.Sprintf("Adding %s %s box to manifest", provider, p.config.Version)) if err := manifest.add(p.config.Version, &Provider{ Name: provider, Url: p.s3.URL(boxPath), ChecksumType: "sha256", Checksum: checksum, }); err != nil { return nil, false, err } // upload the box to S3 (rewinding as we already read the file to generate the checksum) ui.Message(fmt.Sprintf("Uploading box to S3: %s", boxPath)) if _, err := file.Seek(0, 0); err != nil { return nil, false, err } if size > 100*1024*1024 { ui.Message("File size > 100MB. Initiating multipart upload") multi, err := p.s3.InitMulti(boxPath, "application/octet-stream", p.config.ACL) if err != nil { return nil, false, err } ui.Message("Uploading...") const chunkSize = 5 * 1024 * 1024 totalParts := int(math.Ceil(float64(size) / float64(chunkSize))) totalUploadSize := int64(0) parts := make([]s3.Part, totalParts) errorCount := 0 for partNum := int(1); partNum <= totalParts; partNum++ { filePos, err := file.Seek(0, 1) partSize := int64(math.Min(chunkSize, float64(size-filePos))) partBuffer := make([]byte, partSize) ui.Message(fmt.Sprintf("Upload: Uploading part %d of %d, %d (of max %d) bytes", partNum, int(totalParts), int(partSize), int(chunkSize))) readBytes, err := file.Read(partBuffer) ui.Message(fmt.Sprintf("Upload: Read %d bytes from box file on disk", readBytes)) bufferReader := bytes.NewReader(partBuffer) part, err := multi.PutPart(partNum, bufferReader) parts[partNum-1] = part if err != nil { if errorCount < 10 { errorCount++ ui.Message(fmt.Sprintf("Error encountered! %s. Retry %d.", err, errorCount)) time.Sleep(5 * time.Second) //reset seek position to the beginning of this block file.Seek(filePos, 0) partNum-- } else { ui.Message(fmt.Sprintf("Too many errors encountered! Aborting.", err, errorCount)) return nil, false, err } } else { totalUploadSize += part.Size ui.Message(fmt.Sprintf("Upload: Finished part %d of %d, upload total is %d bytes. This part was %d bytes.", partNum, totalParts, int(totalUploadSize), int(part.Size))) } } ui.Message("Parts uploaded, completing upload...") if err := multi.Complete(parts); err != nil { return nil, false, err } } else { if err := p.s3.PutReader(boxPath, file, size, "application/octet-stream", p.config.ACL); err != nil { return nil, false, err } } ui.Message(fmt.Sprintf("Uploading the manifest: %s", p.config.ManifestPath)) if err := p.putManifest(manifest); err != nil { return nil, false, err } return &Artifact{p.s3.URL(p.config.ManifestPath)}, true, nil }