github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/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 ¶llelscommon.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 ¶llelscommon.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 ¶llelscommon.StepAttachParallelsTools{ 181 ParallelsToolsMode: b.config.ParallelsToolsMode, 182 }, 183 new(parallelscommon.StepAttachFloppy), 184 ¶llelscommon.StepPrlctl{ 185 Commands: b.config.Prlctl, 186 Ctx: b.config.ctx, 187 }, 188 ¶llelscommon.StepRun{}, 189 ¶llelscommon.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 }, 196 &communicator.StepConnect{ 197 Config: &b.config.SSHConfig.Comm, 198 Host: parallelscommon.CommHost, 199 SSHConfig: parallelscommon.SSHConfigFunc(b.config.SSHConfig), 200 }, 201 ¶llelscommon.StepUploadVersion{ 202 Path: b.config.PrlctlVersionFile, 203 }, 204 ¶llelscommon.StepUploadParallelsTools{ 205 ParallelsToolsFlavor: b.config.ParallelsToolsFlavor, 206 ParallelsToolsGuestPath: b.config.ParallelsToolsGuestPath, 207 ParallelsToolsMode: b.config.ParallelsToolsMode, 208 Ctx: b.config.ctx, 209 }, 210 new(common.StepProvision), 211 ¶llelscommon.StepShutdown{ 212 Command: b.config.ShutdownCommand, 213 Timeout: b.config.ShutdownTimeout, 214 }, 215 ¶llelscommon.StepPrlctl{ 216 Commands: b.config.PrlctlPost, 217 Ctx: b.config.ctx, 218 }, 219 ¶llelscommon.StepCompactDisk{ 220 Skip: b.config.SkipCompaction, 221 }, 222 } 223 224 // Setup the state bag 225 state := new(multistep.BasicStateBag) 226 state.Put("cache", cache) 227 state.Put("config", &b.config) 228 state.Put("debug", b.config.PackerDebug) 229 state.Put("driver", driver) 230 state.Put("hook", hook) 231 state.Put("ui", ui) 232 233 // Run 234 b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) 235 b.runner.Run(state) 236 237 // If there was an error, return that 238 if rawErr, ok := state.GetOk("error"); ok { 239 return nil, rawErr.(error) 240 } 241 242 // If we were interrupted or cancelled, then just exit. 243 if _, ok := state.GetOk(multistep.StateCancelled); ok { 244 return nil, errors.New("Build was cancelled.") 245 } 246 247 if _, ok := state.GetOk(multistep.StateHalted); ok { 248 return nil, errors.New("Build was halted.") 249 } 250 251 return parallelscommon.NewArtifact(b.config.OutputDir) 252 } 253 254 func (b *Builder) Cancel() { 255 if b.runner != nil { 256 log.Println("Cancelling the step runner...") 257 b.runner.Cancel() 258 } 259 }