github.phpd.cn/hashicorp/packer@v1.3.2/builder/parallels/iso/builder.go (about)

     1  package iso
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  
     8  	parallelscommon "github.com/hashicorp/packer/builder/parallels/common"
     9  	"github.com/hashicorp/packer/common"
    10  	"github.com/hashicorp/packer/common/bootcommand"
    11  	"github.com/hashicorp/packer/helper/communicator"
    12  	"github.com/hashicorp/packer/helper/config"
    13  	"github.com/hashicorp/packer/helper/multistep"
    14  	"github.com/hashicorp/packer/packer"
    15  	"github.com/hashicorp/packer/template/interpolate"
    16  )
    17  
    18  const BuilderId = "rickard-von-essen.parallels"
    19  
    20  type Builder struct {
    21  	config Config
    22  	runner multistep.Runner
    23  }
    24  
    25  type Config struct {
    26  	common.PackerConfig                 `mapstructure:",squash"`
    27  	common.HTTPConfig                   `mapstructure:",squash"`
    28  	common.ISOConfig                    `mapstructure:",squash"`
    29  	common.FloppyConfig                 `mapstructure:",squash"`
    30  	bootcommand.BootConfig              `mapstructure:",squash"`
    31  	parallelscommon.OutputConfig        `mapstructure:",squash"`
    32  	parallelscommon.PrlctlConfig        `mapstructure:",squash"`
    33  	parallelscommon.PrlctlPostConfig    `mapstructure:",squash"`
    34  	parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
    35  	parallelscommon.ShutdownConfig      `mapstructure:",squash"`
    36  	parallelscommon.SSHConfig           `mapstructure:",squash"`
    37  	parallelscommon.ToolsConfig         `mapstructure:",squash"`
    38  
    39  	DiskSize           uint     `mapstructure:"disk_size"`
    40  	DiskType           string   `mapstructure:"disk_type"`
    41  	GuestOSType        string   `mapstructure:"guest_os_type"`
    42  	HardDriveInterface string   `mapstructure:"hard_drive_interface"`
    43  	HostInterfaces     []string `mapstructure:"host_interfaces"`
    44  	SkipCompaction     bool     `mapstructure:"skip_compaction"`
    45  	VMName             string   `mapstructure:"vm_name"`
    46  
    47  	ctx interpolate.Context
    48  }
    49  
    50  func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
    51  	err := config.Decode(&b.config, &config.DecodeOpts{
    52  		Interpolate:        true,
    53  		InterpolateContext: &b.config.ctx,
    54  		InterpolateFilter: &interpolate.RenderFilter{
    55  			Exclude: []string{
    56  				"boot_command",
    57  				"prlctl",
    58  				"prlctl_post",
    59  				"parallels_tools_guest_path",
    60  			},
    61  		},
    62  	}, raws...)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	// Accumulate any errors and warnings
    68  	var errs *packer.MultiError
    69  	warnings := make([]string, 0)
    70  
    71  	isoWarnings, isoErrs := b.config.ISOConfig.Prepare(&b.config.ctx)
    72  	warnings = append(warnings, isoWarnings...)
    73  	errs = packer.MultiErrorAppend(errs, isoErrs...)
    74  
    75  	errs = packer.MultiErrorAppend(errs, b.config.HTTPConfig.Prepare(&b.config.ctx)...)
    76  	errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(&b.config.ctx)...)
    77  	errs = packer.MultiErrorAppend(
    78  		errs, b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...)
    79  	errs = packer.MultiErrorAppend(errs, b.config.PrlctlConfig.Prepare(&b.config.ctx)...)
    80  	errs = packer.MultiErrorAppend(errs, b.config.PrlctlPostConfig.Prepare(&b.config.ctx)...)
    81  	errs = packer.MultiErrorAppend(errs, b.config.PrlctlVersionConfig.Prepare(&b.config.ctx)...)
    82  	errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...)
    83  	errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...)
    84  	errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(&b.config.ctx)...)
    85  	errs = packer.MultiErrorAppend(errs, b.config.BootConfig.Prepare(&b.config.ctx)...)
    86  
    87  	if b.config.DiskSize == 0 {
    88  		b.config.DiskSize = 40000
    89  	}
    90  
    91  	if b.config.DiskType == "" {
    92  		b.config.DiskType = "expand"
    93  	}
    94  
    95  	if b.config.HardDriveInterface == "" {
    96  		b.config.HardDriveInterface = "sata"
    97  	}
    98  
    99  	if b.config.GuestOSType == "" {
   100  		b.config.GuestOSType = "other"
   101  	}
   102  
   103  	if len(b.config.HostInterfaces) == 0 {
   104  		b.config.HostInterfaces = []string{"en0", "en1", "en2", "en3", "en4", "en5", "en6", "en7",
   105  			"en8", "en9", "ppp0", "ppp1", "ppp2"}
   106  	}
   107  
   108  	if b.config.VMName == "" {
   109  		b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName)
   110  	}
   111  
   112  	if b.config.DiskType != "expand" && b.config.DiskType != "plain" {
   113  		errs = packer.MultiErrorAppend(
   114  			errs, errors.New("disk_type can only be expand, or plain"))
   115  	}
   116  
   117  	if b.config.DiskType == "plain" && !b.config.SkipCompaction {
   118  		b.config.SkipCompaction = true
   119  		warnings = append(warnings,
   120  			"'skip_compaction' is enforced to be true for plain disks.")
   121  	}
   122  
   123  	if b.config.HardDriveInterface != "ide" && b.config.HardDriveInterface != "sata" && b.config.HardDriveInterface != "scsi" {
   124  		errs = packer.MultiErrorAppend(
   125  			errs, errors.New("hard_drive_interface can only be ide, sata, or scsi"))
   126  	}
   127  
   128  	// Warnings
   129  	if b.config.ShutdownCommand == "" {
   130  		warnings = append(warnings,
   131  			"A shutdown_command was not specified. Without a shutdown command, Packer\n"+
   132  				"will forcibly halt the virtual machine, which may result in data loss.")
   133  	}
   134  
   135  	if errs != nil && len(errs.Errors) > 0 {
   136  		return warnings, errs
   137  	}
   138  
   139  	return warnings, nil
   140  }
   141  
   142  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
   143  	// Create the driver that we'll use to communicate with Parallels
   144  	driver, err := parallelscommon.NewDriver()
   145  	if err != nil {
   146  		return nil, fmt.Errorf("Failed creating Parallels driver: %s", err)
   147  	}
   148  
   149  	steps := []multistep.Step{
   150  		&parallelscommon.StepPrepareParallelsTools{
   151  			ParallelsToolsFlavor: b.config.ParallelsToolsFlavor,
   152  			ParallelsToolsMode:   b.config.ParallelsToolsMode,
   153  		},
   154  		&common.StepDownload{
   155  			Checksum:     b.config.ISOChecksum,
   156  			ChecksumType: b.config.ISOChecksumType,
   157  			Description:  "ISO",
   158  			Extension:    b.config.TargetExtension,
   159  			ResultKey:    "iso_path",
   160  			TargetPath:   b.config.TargetPath,
   161  			Url:          b.config.ISOUrls,
   162  		},
   163  		&parallelscommon.StepOutputDir{
   164  			Force: b.config.PackerForce,
   165  			Path:  b.config.OutputDir,
   166  		},
   167  		&common.StepCreateFloppy{
   168  			Files:       b.config.FloppyConfig.FloppyFiles,
   169  			Directories: b.config.FloppyConfig.FloppyDirectories,
   170  		},
   171  		&common.StepHTTPServer{
   172  			HTTPDir:     b.config.HTTPDir,
   173  			HTTPPortMin: b.config.HTTPPortMin,
   174  			HTTPPortMax: b.config.HTTPPortMax,
   175  		},
   176  		new(stepCreateVM),
   177  		new(stepCreateDisk),
   178  		new(stepSetBootOrder),
   179  		new(stepAttachISO),
   180  		&parallelscommon.StepAttachParallelsTools{
   181  			ParallelsToolsMode: b.config.ParallelsToolsMode,
   182  		},
   183  		new(parallelscommon.StepAttachFloppy),
   184  		&parallelscommon.StepPrlctl{
   185  			Commands: b.config.Prlctl,
   186  			Ctx:      b.config.ctx,
   187  		},
   188  		&parallelscommon.StepRun{},
   189  		&parallelscommon.StepTypeBootCommand{
   190  			BootWait:       b.config.BootWait,
   191  			BootCommand:    b.config.FlatBootCommand(),
   192  			HostInterfaces: b.config.HostInterfaces,
   193  			VMName:         b.config.VMName,
   194  			Ctx:            b.config.ctx,
   195  			GroupInterval:  b.config.BootConfig.BootGroupInterval,
   196  		},
   197  		&communicator.StepConnect{
   198  			Config:    &b.config.SSHConfig.Comm,
   199  			Host:      parallelscommon.CommHost,
   200  			SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(),
   201  		},
   202  		&parallelscommon.StepUploadVersion{
   203  			Path: b.config.PrlctlVersionFile,
   204  		},
   205  		&parallelscommon.StepUploadParallelsTools{
   206  			ParallelsToolsFlavor:    b.config.ParallelsToolsFlavor,
   207  			ParallelsToolsGuestPath: b.config.ParallelsToolsGuestPath,
   208  			ParallelsToolsMode:      b.config.ParallelsToolsMode,
   209  			Ctx:                     b.config.ctx,
   210  		},
   211  		new(common.StepProvision),
   212  		&common.StepCleanupTempKeys{
   213  			Comm: &b.config.SSHConfig.Comm,
   214  		},
   215  		&parallelscommon.StepShutdown{
   216  			Command: b.config.ShutdownCommand,
   217  			Timeout: b.config.ShutdownTimeout,
   218  		},
   219  		&parallelscommon.StepPrlctl{
   220  			Commands: b.config.PrlctlPost,
   221  			Ctx:      b.config.ctx,
   222  		},
   223  		&parallelscommon.StepCompactDisk{
   224  			Skip: b.config.SkipCompaction,
   225  		},
   226  	}
   227  
   228  	// Setup the state bag
   229  	state := new(multistep.BasicStateBag)
   230  	state.Put("cache", cache)
   231  	state.Put("config", &b.config)
   232  	state.Put("debug", b.config.PackerDebug)
   233  	state.Put("driver", driver)
   234  	state.Put("hook", hook)
   235  	state.Put("ui", ui)
   236  
   237  	// Run
   238  	b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state)
   239  	b.runner.Run(state)
   240  
   241  	// If there was an error, return that
   242  	if rawErr, ok := state.GetOk("error"); ok {
   243  		return nil, rawErr.(error)
   244  	}
   245  
   246  	// If we were interrupted or cancelled, then just exit.
   247  	if _, ok := state.GetOk(multistep.StateCancelled); ok {
   248  		return nil, errors.New("Build was cancelled.")
   249  	}
   250  
   251  	if _, ok := state.GetOk(multistep.StateHalted); ok {
   252  		return nil, errors.New("Build was halted.")
   253  	}
   254  
   255  	return parallelscommon.NewArtifact(b.config.OutputDir)
   256  }
   257  
   258  func (b *Builder) Cancel() {
   259  	if b.runner != nil {
   260  		log.Println("Cancelling the step runner...")
   261  		b.runner.Cancel()
   262  	}
   263  }