func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { ppName, ok := builtins[artifact.BuilderId()] if !ok { return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } // Use the premade PostProcessor if we have one. Otherwise, we // create it and configure it here. pp, ok := p.premade[ppName] if !ok { log.Printf("Premade post-processor for '%s' not found. Creating.", ppName) var err error pp, err = p.subPostProcessor(ppName, nil, p.extraConfig) if err != nil { return nil, false, err } if pp == nil { return nil, false, fmt.Errorf("Vagrant box post-processor not found: %s", ppName) } } ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", ppName)) return pp.PostProcess(ui, artifact) }
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 (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 *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) { ppName, ok := builtins[artifact.BuilderId()] if !ok { return nil, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } // Use the premade PostProcessor if we have one. Otherwise, we // create it and configure it here. pp, ok := p.premade[ppName] if !ok { log.Printf("Premade post-processor for '%s' not found. Creating.", ppName) pp = keyToPostProcessor(ppName) if pp == nil { return nil, fmt.Errorf("Vagrant box post-processor not found: %s", ppName) } config := map[string]string{"output": p.config.OutputPath} if err := pp.Configure(config); err != nil { return nil, err } } ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", ppName)) return pp.PostProcess(ui, artifact) }
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 *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 (self *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { ui.Say(fmt.Sprintf("Creating archive for '%s'", artifact.BuilderId())) // Create the compressed archive file at the appropriate OutputPath. fw, err := os.Create(self.config.OutputPath) if err != nil { return nil, false, fmt.Errorf( "Failed creating file for compressed archive: %s", self.config.OutputPath) } defer fw.Close() gw := gzip.NewWriter(fw) defer gw.Close() // Iterate through all of the artifact's files and put them into the // compressed archive using the tar/gzip writers. for _, path := range artifact.Files() { fi, err := os.Stat(path) if err != nil { return nil, false, fmt.Errorf( "Failed stating file: %s", path) } target, _ := os.Readlink(path) header, err := tar.FileInfoHeader(fi, target) if err != nil { return nil, false, fmt.Errorf( "Failed creating archive header: %s", path) } tw := tar.NewWriter(gw) defer tw.Close() // Write the header first to the archive. This takes partial data // from the FileInfo that is grabbed by running the stat command. if err := tw.WriteHeader(header); err != nil { return nil, false, fmt.Errorf( "Failed writing archive header: %s", path) } // Open the target file for archiving and compressing. fr, err := os.Open(path) if err != nil { return nil, false, fmt.Errorf( "Failed opening file '%s' to write compressed archive.", path) } defer fr.Close() if _, err = io.Copy(tw, fr); err != nil { return nil, false, fmt.Errorf( "Failed copying file to archive: %s", path) } } return NewArtifact(artifact.BuilderId(), self.config.OutputPath), false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, ok := builtins[artifact.BuilderId()]; !ok { return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } vmx := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".vmx") { vmx = path break } } if vmx == "" { return nil, false, fmt.Errorf("VMX file not found") } if p.config.RemoveEthernet == "true" { if err := p.RemoveEthernet(vmx, ui, artifact); err != nil { return nil, false, fmt.Errorf("Removing ethernet0 interface from VMX failed!") } } if p.config.RemoveFloppy == "true" { if err := p.RemoveFloppy(vmx, ui, artifact); err != nil { return nil, false, fmt.Errorf("Removing floppy drive from VMX failed!") } } if p.config.RemoveOpticalDrive == "true" { if err := p.RemoveOpticalDrive(vmx, ui, artifact); err != nil { return nil, false, fmt.Errorf("Removing CD/DVD Drive from VMX failed!") } } args := []string{ "--acceptAllEulas", fmt.Sprintf("--diskMode=%s", p.config.DiskMode), fmt.Sprintf("%s", vmx), fmt.Sprintf("%s", p.config.Target), } ui.Message(fmt.Sprintf("Exporting %s to %s", vmx, p.config.Target)) var out bytes.Buffer log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " ")) cmd := exec.Command("ovftool", args...) cmd.Stdout = &out if err := cmd.Run(); err != nil { return nil, false, fmt.Errorf("Failed: %s\nStdout: %s", err, out.String()) } ui.Message(fmt.Sprintf("%s", out.String())) return artifact, false, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, ok := builtins[artifact.BuilderId()]; !ok { return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } vmx := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".vmx") { vmx = path break } } if vmx == "" { return nil, false, fmt.Errorf("VMX file not found") } ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s", url.QueryEscape(p.config.Username), url.QueryEscape(p.config.Password), p.config.Host, p.config.Datacenter, p.config.Cluster) if p.config.ResourcePool != "" { ovftool_uri += "/Resources/" + p.config.ResourcePool } args := []string{ fmt.Sprintf("--noSSLVerify=%t", p.config.Insecure), "--acceptAllEulas", fmt.Sprintf("--name=%s", p.config.VMName), fmt.Sprintf("--datastore=%s", p.config.Datastore), fmt.Sprintf("--diskMode=%s", p.config.DiskMode), fmt.Sprintf("--network=%s", p.config.VMNetwork), fmt.Sprintf("--vmFolder=%s", p.config.VMFolder), fmt.Sprintf("%s", vmx), fmt.Sprintf("%s", ovftool_uri), } ui.Message(fmt.Sprintf("Uploading %s to vSphere", vmx)) var out bytes.Buffer log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " ")) cmd := exec.Command("ovftool", args...) cmd.Stdout = &out if err := cmd.Run(); err != nil { return nil, false, fmt.Errorf("Failed: %s\nStdout: %s", err, out.String()) } ui.Message(fmt.Sprintf("%s", out.String())) return artifact, false, 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)) } return p.PostProcessProvider(name, provider, ui, artifact) }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, ok := builtins[artifact.BuilderId()]; !ok { return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } source := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") { source = path break } } if source == "" { return nil, false, fmt.Errorf("VMX, OVF or OVA file not found") } ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s", url.QueryEscape(p.config.Username), url.QueryEscape(p.config.Password), p.config.Host, p.config.Datacenter, p.config.Cluster) if p.config.ResourcePool != "" { ovftool_uri += "/Resources/" + p.config.ResourcePool } ui.Message(fmt.Sprintf("Uploading %s to vSphere", source)) args, err := p.BuildArgs(source, ovftool_uri) if err != nil { ui.Message(fmt.Sprintf("Failed: %s\n", err)) } ui.Message(fmt.Sprintf("Uploading %s to vSphere", source)) log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " ")) cmd := exec.Command("ovftool", args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return nil, false, fmt.Errorf("Failed: %s\n", err) } return artifact, false, nil }
func (self *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 diskimage: %s", artifact.BuilderId()) } // Sanity check since all of these are hardcoded in the application. provider := providerForName(name) if provider == nil { panic(fmt.Sprintf("Bad provider name: %s", name)) } ui.Say(fmt.Sprintf("Creating diskimage for '%s' provider", name)) return NewArtifact(name, outputPath), provider.KeepInputArtifact(), nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, ok := builtins[artifact.BuilderId()]; !ok { return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) } vmx := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".vmx") { vmx = path break } } if vmx == "" { return nil, false, fmt.Errorf("VMX file not found") } ui.Message(fmt.Sprintf("Uploading %s to vSphere", vmx)) args := []string{ fmt.Sprintf("--noSSLVerify=%t", p.config.Insecure), "--acceptAllEulas", fmt.Sprintf("--name=%s", p.config.VMName), fmt.Sprintf("--datastore=%s", p.config.Datastore), fmt.Sprintf("--network=%s", p.config.VMNetwork), fmt.Sprintf("--vmFolder=%s", p.config.VMFolder), fmt.Sprintf("vi://%s:%s@%s/%s/%s", p.config.Username, p.config.Password, p.config.Host, p.config.Datacenter, p.config.PathToResourcePool), } var out bytes.Buffer cmd := exec.Command("ovftool", args...) cmd.Stdout = &out if err := cmd.Run(); err != nil { return nil, false, fmt.Errorf("Failed: %s\nStdout: %s", err, out.String()) } ui.Message(fmt.Sprintf("%s", out.String())) return artifact, false, nil }
// 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 *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 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 && 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 *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) { 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 (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, 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), provider.KeepInputArtifact(), 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 }
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 *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.Multi(boxPath, "application/octet-stream", p.config.ACL) if err != nil { return nil, false, err } parts, err := multi.PutAll(file, 5*1024*1024) if err != nil { return nil, false, err } 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 }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { ui.Say("Starting googlecompute-export...") ui.Say(fmt.Sprintf("Exporting image to destinations: %v", p.config.Paths)) if artifact.BuilderId() != googlecompute.BuilderId { err := fmt.Errorf( "Unknown artifact type: %s\nCan only export from Google Compute Engine builder artifacts.", artifact.BuilderId()) return nil, p.config.KeepOriginalImage, err } result := &Artifact{paths: p.config.Paths} if len(p.config.Paths) > 0 { accountKeyFilePath := artifact.State("AccountFilePath").(string) imageName := artifact.State("ImageName").(string) imageSizeGb := artifact.State("ImageSizeGb").(int64) projectId := artifact.State("ProjectId").(string) zone := artifact.State("BuildZone").(string) // Set up instance configuration. instanceName := fmt.Sprintf("%s-exporter", artifact.Id()) metadata := map[string]string{ "image_name": imageName, "name": instanceName, "paths": strings.Join(p.config.Paths, " "), "startup-script": StartupScript, "zone": zone, } exporterConfig := googlecompute.Config{ InstanceName: instanceName, SourceImageProjectId: "debian-cloud", SourceImage: "debian-8-jessie-v20160629", DiskName: instanceName, DiskSizeGb: imageSizeGb + 10, DiskType: "pd-standard", Metadata: metadata, MachineType: "n1-standard-4", Zone: zone, Network: "default", RawStateTimeout: "5m", } exporterConfig.CalcTimeout() // Set up credentials and GCE driver. b, err := ioutil.ReadFile(accountKeyFilePath) if err != nil { err = fmt.Errorf("Error fetching account credentials: %s", err) return nil, p.config.KeepOriginalImage, err } accountKeyContents := string(b) googlecompute.ProcessAccountFile(&exporterConfig.Account, accountKeyContents) driver, err := googlecompute.NewDriverGCE(ui, projectId, &exporterConfig.Account) if err != nil { return nil, p.config.KeepOriginalImage, err } // Set up the state. state := new(multistep.BasicStateBag) state.Put("config", &exporterConfig) state.Put("driver", driver) state.Put("ui", ui) // Build the steps. steps := []multistep.Step{ &googlecompute.StepCreateSSHKey{ Debug: p.config.PackerDebug, DebugKeyPath: fmt.Sprintf("gce_%s.pem", p.config.PackerBuildName), }, &googlecompute.StepCreateInstance{ Debug: p.config.PackerDebug, }, new(googlecompute.StepWaitInstanceStartup), new(googlecompute.StepTeardownInstance), } // 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) } return result, p.config.KeepOriginalImage, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { // These are extra variables that will be made available for interpolation. p.config.ctx.Data = map[string]string{ "BuildName": p.config.PackerBuildName, "BuilderType": p.config.PackerBuilderType, } if artifact.BuilderId() != "transcend.qemu" { return nil, false, fmt.Errorf("tarball post-processor can only be used with Qemu builder: %s", artifact.BuilderId()) } outputPath, err := interpolate.Render(p.config.OutputPath, &p.config.ctx) if err != nil { return nil, false, fmt.Errorf("Error interpolating output path: %s", err) } if _, err := os.Stat(outputPath); err == nil { return nil, false, fmt.Errorf("Output directory %s already exists", outputPath) } if err := os.MkdirAll(outputPath, 0755); err != nil { return nil, false, fmt.Errorf("Error creating output directory %s: %s", outputPath, err) } keep := p.config.KeepInputArtifact newArtifact := &Artifact{Path: outputPath} for _, src := range artifact.Files() { var outfile string if p.config.TarballFile == "" { outfile = filepath.Join(newArtifact.Path, filepath.Base(src)) } else { outfile = filepath.Join(newArtifact.Path, p.config.TarballFile) } outfile += ".tar.gz" gf := exec.Command(p.config.GuestfishBinary) w, _ := gf.StdinPipe() r, _ := gf.StdoutPipe() br := bufio.NewReader(r) defer w.Close() defer r.Close() if err := gf.Start(); err != nil { return nil, false, fmt.Errorf("Error running guestfish: %s", err) } ui.Say(fmt.Sprintf("Loading %s into guestfish", src)) io.WriteString(w, fmt.Sprintf("add-drive %s\n", src)) io.WriteString(w, "run\n") ui.Message("Finding root filesystem") io.WriteString(w, "inspect-os\n") // Read the response from Guestfish in a goroutine so that we can timeout // if it is having problems finding the root filesystem. var result Result input := make(chan Result) go func(chan Result) { line, err := br.ReadString('\n') input <- Result{Value: line, Err: err} }(input) select { case result = <-input: if result.Err != nil && result.Err != io.EOF { return nil, false, fmt.Errorf("Failed to locate root filesystem: %s", err) } case <-time.After(time.Second * 10): return nil, false, fmt.Errorf("Failed to locate root filesystem: timed out waiting for response from Guestfish.") } device := strings.TrimSpace(result.Value) ui.Message(fmt.Sprintf("Found root filesystem at %s", device)) ui.Message(fmt.Sprintf("Mounting %s to /", device)) io.WriteString(w, fmt.Sprintf("mount %s /\n", device)) ui.Message("Creating character devices") io.WriteString(w, makeCharDevices) ui.Message(fmt.Sprintf("Packing filesystem into tarball %s", outfile)) io.WriteString(w, fmt.Sprintf("tar-out / %s compress:gzip\n", outfile)) io.WriteString(w, "quit\n") newArtifact.files = append(newArtifact.files, outfile) } return newArtifact, keep, nil }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, ok := builtins[artifact.BuilderId()]; !ok { return nil, false, fmt.Errorf("Unknown artifact type, can't process artifact: %s", artifact.BuilderId()) } vhd := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".vhd") { vhd = path break } } if vhd == "" { return nil, false, fmt.Errorf("No VHD artifact file found") } vmType := artifact.State("virtualizationType") if vhd == "" { return nil, false, fmt.Errorf("Virtualization type wasn't specified") } requiresHVM := "false" if strings.ToLower(vmType.(string)) == "hvm" { requiresHVM = "true" } dir, file := path.Split(vhd) copyFromUrl := "" uploadFile := vhd if p.config.CompressVhd { uploadFile = dir + "template.vhd.gzip" os.Remove(uploadFile) // remove any existing file to ensure no corruption ui.Message(fmt.Sprintf("Compressing '%s' to '%s'", vhd, uploadFile)) err := compressVhd(vhd, uploadFile) if err != nil { return nil, false, fmt.Errorf("Error compressing template '%s': %s", vhd, err) } if strings.HasSuffix(p.config.DownloadUrl, "/") { copyFromUrl = p.config.DownloadUrl + "template.vhd.gzip" } else { copyFromUrl = fmt.Sprintf("%s/%s", p.config.DownloadUrl, "template.vhd.gzip") } } else { if strings.HasSuffix(p.config.DownloadUrl, "/") { copyFromUrl = p.config.DownloadUrl + file } else { copyFromUrl = fmt.Sprintf("%s/%s", p.config.DownloadUrl, file) } } ui.Message(fmt.Sprintf("Uploading %s to CloudStack", uploadFile)) // Create a new caching client acs, err := gocs.NewCachingClient(p.config.ApiUrl, p.config.ApiKey, p.config.Secret, 0, false) if err != nil { return nil, false, fmt.Errorf("Connection error: %s", err) } ostypeid, err := acs.Request("listOsTypes", fmt.Sprintf("description:%s", p.config.OsType)) if err != nil { return nil, false, fmt.Errorf("Error locating OS type '%s': %s", p.config.OsType, err) } ui.Say(fmt.Sprintf("OS '%s' has id '%s'", p.config.OsType, ostypeid)) zoneid, err := acs.Request("listZones", fmt.Sprintf("name:%s", p.config.Zone)) if err != nil { return nil, false, fmt.Errorf("Error locating Zone '%s': %s", p.config.Zone, err) } ui.Say(fmt.Sprintf("Zone '%s' has id '%s'", p.config.Zone, zoneid)) templateid, err := acs.Request("registerTemplate", fmt.Sprintf("displaytext:%s, ostypeid:%s, format:vhd, hypervisor:xenserver, name:%s, zoneid:%s, url:%s, requireshvm:%t, passwordenabled:%t, sshkeyenabled:%t, isdynamicallyscalable:%t", p.config.DisplayText, ostypeid, p.config.TemplateName, zoneid, copyFromUrl, requiresHVM, p.config.PwdEnabled, p.config.SshEnabled, p.config.HasTools)) if err != nil { return nil, false, fmt.Errorf("Error registering template '%s': %s", p.config.TemplateName, err) } ui.Say(fmt.Sprintf("Template registered as '%s'", templateid)) lastStatus := "" downloadStarted := false iterations := int(p.config.UploadTimer) / 5 for i := 0; i < iterations; i++ { templateDetails, err := acs.RawRequest("listTemplates", fmt.Sprintf("id:%s, templatefilter:all", templateid)) if err != nil { return nil, false, fmt.Errorf("Error locating template '%s': %s", templateid, err) } jsonResponse, err := gocs.UnmarshalResponse("template", templateDetails) if err != nil { return nil, false, fmt.Errorf("Error unmarshalling template repsonse: %s", err) } // a normal download will see the "status" start blank, then become non-blank in a few seconds, ending with isready:true // anything else is an error var status []TemplateResponse if err := json.Unmarshal(jsonResponse, &status); err != nil { return nil, false, fmt.Errorf("Error unmarshalling template repsonse: %s", err) } if status[0].Status != lastStatus { ui.Say(fmt.Sprintf("Template processing status '%s'", status[0].Status)) lastStatus = status[0].Status if strings.TrimSpace(lastStatus) != "" && !downloadStarted { if strings.Contains(lastStatus, "%") { downloadStarted = true } else if strings.HasPrefix(lastStatus, "Failed") { return nil, false, fmt.Errorf("Template '%s' processing aborted due to error: '%s'", p.config.TemplateName, strings.TrimSpace(lastStatus)) } else { return nil, false, fmt.Errorf("Template '%s' download aborted due to error: '%s'", p.config.TemplateName, strings.TrimSpace(lastStatus)) } } } if status[0].IsReady { ui.Say(fmt.Sprintf("Template '%s' is ready ", p.config.TemplateName)) break } time.Sleep(time.Duration(5) * time.Second) } return artifact, false, nil }