示例#1
0
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)
}
示例#2
0
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
}
示例#3
0
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
}
示例#4
0
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
}
示例#5
0
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(),
	}
}
示例#8
0
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
}
示例#11
0
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
}
示例#13
0
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
}
示例#14
0
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)
}
示例#15
0
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
}
示例#16
0
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
}
示例#17
0
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
}
示例#19
0
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
}
示例#20
0
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
}
示例#21
0
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
}
示例#22
0
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
}
示例#24
0
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
}
示例#28
0
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
}
示例#30
0
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
}