github.com/kimor79/packer@v0.8.7-0.20151221212622-d507b18eb4cf/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.ISOConfig `mapstructure:",squash"` 27 parallelscommon.FloppyConfig `mapstructure:",squash"` 28 parallelscommon.OutputConfig `mapstructure:",squash"` 29 parallelscommon.PrlctlConfig `mapstructure:",squash"` 30 parallelscommon.PrlctlPostConfig `mapstructure:",squash"` 31 parallelscommon.PrlctlVersionConfig `mapstructure:",squash"` 32 parallelscommon.RunConfig `mapstructure:",squash"` 33 parallelscommon.ShutdownConfig `mapstructure:",squash"` 34 parallelscommon.SSHConfig `mapstructure:",squash"` 35 parallelscommon.ToolsConfig `mapstructure:",squash"` 36 37 BootCommand []string `mapstructure:"boot_command"` 38 DiskSize uint `mapstructure:"disk_size"` 39 GuestOSType string `mapstructure:"guest_os_type"` 40 HardDriveInterface string `mapstructure:"hard_drive_interface"` 41 HostInterfaces []string `mapstructure:"host_interfaces"` 42 HTTPDir string `mapstructure:"http_directory"` 43 HTTPPortMin uint `mapstructure:"http_port_min"` 44 HTTPPortMax uint `mapstructure:"http_port_max"` 45 SkipCompaction bool `mapstructure:"skip_compaction"` 46 VMName string `mapstructure:"vm_name"` 47 48 // Deprecated parameters 49 GuestOSDistribution string `mapstructure:"guest_os_distribution"` 50 ParallelsToolsHostPath string `mapstructure:"parallels_tools_host_path"` 51 52 ctx interpolate.Context 53 } 54 55 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 56 err := config.Decode(&b.config, &config.DecodeOpts{ 57 Interpolate: true, 58 InterpolateContext: &b.config.ctx, 59 InterpolateFilter: &interpolate.RenderFilter{ 60 Exclude: []string{ 61 "boot_command", 62 "prlctl", 63 "prlctl_post", 64 "parallels_tools_guest_path", 65 }, 66 }, 67 }, raws...) 68 if err != nil { 69 return nil, err 70 } 71 72 // Accumulate any errors and warnings 73 var errs *packer.MultiError 74 warnings := make([]string, 0) 75 76 isoWarnings, isoErrs := b.config.ISOConfig.Prepare(&b.config.ctx) 77 warnings = append(warnings, isoWarnings...) 78 errs = packer.MultiErrorAppend(errs, isoErrs...) 79 80 errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(&b.config.ctx)...) 81 errs = packer.MultiErrorAppend( 82 errs, b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...) 83 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) 84 errs = packer.MultiErrorAppend(errs, b.config.PrlctlConfig.Prepare(&b.config.ctx)...) 85 errs = packer.MultiErrorAppend(errs, b.config.PrlctlPostConfig.Prepare(&b.config.ctx)...) 86 errs = packer.MultiErrorAppend(errs, b.config.PrlctlVersionConfig.Prepare(&b.config.ctx)...) 87 errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...) 88 errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...) 89 errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(&b.config.ctx)...) 90 91 if b.config.DiskSize == 0 { 92 b.config.DiskSize = 40000 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 b.config.GuestOSDistribution != "" { 104 // Compatibility with older templates: 105 // Use value of 'guest_os_distribution' if it is defined. 106 b.config.GuestOSType = b.config.GuestOSDistribution 107 warnings = append(warnings, 108 "A 'guest_os_distribution' has been completely replaced with 'guest_os_type'\n"+ 109 "It is recommended to remove it and assign the previous value to 'guest_os_type'.\n"+ 110 "Run it to see all available values: `prlctl create x -d list` ") 111 } 112 113 if b.config.HTTPPortMin == 0 { 114 b.config.HTTPPortMin = 8000 115 } 116 117 if b.config.HTTPPortMax == 0 { 118 b.config.HTTPPortMax = 9000 119 } 120 121 if len(b.config.HostInterfaces) == 0 { 122 b.config.HostInterfaces = []string{"en0", "en1", "en2", "en3", "en4", "en5", "en6", "en7", 123 "en8", "en9", "ppp0", "ppp1", "ppp2"} 124 } 125 126 if b.config.VMName == "" { 127 b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName) 128 } 129 130 if b.config.HardDriveInterface != "ide" && b.config.HardDriveInterface != "sata" && b.config.HardDriveInterface != "scsi" { 131 errs = packer.MultiErrorAppend( 132 errs, errors.New("hard_drive_interface can only be ide, sata, or scsi")) 133 } 134 135 if b.config.HTTPPortMin > b.config.HTTPPortMax { 136 errs = packer.MultiErrorAppend( 137 errs, errors.New("http_port_min must be less than http_port_max")) 138 } 139 140 // Warnings 141 if b.config.ShutdownCommand == "" { 142 warnings = append(warnings, 143 "A shutdown_command was not specified. Without a shutdown command, Packer\n"+ 144 "will forcibly halt the virtual machine, which may result in data loss.") 145 } 146 147 if b.config.ParallelsToolsHostPath != "" { 148 warnings = append(warnings, 149 "A 'parallels_tools_host_path' has been deprecated and not in use anymore\n"+ 150 "You can remove it from your Packer template.") 151 } 152 153 if errs != nil && len(errs.Errors) > 0 { 154 return warnings, errs 155 } 156 157 return warnings, nil 158 } 159 160 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 161 // Create the driver that we'll use to communicate with Parallels 162 driver, err := parallelscommon.NewDriver() 163 if err != nil { 164 return nil, fmt.Errorf("Failed creating Parallels driver: %s", err) 165 } 166 167 steps := []multistep.Step{ 168 ¶llelscommon.StepPrepareParallelsTools{ 169 ParallelsToolsFlavor: b.config.ParallelsToolsFlavor, 170 ParallelsToolsMode: b.config.ParallelsToolsMode, 171 }, 172 &common.StepDownload{ 173 Checksum: b.config.ISOChecksum, 174 ChecksumType: b.config.ISOChecksumType, 175 Description: "ISO", 176 Extension: "iso", 177 ResultKey: "iso_path", 178 TargetPath: b.config.TargetPath, 179 Url: b.config.ISOUrls, 180 }, 181 ¶llelscommon.StepOutputDir{ 182 Force: b.config.PackerForce, 183 Path: b.config.OutputDir, 184 }, 185 &common.StepCreateFloppy{ 186 Files: b.config.FloppyFiles, 187 }, 188 new(stepHTTPServer), 189 new(stepCreateVM), 190 new(stepCreateDisk), 191 new(stepSetBootOrder), 192 new(stepAttachISO), 193 ¶llelscommon.StepAttachParallelsTools{ 194 ParallelsToolsMode: b.config.ParallelsToolsMode, 195 }, 196 new(parallelscommon.StepAttachFloppy), 197 ¶llelscommon.StepPrlctl{ 198 Commands: b.config.Prlctl, 199 Ctx: b.config.ctx, 200 }, 201 ¶llelscommon.StepRun{ 202 BootWait: b.config.BootWait, 203 }, 204 ¶llelscommon.StepTypeBootCommand{ 205 BootCommand: b.config.BootCommand, 206 HostInterfaces: b.config.HostInterfaces, 207 VMName: b.config.VMName, 208 Ctx: b.config.ctx, 209 }, 210 &communicator.StepConnect{ 211 Config: &b.config.SSHConfig.Comm, 212 Host: parallelscommon.CommHost, 213 SSHConfig: parallelscommon.SSHConfigFunc(b.config.SSHConfig), 214 }, 215 ¶llelscommon.StepUploadVersion{ 216 Path: b.config.PrlctlVersionFile, 217 }, 218 ¶llelscommon.StepUploadParallelsTools{ 219 ParallelsToolsFlavor: b.config.ParallelsToolsFlavor, 220 ParallelsToolsGuestPath: b.config.ParallelsToolsGuestPath, 221 ParallelsToolsMode: b.config.ParallelsToolsMode, 222 Ctx: b.config.ctx, 223 }, 224 new(common.StepProvision), 225 ¶llelscommon.StepShutdown{ 226 Command: b.config.ShutdownCommand, 227 Timeout: b.config.ShutdownTimeout, 228 }, 229 ¶llelscommon.StepPrlctl{ 230 Commands: b.config.PrlctlPost, 231 Ctx: b.config.ctx, 232 }, 233 ¶llelscommon.StepCompactDisk{ 234 Skip: b.config.SkipCompaction, 235 }, 236 } 237 238 // Setup the state bag 239 state := new(multistep.BasicStateBag) 240 state.Put("cache", cache) 241 state.Put("config", &b.config) 242 state.Put("driver", driver) 243 state.Put("hook", hook) 244 state.Put("ui", ui) 245 246 // Run 247 if b.config.PackerDebug { 248 b.runner = &multistep.DebugRunner{ 249 Steps: steps, 250 PauseFn: common.MultistepDebugFn(ui), 251 } 252 } else { 253 b.runner = &multistep.BasicRunner{Steps: steps} 254 } 255 256 b.runner.Run(state) 257 258 // If there was an error, return that 259 if rawErr, ok := state.GetOk("error"); ok { 260 return nil, rawErr.(error) 261 } 262 263 // If we were interrupted or cancelled, then just exit. 264 if _, ok := state.GetOk(multistep.StateCancelled); ok { 265 return nil, errors.New("Build was cancelled.") 266 } 267 268 if _, ok := state.GetOk(multistep.StateHalted); ok { 269 return nil, errors.New("Build was halted.") 270 } 271 272 return parallelscommon.NewArtifact(b.config.OutputDir) 273 } 274 275 func (b *Builder) Cancel() { 276 if b.runner != nil { 277 log.Println("Cancelling the step runner...") 278 b.runner.Cancel() 279 } 280 }