github.com/rothwerx/packer@v0.9.0/builder/parallels/iso/builder.go (about)

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