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 ¶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 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 ¶llelscommon.StepUploadVersion{ 203 Path: b.config.PrlctlVersionFile, 204 }, 205 ¶llelscommon.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 ¶llelscommon.StepShutdown{ 216 Command: b.config.ShutdownCommand, 217 Timeout: b.config.ShutdownTimeout, 218 }, 219 ¶llelscommon.StepPrlctl{ 220 Commands: b.config.PrlctlPost, 221 Ctx: b.config.ctx, 222 }, 223 ¶llelscommon.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 }