diff --git a/.web-docs/components/builder/iso/README.md b/.web-docs/components/builder/iso/README.md index 4d51550..e5dafcf 100644 --- a/.web-docs/components/builder/iso/README.md +++ b/.web-docs/components/builder/iso/README.md @@ -241,6 +241,17 @@ In HCL2: Kickstart or other early initialization tools, which can benefit from labelled floppy disks. By default, the floppy label will be 'packer'. +- `cd_files` ([]string) - A list of files to place onto a CD that is attached when the VM is + booted. This can include either files or directories; any directories + will be copied onto the CD recursively, preserving directory structure + hierarchy. Symlinks will have the link's target copied into the directory + tree on the CD where the symlink was. File globbing is allowed. + +- `cd_content` (map[string]string) - Key/Values to add to the CD. The keys represent the paths, and the values + contents. It can be used alongside `cd_files`, which is useful to add large + files without loading them into memory. If any paths are specified by both, + the contents in `cd_content` will take precedence. + - `guest_os_type` (string) - The guest OS type being installed. By default this is "other", but you can get _dramatic_ performance improvements by setting this to the proper value. To view all available values for this run diff --git a/.web-docs/components/builder/pvm/README.md b/.web-docs/components/builder/pvm/README.md index 409b0c3..12fe909 100644 --- a/.web-docs/components/builder/pvm/README.md +++ b/.web-docs/components/builder/pvm/README.md @@ -93,6 +93,17 @@ can also be supplied to override the typical auto-generated key: Kickstart or other early initialization tools, which can benefit from labelled floppy disks. By default, the floppy label will be 'packer'. +- `cd_files` ([]string) - A list of files to place onto a CD that is attached when the VM is + booted. This can include either files or directories; any directories + will be copied onto the CD recursively, preserving directory structure + hierarchy. Symlinks will have the link's target copied into the directory + tree on the CD where the symlink was. File globbing is allowed. + +- `cd_content` (map[string]string) - Key/Values to add to the CD. The keys represent the paths, and the values + contents. It can be used alongside `cd_files`, which is useful to add large + files without loading them into memory. If any paths are specified by both, + the contents in `cd_content` will take precedence. + - `output_directory` (string) - This is the path to the directory where the resulting virtual machine will be created. This may be relative or absolute. If relative, the path is relative to the working directory when `packer` diff --git a/builder/parallels/common/driver_mock.go b/builder/parallels/common/driver_mock.go index 95ce30b..cf72c8c 100644 --- a/builder/parallels/common/driver_mock.go +++ b/builder/parallels/common/driver_mock.go @@ -76,6 +76,8 @@ func (d *DriverMock) DeviceAddCDROM(name string, image string) (string, error) { d.DeviceAddCDROMCalled = true d.DeviceAddCDROMName = name d.DeviceAddCDROMImage = image + d.DeviceAddCDROMResult = "cdrom0" + d.DeviceAddCDROMErr = nil return d.DeviceAddCDROMResult, d.DeviceAddCDROMErr } diff --git a/builder/parallels/common/step_attach_cd.go b/builder/parallels/common/step_attach_cd.go new file mode 100644 index 0000000..a43b640 --- /dev/null +++ b/builder/parallels/common/step_attach_cd.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" +) + +// StepAttachCD is a step that attaches a cd to the virtual machine. +// +// Uses: +// +// driver Driver +// ui packersdk.Ui +// vmName string +// +// Produces: +type StepAttachCD struct { + cdPath string + cdromDevice string +} + +// Run adds a virtual CD to the VM and attaches the image. +// If the image is not specified, then this step will be skipped. +func (s *StepAttachCD) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + // Determine if we even have a cd to attach + var cdPath string + if cdPathRaw, ok := state.GetOk("cd_path"); ok { + cdPath = cdPathRaw.(string) + } else { + log.Println("No cd found, not attaching.") + return multistep.ActionContinue + } + + driver := state.Get("driver").(Driver) + ui := state.Get("ui").(packersdk.Ui) + vmName := state.Get("vmName").(string) + + ui.Say("Attaching cd...") + // Attaching the cd using the driver + cdrom, err := driver.DeviceAddCDROM(vmName, cdPath) + if err != nil { + err = fmt.Errorf("error attaching cd: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + // Track the device name so that we can can delete later + s.cdromDevice = cdrom + + return multistep.ActionContinue +} + +// Cleanup removes the virtual FDD device attached to the VM. +func (s *StepAttachCD) Cleanup(state multistep.StateBag) { + driver := state.Get("driver").(Driver) + vmName := state.Get("vmName").(string) + + if s.cdPath == "" { + return + } + + log.Println("Detaching cd disk...") + command := []string{ + "set", vmName, + "--device-del", s.cdromDevice, + } + _ = driver.Prlctl(command...) +} diff --git a/builder/parallels/common/step_attach_cd_test.go b/builder/parallels/common/step_attach_cd_test.go new file mode 100644 index 0000000..ff199d2 --- /dev/null +++ b/builder/parallels/common/step_attach_cd_test.go @@ -0,0 +1,76 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common + +import ( + "context" + "io/ioutil" + "os" + "testing" + + "github.com/hashicorp/packer-plugin-sdk/multistep" +) + +func TestStepAttachCD_impl(t *testing.T) { + var _ multistep.Step = new(StepAttachCD) +} + +func TestStepAttachCD(t *testing.T) { + state := testState(t) + step := new(StepAttachCD) + + // Create a temporary file for our CD + tf, err := ioutil.TempFile("", "packer") + if err != nil { + t.Fatalf("err: %s", err) + } + tf.Close() + defer os.Remove(tf.Name()) + + state.Put("cd_path", tf.Name()) + state.Put("vmName", "foo") + + driver := state.Get("driver").(*DriverMock) + + // Test the run + if action := step.Run(context.Background(), state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + if _, ok := state.GetOk("error"); ok { + t.Fatal("should NOT have error") + } + + if !driver.DeviceAddCDROMCalled { + t.Fatal("DeviceAddCDROM not called") + } + if driver.DeviceAddCDROMName != "foo" { + t.Fatal("DeviceAddCDROM name isn't what we specified (foo)") + } + if driver.DeviceAddCDROMResult != "cdrom0" { + t.Fatal("DeviceAddCDROM didn't return cdrom0") + } + if driver.DeviceAddCDROMErr != nil { + t.Fatal("DeviceAddCDROM returned an error") + } + +} + +func TestStepAttachCD_noCD(t *testing.T) { + state := testState(t) + step := new(StepAttachCD) + + driver := state.Get("driver").(*DriverMock) + + // Test the run + if action := step.Run(context.Background(), state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + if _, ok := state.GetOk("error"); ok { + t.Fatal("should NOT have error") + } + + if driver.DeviceAddCDROMCalled { + t.Fatal("DeviceAddCDROM has been called") + } +} diff --git a/builder/parallels/iso/builder.go b/builder/parallels/iso/builder.go index 874790b..797d676 100644 --- a/builder/parallels/iso/builder.go +++ b/builder/parallels/iso/builder.go @@ -36,6 +36,7 @@ type Config struct { commonsteps.HTTPConfig `mapstructure:",squash"` commonsteps.ISOConfig `mapstructure:",squash"` commonsteps.FloppyConfig `mapstructure:",squash"` + commonsteps.CDConfig `mapstructure:",squash"` bootcommand.BootConfig `mapstructure:",squash"` parallelscommon.OutputConfig `mapstructure:",squash"` parallelscommon.HWConfig `mapstructure:",squash"` @@ -214,6 +215,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Directories: b.config.FloppyConfig.FloppyDirectories, Label: b.config.FloppyConfig.FloppyLabel, }, + &commonsteps.StepCreateCD{ + Files: b.config.CDConfig.CDFiles, + Content: b.config.CDConfig.CDContent, + }, commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), new(stepCreateVM), new(stepCreateDisk), @@ -223,6 +228,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) ParallelsToolsMode: b.config.ParallelsToolsMode, }, new(parallelscommon.StepAttachFloppy), + new(parallelscommon.StepAttachCD), ¶llelscommon.StepPrlctl{ Commands: b.config.Prlctl, Ctx: b.config.ctx, diff --git a/builder/parallels/iso/builder.hcl2spec.go b/builder/parallels/iso/builder.hcl2spec.go index fa17d7e..fb09f77 100644 --- a/builder/parallels/iso/builder.hcl2spec.go +++ b/builder/parallels/iso/builder.hcl2spec.go @@ -33,6 +33,9 @@ type FlatConfig struct { FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` FloppyContent map[string]string `mapstructure:"floppy_content" cty:"floppy_content" hcl:"floppy_content"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` + CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"` + CDContent map[string]string `mapstructure:"cd_content" cty:"cd_content" hcl:"cd_content"` + CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"` BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"` BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"` BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"` @@ -142,6 +145,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, "floppy_content": &hcldec.AttrSpec{Name: "floppy_content", Type: cty.Map(cty.String), Required: false}, "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, + "cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false}, + "cd_content": &hcldec.AttrSpec{Name: "cd_content", Type: cty.Map(cty.String), Required: false}, + "cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false}, "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, diff --git a/builder/parallels/pvm/builder.go b/builder/parallels/pvm/builder.go index b47bc39..e64bf09 100644 --- a/builder/parallels/pvm/builder.go +++ b/builder/parallels/pvm/builder.go @@ -67,6 +67,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Directories: b.config.FloppyConfig.FloppyDirectories, Label: b.config.FloppyConfig.FloppyLabel, }, + &commonsteps.StepCreateCD{ + Files: b.config.CDConfig.CDFiles, + Content: b.config.CDConfig.CDContent, + }, ¶llelscommon.StepImport{ Name: b.config.VMName, SourcePath: b.config.SourcePath, @@ -77,6 +81,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) ParallelsToolsMode: b.config.ParallelsToolsMode, }, new(parallelscommon.StepAttachFloppy), + new(parallelscommon.StepAttachCD), ¶llelscommon.StepPrlctl{ Commands: b.config.Prlctl, Ctx: b.config.ctx, diff --git a/builder/parallels/pvm/config.go b/builder/parallels/pvm/config.go index 3275920..cf04617 100644 --- a/builder/parallels/pvm/config.go +++ b/builder/parallels/pvm/config.go @@ -24,6 +24,7 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` commonsteps.FloppyConfig `mapstructure:",squash"` + commonsteps.CDConfig `mapstructure:",squash"` parallelscommon.OutputConfig `mapstructure:",squash"` parallelscommon.PrlctlConfig `mapstructure:",squash"` parallelscommon.PrlctlPostConfig `mapstructure:",squash"` diff --git a/builder/parallels/pvm/config.hcl2spec.go b/builder/parallels/pvm/config.hcl2spec.go index 7a1c8c7..eb17a27 100644 --- a/builder/parallels/pvm/config.hcl2spec.go +++ b/builder/parallels/pvm/config.hcl2spec.go @@ -22,6 +22,9 @@ type FlatConfig struct { FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` FloppyContent map[string]string `mapstructure:"floppy_content" cty:"floppy_content" hcl:"floppy_content"` FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` + CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"` + CDContent map[string]string `mapstructure:"cd_content" cty:"cd_content" hcl:"cd_content"` + CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` Prlctl [][]string `mapstructure:"prlctl" required:"false" cty:"prlctl" hcl:"prlctl"` PrlctlPost [][]string `mapstructure:"prlctl_post" required:"false" cty:"prlctl_post" hcl:"prlctl_post"` @@ -113,6 +116,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, "floppy_content": &hcldec.AttrSpec{Name: "floppy_content", Type: cty.Map(cty.String), Required: false}, "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, + "cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false}, + "cd_content": &hcldec.AttrSpec{Name: "cd_content", Type: cty.Map(cty.String), Required: false}, + "cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, "prlctl": &hcldec.AttrSpec{Name: "prlctl", Type: cty.List(cty.List(cty.String)), Required: false}, "prlctl_post": &hcldec.AttrSpec{Name: "prlctl_post", Type: cty.List(cty.List(cty.String)), Required: false}, diff --git a/docs/builders/iso.mdx b/docs/builders/iso.mdx index 9017ca3..f8a9ce0 100644 --- a/docs/builders/iso.mdx +++ b/docs/builders/iso.mdx @@ -129,6 +129,17 @@ can also be supplied to override the typical auto-generated key: Kickstart or other early initialization tools, which can benefit from labelled floppy disks. By default, the floppy label will be 'packer'. +- `cd_files` ([]string) - A list of files to place onto a CD that is attached when the VM is + booted. This can include either files or directories; any directories + will be copied onto the CD recursively, preserving directory structure + hierarchy. Symlinks will have the link's target copied into the directory + tree on the CD where the symlink was. File globbing is allowed. + +- `cd_content` (map[string]string) - Key/Values to add to the CD. The keys represent the paths, and the values + contents. It can be used alongside `cd_files`, which is useful to add large + files without loading them into memory. If any paths are specified by both, + the contents in `cd_content` will take precedence. + - `guest_os_type` (string) - The guest OS type being installed. By default this is "other", but you can get _dramatic_ performance improvements by setting this to the proper value. To view all available values for this run diff --git a/docs/builders/pvm.mdx b/docs/builders/pvm.mdx index 3cc0812..4a0e639 100644 --- a/docs/builders/pvm.mdx +++ b/docs/builders/pvm.mdx @@ -103,6 +103,17 @@ can also be supplied to override the typical auto-generated key: Kickstart or other early initialization tools, which can benefit from labelled floppy disks. By default, the floppy label will be 'packer'. +- `cd_files` ([]string) - A list of files to place onto a CD that is attached when the VM is + booted. This can include either files or directories; any directories + will be copied onto the CD recursively, preserving directory structure + hierarchy. Symlinks will have the link's target copied into the directory + tree on the CD where the symlink was. File globbing is allowed. + +- `cd_content` (map[string]string) - Key/Values to add to the CD. The keys represent the paths, and the values + contents. It can be used alongside `cd_files`, which is useful to add large + files without loading them into memory. If any paths are specified by both, + the contents in `cd_content` will take precedence. + - `output_directory` (string) - This is the path to the directory where the resulting virtual machine will be created. This may be relative or absolute. If relative, the path is relative to the working directory when `packer`