From ee8c8321e54d595097191a3c3a63c3ab5667736c Mon Sep 17 00:00:00 2001 From: Juanma Reyes Date: Sun, 17 May 2020 18:23:42 +0200 Subject: [PATCH] Add support for extra ISO in Proxmox builder --- builder/proxmox/builder.go | 31 +++++++++- builder/proxmox/config.go | 58 ++++++++++++++----- .../proxmox/step_finalize_template_config.go | 24 +++++--- builder/proxmox/step_start_vm.go | 2 + builder/proxmox/step_upload_iso.go | 19 ++++-- builder/proxmox/step_upload_iso_test.go | 8 ++- 6 files changed, 110 insertions(+), 32 deletions(-) diff --git a/builder/proxmox/builder.go b/builder/proxmox/builder.go index 79f51a3b163..8a63c3e1ce7 100644 --- a/builder/proxmox/builder.go +++ b/builder/proxmox/builder.go @@ -38,7 +38,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { return nil, nil, nil } -const downloadPathKey = "downloaded_iso_path" +const ( + downloadPathKey = "downloaded_iso_path" + targetPathKey = "iso_file" + downloadPathKeyExtra = "downloaded_iso_path_extra" + targetPathKeyExtra = "iso_file_extra" +) func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { var err error @@ -73,7 +78,29 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack TargetPath: b.config.TargetPath, Url: b.config.ISOUrls, }, - &stepUploadISO{}, + &common.StepDownload{ + Checksum: b.config.extraISOConfig.ISOChecksum, + ChecksumType: b.config.extraISOConfig.ISOChecksumType, + Description: "ISO", + Extension: b.config.TargetExtension, + ResultKey: downloadPathKeyExtra, + TargetPath: b.config.TargetPath, + Url: b.config.extraISOConfig.ISOUrls, + }, + &stepUploadISO{ + ShouldUpload: b.config.shouldUploadISO, + DownloadPathKey: downloadPathKey, + TargetStoragePathKey: targetPathKey, + ISOUrls: b.config.ISOUrls, + ISOFile: b.config.ISOFile, + }, + &stepUploadISO{ + ShouldUpload: b.config.shouldUploadExtraISO, + DownloadPathKey: downloadPathKeyExtra, + TargetStoragePathKey: targetPathKeyExtra, + ISOUrls: b.config.extraISOConfig.ISOUrls, + ISOFile: b.config.ISOFileExtra, + }, &stepStartVM{}, &common.StepHTTPServer{ HTTPDir: b.config.HTTPDir, diff --git a/builder/proxmox/config.go b/builder/proxmox/config.go index 92b6b9cef80..e24a8385013 100644 --- a/builder/proxmox/config.go +++ b/builder/proxmox/config.go @@ -40,28 +40,36 @@ type Config struct { VMName string `mapstructure:"vm_name"` VMID int `mapstructure:"vm_id"` - Memory int `mapstructure:"memory"` - Cores int `mapstructure:"cores"` - CPUType string `mapstructure:"cpu_type"` - Sockets int `mapstructure:"sockets"` - OS string `mapstructure:"os"` - VGA vgaConfig `mapstructure:"vga"` - NICs []nicConfig `mapstructure:"network_adapters"` - Disks []diskConfig `mapstructure:"disks"` - ISOFile string `mapstructure:"iso_file"` - ISOStoragePool string `mapstructure:"iso_storage_pool"` - Agent bool `mapstructure:"qemu_agent"` - SCSIController string `mapstructure:"scsi_controller"` - Onboot bool `mapstructure:"onboot"` + Memory int `mapstructure:"memory"` + Cores int `mapstructure:"cores"` + CPUType string `mapstructure:"cpu_type"` + Sockets int `mapstructure:"sockets"` + OS string `mapstructure:"os"` + VGA vgaConfig `mapstructure:"vga"` + NICs []nicConfig `mapstructure:"network_adapters"` + Disks []diskConfig `mapstructure:"disks"` + ISOFile string `mapstructure:"iso_file"` + ISOFileExtra string `mapstructure:"iso_file_extra"` + ISOUrlExtra string `mapstructure:"iso_url_extra"` + ISOChecksumExtra string `mapstructure:"iso_checksum_extra"` + ISOChecksumURLExtra string `mapstructure:"iso_checksum_url_extra"` + ISOChecksumTypeExtra string `mapstructure:"iso_checksum_type_extra"` + ISOStoragePool string `mapstructure:"iso_storage_pool"` + Agent bool `mapstructure:"qemu_agent"` + SCSIController string `mapstructure:"scsi_controller"` + Onboot bool `mapstructure:"onboot"` TemplateName string `mapstructure:"template_name"` TemplateDescription string `mapstructure:"template_description"` UnmountISO bool `mapstructure:"unmount_iso"` + UnmountExtraISO bool `mapstructure:"unmount_extra_iso"` CloudInit bool `mapstructure:"cloud_init"` CloudInitStoragePool string `mapstructure:"cloud_init_storage_pool"` - shouldUploadISO bool + shouldUploadISO bool + shouldUploadExtraISO bool + extraISOConfig common.ISOConfig ctx interpolate.Context } @@ -202,11 +210,29 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { c.shouldUploadISO = true } + if c.ISOFileExtra != "" { + c.shouldUploadExtraISO = false + } else if c.ISOUrlExtra != "" { + c.extraISOConfig = common.ISOConfig{ + RawSingleISOUrl: c.ISOUrlExtra, + ISOChecksum: c.ISOChecksumExtra, + ISOChecksumURL: c.ISOChecksumURLExtra, + ISOChecksumType: c.ISOChecksumTypeExtra, + } + isoWarnings, isoErrors := c.extraISOConfig.Prepare(&c.ctx) + errs = packer.MultiErrorAppend(errs, isoErrors...) + warnings = append(warnings, isoWarnings...) + c.shouldUploadExtraISO = true + } + if (c.ISOFile == "" && len(c.ISOConfig.ISOUrls) == 0) || (c.ISOFile != "" && len(c.ISOConfig.ISOUrls) != 0) { errs = packer.MultiErrorAppend(errs, errors.New("either iso_file or iso_url, but not both, must be specified")) } - if len(c.ISOConfig.ISOUrls) != 0 && c.ISOStoragePool == "" { - errs = packer.MultiErrorAppend(errs, errors.New("when specifying iso_url, iso_storage_pool must also be specified")) + if c.ISOFileExtra != "" && c.ISOUrlExtra != "" { + errs = packer.MultiErrorAppend(errs, errors.New("either iso_file_extra or iso_url_extra, but not both, can be specified")) + } + if (len(c.ISOConfig.ISOUrls) != 0 || c.ISOUrlExtra != "") && c.ISOStoragePool == "" { + errs = packer.MultiErrorAppend(errs, errors.New("when specifying iso_url or iso_url_extra, iso_storage_pool must also be specified")) } // Required configurations that will display errors if not set diff --git a/builder/proxmox/step_finalize_template_config.go b/builder/proxmox/step_finalize_template_config.go index 1e2deba6947..05f5c6b7dd8 100644 --- a/builder/proxmox/step_finalize_template_config.go +++ b/builder/proxmox/step_finalize_template_config.go @@ -38,7 +38,7 @@ func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.St // set, we need to clear it changes["description"] = c.TemplateDescription - if c.UnmountISO { + if c.UnmountISO || c.UnmountExtraISO { vmParams, err := client.GetVmConfig(vmRef) if err != nil { err := fmt.Errorf("Error fetching template config: %s", err) @@ -47,13 +47,23 @@ func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.St return multistep.ActionHalt } - if vmParams["ide2"] == nil || !strings.HasSuffix(vmParams["ide2"].(string), "media=cdrom") { - err := fmt.Errorf("Cannot eject ISO from cdrom drive, ide2 is not present, or not a cdrom media") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt + devices := []string{} + if c.UnmountISO { + devices = append(devices, "ide2") + } + if c.UnmountExtraISO { + devices = append(devices, "ide3") + } + + for _, device := range devices { + if vmParams[device] == nil || !strings.HasSuffix(vmParams[device].(string), "media=cdrom") { + err := fmt.Errorf("Cannot eject ISO from cdrom drive, %v is not present, or not a cdrom media", device) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + changes[device] = "none,media=cdrom" } - changes["ide2"] = "none,media=cdrom" } if c.CloudInit { diff --git a/builder/proxmox/step_start_vm.go b/builder/proxmox/step_start_vm.go index 34cdb186431..564e163f5ad 100644 --- a/builder/proxmox/step_start_vm.go +++ b/builder/proxmox/step_start_vm.go @@ -27,6 +27,7 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist } isoFile := state.Get("iso_file").(string) + isoFileExtra := state.Get("iso_file_extra").(string) ui.Say("Creating VM") config := proxmox.ConfigQemu{ @@ -41,6 +42,7 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist QemuOs: c.OS, QemuVga: generateProxmoxVga(c.VGA), QemuIso: isoFile, + QemuIsoExtra: isoFileExtra, QemuNetworks: generateProxmoxNetworkAdapters(c.NICs), QemuDisks: generateProxmoxDisks(c.Disks), Scsihw: c.SCSIController, diff --git a/builder/proxmox/step_upload_iso.go b/builder/proxmox/step_upload_iso.go index deba1672f8e..7bc79d51f61 100644 --- a/builder/proxmox/step_upload_iso.go +++ b/builder/proxmox/step_upload_iso.go @@ -13,7 +13,13 @@ import ( ) // stepUploadISO uploads an ISO file to Proxmox so we can boot from it -type stepUploadISO struct{} +type stepUploadISO struct { + ShouldUpload bool + DownloadPathKey string + TargetStoragePathKey string + ISOUrls []string + ISOFile string +} type uploader interface { Upload(node string, storage string, contentType string, filename string, file io.Reader) error @@ -26,12 +32,12 @@ func (s *stepUploadISO) Run(ctx context.Context, state multistep.StateBag) multi client := state.Get("proxmoxClient").(uploader) c := state.Get("config").(*Config) - if !c.shouldUploadISO { - state.Put("iso_file", c.ISOFile) + if !s.ShouldUpload { + state.Put(s.TargetStoragePathKey, s.ISOFile) return multistep.ActionContinue } - p := state.Get(downloadPathKey).(string) + p := state.Get(s.DownloadPathKey).(string) if p == "" { err := fmt.Errorf("Path to downloaded ISO was empty") state.Put("error", err) @@ -48,7 +54,8 @@ func (s *stepUploadISO) Run(ctx context.Context, state multistep.StateBag) multi return multistep.ActionHalt } - filename := filepath.Base(c.ISOUrls[0]) + filename := filepath.Base(s.ISOUrls[0]) + ui.Say(fmt.Sprintf("Uploading %s...", filename)) err = client.Upload(c.Node, c.ISOStoragePool, "iso", filename, r) if err != nil { state.Put("error", err) @@ -57,7 +64,7 @@ func (s *stepUploadISO) Run(ctx context.Context, state multistep.StateBag) multi } isoStoragePath := fmt.Sprintf("%s:iso/%s", c.ISOStoragePool, filename) - state.Put("iso_file", isoStoragePath) + state.Put(s.TargetStoragePathKey, isoStoragePath) return multistep.ActionContinue } diff --git a/builder/proxmox/step_upload_iso_test.go b/builder/proxmox/step_upload_iso_test.go index a009d6686c5..a2c7c8da03b 100644 --- a/builder/proxmox/step_upload_iso_test.go +++ b/builder/proxmox/step_upload_iso_test.go @@ -110,7 +110,13 @@ func TestUploadISO(t *testing.T) { state.Put(downloadPathKey, c.downloadPath) state.Put("proxmoxClient", m) - step := stepUploadISO{} + step := stepUploadISO{ + ShouldUpload: c.builderConfig.shouldUploadISO, + DownloadPathKey: downloadPathKey, + TargetStoragePathKey: targetPathKey, + ISOUrls: c.builderConfig.ISOUrls, + ISOFile: c.builderConfig.ISOFile, + } action := step.Run(context.TODO(), state) step.Cleanup(state)