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 ¶llelscommon.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 ¶llelscommon.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 ¶llelscommon.StepAttachParallelsTools{ 164 ParallelsToolsMode: b.config.ParallelsToolsMode, 165 }, 166 new(parallelscommon.StepAttachFloppy), 167 ¶llelscommon.StepPrlctl{ 168 Commands: b.config.Prlctl, 169 Ctx: b.config.ctx, 170 }, 171 ¶llelscommon.StepRun{ 172 BootWait: b.config.BootWait, 173 }, 174 ¶llelscommon.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 ¶llelscommon.StepUploadVersion{ 186 Path: b.config.PrlctlVersionFile, 187 }, 188 ¶llelscommon.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 ¶llelscommon.StepShutdown{ 196 Command: b.config.ShutdownCommand, 197 Timeout: b.config.ShutdownTimeout, 198 }, 199 ¶llelscommon.StepPrlctl{ 200 Commands: b.config.PrlctlPost, 201 Ctx: b.config.ctx, 202 }, 203 ¶llelscommon.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 }