From 905869308df4650c4a8e88cfb3b2d90e9a821f09 Mon Sep 17 00:00:00 2001 From: Calle Pettersson Date: Fri, 4 Sep 2020 23:53:09 +0200 Subject: [PATCH 01/24] Split proxmox builder into a common part and iso/clone builders Clone builder is still just a stub. Proof-of-concept for #9626 Signed-off-by: Calle Pettersson --- builder/proxmox/clone/builder.go | 39 ++ builder/proxmox/clone/config.go | 27 ++ builder/proxmox/clone/config.hcl2spec.go | 219 +++++++++++ builder/proxmox/{ => common}/artifact.go | 5 +- .../{ => common}/bootcommand_driver.go | 0 builder/proxmox/{ => common}/builder.go | 66 +--- builder/proxmox/{ => common}/config.go | 121 +----- builder/proxmox/common/config.hcl2spec.go | 307 +++++++++++++++ builder/proxmox/common/config_test.go | 104 ++++++ .../{ => common}/step_convert_to_template.go | 0 .../step_convert_to_template_test.go | 0 .../step_finalize_template_config.go | 41 --- .../step_finalize_template_config_test.go | 26 +- builder/proxmox/{ => common}/step_start_vm.go | 23 +- .../{ => common}/step_start_vm_test.go | 0 builder/proxmox/{ => common}/step_success.go | 0 .../{ => common}/step_type_boot_command.go | 0 .../step_type_boot_command_test.go | 2 +- builder/proxmox/config.hcl2spec.go | 348 ------------------ builder/proxmox/iso/builder.go | 81 ++++ builder/proxmox/iso/config.go | 125 +++++++ builder/proxmox/iso/config.hcl2spec.go | 274 ++++++++++++++ builder/proxmox/{ => iso}/config_test.go | 106 +----- builder/proxmox/iso/step_finalize_iso.go | 87 +++++ builder/proxmox/iso/step_finalize_iso_test.go | 131 +++++++ .../{ => iso}/step_upload_additional_isos.go | 9 +- builder/proxmox/{ => iso}/step_upload_iso.go | 10 +- .../proxmox/{ => iso}/step_upload_iso_test.go | 4 +- builder/proxmox/{ => iso}/testdata/test.iso | Bin command/plugin.go | 7 +- 30 files changed, 1459 insertions(+), 703 deletions(-) create mode 100644 builder/proxmox/clone/builder.go create mode 100644 builder/proxmox/clone/config.go create mode 100644 builder/proxmox/clone/config.hcl2spec.go rename builder/proxmox/{ => common}/artifact.go (91%) rename builder/proxmox/{ => common}/bootcommand_driver.go (100%) rename builder/proxmox/{ => common}/builder.go (70%) rename builder/proxmox/{ => common}/config.go (60%) create mode 100644 builder/proxmox/common/config.hcl2spec.go create mode 100644 builder/proxmox/common/config_test.go rename builder/proxmox/{ => common}/step_convert_to_template.go (100%) rename builder/proxmox/{ => common}/step_convert_to_template_test.go (100%) rename builder/proxmox/{ => common}/step_finalize_template_config.go (66%) rename builder/proxmox/{ => common}/step_finalize_template_config_test.go (84%) rename builder/proxmox/{ => common}/step_start_vm.go (91%) rename builder/proxmox/{ => common}/step_start_vm_test.go (100%) rename builder/proxmox/{ => common}/step_success.go (100%) rename builder/proxmox/{ => common}/step_type_boot_command.go (100%) rename builder/proxmox/{ => common}/step_type_boot_command_test.go (99%) delete mode 100644 builder/proxmox/config.hcl2spec.go create mode 100644 builder/proxmox/iso/builder.go create mode 100644 builder/proxmox/iso/config.go create mode 100644 builder/proxmox/iso/config.hcl2spec.go rename builder/proxmox/{ => iso}/config_test.go (53%) create mode 100644 builder/proxmox/iso/step_finalize_iso.go create mode 100644 builder/proxmox/iso/step_finalize_iso_test.go rename builder/proxmox/{ => iso}/step_upload_additional_isos.go (90%) rename builder/proxmox/{ => iso}/step_upload_iso.go (88%) rename builder/proxmox/{ => iso}/step_upload_iso_test.go (98%) rename builder/proxmox/{ => iso}/testdata/test.iso (100%) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go new file mode 100644 index 000000000..c56db14d4 --- /dev/null +++ b/builder/proxmox/clone/builder.go @@ -0,0 +1,39 @@ +package proxmoxclone + +import ( + "context" + + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +// The unique id for the builder +const BuilderID = "proxmox.clone" + +type Builder struct { + config Config +} + +// Builder implements packer.Builder +var _ packer.Builder = &Builder{} + +var pluginVersion = "1.0.0" + +func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } + +func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { + return b.config.Prepare(raws...) +} + +func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { + state := new(multistep.BasicStateBag) + state.Put("clone-config", &b.config) + + steps := []multistep.Step{} + postSteps := []multistep.Step{} + + sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, steps, postSteps) + return sb.Run(ctx, ui, hook, state) +} diff --git a/builder/proxmox/clone/config.go b/builder/proxmox/clone/config.go new file mode 100644 index 000000000..bede7db14 --- /dev/null +++ b/builder/proxmox/clone/config.go @@ -0,0 +1,27 @@ +//go:generate mapstructure-to-hcl2 -type Config + +package proxmoxclone + +import ( + "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/hashicorp/packer/packer" +) + +type Config struct { + proxmox.Config `mapstructure:",squash"` + + CloneVM string `mapstructure:"clone_vm"` +} + +func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { + var errs *packer.MultiError + _, warnings, merrs := c.Config.Prepare(c, raws...) + if merrs != nil { + errs = packer.MultiErrorAppend(errs, merrs) + } + + if errs != nil && len(errs.Errors) > 0 { + return nil, warnings, errs + } + return nil, warnings, nil +} diff --git a/builder/proxmox/clone/config.hcl2spec.go b/builder/proxmox/clone/config.hcl2spec.go new file mode 100644 index 000000000..cc5a87d09 --- /dev/null +++ b/builder/proxmox/clone/config.hcl2spec.go @@ -0,0 +1,219 @@ +// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. +package proxmoxclone + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + proxmox "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/zclconf/go-cty/cty" +) + +// FlatConfig is an auto-generated flat version of Config. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatConfig struct { + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` + HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` + 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"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` + SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` + Username *string `mapstructure:"username" cty:"username" hcl:"username"` + Password *string `mapstructure:"password" cty:"password" hcl:"password"` + Node *string `mapstructure:"node" cty:"node" hcl:"node"` + Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` + VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` + VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` + Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` + CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` + Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` + OS *string `mapstructure:"os" cty:"os" hcl:"os"` + VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` + NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` + Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` + Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` + SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` + Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` + DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` + TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` + CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` + CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` + Data interface{} `cty:"data" hcl:"data"` + Funcs map[string]interface{} `cty:"funcs" hcl:"funcs"` + UserVariables map[string]string `cty:"user_variables" hcl:"user_variables"` + SensitiveVariables []string `cty:"sensitive_variables" hcl:"sensitive_variables"` + EnableEnv *bool `cty:"enable_env" hcl:"enable_env"` + BuildName *string `cty:"build_name" hcl:"build_name"` + BuildType *string `cty:"build_type" hcl:"build_type"` + TemplatePath *string `cty:"template_path" hcl:"template_path"` + CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"` +} + +// FlatMapstructure returns a new FlatConfig. +// FlatConfig is an auto-generated flat version of Config. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatConfig) +} + +// HCL2Spec returns the hcl spec of a Config. +// This spec is used by HCL to read the fields of Config. +// The decoded values from this spec will then be applied to a FlatConfig. +func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, + "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, + "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, + "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, + "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, + "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, + "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, + "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, + "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, + "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, + "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", 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}, + "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, + "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, + "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, + "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, + "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, + "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, + "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, + "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, + "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, + "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, + "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, + "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, + "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, + "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, + "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, + "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, + "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, + "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, + "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, + "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, + "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, + "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, + "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, + "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, + "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, + "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, + "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, + "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, + "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, + "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, + "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, + "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, + "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, + "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, + "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, + "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, + "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, + "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, + "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, + "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, + "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, + "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, + "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, + "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, + "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, + "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, + "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, + "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, + "proxmox_url": &hcldec.AttrSpec{Name: "proxmox_url", Type: cty.String, Required: false}, + "insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false}, + "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, + "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, + "node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false}, + "pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false}, + "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, + "vm_id": &hcldec.AttrSpec{Name: "vm_id", Type: cty.Number, Required: false}, + "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, + "cores": &hcldec.AttrSpec{Name: "cores", Type: cty.Number, Required: false}, + "cpu_type": &hcldec.AttrSpec{Name: "cpu_type", Type: cty.String, Required: false}, + "sockets": &hcldec.AttrSpec{Name: "sockets", Type: cty.Number, Required: false}, + "os": &hcldec.AttrSpec{Name: "os", Type: cty.String, Required: false}, + "vga": &hcldec.BlockSpec{TypeName: "vga", Nested: hcldec.ObjectSpec((*proxmox.FlatvgaConfig)(nil).HCL2Spec())}, + "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*proxmox.FlatnicConfig)(nil).HCL2Spec())}, + "disks": &hcldec.BlockListSpec{TypeName: "disks", Nested: hcldec.ObjectSpec((*proxmox.FlatdiskConfig)(nil).HCL2Spec())}, + "qemu_agent": &hcldec.AttrSpec{Name: "qemu_agent", Type: cty.Bool, Required: false}, + "scsi_controller": &hcldec.AttrSpec{Name: "scsi_controller", Type: cty.String, Required: false}, + "onboot": &hcldec.AttrSpec{Name: "onboot", Type: cty.Bool, Required: false}, + "disable_kvm": &hcldec.AttrSpec{Name: "disable_kvm", Type: cty.Bool, Required: false}, + "template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false}, + "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, + "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, + "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, + "data": &hcldec.AttrSpec{Name: "data", Type: cty.Bool, Required: false}, /* TODO(azr): could not find type */ + "funcs": &hcldec.AttrSpec{Name: "funcs", Type: cty.Map(cty.String), Required: false}, + "user_variables": &hcldec.AttrSpec{Name: "user_variables", Type: cty.Map(cty.String), Required: false}, + "sensitive_variables": &hcldec.AttrSpec{Name: "sensitive_variables", Type: cty.List(cty.String), Required: false}, + "enable_env": &hcldec.AttrSpec{Name: "enable_env", Type: cty.Bool, Required: false}, + "build_name": &hcldec.AttrSpec{Name: "build_name", Type: cty.String, Required: false}, + "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, + "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, + "clone_vm": &hcldec.AttrSpec{Name: "clone_vm", Type: cty.String, Required: false}, + } + return s +} diff --git a/builder/proxmox/artifact.go b/builder/proxmox/common/artifact.go similarity index 91% rename from builder/proxmox/artifact.go rename to builder/proxmox/common/artifact.go index 8b11e266d..059d8ed81 100644 --- a/builder/proxmox/artifact.go +++ b/builder/proxmox/common/artifact.go @@ -10,6 +10,7 @@ import ( ) type Artifact struct { + builderID string templateID int proxmoxClient *proxmox.Client @@ -21,8 +22,8 @@ type Artifact struct { // Artifact implements packer.Artifact var _ packer.Artifact = &Artifact{} -func (*Artifact) BuilderId() string { - return BuilderId +func (a *Artifact) BuilderId() string { + return a.builderID } func (*Artifact) Files() []string { diff --git a/builder/proxmox/bootcommand_driver.go b/builder/proxmox/common/bootcommand_driver.go similarity index 100% rename from builder/proxmox/bootcommand_driver.go rename to builder/proxmox/common/bootcommand_driver.go diff --git a/builder/proxmox/builder.go b/builder/proxmox/common/builder.go similarity index 70% rename from builder/proxmox/builder.go rename to builder/proxmox/common/builder.go index b2387e1c0..b6742b1ee 100644 --- a/builder/proxmox/builder.go +++ b/builder/proxmox/common/builder.go @@ -7,40 +7,31 @@ import ( "fmt" "github.com/Telmate/proxmox-api-go/proxmox" - "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" ) -// The unique id for the builder -const BuilderId = "proxmox.builder" +func NewSharedBuilder(id string, config Config, preSteps []multistep.Step, postSteps []multistep.Step) *Builder { + return &Builder{ + id: id, + config: config, + preSteps: preSteps, + postSteps: postSteps, + } +} type Builder struct { + id string config Config + preSteps []multistep.Step + postSteps []multistep.Step runner multistep.Runner proxmoxClient *proxmox.Client } -// Builder implements packer.Builder -var _ packer.Builder = &Builder{} - -var pluginVersion = "1.0.0" - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - warnings, errs := b.config.Prepare(raws...) - if errs != nil { - return nil, warnings, errs - } - return nil, nil, nil -} - -const downloadPathKey = "downloaded_iso_path" - -func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { +func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state multistep.StateBag) (packer.Artifact, error) { var err error tlsConfig := &tls.Config{ InsecureSkipVerify: b.config.SkipCertValidation, @@ -56,36 +47,13 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } // Set up the state - state := new(multistep.BasicStateBag) state.Put("config", &b.config) state.Put("proxmoxClient", b.proxmoxClient) state.Put("hook", hook) state.Put("ui", ui) // Build the steps - steps := []multistep.Step{ - &common.StepDownload{ - Checksum: b.config.ISOChecksum, - Description: "ISO", - Extension: b.config.TargetExtension, - ResultKey: downloadPathKey, - TargetPath: b.config.TargetPath, - Url: b.config.ISOUrls, - }} - - for idx := range b.config.AdditionalISOFiles { - steps = append(steps, &common.StepDownload{ - Checksum: b.config.AdditionalISOFiles[idx].ISOChecksum, - Description: "additional ISO", - Extension: b.config.AdditionalISOFiles[idx].TargetExtension, - ResultKey: b.config.AdditionalISOFiles[idx].downloadPathKey, - TargetPath: b.config.AdditionalISOFiles[idx].downloadPathKey, - Url: b.config.AdditionalISOFiles[idx].ISOUrls, - }) - } - steps = append(steps, - &stepUploadISO{}, - &stepUploadAdditionalISOs{}, + coreSteps := []multistep.Step{ &stepStartVM{}, &common.StepHTTPServer{ HTTPDir: b.config.HTTPDir, @@ -95,7 +63,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &stepTypeBootCommand{ BootConfig: b.config.BootConfig, - Ctx: b.config.ctx, + Ctx: b.config.Ctx, }, &communicator.StepConnect{ Config: &b.config.Comm, @@ -109,8 +77,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &stepConvertToTemplate{}, &stepFinalizeTemplateConfig{}, &stepSuccess{}, - ) - + } + steps := append(b.preSteps, coreSteps...) + steps = append(steps, b.postSteps...) // Run the steps b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(ctx, state) @@ -130,6 +99,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } artifact := &Artifact{ + builderID: b.id, templateID: tplID, proxmoxClient: b.proxmoxClient, StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, diff --git a/builder/proxmox/config.go b/builder/proxmox/common/config.go similarity index 60% rename from builder/proxmox/config.go rename to builder/proxmox/common/config.go index f888a3c4e..ceeb19a1f 100644 --- a/builder/proxmox/config.go +++ b/builder/proxmox/common/config.go @@ -1,4 +1,4 @@ -//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig +//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig package proxmox @@ -8,7 +8,6 @@ import ( "log" "net/url" "os" - "strconv" "strings" "time" @@ -25,7 +24,6 @@ import ( type Config struct { common.PackerConfig `mapstructure:",squash"` common.HTTPConfig `mapstructure:",squash"` - common.ISOConfig `mapstructure:",squash"` bootcommand.BootConfig `mapstructure:",squash"` BootKeyInterval time.Duration `mapstructure:"boot_key_interval"` Comm communicator.Config `mapstructure:",squash"` @@ -49,8 +47,6 @@ type Config struct { 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"` @@ -58,16 +54,11 @@ type Config struct { TemplateName string `mapstructure:"template_name"` TemplateDescription string `mapstructure:"template_description"` - UnmountISO bool `mapstructure:"unmount_iso"` CloudInit bool `mapstructure:"cloud_init"` CloudInitStoragePool string `mapstructure:"cloud_init_storage_pool"` - shouldUploadISO bool - - AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"` - - ctx interpolate.Context + Ctx interpolate.Context `mapstructure:",squash",mapstructure-to-hcl2:"skip"` } type nicConfig struct { @@ -90,27 +81,18 @@ type vgaConfig struct { Type string `mapstructure:"type"` Memory int `mapstructure:"memory"` } -type storageConfig struct { - common.ISOConfig `mapstructure:",squash"` - Device string `mapstructure:"device"` - ISOFile string `mapstructure:"iso_file"` - ISOStoragePool string `mapstructure:"iso_storage_pool"` - Unmount bool `mapstructure:"unmount"` - shouldUploadISO bool - downloadPathKey string -} -func (c *Config) Prepare(raws ...interface{}) ([]string, error) { +func (c *Config) Prepare(upper interface{}, raws ...interface{}) ([]string, []string, error) { // Agent defaults to true c.Agent = true // Do not add a cloud-init cdrom by default c.CloudInit = false var md mapstructure.Metadata - err := config.Decode(c, &config.DecodeOpts{ + err := config.Decode(upper, &config.DecodeOpts{ Metadata: &md, Interpolate: true, - InterpolateContext: &c.ctx, + InterpolateContext: &c.Ctx, InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "boot_command", @@ -118,11 +100,13 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { }, }, raws...) if err != nil { - return nil, err + return nil, nil, err } var errs *packer.MultiError - warnings := make([]string, 0) + var warnings []string + + packer.LogSecretFilter.Set(c.Password) // Defaults if c.ProxmoxURLRaw == "" { @@ -195,89 +179,14 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, fmt.Errorf("disk format must be specified for pool type %q", c.Disks[idx].StoragePoolType)) } } - for idx := range c.AdditionalISOFiles { - // Check AdditionalISO config - // Either a pre-uploaded ISO should be referenced in iso_file, OR a URL - // (possibly to a local file) to an ISO file that will be downloaded and - // then uploaded to Proxmox. - if c.AdditionalISOFiles[idx].ISOFile != "" { - c.AdditionalISOFiles[idx].shouldUploadISO = false - } else { - c.AdditionalISOFiles[idx].downloadPathKey = "downloaded_additional_iso_path_" + strconv.Itoa(idx) - isoWarnings, isoErrors := c.AdditionalISOFiles[idx].ISOConfig.Prepare(&c.ctx) - errs = packer.MultiErrorAppend(errs, isoErrors...) - warnings = append(warnings, isoWarnings...) - c.AdditionalISOFiles[idx].shouldUploadISO = true - } - if c.AdditionalISOFiles[idx].Device == "" { - log.Printf("AdditionalISOFile %d Device not set, using default 'ide3'", idx) - c.AdditionalISOFiles[idx].Device = "ide3" - } - if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "ide") { - busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[3:]) - if err != nil { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[3:])) - } - if busnumber == 2 { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("IDE bus 2 is used by boot ISO")) - } - if busnumber > 3 { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("IDE bus index can't be higher than 3")) - } - } - if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "sata") { - busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:]) - if err != nil { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:])) - } - if busnumber > 5 { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("SATA bus index can't be higher than 5")) - } - } - if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "scsi") { - busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:]) - if err != nil { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:])) - } - if busnumber > 30 { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("SCSI bus index can't be higher than 30")) - } - } - if (c.AdditionalISOFiles[idx].ISOFile == "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) == 0) || (c.AdditionalISOFiles[idx].ISOFile != "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) != 0) { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("either iso_file or iso_url, but not both, must be specified for AdditionalISO file %s", c.AdditionalISOFiles[idx].Device)) - } - 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.SCSIController == "" { log.Printf("SCSI controller not set, using default 'lsi'") c.SCSIController = "lsi" } - errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) - errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...) - errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...) - - // Check ISO config - // Either a pre-uploaded ISO should be referenced in iso_file, OR a URL - // (possibly to a local file) to an ISO file that will be downloaded and - // then uploaded to Proxmox. - if c.ISOFile != "" { - c.shouldUploadISO = false - } else { - isoWarnings, isoErrors := c.ISOConfig.Prepare(&c.ctx) - errs = packer.MultiErrorAppend(errs, isoErrors...) - warnings = append(warnings, isoWarnings...) - c.shouldUploadISO = 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")) - } + errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.Ctx)...) + errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.Ctx)...) + errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.Ctx)...) // Required configurations that will display errors if not set if c.Username == "" { @@ -316,11 +225,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { } if errs != nil && len(errs.Errors) > 0 { - return nil, errs + return nil, warnings, errs } - - packer.LogSecretFilter.Set(c.Password) - return nil, nil + return nil, warnings, nil } func contains(haystack []string, needle string) bool { diff --git a/builder/proxmox/common/config.hcl2spec.go b/builder/proxmox/common/config.hcl2spec.go new file mode 100644 index 000000000..973eb7158 --- /dev/null +++ b/builder/proxmox/common/config.hcl2spec.go @@ -0,0 +1,307 @@ +// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig"; DO NOT EDIT. +package proxmox + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/zclconf/go-cty/cty" +) + +// FlatConfig is an auto-generated flat version of Config. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatConfig struct { + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` + HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` + 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"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` + SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` + Username *string `mapstructure:"username" cty:"username" hcl:"username"` + Password *string `mapstructure:"password" cty:"password" hcl:"password"` + Node *string `mapstructure:"node" cty:"node" hcl:"node"` + Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` + VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` + VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` + Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` + CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` + Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` + OS *string `mapstructure:"os" cty:"os" hcl:"os"` + VGA *FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` + NICs []FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` + Disks []FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` + Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` + SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` + Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` + DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` + TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` + CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` + CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` + Data interface{} `cty:"data" hcl:"data"` + Funcs map[string]interface{} `cty:"funcs" hcl:"funcs"` + UserVariables map[string]string `cty:"user_variables" hcl:"user_variables"` + SensitiveVariables []string `cty:"sensitive_variables" hcl:"sensitive_variables"` + EnableEnv *bool `cty:"enable_env" hcl:"enable_env"` + BuildName *string `cty:"build_name" hcl:"build_name"` + BuildType *string `cty:"build_type" hcl:"build_type"` + TemplatePath *string `cty:"template_path" hcl:"template_path"` +} + +// FlatMapstructure returns a new FlatConfig. +// FlatConfig is an auto-generated flat version of Config. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatConfig) +} + +// HCL2Spec returns the hcl spec of a Config. +// This spec is used by HCL to read the fields of Config. +// The decoded values from this spec will then be applied to a FlatConfig. +func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, + "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, + "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, + "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, + "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, + "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, + "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, + "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, + "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, + "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, + "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", 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}, + "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, + "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, + "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, + "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, + "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, + "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, + "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, + "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, + "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, + "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, + "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, + "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, + "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, + "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, + "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, + "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, + "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, + "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, + "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, + "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, + "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, + "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, + "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, + "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, + "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, + "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, + "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, + "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, + "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, + "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, + "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, + "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, + "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, + "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, + "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, + "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, + "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, + "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, + "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, + "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, + "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, + "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, + "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, + "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, + "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, + "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, + "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, + "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, + "proxmox_url": &hcldec.AttrSpec{Name: "proxmox_url", Type: cty.String, Required: false}, + "insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false}, + "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, + "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, + "node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false}, + "pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false}, + "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, + "vm_id": &hcldec.AttrSpec{Name: "vm_id", Type: cty.Number, Required: false}, + "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, + "cores": &hcldec.AttrSpec{Name: "cores", Type: cty.Number, Required: false}, + "cpu_type": &hcldec.AttrSpec{Name: "cpu_type", Type: cty.String, Required: false}, + "sockets": &hcldec.AttrSpec{Name: "sockets", Type: cty.Number, Required: false}, + "os": &hcldec.AttrSpec{Name: "os", Type: cty.String, Required: false}, + "vga": &hcldec.BlockSpec{TypeName: "vga", Nested: hcldec.ObjectSpec((*FlatvgaConfig)(nil).HCL2Spec())}, + "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatnicConfig)(nil).HCL2Spec())}, + "disks": &hcldec.BlockListSpec{TypeName: "disks", Nested: hcldec.ObjectSpec((*FlatdiskConfig)(nil).HCL2Spec())}, + "qemu_agent": &hcldec.AttrSpec{Name: "qemu_agent", Type: cty.Bool, Required: false}, + "scsi_controller": &hcldec.AttrSpec{Name: "scsi_controller", Type: cty.String, Required: false}, + "onboot": &hcldec.AttrSpec{Name: "onboot", Type: cty.Bool, Required: false}, + "disable_kvm": &hcldec.AttrSpec{Name: "disable_kvm", Type: cty.Bool, Required: false}, + "template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false}, + "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, + "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, + "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, + "data": &hcldec.AttrSpec{Name: "data", Type: cty.Bool, Required: false}, /* TODO(azr): could not find type */ + "funcs": &hcldec.AttrSpec{Name: "funcs", Type: cty.Map(cty.String), Required: false}, + "user_variables": &hcldec.AttrSpec{Name: "user_variables", Type: cty.Map(cty.String), Required: false}, + "sensitive_variables": &hcldec.AttrSpec{Name: "sensitive_variables", Type: cty.List(cty.String), Required: false}, + "enable_env": &hcldec.AttrSpec{Name: "enable_env", Type: cty.Bool, Required: false}, + "build_name": &hcldec.AttrSpec{Name: "build_name", Type: cty.String, Required: false}, + "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, + "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, + } + return s +} + +// FlatdiskConfig is an auto-generated flat version of diskConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatdiskConfig struct { + Type *string `mapstructure:"type" cty:"type" hcl:"type"` + StoragePool *string `mapstructure:"storage_pool" cty:"storage_pool" hcl:"storage_pool"` + StoragePoolType *string `mapstructure:"storage_pool_type" cty:"storage_pool_type" hcl:"storage_pool_type"` + Size *string `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"` + CacheMode *string `mapstructure:"cache_mode" cty:"cache_mode" hcl:"cache_mode"` + DiskFormat *string `mapstructure:"format" cty:"format" hcl:"format"` +} + +// FlatMapstructure returns a new FlatdiskConfig. +// FlatdiskConfig is an auto-generated flat version of diskConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*diskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatdiskConfig) +} + +// HCL2Spec returns the hcl spec of a diskConfig. +// This spec is used by HCL to read the fields of diskConfig. +// The decoded values from this spec will then be applied to a FlatdiskConfig. +func (*FlatdiskConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "type": &hcldec.AttrSpec{Name: "type", Type: cty.String, Required: false}, + "storage_pool": &hcldec.AttrSpec{Name: "storage_pool", Type: cty.String, Required: false}, + "storage_pool_type": &hcldec.AttrSpec{Name: "storage_pool_type", Type: cty.String, Required: false}, + "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.String, Required: false}, + "cache_mode": &hcldec.AttrSpec{Name: "cache_mode", Type: cty.String, Required: false}, + "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, + } + return s +} + +// FlatnicConfig is an auto-generated flat version of nicConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatnicConfig struct { + Model *string `mapstructure:"model" cty:"model" hcl:"model"` + PacketQueues *int `mapstructure:"packet_queues" cty:"packet_queues" hcl:"packet_queues"` + MACAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` + Bridge *string `mapstructure:"bridge" cty:"bridge" hcl:"bridge"` + VLANTag *string `mapstructure:"vlan_tag" cty:"vlan_tag" hcl:"vlan_tag"` + Firewall *bool `mapstructure:"firewall" cty:"firewall" hcl:"firewall"` +} + +// FlatMapstructure returns a new FlatnicConfig. +// FlatnicConfig is an auto-generated flat version of nicConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*nicConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatnicConfig) +} + +// HCL2Spec returns the hcl spec of a nicConfig. +// This spec is used by HCL to read the fields of nicConfig. +// The decoded values from this spec will then be applied to a FlatnicConfig. +func (*FlatnicConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "model": &hcldec.AttrSpec{Name: "model", Type: cty.String, Required: false}, + "packet_queues": &hcldec.AttrSpec{Name: "packet_queues", Type: cty.Number, Required: false}, + "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, + "bridge": &hcldec.AttrSpec{Name: "bridge", Type: cty.String, Required: false}, + "vlan_tag": &hcldec.AttrSpec{Name: "vlan_tag", Type: cty.String, Required: false}, + "firewall": &hcldec.AttrSpec{Name: "firewall", Type: cty.Bool, Required: false}, + } + return s +} + +// FlatvgaConfig is an auto-generated flat version of vgaConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatvgaConfig struct { + Type *string `mapstructure:"type" cty:"type" hcl:"type"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` +} + +// FlatMapstructure returns a new FlatvgaConfig. +// FlatvgaConfig is an auto-generated flat version of vgaConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*vgaConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatvgaConfig) +} + +// HCL2Spec returns the hcl spec of a vgaConfig. +// This spec is used by HCL to read the fields of vgaConfig. +// The decoded values from this spec will then be applied to a FlatvgaConfig. +func (*FlatvgaConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "type": &hcldec.AttrSpec{Name: "type", Type: cty.String, Required: false}, + "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, + } + return s +} diff --git a/builder/proxmox/common/config_test.go b/builder/proxmox/common/config_test.go new file mode 100644 index 000000000..b68c6fcc8 --- /dev/null +++ b/builder/proxmox/common/config_test.go @@ -0,0 +1,104 @@ +package proxmox + +import ( + "strings" + "testing" + + "github.com/hashicorp/packer/packer" +) + +func mandatoryConfig(t *testing.T) map[string]interface{} { + return map[string]interface{}{ + "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json", + "username": "apiuser@pve", + "password": "supersecret", + "node": "my-proxmox", + "ssh_username": "root", + } +} + +func TestRequiredParameters(t *testing.T) { + var c Config + _, _, err := c.Prepare(&c, make(map[string]interface{})) + if err == nil { + t.Fatal("Expected empty configuration to fail") + } + errs, ok := err.(*packer.MultiError) + if !ok { + t.Fatal("Expected errors to be packer.MultiError") + } + + required := []string{"username", "password", "proxmox_url", "node", "ssh_username"} + for _, param := range required { + found := false + for _, err := range errs.Errors { + if strings.Contains(err.Error(), param) { + found = true + break + } + } + if !found { + t.Errorf("Expected error about missing parameter %q", required) + } + } +} + +func TestAgentSetToFalse(t *testing.T) { + cfg := mandatoryConfig(t) + cfg["qemu_agent"] = false + + var c Config + _, _, err := c.Prepare(&c, cfg) + if err != nil { + t.Fatal(err) + } + + if c.Agent != false { + t.Errorf("Expected Agent to be false, got %t", c.Agent) + } +} + +func TestPacketQueueSupportForNetworkAdapters(t *testing.T) { + drivertests := []struct { + expectedToFail bool + model string + }{ + {expectedToFail: false, model: "virtio"}, + {expectedToFail: true, model: "e1000"}, + {expectedToFail: true, model: "e1000-82540em"}, + {expectedToFail: true, model: "e1000-82544gc"}, + {expectedToFail: true, model: "e1000-82545em"}, + {expectedToFail: true, model: "i82551"}, + {expectedToFail: true, model: "i82557b"}, + {expectedToFail: true, model: "i82559er"}, + {expectedToFail: true, model: "ne2k_isa"}, + {expectedToFail: true, model: "ne2k_pci"}, + {expectedToFail: true, model: "pcnet"}, + {expectedToFail: true, model: "rtl8139"}, + {expectedToFail: true, model: "vmxnet3"}, + } + + for _, tt := range drivertests { + device := make(map[string]interface{}) + device["bridge"] = "vmbr0" + device["model"] = tt.model + device["packet_queues"] = 2 + + devices := make([]map[string]interface{}, 0) + devices = append(devices, device) + + cfg := mandatoryConfig(t) + cfg["network_adapters"] = devices + + var c Config + _, _, err := c.Prepare(&c, cfg) + + if tt.expectedToFail == true && err == nil { + t.Error("expected config preparation to fail, but no error occured") + } + + if tt.expectedToFail == false && err != nil { + t.Errorf("expected config preparation to succeed, but %s", err.Error()) + } + } +} diff --git a/builder/proxmox/step_convert_to_template.go b/builder/proxmox/common/step_convert_to_template.go similarity index 100% rename from builder/proxmox/step_convert_to_template.go rename to builder/proxmox/common/step_convert_to_template.go diff --git a/builder/proxmox/step_convert_to_template_test.go b/builder/proxmox/common/step_convert_to_template_test.go similarity index 100% rename from builder/proxmox/step_convert_to_template_test.go rename to builder/proxmox/common/step_convert_to_template_test.go diff --git a/builder/proxmox/step_finalize_template_config.go b/builder/proxmox/common/step_finalize_template_config.go similarity index 66% rename from builder/proxmox/step_finalize_template_config.go rename to builder/proxmox/common/step_finalize_template_config.go index 570c77b0b..0aebb9aca 100644 --- a/builder/proxmox/step_finalize_template_config.go +++ b/builder/proxmox/common/step_finalize_template_config.go @@ -38,24 +38,6 @@ func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.St // set, we need to clear it changes["description"] = c.TemplateDescription - if c.UnmountISO { - vmParams, err := client.GetVmConfig(vmRef) - if err != nil { - err := fmt.Errorf("Error fetching template config: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - 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 - } - changes["ide2"] = "none,media=cdrom" - } - if c.CloudInit { vmParams, err := client.GetVmConfig(vmRef) if err != nil { @@ -93,29 +75,6 @@ func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.St } } - if len(c.AdditionalISOFiles) > 0 { - vmParams, err := client.GetVmConfig(vmRef) - if err != nil { - err := fmt.Errorf("Error fetching template config: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - for idx := range c.AdditionalISOFiles { - cdrom := c.AdditionalISOFiles[idx].Device - if c.AdditionalISOFiles[idx].Unmount { - if vmParams[cdrom] == nil || !strings.Contains(vmParams[cdrom].(string), "media=cdrom") { - err := fmt.Errorf("Cannot eject ISO from cdrom drive, %s is not present or not a cdrom media", cdrom) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - changes[cdrom] = "none,media=cdrom" - } else { - changes[cdrom] = c.AdditionalISOFiles[idx].ISOFile + ",media=cdrom" - } - } - } if len(changes) > 0 { _, err := client.SetVmConfig(vmRef, changes) if err != nil { diff --git a/builder/proxmox/step_finalize_template_config_test.go b/builder/proxmox/common/step_finalize_template_config_test.go similarity index 84% rename from builder/proxmox/step_finalize_template_config_test.go rename to builder/proxmox/common/step_finalize_template_config_test.go index e045cb0ce..646e6f73d 100644 --- a/builder/proxmox/step_finalize_template_config_test.go +++ b/builder/proxmox/common/step_finalize_template_config_test.go @@ -56,18 +56,15 @@ func TestTemplateFinalize(t *testing.T) { builderConfig: &Config{ TemplateName: "my-template", TemplateDescription: "some-description", - UnmountISO: true, }, initialVMConfig: map[string]interface{}{ "name": "dummy", "description": "Packer ephemeral build VM", - "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", }, expectCallSetConfig: true, expectedVMConfig: map[string]interface{}{ "name": "my-template", "description": "some-description", - "ide2": "none,media=cdrom", }, expectedAction: multistep.ActionContinue, }, @@ -76,13 +73,11 @@ func TestTemplateFinalize(t *testing.T) { builderConfig: &Config{ TemplateName: "my-template", TemplateDescription: "some-description", - UnmountISO: true, CloudInit: true, }, initialVMConfig: map[string]interface{}{ "name": "dummy", "description": "Packer ephemeral build VM", - "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", "bootdisk": "virtio0", "virtio0": "ceph01:base-223-disk-0,cache=unsafe,media=disk,size=32G", }, @@ -90,7 +85,6 @@ func TestTemplateFinalize(t *testing.T) { expectedVMConfig: map[string]interface{}{ "name": "my-template", "description": "some-description", - "ide2": "none,media=cdrom", "ide3": "ceph01:cloudinit", }, expectedAction: multistep.ActionContinue, @@ -100,7 +94,6 @@ func TestTemplateFinalize(t *testing.T) { builderConfig: &Config{ TemplateName: "my-template", TemplateDescription: "some-description", - UnmountISO: false, CloudInit: true, }, initialVMConfig: map[string]interface{}{ @@ -116,27 +109,12 @@ func TestTemplateFinalize(t *testing.T) { expectCallSetConfig: false, expectedAction: multistep.ActionHalt, }, - { - name: "no cd-drive with unmount=true should returns halt", - builderConfig: &Config{ - TemplateName: "my-template", - TemplateDescription: "some-description", - UnmountISO: true, - }, - initialVMConfig: map[string]interface{}{ - "name": "dummy", - "description": "Packer ephemeral build VM", - "ide1": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", - }, - expectCallSetConfig: false, - expectedAction: multistep.ActionHalt, - }, { name: "GetVmConfig error should return halt", builderConfig: &Config{ TemplateName: "my-template", TemplateDescription: "some-description", - UnmountISO: true, + CloudInit: true, }, getConfigErr: fmt.Errorf("some error"), expectCallSetConfig: false, @@ -147,12 +125,10 @@ func TestTemplateFinalize(t *testing.T) { builderConfig: &Config{ TemplateName: "my-template", TemplateDescription: "some-description", - UnmountISO: true, }, initialVMConfig: map[string]interface{}{ "name": "dummy", "description": "Packer ephemeral build VM", - "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", }, expectCallSetConfig: true, setConfigErr: fmt.Errorf("some error"), diff --git a/builder/proxmox/step_start_vm.go b/builder/proxmox/common/step_start_vm.go similarity index 91% rename from builder/proxmox/step_start_vm.go rename to builder/proxmox/common/step_start_vm.go index c128fe44c..b364b9a67 100644 --- a/builder/proxmox/step_start_vm.go +++ b/builder/proxmox/common/step_start_vm.go @@ -17,6 +17,10 @@ import ( // in API calls. type stepStartVM struct{} +type ProxmoxVMCreator interface { + Create(*proxmox.VmRef, proxmox.ConfigQemu, multistep.StateBag) error +} + func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) client := state.Get("proxmoxClient").(*proxmox.Client) @@ -32,7 +36,7 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist kvm = false } - isoFile := state.Get("iso_file").(string) + vmStarter := state.Get("vm-creator").(ProxmoxVMCreator) ui.Say("Creating VM") config := proxmox.ConfigQemu{ @@ -47,7 +51,6 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist QemuSockets: c.Sockets, QemuOs: c.OS, QemuVga: generateProxmoxVga(c.VGA), - QemuIso: isoFile, QemuNetworks: generateProxmoxNetworkAdapters(c.NICs), QemuDisks: generateProxmoxDisks(c.Disks), Scsihw: c.SCSIController, @@ -78,8 +81,9 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist vmRef.SetPool(c.Pool) } - err := config.CreateVm(vmRef, client) + err := vmStarter.Create(vmRef, config, state) if err != nil { + err := fmt.Errorf("Error creating VM: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -91,19 +95,6 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist // instance id inside of the provisioners, used in step_provision. state.Put("instance_id", vmRef) - for idx := range c.AdditionalISOFiles { - params := map[string]interface{}{ - c.AdditionalISOFiles[idx].Device: c.AdditionalISOFiles[idx].ISOFile + ",media=cdrom", - } - _, err = client.SetVmConfig(vmRef, params) - if err != nil { - err := fmt.Errorf("Error configuring VM: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - ui.Say("Starting VM") _, err = client.StartVm(vmRef) if err != nil { diff --git a/builder/proxmox/step_start_vm_test.go b/builder/proxmox/common/step_start_vm_test.go similarity index 100% rename from builder/proxmox/step_start_vm_test.go rename to builder/proxmox/common/step_start_vm_test.go diff --git a/builder/proxmox/step_success.go b/builder/proxmox/common/step_success.go similarity index 100% rename from builder/proxmox/step_success.go rename to builder/proxmox/common/step_success.go diff --git a/builder/proxmox/step_type_boot_command.go b/builder/proxmox/common/step_type_boot_command.go similarity index 100% rename from builder/proxmox/step_type_boot_command.go rename to builder/proxmox/common/step_type_boot_command.go diff --git a/builder/proxmox/step_type_boot_command_test.go b/builder/proxmox/common/step_type_boot_command_test.go similarity index 99% rename from builder/proxmox/step_type_boot_command_test.go rename to builder/proxmox/common/step_type_boot_command_test.go index c1581a3f8..88034753a 100644 --- a/builder/proxmox/step_type_boot_command_test.go +++ b/builder/proxmox/common/step_type_boot_command_test.go @@ -108,7 +108,7 @@ func TestTypeBootCommand(t *testing.T) { step := stepTypeBootCommand{ c.builderConfig.BootConfig, - c.builderConfig.ctx, + c.builderConfig.Ctx, } action := step.Run(context.TODO(), state) step.Cleanup(state) diff --git a/builder/proxmox/config.hcl2spec.go b/builder/proxmox/config.hcl2spec.go deleted file mode 100644 index ac804f32e..000000000 --- a/builder/proxmox/config.hcl2spec.go +++ /dev/null @@ -1,348 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig"; DO NOT EDIT. -package proxmox - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - 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"` - BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` - SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - Node *string `mapstructure:"node" cty:"node" hcl:"node"` - Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` - Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` - Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` - CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` - Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` - OS *string `mapstructure:"os" cty:"os" hcl:"os"` - VGA *FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` - NICs []FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` - Disks []FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` - ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` - ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` - Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` - SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` - Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` - DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` - TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` - TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` - UnmountISO *bool `mapstructure:"unmount_iso" cty:"unmount_iso" hcl:"unmount_iso"` - CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` - CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` - AdditionalISOFiles []FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, - "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, - "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, - "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, - "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, - "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, - "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, - "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, - "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", 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}, - "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - "proxmox_url": &hcldec.AttrSpec{Name: "proxmox_url", Type: cty.String, Required: false}, - "insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false}, - "pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "vm_id": &hcldec.AttrSpec{Name: "vm_id", Type: cty.Number, Required: false}, - "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, - "cores": &hcldec.AttrSpec{Name: "cores", Type: cty.Number, Required: false}, - "cpu_type": &hcldec.AttrSpec{Name: "cpu_type", Type: cty.String, Required: false}, - "sockets": &hcldec.AttrSpec{Name: "sockets", Type: cty.Number, Required: false}, - "os": &hcldec.AttrSpec{Name: "os", Type: cty.String, Required: false}, - "vga": &hcldec.BlockSpec{TypeName: "vga", Nested: hcldec.ObjectSpec((*FlatvgaConfig)(nil).HCL2Spec())}, - "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatnicConfig)(nil).HCL2Spec())}, - "disks": &hcldec.BlockListSpec{TypeName: "disks", Nested: hcldec.ObjectSpec((*FlatdiskConfig)(nil).HCL2Spec())}, - "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, - "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, - "qemu_agent": &hcldec.AttrSpec{Name: "qemu_agent", Type: cty.Bool, Required: false}, - "scsi_controller": &hcldec.AttrSpec{Name: "scsi_controller", Type: cty.String, Required: false}, - "onboot": &hcldec.AttrSpec{Name: "onboot", Type: cty.Bool, Required: false}, - "disable_kvm": &hcldec.AttrSpec{Name: "disable_kvm", Type: cty.Bool, Required: false}, - "template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false}, - "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, - "unmount_iso": &hcldec.AttrSpec{Name: "unmount_iso", Type: cty.Bool, Required: false}, - "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, - "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, - "additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*FlatstorageConfig)(nil).HCL2Spec())}, - } - return s -} - -// FlatdiskConfig is an auto-generated flat version of diskConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatdiskConfig struct { - Type *string `mapstructure:"type" cty:"type" hcl:"type"` - StoragePool *string `mapstructure:"storage_pool" cty:"storage_pool" hcl:"storage_pool"` - StoragePoolType *string `mapstructure:"storage_pool_type" cty:"storage_pool_type" hcl:"storage_pool_type"` - Size *string `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"` - CacheMode *string `mapstructure:"cache_mode" cty:"cache_mode" hcl:"cache_mode"` - DiskFormat *string `mapstructure:"format" cty:"format" hcl:"format"` -} - -// FlatMapstructure returns a new FlatdiskConfig. -// FlatdiskConfig is an auto-generated flat version of diskConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*diskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatdiskConfig) -} - -// HCL2Spec returns the hcl spec of a diskConfig. -// This spec is used by HCL to read the fields of diskConfig. -// The decoded values from this spec will then be applied to a FlatdiskConfig. -func (*FlatdiskConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "type": &hcldec.AttrSpec{Name: "type", Type: cty.String, Required: false}, - "storage_pool": &hcldec.AttrSpec{Name: "storage_pool", Type: cty.String, Required: false}, - "storage_pool_type": &hcldec.AttrSpec{Name: "storage_pool_type", Type: cty.String, Required: false}, - "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.String, Required: false}, - "cache_mode": &hcldec.AttrSpec{Name: "cache_mode", Type: cty.String, Required: false}, - "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, - } - return s -} - -// FlatnicConfig is an auto-generated flat version of nicConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatnicConfig struct { - Model *string `mapstructure:"model" cty:"model" hcl:"model"` - PacketQueues *int `mapstructure:"packet_queues" cty:"packet_queues" hcl:"packet_queues"` - MACAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` - Bridge *string `mapstructure:"bridge" cty:"bridge" hcl:"bridge"` - VLANTag *string `mapstructure:"vlan_tag" cty:"vlan_tag" hcl:"vlan_tag"` - Firewall *bool `mapstructure:"firewall" cty:"firewall" hcl:"firewall"` -} - -// FlatMapstructure returns a new FlatnicConfig. -// FlatnicConfig is an auto-generated flat version of nicConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*nicConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatnicConfig) -} - -// HCL2Spec returns the hcl spec of a nicConfig. -// This spec is used by HCL to read the fields of nicConfig. -// The decoded values from this spec will then be applied to a FlatnicConfig. -func (*FlatnicConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "model": &hcldec.AttrSpec{Name: "model", Type: cty.String, Required: false}, - "packet_queues": &hcldec.AttrSpec{Name: "packet_queues", Type: cty.Number, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "bridge": &hcldec.AttrSpec{Name: "bridge", Type: cty.String, Required: false}, - "vlan_tag": &hcldec.AttrSpec{Name: "vlan_tag", Type: cty.String, Required: false}, - "firewall": &hcldec.AttrSpec{Name: "firewall", Type: cty.Bool, Required: false}, - } - return s -} - -// FlatstorageConfig is an auto-generated flat version of storageConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatstorageConfig struct { - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - Device *string `mapstructure:"device" cty:"device" hcl:"device"` - ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` - ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` - Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"` -} - -// FlatMapstructure returns a new FlatstorageConfig. -// FlatstorageConfig is an auto-generated flat version of storageConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*storageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatstorageConfig) -} - -// HCL2Spec returns the hcl spec of a storageConfig. -// This spec is used by HCL to read the fields of storageConfig. -// The decoded values from this spec will then be applied to a FlatstorageConfig. -func (*FlatstorageConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, - "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, - "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, - "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, - "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, - "device": &hcldec.AttrSpec{Name: "device", Type: cty.String, Required: false}, - "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, - "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, - "unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false}, - } - return s -} - -// FlatvgaConfig is an auto-generated flat version of vgaConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatvgaConfig struct { - Type *string `mapstructure:"type" cty:"type" hcl:"type"` - Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` -} - -// FlatMapstructure returns a new FlatvgaConfig. -// FlatvgaConfig is an auto-generated flat version of vgaConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*vgaConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatvgaConfig) -} - -// HCL2Spec returns the hcl spec of a vgaConfig. -// This spec is used by HCL to read the fields of vgaConfig. -// The decoded values from this spec will then be applied to a FlatvgaConfig. -func (*FlatvgaConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "type": &hcldec.AttrSpec{Name: "type", Type: cty.String, Required: false}, - "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, - } - return s -} diff --git a/builder/proxmox/iso/builder.go b/builder/proxmox/iso/builder.go new file mode 100644 index 000000000..bffa0193c --- /dev/null +++ b/builder/proxmox/iso/builder.go @@ -0,0 +1,81 @@ +package proxmoxiso + +import ( + "context" + + proxmoxapi "github.com/Telmate/proxmox-api-go/proxmox" + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +// The unique id for the builder +const BuilderID = "proxmox.clone" + +type Builder struct { + config Config +} + +// Builder implements packer.Builder +var _ packer.Builder = &Builder{} + +var pluginVersion = "1.0.0" + +func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } + +func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { + return b.config.Prepare(raws...) +} + +const downloadPathKey = "downloaded_iso_path" + +func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { + state := new(multistep.BasicStateBag) + state.Put("iso-config", &b.config) + state.Put("vm-creator", &isoVMCreator{}) + + preSteps := []multistep.Step{ + &common.StepDownload{ + Checksum: b.config.ISOChecksum, + Description: "ISO", + Extension: b.config.TargetExtension, + ResultKey: downloadPathKey, + TargetPath: b.config.TargetPath, + Url: b.config.ISOUrls, + }, + } + for idx := range b.config.AdditionalISOFiles { + preSteps = append(preSteps, &common.StepDownload{ + Checksum: b.config.AdditionalISOFiles[idx].ISOChecksum, + Description: "additional ISO", + Extension: b.config.AdditionalISOFiles[idx].TargetExtension, + ResultKey: b.config.AdditionalISOFiles[idx].downloadPathKey, + TargetPath: b.config.AdditionalISOFiles[idx].downloadPathKey, + Url: b.config.AdditionalISOFiles[idx].ISOUrls, + }) + } + preSteps = append(preSteps, + &stepUploadISO{}, + &stepUploadAdditionalISOs{}, + ) + postSteps := []multistep.Step{ + &stepFinalizeISOTemplate{}, + } + + sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps) + return sb.Run(ctx, ui, hook, state) +} + +type isoVMCreator struct{} + +var _ proxmox.ProxmoxVMCreator = &isoVMCreator{} + +func (*isoVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQemu, state multistep.StateBag) error { + isoFile := state.Get("iso_file").(string) + config.QemuIso = isoFile + + client := state.Get("proxmoxClient").(*proxmoxapi.Client) + return config.CreateVm(vmRef, client) +} diff --git a/builder/proxmox/iso/config.go b/builder/proxmox/iso/config.go new file mode 100644 index 000000000..9346a24a0 --- /dev/null +++ b/builder/proxmox/iso/config.go @@ -0,0 +1,125 @@ +//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig + +package proxmoxiso + +import ( + "errors" + "fmt" + "log" + "strconv" + "strings" + + "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/packer" +) + +type Config struct { + proxmox.Config `mapstructure:",squash"` + + common.ISOConfig `mapstructure:",squash"` + ISOFile string `mapstructure:"iso_file"` + AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"` + ISOStoragePool string `mapstructure:"iso_storage_pool"` + UnmountISO bool `mapstructure:"unmount_iso"` + shouldUploadISO bool +} + +type storageConfig struct { + common.ISOConfig `mapstructure:",squash"` + Device string `mapstructure:"device"` + ISOFile string `mapstructure:"iso_file"` + ISOStoragePool string `mapstructure:"iso_storage_pool"` + Unmount bool `mapstructure:"unmount"` + shouldUploadISO bool + downloadPathKey string +} + +func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { + var errs *packer.MultiError + _, warnings, merrs := c.Config.Prepare(c, raws...) + if merrs != nil { + errs = packer.MultiErrorAppend(errs, merrs) + } + + // Check ISO config + // Either a pre-uploaded ISO should be referenced in iso_file, OR a URL + // (possibly to a local file) to an ISO file that will be downloaded and + // then uploaded to Proxmox. + if c.ISOFile != "" { + c.shouldUploadISO = false + } else { + isoWarnings, isoErrors := c.ISOConfig.Prepare(&c.Ctx) + errs = packer.MultiErrorAppend(errs, isoErrors...) + warnings = append(warnings, isoWarnings...) + c.shouldUploadISO = 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")) + } + + for idx := range c.AdditionalISOFiles { + // Check AdditionalISO config + // Either a pre-uploaded ISO should be referenced in iso_file, OR a URL + // (possibly to a local file) to an ISO file that will be downloaded and + // then uploaded to Proxmox. + if c.AdditionalISOFiles[idx].ISOFile != "" { + c.AdditionalISOFiles[idx].shouldUploadISO = false + } else { + c.AdditionalISOFiles[idx].downloadPathKey = "downloaded_additional_iso_path_" + strconv.Itoa(idx) + isoWarnings, isoErrors := c.AdditionalISOFiles[idx].ISOConfig.Prepare(&c.Ctx) + errs = packer.MultiErrorAppend(errs, isoErrors...) + warnings = append(warnings, isoWarnings...) + c.AdditionalISOFiles[idx].shouldUploadISO = true + } + if c.AdditionalISOFiles[idx].Device == "" { + log.Printf("AdditionalISOFile %d Device not set, using default 'ide3'", idx) + c.AdditionalISOFiles[idx].Device = "ide3" + } + if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "ide") { + busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[3:]) + if err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[3:])) + } + if busnumber == 2 { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("IDE bus 2 is used by boot ISO")) + } + if busnumber > 3 { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("IDE bus index can't be higher than 3")) + } + } + if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "sata") { + busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:]) + if err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:])) + } + if busnumber > 5 { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("SATA bus index can't be higher than 5")) + } + } + if strings.HasPrefix(c.AdditionalISOFiles[idx].Device, "scsi") { + busnumber, err := strconv.Atoi(c.AdditionalISOFiles[idx].Device[4:]) + if err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s is not a valid bus index", c.AdditionalISOFiles[idx].Device[4:])) + } + if busnumber > 30 { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("SCSI bus index can't be higher than 30")) + } + } + if (c.AdditionalISOFiles[idx].ISOFile == "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) == 0) || (c.AdditionalISOFiles[idx].ISOFile != "" && len(c.AdditionalISOFiles[idx].ISOConfig.ISOUrls) != 0) { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("either iso_file or iso_url, but not both, must be specified for AdditionalISO file %s", c.AdditionalISOFiles[idx].Device)) + } + 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 errs != nil && len(errs.Errors) > 0 { + return nil, warnings, errs + } + return nil, warnings, nil +} diff --git a/builder/proxmox/iso/config.hcl2spec.go b/builder/proxmox/iso/config.hcl2spec.go new file mode 100644 index 000000000..2616baf91 --- /dev/null +++ b/builder/proxmox/iso/config.hcl2spec.go @@ -0,0 +1,274 @@ +// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig"; DO NOT EDIT. +package proxmoxiso + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + proxmox "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/zclconf/go-cty/cty" +) + +// FlatConfig is an auto-generated flat version of Config. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatConfig struct { + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` + HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` + 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"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` + SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` + Username *string `mapstructure:"username" cty:"username" hcl:"username"` + Password *string `mapstructure:"password" cty:"password" hcl:"password"` + Node *string `mapstructure:"node" cty:"node" hcl:"node"` + Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` + VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` + VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` + Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` + CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` + Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` + OS *string `mapstructure:"os" cty:"os" hcl:"os"` + VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` + NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` + Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` + Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` + SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` + Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` + DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` + TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` + CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` + CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` + Data interface{} `cty:"data" hcl:"data"` + Funcs map[string]interface{} `cty:"funcs" hcl:"funcs"` + UserVariables map[string]string `cty:"user_variables" hcl:"user_variables"` + SensitiveVariables []string `cty:"sensitive_variables" hcl:"sensitive_variables"` + EnableEnv *bool `cty:"enable_env" hcl:"enable_env"` + BuildName *string `cty:"build_name" hcl:"build_name"` + BuildType *string `cty:"build_type" hcl:"build_type"` + TemplatePath *string `cty:"template_path" hcl:"template_path"` + ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` + RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` + ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` + TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` + TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` + ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` + AdditionalISOFiles []FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` + ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` + UnmountISO *bool `mapstructure:"unmount_iso" cty:"unmount_iso" hcl:"unmount_iso"` +} + +// FlatMapstructure returns a new FlatConfig. +// FlatConfig is an auto-generated flat version of Config. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatConfig) +} + +// HCL2Spec returns the hcl spec of a Config. +// This spec is used by HCL to read the fields of Config. +// The decoded values from this spec will then be applied to a FlatConfig. +func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, + "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, + "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, + "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, + "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, + "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, + "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, + "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, + "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, + "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, + "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", 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}, + "boot_key_interval": &hcldec.AttrSpec{Name: "boot_key_interval", Type: cty.String, Required: false}, + "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, + "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, + "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, + "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, + "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, + "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, + "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, + "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, + "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, + "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, + "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, + "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, + "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, + "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, + "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, + "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, + "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, + "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, + "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, + "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, + "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, + "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, + "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, + "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, + "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, + "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, + "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, + "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, + "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, + "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, + "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, + "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, + "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, + "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, + "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, + "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, + "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, + "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, + "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, + "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, + "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, + "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, + "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, + "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, + "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, + "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, + "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, + "proxmox_url": &hcldec.AttrSpec{Name: "proxmox_url", Type: cty.String, Required: false}, + "insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false}, + "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, + "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, + "node": &hcldec.AttrSpec{Name: "node", Type: cty.String, Required: false}, + "pool": &hcldec.AttrSpec{Name: "pool", Type: cty.String, Required: false}, + "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, + "vm_id": &hcldec.AttrSpec{Name: "vm_id", Type: cty.Number, Required: false}, + "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, + "cores": &hcldec.AttrSpec{Name: "cores", Type: cty.Number, Required: false}, + "cpu_type": &hcldec.AttrSpec{Name: "cpu_type", Type: cty.String, Required: false}, + "sockets": &hcldec.AttrSpec{Name: "sockets", Type: cty.Number, Required: false}, + "os": &hcldec.AttrSpec{Name: "os", Type: cty.String, Required: false}, + "vga": &hcldec.BlockSpec{TypeName: "vga", Nested: hcldec.ObjectSpec((*proxmox.FlatvgaConfig)(nil).HCL2Spec())}, + "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*proxmox.FlatnicConfig)(nil).HCL2Spec())}, + "disks": &hcldec.BlockListSpec{TypeName: "disks", Nested: hcldec.ObjectSpec((*proxmox.FlatdiskConfig)(nil).HCL2Spec())}, + "qemu_agent": &hcldec.AttrSpec{Name: "qemu_agent", Type: cty.Bool, Required: false}, + "scsi_controller": &hcldec.AttrSpec{Name: "scsi_controller", Type: cty.String, Required: false}, + "onboot": &hcldec.AttrSpec{Name: "onboot", Type: cty.Bool, Required: false}, + "disable_kvm": &hcldec.AttrSpec{Name: "disable_kvm", Type: cty.Bool, Required: false}, + "template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false}, + "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, + "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, + "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, + "data": &hcldec.AttrSpec{Name: "data", Type: cty.Bool, Required: false}, /* TODO(azr): could not find type */ + "funcs": &hcldec.AttrSpec{Name: "funcs", Type: cty.Map(cty.String), Required: false}, + "user_variables": &hcldec.AttrSpec{Name: "user_variables", Type: cty.Map(cty.String), Required: false}, + "sensitive_variables": &hcldec.AttrSpec{Name: "sensitive_variables", Type: cty.List(cty.String), Required: false}, + "enable_env": &hcldec.AttrSpec{Name: "enable_env", Type: cty.Bool, Required: false}, + "build_name": &hcldec.AttrSpec{Name: "build_name", Type: cty.String, Required: false}, + "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, + "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, + "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, + "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, + "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, + "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, + "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, + "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, + "additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*FlatstorageConfig)(nil).HCL2Spec())}, + "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, + "unmount_iso": &hcldec.AttrSpec{Name: "unmount_iso", Type: cty.Bool, Required: false}, + } + return s +} + +// FlatstorageConfig is an auto-generated flat version of storageConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatstorageConfig struct { + ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` + RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` + ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` + TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` + TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` + Device *string `mapstructure:"device" cty:"device" hcl:"device"` + ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` + ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` + Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"` +} + +// FlatMapstructure returns a new FlatstorageConfig. +// FlatstorageConfig is an auto-generated flat version of storageConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*storageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatstorageConfig) +} + +// HCL2Spec returns the hcl spec of a storageConfig. +// This spec is used by HCL to read the fields of storageConfig. +// The decoded values from this spec will then be applied to a FlatstorageConfig. +func (*FlatstorageConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, + "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, + "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, + "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, + "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, + "device": &hcldec.AttrSpec{Name: "device", Type: cty.String, Required: false}, + "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, + "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, + "unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false}, + } + return s +} diff --git a/builder/proxmox/config_test.go b/builder/proxmox/iso/config_test.go similarity index 53% rename from builder/proxmox/config_test.go rename to builder/proxmox/iso/config_test.go index e17d2e82f..836436422 100644 --- a/builder/proxmox/config_test.go +++ b/builder/proxmox/iso/config_test.go @@ -1,55 +1,17 @@ -package proxmox +package proxmoxiso import ( "strings" "testing" - "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template" ) -func mandatoryConfig(t *testing.T) map[string]interface{} { - return map[string]interface{}{ - "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json", - "username": "apiuser@pve", - "password": "supersecret", - "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso", - "node": "my-proxmox", - "ssh_username": "root", - } -} - -func TestRequiredParameters(t *testing.T) { - var c Config - _, err := c.Prepare(make(map[string]interface{})) - if err == nil { - t.Fatal("Expected empty configuration to fail") - } - errs, ok := err.(*packer.MultiError) - if !ok { - t.Fatal("Expected errors to be packer.MultiError") - } - - required := []string{"username", "password", "proxmox_url", "iso_file", "node", "ssh_username"} - for _, param := range required { - found := false - for _, err := range errs.Errors { - if strings.Contains(err.Error(), param) { - found = true - break - } - } - if !found { - t.Errorf("Expected error about missing parameter %q", required) - } - } -} - func TestBasicExampleFromDocsIsValid(t *testing.T) { const config = `{ "builders": [ { - "type": "proxmox", + "type": "proxmox-iso", "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json", "insecure_skip_tls_verify": true, "username": "apiuser@pve", @@ -93,9 +55,9 @@ func TestBasicExampleFromDocsIsValid(t *testing.T) { } b := &Builder{} - _, warn, err := b.Prepare(tpl.Builders["proxmox"].Config) + _, _, err = b.Prepare(tpl.Builders["proxmox-iso"].Config) if err != nil { - t.Fatal(err, warn) + t.Fatal(err) } // The example config does not set a number of optional fields. Validate that: @@ -148,63 +110,3 @@ func TestBasicExampleFromDocsIsValid(t *testing.T) { t.Errorf("Expected CloudInit to be false, got %t", b.config.CloudInit) } } - -func TestAgentSetToFalse(t *testing.T) { - cfg := mandatoryConfig(t) - cfg["qemu_agent"] = false - - var c Config - warn, err := c.Prepare(cfg) - if err != nil { - t.Fatal(err, warn) - } - - if c.Agent != false { - t.Errorf("Expected Agent to be false, got %t", c.Agent) - } -} - -func TestPacketQueueSupportForNetworkAdapters(t *testing.T) { - drivertests := []struct { - expectedToFail bool - model string - }{ - {expectedToFail: false, model: "virtio"}, - {expectedToFail: true, model: "e1000"}, - {expectedToFail: true, model: "e1000-82540em"}, - {expectedToFail: true, model: "e1000-82544gc"}, - {expectedToFail: true, model: "e1000-82545em"}, - {expectedToFail: true, model: "i82551"}, - {expectedToFail: true, model: "i82557b"}, - {expectedToFail: true, model: "i82559er"}, - {expectedToFail: true, model: "ne2k_isa"}, - {expectedToFail: true, model: "ne2k_pci"}, - {expectedToFail: true, model: "pcnet"}, - {expectedToFail: true, model: "rtl8139"}, - {expectedToFail: true, model: "vmxnet3"}, - } - - for _, tt := range drivertests { - device := make(map[string]interface{}) - device["bridge"] = "vmbr0" - device["model"] = tt.model - device["packet_queues"] = 2 - - devices := make([]map[string]interface{}, 0) - devices = append(devices, device) - - cfg := mandatoryConfig(t) - cfg["network_adapters"] = devices - - var c Config - _, err := c.Prepare(cfg) - - if tt.expectedToFail == true && err == nil { - t.Error("expected config preparation to fail, but no error occured") - } - - if tt.expectedToFail == false && err != nil { - t.Errorf("expected config preparation to succeed, but %s", err.Error()) - } - } -} diff --git a/builder/proxmox/iso/step_finalize_iso.go b/builder/proxmox/iso/step_finalize_iso.go new file mode 100644 index 000000000..88ef44bd2 --- /dev/null +++ b/builder/proxmox/iso/step_finalize_iso.go @@ -0,0 +1,87 @@ +package proxmoxiso + +import ( + "context" + "fmt" + "strings" + + "github.com/Telmate/proxmox-api-go/proxmox" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +// stepFinalizeISOTemplate does any ISO-builder specific modifications after +// conversion to a template, and after the non-specific modifications in +// common.stepFinalizeTemplateConfig +type stepFinalizeISOTemplate struct{} + +type templateFinalizer interface { + GetVmConfig(*proxmox.VmRef) (map[string]interface{}, error) + SetVmConfig(*proxmox.VmRef, map[string]interface{}) (interface{}, error) +} + +var _ templateFinalizer = &proxmox.Client{} + +func (s *stepFinalizeISOTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + client := state.Get("proxmoxClient").(templateFinalizer) + c := state.Get("iso-config").(*Config) + vmRef := state.Get("vmRef").(*proxmox.VmRef) + + changes := make(map[string]interface{}) + + if c.UnmountISO { + vmParams, err := client.GetVmConfig(vmRef) + if err != nil { + err := fmt.Errorf("Error fetching template config: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + 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 + } + changes["ide2"] = "none,media=cdrom" + } + if len(c.AdditionalISOFiles) > 0 { + vmParams, err := client.GetVmConfig(vmRef) + if err != nil { + err := fmt.Errorf("Error fetching template config: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + for idx := range c.AdditionalISOFiles { + cdrom := c.AdditionalISOFiles[idx].Device + if c.AdditionalISOFiles[idx].Unmount { + if vmParams[cdrom] == nil || !strings.Contains(vmParams[cdrom].(string), "media=cdrom") { + err := fmt.Errorf("Cannot eject ISO from cdrom drive, %s is not present or not a cdrom media", cdrom) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + changes[cdrom] = "none,media=cdrom" + } else { + changes[cdrom] = c.AdditionalISOFiles[idx].ISOFile + ",media=cdrom" + } + } + } + + if len(changes) > 0 { + _, err := client.SetVmConfig(vmRef, changes) + if err != nil { + err := fmt.Errorf("Error updating template: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + } + + return multistep.ActionContinue +} + +func (s *stepFinalizeISOTemplate) Cleanup(state multistep.StateBag) { +} diff --git a/builder/proxmox/iso/step_finalize_iso_test.go b/builder/proxmox/iso/step_finalize_iso_test.go new file mode 100644 index 000000000..a35a7f5a2 --- /dev/null +++ b/builder/proxmox/iso/step_finalize_iso_test.go @@ -0,0 +1,131 @@ +package proxmoxiso + +import ( + "context" + "fmt" + "testing" + + "github.com/Telmate/proxmox-api-go/proxmox" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +type finalizerMock struct { + getConfig func() (map[string]interface{}, error) + setConfig func(map[string]interface{}) (string, error) +} + +func (m finalizerMock) GetVmConfig(*proxmox.VmRef) (map[string]interface{}, error) { + return m.getConfig() +} +func (m finalizerMock) SetVmConfig(vmref *proxmox.VmRef, c map[string]interface{}) (interface{}, error) { + return m.setConfig(c) +} + +var _ templateFinalizer = finalizerMock{} + +func TestISOTemplateFinalize(t *testing.T) { + cs := []struct { + name string + builderConfig *Config + initialVMConfig map[string]interface{} + getConfigErr error + expectCallSetConfig bool + expectedVMConfig map[string]interface{} + setConfigErr error + expectedAction multistep.StepAction + }{ + { + name: "default config does nothing", + builderConfig: &Config{}, + initialVMConfig: map[string]interface{}{ + "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", + }, + expectCallSetConfig: false, + expectedVMConfig: map[string]interface{}{ + "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", + }, + expectedAction: multistep.ActionContinue, + }, + { + name: "should unmount when configured", + builderConfig: &Config{ + UnmountISO: true, + }, + initialVMConfig: map[string]interface{}{ + "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", + }, + expectCallSetConfig: true, + expectedVMConfig: map[string]interface{}{ + "ide2": "none,media=cdrom", + }, + expectedAction: multistep.ActionContinue, + }, + { + name: "no cd-drive with unmount=true should returns halt", + builderConfig: &Config{ + UnmountISO: true, + }, + initialVMConfig: map[string]interface{}{ + "ide1": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", + }, + expectCallSetConfig: false, + expectedAction: multistep.ActionHalt, + }, + { + name: "GetVmConfig error should return halt", + builderConfig: &Config{ + UnmountISO: true, + }, + getConfigErr: fmt.Errorf("some error"), + expectCallSetConfig: false, + expectedAction: multistep.ActionHalt, + }, + { + name: "SetVmConfig error should return halt", + builderConfig: &Config{ + UnmountISO: true, + }, + initialVMConfig: map[string]interface{}{ + "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", + }, + expectCallSetConfig: true, + setConfigErr: fmt.Errorf("some error"), + expectedAction: multistep.ActionHalt, + }, + } + + for _, c := range cs { + t.Run(c.name, func(t *testing.T) { + finalizer := finalizerMock{ + getConfig: func() (map[string]interface{}, error) { + return c.initialVMConfig, c.getConfigErr + }, + setConfig: func(cfg map[string]interface{}) (string, error) { + if !c.expectCallSetConfig { + t.Error("Did not expect SetVmConfig to be called") + } + for key, val := range c.expectedVMConfig { + if cfg[key] != val { + t.Errorf("Expected %q to be %q, got %q", key, val, cfg[key]) + } + } + + return "", c.setConfigErr + }, + } + + state := new(multistep.BasicStateBag) + state.Put("ui", packer.TestUi(t)) + state.Put("iso-config", c.builderConfig) + state.Put("vmRef", proxmox.NewVmRef(1)) + state.Put("proxmoxClient", finalizer) + + step := stepFinalizeISOTemplate{} + action := step.Run(context.TODO(), state) + if action != c.expectedAction { + t.Errorf("Expected action to be %v, got %v", c.expectedAction, action) + } + }) + } +} diff --git a/builder/proxmox/step_upload_additional_isos.go b/builder/proxmox/iso/step_upload_additional_isos.go similarity index 90% rename from builder/proxmox/step_upload_additional_isos.go rename to builder/proxmox/iso/step_upload_additional_isos.go index b867032c0..c6e808ffc 100644 --- a/builder/proxmox/step_upload_additional_isos.go +++ b/builder/proxmox/iso/step_upload_additional_isos.go @@ -1,9 +1,8 @@ -package proxmox +package proxmoxiso import ( "context" "fmt" - "io" "os" "path/filepath" @@ -16,16 +15,12 @@ import ( // to the VM type stepUploadAdditionalISOs struct{} -type uploader interface { - Upload(node string, storage string, contentType string, filename string, file io.Reader) error -} - var _ uploader = &proxmox.Client{} func (s *stepUploadAdditionalISOs) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) client := state.Get("proxmoxClient").(uploader) - c := state.Get("config").(*Config) + c := state.Get("iso-config").(*Config) for idx := range c.AdditionalISOFiles { if !c.AdditionalISOFiles[idx].shouldUploadISO { diff --git a/builder/proxmox/step_upload_iso.go b/builder/proxmox/iso/step_upload_iso.go similarity index 88% rename from builder/proxmox/step_upload_iso.go rename to builder/proxmox/iso/step_upload_iso.go index de947075c..79096bfe0 100644 --- a/builder/proxmox/step_upload_iso.go +++ b/builder/proxmox/iso/step_upload_iso.go @@ -1,8 +1,9 @@ -package proxmox +package proxmoxiso import ( "context" "fmt" + "io" "os" "path/filepath" @@ -14,12 +15,16 @@ import ( // stepUploadISO uploads an ISO file to Proxmox so we can boot from it type stepUploadISO struct{} +type uploader interface { + Upload(node string, storage string, contentType string, filename string, file io.Reader) error +} + var _ uploader = &proxmox.Client{} func (s *stepUploadISO) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) client := state.Get("proxmoxClient").(uploader) - c := state.Get("config").(*Config) + c := state.Get("iso-config").(*Config) if !c.shouldUploadISO { state.Put("iso_file", c.ISOFile) @@ -53,6 +58,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) + return multistep.ActionContinue } diff --git a/builder/proxmox/step_upload_iso_test.go b/builder/proxmox/iso/step_upload_iso_test.go similarity index 98% rename from builder/proxmox/step_upload_iso_test.go rename to builder/proxmox/iso/step_upload_iso_test.go index a009d6686..418005a0c 100644 --- a/builder/proxmox/step_upload_iso_test.go +++ b/builder/proxmox/iso/step_upload_iso_test.go @@ -1,4 +1,4 @@ -package proxmox +package proxmoxiso import ( "context" @@ -106,7 +106,7 @@ func TestUploadISO(t *testing.T) { state := new(multistep.BasicStateBag) state.Put("ui", packer.TestUi(t)) - state.Put("config", c.builderConfig) + state.Put("iso-config", c.builderConfig) state.Put(downloadPathKey, c.downloadPath) state.Put("proxmoxClient", m) diff --git a/builder/proxmox/testdata/test.iso b/builder/proxmox/iso/testdata/test.iso similarity index 100% rename from builder/proxmox/testdata/test.iso rename to builder/proxmox/iso/testdata/test.iso diff --git a/command/plugin.go b/command/plugin.go index 82a4ad016..38adb929c 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -48,7 +48,8 @@ import ( parallelsisobuilder "github.com/hashicorp/packer/builder/parallels/iso" parallelspvmbuilder "github.com/hashicorp/packer/builder/parallels/pvm" profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks" - proxmoxbuilder "github.com/hashicorp/packer/builder/proxmox" + proxmoxclonebuilder "github.com/hashicorp/packer/builder/proxmox/clone" + proxmoxisobuilder "github.com/hashicorp/packer/builder/proxmox/iso" qemubuilder "github.com/hashicorp/packer/builder/qemu" scalewaybuilder "github.com/hashicorp/packer/builder/scaleway" tencentcloudcvmbuilder "github.com/hashicorp/packer/builder/tencentcloud/cvm" @@ -145,7 +146,9 @@ var Builders = map[string]packer.Builder{ "parallels-iso": new(parallelsisobuilder.Builder), "parallels-pvm": new(parallelspvmbuilder.Builder), "profitbricks": new(profitbricksbuilder.Builder), - "proxmox": new(proxmoxbuilder.Builder), + "proxmox-clone": new(proxmoxclonebuilder.Builder), + "proxmox-iso": new(proxmoxisobuilder.Builder), + "proxmox": new(proxmoxisobuilder.Builder), "qemu": new(qemubuilder.Builder), "scaleway": new(scalewaybuilder.Builder), "tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder), From cfece501d09c94f979a567ce3b082624b94b2cc8 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Wed, 9 Sep 2020 21:46:57 -0700 Subject: [PATCH 02/24] Implement proxmox-clone --- builder/proxmox/clone/builder.go | 49 +++++++++- builder/proxmox/clone/config.go | 1 + builder/proxmox/clone/config.hcl2spec.go | 2 + builder/proxmox/clone/step_ssh_key_pair.go | 107 +++++++++++++++++++++ builder/proxmox/common/builder.go | 11 ++- 5 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 builder/proxmox/clone/step_ssh_key_pair.go diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index c56db14d4..c9e935686 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -2,10 +2,14 @@ package proxmoxclone import ( "context" + "time" + "fmt" + proxmoxapi "github.com/Telmate/proxmox-api-go/proxmox" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer/builder/proxmox/common" "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/packer" ) @@ -30,10 +34,51 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { state := new(multistep.BasicStateBag) state.Put("clone-config", &b.config) + state.Put("vm-creator", &cloneVMCreator{}) + state.Put("comm", &b.config.Comm) - steps := []multistep.Step{} + preSteps := []multistep.Step{ + &StepSshKeyPair{ + Debug: b.config.PackerDebug, + DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName), + Comm: &b.config.Comm, + }, + } postSteps := []multistep.Step{} - sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, steps, postSteps) + sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps) return sb.Run(ctx, ui, hook, state) } + +type cloneVMCreator struct{} + +var _ proxmox.ProxmoxVMCreator = &cloneVMCreator{} + +func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQemu, state multistep.StateBag) error { + client := state.Get("proxmoxClient").(*proxmoxapi.Client) + c := state.Get("clone-config").(*Config) + comm := state.Get("comm").(*communicator.Config) + + fullClone := 1 + if c.FullClone { + fullClone = 0 + } + + config.FullClone = &fullClone + config.CIuser = comm.SSHUsername + config.Sshkeys = string(comm.SSHPublicKey) + sourceVmr, err := client.GetVmRefByName(c.CloneVM) + if err != nil { + return err + } + err = config.CloneVm(sourceVmr, vmRef, client) + if err != nil { + return err + } + err = config.UpdateConfig(vmRef, client) + if err != nil { + return err + } + time.Sleep(time.Duration(15) * time.Second) + return nil +} diff --git a/builder/proxmox/clone/config.go b/builder/proxmox/clone/config.go index bede7db14..d481d3c39 100644 --- a/builder/proxmox/clone/config.go +++ b/builder/proxmox/clone/config.go @@ -11,6 +11,7 @@ type Config struct { proxmox.Config `mapstructure:",squash"` CloneVM string `mapstructure:"clone_vm"` + FullClone bool `mapstructure:"full_clone"` } func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { diff --git a/builder/proxmox/clone/config.hcl2spec.go b/builder/proxmox/clone/config.hcl2spec.go index cc5a87d09..99133765a 100644 --- a/builder/proxmox/clone/config.hcl2spec.go +++ b/builder/proxmox/clone/config.hcl2spec.go @@ -105,6 +105,7 @@ type FlatConfig struct { BuildType *string `cty:"build_type" hcl:"build_type"` TemplatePath *string `cty:"template_path" hcl:"template_path"` CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"` + FullClone *bool `mapstructure:"full_clone" cty:"full_clone" hcl:"full_clone"` } // FlatMapstructure returns a new FlatConfig. @@ -214,6 +215,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, "clone_vm": &hcldec.AttrSpec{Name: "clone_vm", Type: cty.String, Required: false}, + "full_clone": &hcldec.AttrSpec{Name: "full_clone", Type: cty.Bool, Required: false}, } return s } diff --git a/builder/proxmox/clone/step_ssh_key_pair.go b/builder/proxmox/clone/step_ssh_key_pair.go new file mode 100644 index 000000000..96e97d5a8 --- /dev/null +++ b/builder/proxmox/clone/step_ssh_key_pair.go @@ -0,0 +1,107 @@ +package proxmoxclone + +import ( + "context" + "fmt" + "os" + + "github.com/hashicorp/packer/common/uuid" + "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/helper/ssh" + "github.com/hashicorp/packer/packer" +) + +// StepSshKeyPair executes the business logic for setting the SSH key pair in +// the specified communicator.Config. +type StepSshKeyPair struct { + Debug bool + DebugKeyPath string + Comm *communicator.Config +} + +func (s *StepSshKeyPair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + + if s.Comm.SSHPassword != "" { + return multistep.ActionContinue + } + + if s.Comm.SSHPrivateKeyFile != "" { + ui.Say("Using existing SSH private key for the communicator...") + privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile() + if err != nil { + state.Put("error", err) + return multistep.ActionHalt + } + + kp, err := ssh.KeyPairFromPrivateKey(ssh.FromPrivateKeyConfig{ + RawPrivateKeyPemBlock: privateKeyBytes, + Comment: fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()), + }) + if err != nil { + state.Put("error", err) + return multistep.ActionHalt + } + + s.Comm.SSHPrivateKey = privateKeyBytes + s.Comm.SSHKeyPairName = kp.Comment + s.Comm.SSHTemporaryKeyPairName = kp.Comment + s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine + + return multistep.ActionContinue + } + + if s.Comm.SSHAgentAuth { + ui.Say("Using local SSH Agent to authenticate connections for the communicator...") + return multistep.ActionContinue + } + + ui.Say("Creating ephemeral key pair for SSH communicator...") + + kp, err := ssh.NewKeyPair(ssh.CreateKeyPairConfig{ + Comment: fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()), + }) + if err != nil { + state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err)) + return multistep.ActionHalt + } + + s.Comm.SSHKeyPairName = kp.Comment + s.Comm.SSHTemporaryKeyPairName = kp.Comment + s.Comm.SSHPrivateKey = kp.PrivateKeyPemBlock + s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine + s.Comm.SSHClearAuthorizedKeys = true + + ui.Say("Created ephemeral SSH key pair for communicator") + + // If we're in debug mode, output the private key to the working + // directory. + if s.Debug { + ui.Message(fmt.Sprintf("Saving communicator private key for debug purposes: %s", s.DebugKeyPath)) + f, err := os.OpenFile(s.DebugKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) + return multistep.ActionHalt + } + defer f.Close() + + // Write the key out + if _, err := f.Write(kp.PrivateKeyPemBlock); err != nil { + state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) + return multistep.ActionHalt + } + } + + return multistep.ActionContinue +} + +func (s *StepSshKeyPair) Cleanup(state multistep.StateBag) { + if s.Debug { + if err := os.Remove(s.DebugKeyPath); err != nil { + ui := state.Get("ui").(packer.Ui) + ui.Error(fmt.Sprintf( + "Error removing debug key '%s': %s", s.DebugKeyPath, err)) + } + } +} diff --git a/builder/proxmox/common/builder.go b/builder/proxmox/common/builder.go index b6742b1ee..83e1cecd3 100644 --- a/builder/proxmox/common/builder.go +++ b/builder/proxmox/common/builder.go @@ -52,6 +52,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state state.Put("hook", hook) state.Put("ui", ui) + comm := &b.config.Comm + if(state.Get("comm") != nil) { + comm = state.Get("comm").(*communicator.Config) + } + // Build the steps coreSteps := []multistep.Step{ &stepStartVM{}, @@ -66,9 +71,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state Ctx: b.config.Ctx, }, &communicator.StepConnect{ - Config: &b.config.Comm, - Host: commHost(b.config.Comm.Host()), - SSHConfig: b.config.Comm.SSHConfigFunc(), + Config: comm, + Host: commHost((*comm).Host()), + SSHConfig: (*comm).SSHConfigFunc(), }, &common.StepProvision{}, &common.StepCleanupTempKeys{ From 8aeafa986f7ee47d6b4571620e500dc18b56ffee Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Thu, 10 Sep 2020 17:33:30 -0700 Subject: [PATCH 03/24] DOCS: split proxmox docs for clone --- website/pages/docs/builders/proxmox/clone.mdx | 234 ++++++++++++++++++ website/pages/docs/builders/proxmox/index.mdx | 29 +++ .../docs/builders/{ => proxmox}/proxmox.mdx | 12 +- 3 files changed, 269 insertions(+), 6 deletions(-) create mode 100644 website/pages/docs/builders/proxmox/clone.mdx create mode 100644 website/pages/docs/builders/proxmox/index.mdx rename website/pages/docs/builders/{ => proxmox}/proxmox.mdx (98%) diff --git a/website/pages/docs/builders/proxmox/clone.mdx b/website/pages/docs/builders/proxmox/clone.mdx new file mode 100644 index 000000000..df5b3fc14 --- /dev/null +++ b/website/pages/docs/builders/proxmox/clone.mdx @@ -0,0 +1,234 @@ +--- +description: | + The proxmox image Packer builder is able to create new images for use with + Proxmox VE. The builder takes a cloud-init enabled virtual machine + template name, runs any provisioning necessary on the image after + launching it, then creates a virtual machine template. +layout: docs +page_title: Proxmox Clone - Builders +sidebar_title: Clone +--- + +# Proxmox Builder (from an image) + +Type: `proxmox-clone` + +The `proxmox-clone` Packer builder is able to create new images for use with +[Proxmox](https://www.proxmox.com/en/proxmox-ve). The builder takes a virtual +machine template, runs any provisioning necessary on the image after launching it, +then creates a virtual machine template. This template can then be used as to +create new virtual machines within Proxmox. + +The builder does _not_ manage templates. Once it creates a template, it is up +to you to use it or delete it. + +## Configuration Reference + +There are many configuration options available for the builder. They are +segmented below into two categories: required and optional parameters. Within +each category, the available configuration keys are alphabetized. + +In addition to the options listed here, a +[communicator](/docs/templates/communicator) can be configured for this +builder. + +If no communicator is defined, an SSH key is generated for use, and is used +in the image's Cloud-Init settings for provisioning. + +### Required: + +- `proxmox_url` (string) - URL to the Proxmox API, including the full path, + so `https://:/api2/json` for example. + Can also be set via the `PROXMOX_URL` environment variable. + +- `username` (string) - Username when authenticating to Proxmox, including + the realm. For example `user@pve` to use the local Proxmox realm. + Can also be set via the `PROXMOX_USERNAME` environment variable. + +- `password` (string) - Password for the user. + Can also be set via the `PROXMOX_PASSWORD` environment variable. + +- `node` (string) - Which node in the Proxmox cluster to start the virtual + machine on during creation. + +- `clone_vm` (string) - The name of the VM packer should clone and build from. + +### Optional: + +- `insecure_skip_tls_verify` (bool) - Skip validating the certificate. + +- `pool` (string) - Name of resource pool to create virtual machine in. + +- `vm_name` (string) - Name of the virtual machine during creation. If not + given, a random uuid will be used. + +- `vm_id` (int) - The ID used to reference the virtual machine. This will + also be the ID of the final template. If not given, the next free ID on + the node will be used. + +- `memory` (int) - How much memory, in megabytes, to give the virtual + machine. Defaults to `512`. + +- `cores` (int) - How many CPU cores to give the virtual machine. Defaults + to `1`. + +- `sockets` (int) - How many CPU sockets to give the virtual machine. + Defaults to `1` + +- `cpu_type` (string) - The CPU type to emulate. See the Proxmox API + documentation for the complete list of accepted values. For best + performance, set this to `host`. Defaults to `kvm64`. + +- `os` (string) - The operating system. Can be `wxp`, `w2k`, `w2k3`, `w2k8`, + `wvista`, `win7`, `win8`, `win10`, `l24` (Linux 2.4), `l26` (Linux 2.6+), + `solaris` or `other`. Defaults to `other`. + +- `vga` (object) - The graphics adapter to use. Example: + + ```json + { + "type": "vmware", + "memory": 32 + } + ``` + + - `type` (string) - Can be `cirrus`, `none`, `qxl`,`qxl2`, `qxl3`, + `qxl4`, `serial0`, `serial1`, `serial2`, `serial3`, `std`, `virtio`, `vmware`. + Defaults to `std`. + + - `memory` (int) - How much memory to assign. + +- `network_adapters` (array of objects) - Network adapters attached to the + virtual machine. Example: + + ```json + [ + { + "model": "virtio", + "bridge": "vmbr0", + "vlan_tag": "10", + "firewall": true + } + ] + ``` + + - `bridge` (string) - Required. Which Proxmox bridge to attach the + adapter to. + + - `model` (string) - Model of the virtual network adapter. Can be + `rtl8139`, `ne2k_pci`, `e1000`, `pcnet`, `virtio`, `ne2k_isa`, + `i82551`, `i82557b`, `i82559er`, `vmxnet3`, `e1000-82540em`, + `e1000-82544gc` or `e1000-82545em`. Defaults to `e1000`. + + - `mac_address` (string) - Give the adapter a specific MAC address. If + not set, defaults to a random MAC. + + - `vlan_tag` (string) - If the adapter should tag packets. Defaults to + no tagging. + + - `firewall` (bool) - If the interface should be protected by the firewall. + Defaults to `false`. + + - `packet_queues` (int) - Number of packet queues to be used on the device. + Values greater than 1 indicate that the multiqueue feature is activated. + For best performance, set this to the number of cores available to the + virtual machine. CPU load on the host and guest systems will increase as + the traffic increases, so activate this option only when the VM has to + handle a great number of incoming connections, such as when the VM is + operating as a router, reverse proxy or a busy HTTP server. Requires + `virtio` network adapter. Defaults to `0`. + +- `disks` (array of objects) - Disks attached to the virtual machine. + Example: + + ```json + [ + { + "type": "scsi", + "disk_size": "5G", + "storage_pool": "local-lvm", + "storage_pool_type": "lvm" + } + ] + ``` + + - `storage_pool` (string) - Required. Name of the Proxmox storage pool + to store the virtual machine disk on. A `local-lvm` pool is allocated + by the installer, for example. + + - `storage_pool_type` (string) - Required. The type of the pool, can + be `lvm`, `lvm-thin`, `zfspool`, `cephfs`, `rbd` or `directory`. + + - `type` (string) - The type of disk. Can be `scsi`, `sata`, `virtio` or + `ide`. Defaults to `scsi`. + + - `disk_size` (string) - The size of the disk, including a unit suffix, such + as `10G` to indicate 10 gigabytes. + + - `cache_mode` (string) - How to cache operations to the disk. Can be + `none`, `writethrough`, `writeback`, `unsafe` or `directsync`. + Defaults to `none`. + + - `format` (string) - The format of the file backing the disk. Can be + `raw`, `cow`, `qcow`, `qed`, `qcow2`, `vmdk` or `cloop`. Defaults to + `raw`. + +- `template_name` (string) - Name of the template. Defaults to the generated + name used during creation. + +- `template_description` (string) - Description of the template, visible in + the Proxmox interface. + +- `onboot` (boolean) - Specifies whether a VM will be started during system + bootup. Defaults to `false`. + +- `disable_kvm` (boolean) - Disables KVM hardware virtualization. Defaults to `false`. + +- `scsi_controller` (string) - The SCSI controller model to emulate. Can be `lsi`, + `lsi53c810`, `virtio-scsi-pci`, `virtio-scsi-single`, `megasas`, or `pvscsi`. + Defaults to `lsi`. + +- `full_clone` (bool) - Whether to run a full or shallow clone from the base clone_vm. Defaults to `true`. + +## Example: Cloud-Init enabled Debian + +Here is a basic example creating a Debian 10 server image. This assumes +that there exists a Cloud-Init enabled image on the Proxmox server named +`debian-10-4`. + +```json +{ + "variables": { + "proxmox_url": "{{env `PROXMOX_URL`}}", + "proxmox_username": "{{env `PROXMOX_USERNAME`}}", + "proxmox_password": "{{env `PROXMOX_PASSWORD`}}" + }, + + "builders": [ + { + "type": "proxmox-clone", + "proxmox_url": "{{user `proxmox_url`}}", + "username": "{{user `proxmox_username`}}", + "password": "{{user `proxmox_password`}}", + "node": "pve", + "insecure_skip_tls_verify": true, + "clone_vm": "debian-10-4", + "template_name": "debian-scaffolding", + "template_description": "image made from cloud-init image", + + "pool": "api-users", + "os": "l26", + "cores": 1, + "sockets": 1, + "memory": 2048, + "network_adapters": [ + { + "bridge": "vmbr0" + } + ] + } + ], + "description": "A template for building a base" +} + +``` diff --git a/website/pages/docs/builders/proxmox/index.mdx b/website/pages/docs/builders/proxmox/index.mdx new file mode 100644 index 000000000..c5d1731ac --- /dev/null +++ b/website/pages/docs/builders/proxmox/index.mdx @@ -0,0 +1,29 @@ +--- +description: > + The Proxmox Packer builder is able to create Cloud-Init + virtual machine images on a Proxmox server. + +layout: docs +page_title: Proxmox - Builders +sidebar_title: Proxmox +--- + +# Proxmox Builder + +The Proxmox Packer builder is able to create +[Proxmox](https://www.proxmox.com/en/proxmox-ve) virtual +machines and store them as new Proxmox Virutal Machine images. + +Packer is able to target both ISO and existing Cloud-Init images: + +- [proxmox-clone](/docs/builders/proxmox-clone) - The proxmox image + Packer builder is able to create new images for use with + Proxmox VE. The builder takes a cloud-init enabled virtual machine + template name, runs any provisioning necessary on the image after + launching it, then creates a virtual machine template. + +- [proxmox-iso](/docs/builders/proxmox-iso) - The proxmox Packer + builder is able to create new images for use with + Proxmox VE. The builder takes an ISO source, runs any provisioning + necessary on the image after launching it, then creates a virtual machine + template. diff --git a/website/pages/docs/builders/proxmox.mdx b/website/pages/docs/builders/proxmox/proxmox.mdx similarity index 98% rename from website/pages/docs/builders/proxmox.mdx rename to website/pages/docs/builders/proxmox/proxmox.mdx index c9a2679a3..4305be528 100644 --- a/website/pages/docs/builders/proxmox.mdx +++ b/website/pages/docs/builders/proxmox/proxmox.mdx @@ -1,19 +1,19 @@ - +--- description: | The proxmox Packer builder is able to create new images for use with Proxmox VE. The builder takes an ISO source, runs any provisioning necessary on the image after launching it, then creates a virtual machine template. layout: docs -page_title: Proxmox - Builders -sidebar_title: Proxmox +page_title: Proxmox ISO - Builders +sidebar_title: ISO --- -# Proxmox Builder +# Proxmox Builder (from an ISO) -Type: `proxmox` +Type: `proxmox-iso` -The `proxmox` Packer builder is able to create new images for use with +The `proxmox-iso` Packer builder is able to create new images for use with [Proxmox](https://www.proxmox.com/en/proxmox-ve). The builder takes an ISO image, runs any provisioning necessary on the image after launching it, then creates a virtual machine template. This template can then be used as to From aa5eb770d0449ddb2143f73c66f9cc83a5a61205 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Fri, 11 Sep 2020 16:45:16 -0700 Subject: [PATCH 04/24] DEV: use proper interfaces for vmCreator --- builder/proxmox/clone/builder.go | 5 +---- builder/proxmox/common/builder.go | 8 ++++++-- builder/proxmox/common/step_start_vm.go | 8 ++++---- builder/proxmox/iso/builder.go | 5 +---- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index c9e935686..9ef8f9dcc 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -34,7 +34,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { state := new(multistep.BasicStateBag) state.Put("clone-config", &b.config) - state.Put("vm-creator", &cloneVMCreator{}) state.Put("comm", &b.config.Comm) preSteps := []multistep.Step{ @@ -46,14 +45,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack } postSteps := []multistep.Step{} - sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps) + sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps, &cloneVMCreator{}) return sb.Run(ctx, ui, hook, state) } type cloneVMCreator struct{} -var _ proxmox.ProxmoxVMCreator = &cloneVMCreator{} - func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQemu, state multistep.StateBag) error { client := state.Get("proxmoxClient").(*proxmoxapi.Client) c := state.Get("clone-config").(*Config) diff --git a/builder/proxmox/common/builder.go b/builder/proxmox/common/builder.go index 83e1cecd3..0ba157a63 100644 --- a/builder/proxmox/common/builder.go +++ b/builder/proxmox/common/builder.go @@ -13,12 +13,13 @@ import ( "github.com/hashicorp/packer/packer" ) -func NewSharedBuilder(id string, config Config, preSteps []multistep.Step, postSteps []multistep.Step) *Builder { +func NewSharedBuilder(id string, config Config, preSteps []multistep.Step, postSteps []multistep.Step, vmCreator ProxmoxVMCreator) *Builder { return &Builder{ id: id, config: config, preSteps: preSteps, postSteps: postSteps, + vmCreator: vmCreator, } } @@ -29,6 +30,7 @@ type Builder struct { postSteps []multistep.Step runner multistep.Runner proxmoxClient *proxmox.Client + vmCreator ProxmoxVMCreator } func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state multistep.StateBag) (packer.Artifact, error) { @@ -59,7 +61,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state // Build the steps coreSteps := []multistep.Step{ - &stepStartVM{}, + &stepStartVM{ + vmCreator: b.vmCreator, + }, &common.StepHTTPServer{ HTTPDir: b.config.HTTPDir, HTTPPortMin: b.config.HTTPPortMin, diff --git a/builder/proxmox/common/step_start_vm.go b/builder/proxmox/common/step_start_vm.go index b364b9a67..009cf5c35 100644 --- a/builder/proxmox/common/step_start_vm.go +++ b/builder/proxmox/common/step_start_vm.go @@ -15,7 +15,9 @@ import ( // // It sets the vmRef state which is used throughout the later steps to reference the VM // in API calls. -type stepStartVM struct{} +type stepStartVM struct{ + vmCreator ProxmoxVMCreator +} type ProxmoxVMCreator interface { Create(*proxmox.VmRef, proxmox.ConfigQemu, multistep.StateBag) error @@ -36,8 +38,6 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist kvm = false } - vmStarter := state.Get("vm-creator").(ProxmoxVMCreator) - ui.Say("Creating VM") config := proxmox.ConfigQemu{ Name: c.VMName, @@ -81,7 +81,7 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist vmRef.SetPool(c.Pool) } - err := vmStarter.Create(vmRef, config, state) + err := s.vmCreator.Create(vmRef, config, state) if err != nil { err := fmt.Errorf("Error creating VM: %s", err) state.Put("error", err) diff --git a/builder/proxmox/iso/builder.go b/builder/proxmox/iso/builder.go index bffa0193c..752f6c12a 100644 --- a/builder/proxmox/iso/builder.go +++ b/builder/proxmox/iso/builder.go @@ -34,7 +34,6 @@ const downloadPathKey = "downloaded_iso_path" func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { state := new(multistep.BasicStateBag) state.Put("iso-config", &b.config) - state.Put("vm-creator", &isoVMCreator{}) preSteps := []multistep.Step{ &common.StepDownload{ @@ -64,14 +63,12 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack &stepFinalizeISOTemplate{}, } - sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps) + sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps, &isoVMCreator{}) return sb.Run(ctx, ui, hook, state) } type isoVMCreator struct{} -var _ proxmox.ProxmoxVMCreator = &isoVMCreator{} - func (*isoVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQemu, state multistep.StateBag) error { isoFile := state.Get("iso_file").(string) config.QemuIso = isoFile From 99c3872a48bd422e152ab91d517b4b4fe7ffd1b5 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 11:58:50 -0700 Subject: [PATCH 05/24] run go fmt --- builder/proxmox/clone/builder.go | 60 ++++++++++++------------- builder/proxmox/clone/config.go | 4 +- builder/proxmox/common/builder.go | 16 +++---- builder/proxmox/common/step_start_vm.go | 4 +- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index 9ef8f9dcc..7dfb906a8 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -2,14 +2,14 @@ package proxmoxclone import ( "context" - "time" - "fmt" + "fmt" + "time" proxmoxapi "github.com/Telmate/proxmox-api-go/proxmox" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer/builder/proxmox/common" - "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" ) @@ -34,15 +34,15 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { state := new(multistep.BasicStateBag) state.Put("clone-config", &b.config) - state.Put("comm", &b.config.Comm) + state.Put("comm", &b.config.Comm) preSteps := []multistep.Step{ - &StepSshKeyPair{ - Debug: b.config.PackerDebug, + &StepSshKeyPair{ + Debug: b.config.PackerDebug, DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName), Comm: &b.config.Comm, - }, - } + }, + } postSteps := []multistep.Step{} sb := proxmox.NewSharedBuilder(BuilderID, b.config.Config, preSteps, postSteps, &cloneVMCreator{}) @@ -53,29 +53,29 @@ type cloneVMCreator struct{} func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQemu, state multistep.StateBag) error { client := state.Get("proxmoxClient").(*proxmoxapi.Client) - c := state.Get("clone-config").(*Config) - comm := state.Get("comm").(*communicator.Config) + c := state.Get("clone-config").(*Config) + comm := state.Get("comm").(*communicator.Config) - fullClone := 1 - if c.FullClone { - fullClone = 0 - } + fullClone := 1 + if c.FullClone { + fullClone = 0 + } - config.FullClone = &fullClone - config.CIuser = comm.SSHUsername - config.Sshkeys = string(comm.SSHPublicKey) - sourceVmr, err := client.GetVmRefByName(c.CloneVM) - if err != nil { - return err - } - err = config.CloneVm(sourceVmr, vmRef, client) - if err != nil { - return err - } - err = config.UpdateConfig(vmRef, client) - if err != nil { - return err - } - time.Sleep(time.Duration(15) * time.Second) + config.FullClone = &fullClone + config.CIuser = comm.SSHUsername + config.Sshkeys = string(comm.SSHPublicKey) + sourceVmr, err := client.GetVmRefByName(c.CloneVM) + if err != nil { + return err + } + err = config.CloneVm(sourceVmr, vmRef, client) + if err != nil { + return err + } + err = config.UpdateConfig(vmRef, client) + if err != nil { + return err + } + time.Sleep(time.Duration(15) * time.Second) return nil } diff --git a/builder/proxmox/clone/config.go b/builder/proxmox/clone/config.go index d481d3c39..3b8d2d5c6 100644 --- a/builder/proxmox/clone/config.go +++ b/builder/proxmox/clone/config.go @@ -10,8 +10,8 @@ import ( type Config struct { proxmox.Config `mapstructure:",squash"` - CloneVM string `mapstructure:"clone_vm"` - FullClone bool `mapstructure:"full_clone"` + CloneVM string `mapstructure:"clone_vm"` + FullClone bool `mapstructure:"full_clone"` } func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { diff --git a/builder/proxmox/common/builder.go b/builder/proxmox/common/builder.go index 0ba157a63..74b44a883 100644 --- a/builder/proxmox/common/builder.go +++ b/builder/proxmox/common/builder.go @@ -19,7 +19,7 @@ func NewSharedBuilder(id string, config Config, preSteps []multistep.Step, postS config: config, preSteps: preSteps, postSteps: postSteps, - vmCreator: vmCreator, + vmCreator: vmCreator, } } @@ -30,7 +30,7 @@ type Builder struct { postSteps []multistep.Step runner multistep.Runner proxmoxClient *proxmox.Client - vmCreator ProxmoxVMCreator + vmCreator ProxmoxVMCreator } func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state multistep.StateBag) (packer.Artifact, error) { @@ -54,16 +54,16 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state state.Put("hook", hook) state.Put("ui", ui) - comm := &b.config.Comm - if(state.Get("comm") != nil) { - comm = state.Get("comm").(*communicator.Config) - } + comm := &b.config.Comm + if state.Get("comm") != nil { + comm = state.Get("comm").(*communicator.Config) + } // Build the steps coreSteps := []multistep.Step{ &stepStartVM{ - vmCreator: b.vmCreator, - }, + vmCreator: b.vmCreator, + }, &common.StepHTTPServer{ HTTPDir: b.config.HTTPDir, HTTPPortMin: b.config.HTTPPortMin, diff --git a/builder/proxmox/common/step_start_vm.go b/builder/proxmox/common/step_start_vm.go index 009cf5c35..5631dfa07 100644 --- a/builder/proxmox/common/step_start_vm.go +++ b/builder/proxmox/common/step_start_vm.go @@ -15,8 +15,8 @@ import ( // // It sets the vmRef state which is used throughout the later steps to reference the VM // in API calls. -type stepStartVM struct{ - vmCreator ProxmoxVMCreator +type stepStartVM struct { + vmCreator ProxmoxVMCreator } type ProxmoxVMCreator interface { From 681d0f8467357155ab17724b5aaea1a38fa6a2f1 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 11:59:47 -0700 Subject: [PATCH 06/24] Correct builder ID --- builder/proxmox/iso/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/proxmox/iso/builder.go b/builder/proxmox/iso/builder.go index 752f6c12a..4ae4569e7 100644 --- a/builder/proxmox/iso/builder.go +++ b/builder/proxmox/iso/builder.go @@ -12,7 +12,7 @@ import ( ) // The unique id for the builder -const BuilderID = "proxmox.clone" +const BuilderID = "proxmox.iso" type Builder struct { config Config From 018a1a5da09252602c0fe89628daaddb52527da1 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 12:15:07 -0700 Subject: [PATCH 07/24] Correct full clone logic --- builder/proxmox/clone/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index 7dfb906a8..981322634 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -57,7 +57,7 @@ func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQ comm := state.Get("comm").(*communicator.Config) fullClone := 1 - if c.FullClone { + if c.FullClone == false { fullClone = 0 } From f0c76bad521e666326782fb34f545341454b473c Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 12:22:18 -0700 Subject: [PATCH 08/24] DOCS: update docs navigation --- website/data/docs-navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/data/docs-navigation.js b/website/data/docs-navigation.js index 27b4feb97..d6a1a9ad6 100644 --- a/website/data/docs-navigation.js +++ b/website/data/docs-navigation.js @@ -209,7 +209,7 @@ export default [ }, { category: 'parallels', content: ['iso', 'pvm'] }, 'profitbricks', - 'proxmox', + { category: 'proxmox', content: ['iso', 'clone'] }, 'qemu', 'scaleway', 'tencentcloud-cvm', From 3c9969d8416e9173a77e2590f645729c6abca41b Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 12:49:38 -0700 Subject: [PATCH 09/24] cleanup goimports for linter --- builder/proxmox/clone/builder.go | 12 +++++------- builder/proxmox/clone/config.go | 2 +- builder/proxmox/iso/builder.go | 4 +--- builder/proxmox/iso/config.go | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index 981322634..2ba00e18e 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -1,16 +1,16 @@ package proxmoxclone import ( - "context" - "fmt" - "time" - proxmoxapi "github.com/Telmate/proxmox-api-go/proxmox" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/proxmox/common" + proxmox "github.com/hashicorp/packer/builder/proxmox/common" "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" + + "context" + "fmt" + "time" ) // The unique id for the builder @@ -23,8 +23,6 @@ type Builder struct { // Builder implements packer.Builder var _ packer.Builder = &Builder{} -var pluginVersion = "1.0.0" - func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { diff --git a/builder/proxmox/clone/config.go b/builder/proxmox/clone/config.go index 3b8d2d5c6..0fce27b4e 100644 --- a/builder/proxmox/clone/config.go +++ b/builder/proxmox/clone/config.go @@ -3,7 +3,7 @@ package proxmoxclone import ( - "github.com/hashicorp/packer/builder/proxmox/common" + proxmox "github.com/hashicorp/packer/builder/proxmox/common" "github.com/hashicorp/packer/packer" ) diff --git a/builder/proxmox/iso/builder.go b/builder/proxmox/iso/builder.go index 4ae4569e7..650e35ee3 100644 --- a/builder/proxmox/iso/builder.go +++ b/builder/proxmox/iso/builder.go @@ -5,7 +5,7 @@ import ( proxmoxapi "github.com/Telmate/proxmox-api-go/proxmox" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/proxmox/common" + proxmox "github.com/hashicorp/packer/builder/proxmox/common" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" @@ -21,8 +21,6 @@ type Builder struct { // Builder implements packer.Builder var _ packer.Builder = &Builder{} -var pluginVersion = "1.0.0" - func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { diff --git a/builder/proxmox/iso/config.go b/builder/proxmox/iso/config.go index 9346a24a0..65ab9ef92 100644 --- a/builder/proxmox/iso/config.go +++ b/builder/proxmox/iso/config.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/hashicorp/packer/builder/proxmox/common" + proxmox "github.com/hashicorp/packer/builder/proxmox/common" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/packer" ) From bac66b48a62bcd637a4c667cafce3e68898b6a17 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 13:03:30 -0700 Subject: [PATCH 10/24] Move proxmox website docs to iso --- website/pages/docs/builders/proxmox/{proxmox.mdx => iso.mdx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename website/pages/docs/builders/proxmox/{proxmox.mdx => iso.mdx} (100%) diff --git a/website/pages/docs/builders/proxmox/proxmox.mdx b/website/pages/docs/builders/proxmox/iso.mdx similarity index 100% rename from website/pages/docs/builders/proxmox/proxmox.mdx rename to website/pages/docs/builders/proxmox/iso.mdx From 5d15f5e2f4c0e8e90945ed23eaa0f6b35a38087d Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 14 Sep 2020 13:34:25 -0700 Subject: [PATCH 11/24] No longer need a 15 second sleep --- builder/proxmox/clone/builder.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index 2ba00e18e..0e21f05b6 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -10,7 +10,6 @@ import ( "context" "fmt" - "time" ) // The unique id for the builder @@ -74,6 +73,5 @@ func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQ if err != nil { return err } - time.Sleep(time.Duration(15) * time.Second) return nil } From 1260e123aa6b256a365e3fce62134af54d6487f8 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 6 Oct 2020 11:14:09 +0200 Subject: [PATCH 12/24] proxmox.Config: remove mapstructure:",squash" tag --- builder/proxmox/common/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/proxmox/common/config.go b/builder/proxmox/common/config.go index 8b4801310..64aeff961 100644 --- a/builder/proxmox/common/config.go +++ b/builder/proxmox/common/config.go @@ -63,7 +63,7 @@ type Config struct { AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"` VMInterface string `mapstructure:"vm_interface"` - Ctx interpolate.Context `mapstructure:",squash",mapstructure-to-hcl2:"skip"` + Ctx interpolate.Context `mapstructure-to-hcl2:"skip"` } type nicConfig struct { From 5b3ff89cb075c932ed0f5717711329d3fc3afe85 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 6 Oct 2020 11:42:49 +0200 Subject: [PATCH 13/24] proxmox: move iso.storageConfig to common.storageConfig --- builder/proxmox/clone/config.hcl2spec.go | 198 +++++++------- builder/proxmox/common/config.go | 12 +- builder/proxmox/common/config.hcl2spec.go | 237 +++++++++------- builder/proxmox/iso/builder.go | 4 +- builder/proxmox/iso/config.go | 21 +- builder/proxmox/iso/config.hcl2spec.go | 253 +++++++----------- .../iso/step_upload_additional_isos.go | 4 +- 7 files changed, 349 insertions(+), 380 deletions(-) diff --git a/builder/proxmox/clone/config.hcl2spec.go b/builder/proxmox/clone/config.hcl2spec.go index 99133765a..4c946c17f 100644 --- a/builder/proxmox/clone/config.hcl2spec.go +++ b/builder/proxmox/clone/config.hcl2spec.go @@ -10,102 +10,97 @@ import ( // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - 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"` - BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` - SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - Node *string `mapstructure:"node" cty:"node" hcl:"node"` - Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` - Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` - Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` - CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` - Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` - OS *string `mapstructure:"os" cty:"os" hcl:"os"` - VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` - NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` - Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` - Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` - SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` - Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` - DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` - TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` - TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` - CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` - CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` - Data interface{} `cty:"data" hcl:"data"` - Funcs map[string]interface{} `cty:"funcs" hcl:"funcs"` - UserVariables map[string]string `cty:"user_variables" hcl:"user_variables"` - SensitiveVariables []string `cty:"sensitive_variables" hcl:"sensitive_variables"` - EnableEnv *bool `cty:"enable_env" hcl:"enable_env"` - BuildName *string `cty:"build_name" hcl:"build_name"` - BuildType *string `cty:"build_type" hcl:"build_type"` - TemplatePath *string `cty:"template_path" hcl:"template_path"` - CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"` - FullClone *bool `mapstructure:"full_clone" cty:"full_clone" hcl:"full_clone"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` + HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` + HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` + 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"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` + SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` + Username *string `mapstructure:"username" cty:"username" hcl:"username"` + Password *string `mapstructure:"password" cty:"password" hcl:"password"` + Node *string `mapstructure:"node" cty:"node" hcl:"node"` + Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` + VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` + VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` + Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` + CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` + Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` + OS *string `mapstructure:"os" cty:"os" hcl:"os"` + VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` + NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` + Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` + Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` + SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` + Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` + DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` + TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` + CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` + CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` + AdditionalISOFiles []proxmox.FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` + VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"` + CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"` + FullClone *bool `mapstructure:"full_clone" cty:"full_clone" hcl:"full_clone"` } // FlatMapstructure returns a new FlatConfig. @@ -131,6 +126,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, + "http_interface": &hcldec.AttrSpec{Name: "http_interface", 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}, @@ -206,14 +202,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, - "data": &hcldec.AttrSpec{Name: "data", Type: cty.Bool, Required: false}, /* TODO(azr): could not find type */ - "funcs": &hcldec.AttrSpec{Name: "funcs", Type: cty.Map(cty.String), Required: false}, - "user_variables": &hcldec.AttrSpec{Name: "user_variables", Type: cty.Map(cty.String), Required: false}, - "sensitive_variables": &hcldec.AttrSpec{Name: "sensitive_variables", Type: cty.List(cty.String), Required: false}, - "enable_env": &hcldec.AttrSpec{Name: "enable_env", Type: cty.Bool, Required: false}, - "build_name": &hcldec.AttrSpec{Name: "build_name", Type: cty.String, Required: false}, - "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, - "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, + "additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*proxmox.FlatstorageConfig)(nil).HCL2Spec())}, + "vm_interface": &hcldec.AttrSpec{Name: "vm_interface", Type: cty.String, Required: false}, "clone_vm": &hcldec.AttrSpec{Name: "clone_vm", Type: cty.String, Required: false}, "full_clone": &hcldec.AttrSpec{Name: "full_clone", Type: cty.Bool, Required: false}, } diff --git a/builder/proxmox/common/config.go b/builder/proxmox/common/config.go index 64aeff961..2491d6b32 100644 --- a/builder/proxmox/common/config.go +++ b/builder/proxmox/common/config.go @@ -1,4 +1,4 @@ -//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig +//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig package proxmox @@ -66,6 +66,16 @@ type Config struct { Ctx interpolate.Context `mapstructure-to-hcl2:"skip"` } +type storageConfig struct { + common.ISOConfig `mapstructure:",squash"` + Device string `mapstructure:"device"` + ISOFile string `mapstructure:"iso_file"` + ISOStoragePool string `mapstructure:"iso_storage_pool"` + Unmount bool `mapstructure:"unmount"` + ShouldUploadISO bool + DownloadPathKey string +} + type nicConfig struct { Model string `mapstructure:"model"` PacketQueues int `mapstructure:"packet_queues"` diff --git a/builder/proxmox/common/config.hcl2spec.go b/builder/proxmox/common/config.hcl2spec.go index 973eb7158..36176030e 100644 --- a/builder/proxmox/common/config.hcl2spec.go +++ b/builder/proxmox/common/config.hcl2spec.go @@ -1,4 +1,4 @@ -// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig"; DO NOT EDIT. +// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig"; DO NOT EDIT. package proxmox import ( @@ -9,100 +9,95 @@ import ( // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - 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"` - BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` - SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - Node *string `mapstructure:"node" cty:"node" hcl:"node"` - Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` - Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` - Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` - CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` - Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` - OS *string `mapstructure:"os" cty:"os" hcl:"os"` - VGA *FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` - NICs []FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` - Disks []FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` - Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` - SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` - Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` - DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` - TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` - TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` - CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` - CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` - Data interface{} `cty:"data" hcl:"data"` - Funcs map[string]interface{} `cty:"funcs" hcl:"funcs"` - UserVariables map[string]string `cty:"user_variables" hcl:"user_variables"` - SensitiveVariables []string `cty:"sensitive_variables" hcl:"sensitive_variables"` - EnableEnv *bool `cty:"enable_env" hcl:"enable_env"` - BuildName *string `cty:"build_name" hcl:"build_name"` - BuildType *string `cty:"build_type" hcl:"build_type"` - TemplatePath *string `cty:"template_path" hcl:"template_path"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` + HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` + HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` + 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"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` + SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` + Username *string `mapstructure:"username" cty:"username" hcl:"username"` + Password *string `mapstructure:"password" cty:"password" hcl:"password"` + Node *string `mapstructure:"node" cty:"node" hcl:"node"` + Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` + VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` + VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` + Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` + CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` + Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` + OS *string `mapstructure:"os" cty:"os" hcl:"os"` + VGA *FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` + NICs []FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` + Disks []FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` + Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` + SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` + Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` + DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` + TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` + CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` + CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` + AdditionalISOFiles []FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` + VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"` } // FlatMapstructure returns a new FlatConfig. @@ -128,6 +123,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, + "http_interface": &hcldec.AttrSpec{Name: "http_interface", 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}, @@ -203,14 +199,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, - "data": &hcldec.AttrSpec{Name: "data", Type: cty.Bool, Required: false}, /* TODO(azr): could not find type */ - "funcs": &hcldec.AttrSpec{Name: "funcs", Type: cty.Map(cty.String), Required: false}, - "user_variables": &hcldec.AttrSpec{Name: "user_variables", Type: cty.Map(cty.String), Required: false}, - "sensitive_variables": &hcldec.AttrSpec{Name: "sensitive_variables", Type: cty.List(cty.String), Required: false}, - "enable_env": &hcldec.AttrSpec{Name: "enable_env", Type: cty.Bool, Required: false}, - "build_name": &hcldec.AttrSpec{Name: "build_name", Type: cty.String, Required: false}, - "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, - "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, + "additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*FlatstorageConfig)(nil).HCL2Spec())}, + "vm_interface": &hcldec.AttrSpec{Name: "vm_interface", Type: cty.String, Required: false}, } return s } @@ -224,6 +214,7 @@ type FlatdiskConfig struct { Size *string `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"` CacheMode *string `mapstructure:"cache_mode" cty:"cache_mode" hcl:"cache_mode"` DiskFormat *string `mapstructure:"format" cty:"format" hcl:"format"` + IOThread *bool `mapstructure:"io_thread" cty:"io_thread" hcl:"io_thread"` } // FlatMapstructure returns a new FlatdiskConfig. @@ -244,6 +235,7 @@ func (*FlatdiskConfig) HCL2Spec() map[string]hcldec.Spec { "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.String, Required: false}, "cache_mode": &hcldec.AttrSpec{Name: "cache_mode", Type: cty.String, Required: false}, "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, + "io_thread": &hcldec.AttrSpec{Name: "io_thread", Type: cty.Bool, Required: false}, } return s } @@ -281,6 +273,45 @@ func (*FlatnicConfig) HCL2Spec() map[string]hcldec.Spec { return s } +// FlatstorageConfig is an auto-generated flat version of storageConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatstorageConfig struct { + ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` + RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` + ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` + TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` + TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` + Device *string `mapstructure:"device" cty:"device" hcl:"device"` + ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` + ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` + Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"` +} + +// FlatMapstructure returns a new FlatstorageConfig. +// FlatstorageConfig is an auto-generated flat version of storageConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*storageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatstorageConfig) +} + +// HCL2Spec returns the hcl spec of a storageConfig. +// This spec is used by HCL to read the fields of storageConfig. +// The decoded values from this spec will then be applied to a FlatstorageConfig. +func (*FlatstorageConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, + "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, + "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, + "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, + "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, + "device": &hcldec.AttrSpec{Name: "device", Type: cty.String, Required: false}, + "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, + "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, + "unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false}, + } + return s +} + // FlatvgaConfig is an auto-generated flat version of vgaConfig. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatvgaConfig struct { diff --git a/builder/proxmox/iso/builder.go b/builder/proxmox/iso/builder.go index 650e35ee3..3c7fb960b 100644 --- a/builder/proxmox/iso/builder.go +++ b/builder/proxmox/iso/builder.go @@ -48,8 +48,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack Checksum: b.config.AdditionalISOFiles[idx].ISOChecksum, Description: "additional ISO", Extension: b.config.AdditionalISOFiles[idx].TargetExtension, - ResultKey: b.config.AdditionalISOFiles[idx].downloadPathKey, - TargetPath: b.config.AdditionalISOFiles[idx].downloadPathKey, + ResultKey: b.config.AdditionalISOFiles[idx].DownloadPathKey, + TargetPath: b.config.AdditionalISOFiles[idx].DownloadPathKey, Url: b.config.AdditionalISOFiles[idx].ISOUrls, }) } diff --git a/builder/proxmox/iso/config.go b/builder/proxmox/iso/config.go index 65ab9ef92..a04c41c05 100644 --- a/builder/proxmox/iso/config.go +++ b/builder/proxmox/iso/config.go @@ -1,4 +1,4 @@ -//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig +//go:generate mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig package proxmoxiso @@ -17,22 +17,11 @@ import ( type Config struct { proxmox.Config `mapstructure:",squash"` - common.ISOConfig `mapstructure:",squash"` - ISOFile string `mapstructure:"iso_file"` - AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"` - ISOStoragePool string `mapstructure:"iso_storage_pool"` - UnmountISO bool `mapstructure:"unmount_iso"` - shouldUploadISO bool -} - -type storageConfig struct { common.ISOConfig `mapstructure:",squash"` - Device string `mapstructure:"device"` ISOFile string `mapstructure:"iso_file"` ISOStoragePool string `mapstructure:"iso_storage_pool"` - Unmount bool `mapstructure:"unmount"` + UnmountISO bool `mapstructure:"unmount_iso"` shouldUploadISO bool - downloadPathKey string } func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { @@ -68,13 +57,13 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { // (possibly to a local file) to an ISO file that will be downloaded and // then uploaded to Proxmox. if c.AdditionalISOFiles[idx].ISOFile != "" { - c.AdditionalISOFiles[idx].shouldUploadISO = false + c.AdditionalISOFiles[idx].ShouldUploadISO = false } else { - c.AdditionalISOFiles[idx].downloadPathKey = "downloaded_additional_iso_path_" + strconv.Itoa(idx) + c.AdditionalISOFiles[idx].DownloadPathKey = "downloaded_additional_iso_path_" + strconv.Itoa(idx) isoWarnings, isoErrors := c.AdditionalISOFiles[idx].ISOConfig.Prepare(&c.Ctx) errs = packer.MultiErrorAppend(errs, isoErrors...) warnings = append(warnings, isoWarnings...) - c.AdditionalISOFiles[idx].shouldUploadISO = true + c.AdditionalISOFiles[idx].ShouldUploadISO = true } if c.AdditionalISOFiles[idx].Device == "" { log.Printf("AdditionalISOFile %d Device not set, using default 'ide3'", idx) diff --git a/builder/proxmox/iso/config.hcl2spec.go b/builder/proxmox/iso/config.hcl2spec.go index 2616baf91..391d0a106 100644 --- a/builder/proxmox/iso/config.hcl2spec.go +++ b/builder/proxmox/iso/config.hcl2spec.go @@ -1,4 +1,4 @@ -// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig,storageConfig"; DO NOT EDIT. +// Code generated by "mapstructure-to-hcl2 -type Config,nicConfig,diskConfig,vgaConfig"; DO NOT EDIT. package proxmoxiso import ( @@ -10,109 +10,103 @@ import ( // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - 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"` - BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` - SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - Node *string `mapstructure:"node" cty:"node" hcl:"node"` - Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` - Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` - Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` - CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` - Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` - OS *string `mapstructure:"os" cty:"os" hcl:"os"` - VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` - NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` - Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` - Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` - SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` - Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` - DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` - TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` - TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` - CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` - CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` - Data interface{} `cty:"data" hcl:"data"` - Funcs map[string]interface{} `cty:"funcs" hcl:"funcs"` - UserVariables map[string]string `cty:"user_variables" hcl:"user_variables"` - SensitiveVariables []string `cty:"sensitive_variables" hcl:"sensitive_variables"` - EnableEnv *bool `cty:"enable_env" hcl:"enable_env"` - BuildName *string `cty:"build_name" hcl:"build_name"` - BuildType *string `cty:"build_type" hcl:"build_type"` - TemplatePath *string `cty:"template_path" hcl:"template_path"` - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` - AdditionalISOFiles []FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` - ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` - UnmountISO *bool `mapstructure:"unmount_iso" cty:"unmount_iso" hcl:"unmount_iso"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` + HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` + HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` + 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"` + BootKeyInterval *string `mapstructure:"boot_key_interval" cty:"boot_key_interval" hcl:"boot_key_interval"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + ProxmoxURLRaw *string `mapstructure:"proxmox_url" cty:"proxmox_url" hcl:"proxmox_url"` + SkipCertValidation *bool `mapstructure:"insecure_skip_tls_verify" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` + Username *string `mapstructure:"username" cty:"username" hcl:"username"` + Password *string `mapstructure:"password" cty:"password" hcl:"password"` + Node *string `mapstructure:"node" cty:"node" hcl:"node"` + Pool *string `mapstructure:"pool" cty:"pool" hcl:"pool"` + VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` + VMID *int `mapstructure:"vm_id" cty:"vm_id" hcl:"vm_id"` + Memory *int `mapstructure:"memory" cty:"memory" hcl:"memory"` + Cores *int `mapstructure:"cores" cty:"cores" hcl:"cores"` + CPUType *string `mapstructure:"cpu_type" cty:"cpu_type" hcl:"cpu_type"` + Sockets *int `mapstructure:"sockets" cty:"sockets" hcl:"sockets"` + OS *string `mapstructure:"os" cty:"os" hcl:"os"` + VGA *proxmox.FlatvgaConfig `mapstructure:"vga" cty:"vga" hcl:"vga"` + NICs []proxmox.FlatnicConfig `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` + Disks []proxmox.FlatdiskConfig `mapstructure:"disks" cty:"disks" hcl:"disks"` + Agent *bool `mapstructure:"qemu_agent" cty:"qemu_agent" hcl:"qemu_agent"` + SCSIController *string `mapstructure:"scsi_controller" cty:"scsi_controller" hcl:"scsi_controller"` + Onboot *bool `mapstructure:"onboot" cty:"onboot" hcl:"onboot"` + DisableKVM *bool `mapstructure:"disable_kvm" cty:"disable_kvm" hcl:"disable_kvm"` + TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"` + CloudInit *bool `mapstructure:"cloud_init" cty:"cloud_init" hcl:"cloud_init"` + CloudInitStoragePool *string `mapstructure:"cloud_init_storage_pool" cty:"cloud_init_storage_pool" hcl:"cloud_init_storage_pool"` + AdditionalISOFiles []proxmox.FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` + VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"` + ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` + RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` + ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` + TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` + TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` + ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` + ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` + UnmountISO *bool `mapstructure:"unmount_iso" cty:"unmount_iso" hcl:"unmount_iso"` } // FlatMapstructure returns a new FlatConfig. @@ -138,6 +132,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, + "http_interface": &hcldec.AttrSpec{Name: "http_interface", 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}, @@ -213,62 +208,16 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false}, "cloud_init": &hcldec.AttrSpec{Name: "cloud_init", Type: cty.Bool, Required: false}, "cloud_init_storage_pool": &hcldec.AttrSpec{Name: "cloud_init_storage_pool", Type: cty.String, Required: false}, - "data": &hcldec.AttrSpec{Name: "data", Type: cty.Bool, Required: false}, /* TODO(azr): could not find type */ - "funcs": &hcldec.AttrSpec{Name: "funcs", Type: cty.Map(cty.String), Required: false}, - "user_variables": &hcldec.AttrSpec{Name: "user_variables", Type: cty.Map(cty.String), Required: false}, - "sensitive_variables": &hcldec.AttrSpec{Name: "sensitive_variables", Type: cty.List(cty.String), Required: false}, - "enable_env": &hcldec.AttrSpec{Name: "enable_env", Type: cty.Bool, Required: false}, - "build_name": &hcldec.AttrSpec{Name: "build_name", Type: cty.String, Required: false}, - "build_type": &hcldec.AttrSpec{Name: "build_type", Type: cty.String, Required: false}, - "template_path": &hcldec.AttrSpec{Name: "template_path", Type: cty.String, Required: false}, + "additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*proxmox.FlatstorageConfig)(nil).HCL2Spec())}, + "vm_interface": &hcldec.AttrSpec{Name: "vm_interface", Type: cty.String, Required: false}, "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, - "additional_iso_files": &hcldec.BlockListSpec{TypeName: "additional_iso_files", Nested: hcldec.ObjectSpec((*FlatstorageConfig)(nil).HCL2Spec())}, "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, "unmount_iso": &hcldec.AttrSpec{Name: "unmount_iso", Type: cty.Bool, Required: false}, } return s } - -// FlatstorageConfig is an auto-generated flat version of storageConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatstorageConfig struct { - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - Device *string `mapstructure:"device" cty:"device" hcl:"device"` - ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` - ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` - Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"` -} - -// FlatMapstructure returns a new FlatstorageConfig. -// FlatstorageConfig is an auto-generated flat version of storageConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*storageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatstorageConfig) -} - -// HCL2Spec returns the hcl spec of a storageConfig. -// This spec is used by HCL to read the fields of storageConfig. -// The decoded values from this spec will then be applied to a FlatstorageConfig. -func (*FlatstorageConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, - "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, - "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, - "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, - "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, - "device": &hcldec.AttrSpec{Name: "device", Type: cty.String, Required: false}, - "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, - "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, - "unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/proxmox/iso/step_upload_additional_isos.go b/builder/proxmox/iso/step_upload_additional_isos.go index c6e808ffc..f23b949be 100644 --- a/builder/proxmox/iso/step_upload_additional_isos.go +++ b/builder/proxmox/iso/step_upload_additional_isos.go @@ -23,12 +23,12 @@ func (s *stepUploadAdditionalISOs) Run(ctx context.Context, state multistep.Stat c := state.Get("iso-config").(*Config) for idx := range c.AdditionalISOFiles { - if !c.AdditionalISOFiles[idx].shouldUploadISO { + if !c.AdditionalISOFiles[idx].ShouldUploadISO { state.Put("additional_iso_files", c.AdditionalISOFiles) continue } - p := state.Get(c.AdditionalISOFiles[idx].downloadPathKey).(string) + p := state.Get(c.AdditionalISOFiles[idx].DownloadPathKey).(string) if p == "" { err := fmt.Errorf("Path to downloaded ISO was empty") state.Put("erroe", err) From 25d7e7ce17693493b4e75a58afe81348bd9420c1 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 6 Oct 2020 11:48:24 +0200 Subject: [PATCH 14/24] fix tests --- builder/proxmox/iso/config_test.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/builder/proxmox/iso/config_test.go b/builder/proxmox/iso/config_test.go index f9b575fc8..c1de47b64 100644 --- a/builder/proxmox/iso/config_test.go +++ b/builder/proxmox/iso/config_test.go @@ -116,7 +116,7 @@ func TestAgentSetToFalse(t *testing.T) { cfg["qemu_agent"] = false var c Config - warn, err := c.Prepare(cfg) + _, warn, err := c.Prepare(cfg) if err != nil { t.Fatal(err, warn) } @@ -159,7 +159,7 @@ func TestPacketQueueSupportForNetworkAdapters(t *testing.T) { cfg["network_adapters"] = devices var c Config - _, err := c.Prepare(cfg) + _, _, err := c.Prepare(cfg) if tt.expectedToFail == true && err == nil { t.Error("expected config preparation to fail, but no error occured") @@ -208,7 +208,7 @@ func TestHardDiskControllerIOThreadSupport(t *testing.T) { cfg["scsi_controller"] = tt.controller var c Config - _, err := c.Prepare(cfg) + _, _, err := c.Prepare(cfg) if tt.expectedToFail == true && err == nil { t.Error("expected config preparation to fail, but no error occured") @@ -219,3 +219,13 @@ func TestHardDiskControllerIOThreadSupport(t *testing.T) { } } } + +func mandatoryConfig(t *testing.T) map[string]interface{} { + return map[string]interface{}{ + "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json", + "username": "apiuser@pve", + "password": "supersecret", + "node": "my-proxmox", + "ssh_username": "root", + } +} From f6d362d392f99aa2dcec29ddd61846014e56614b Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 6 Oct 2020 11:54:04 +0200 Subject: [PATCH 15/24] skip Ctx --- builder/proxmox/common/config.go | 2 +- builder/proxmox/common/config.hcl2spec.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/builder/proxmox/common/config.go b/builder/proxmox/common/config.go index 2491d6b32..f4a7f7801 100644 --- a/builder/proxmox/common/config.go +++ b/builder/proxmox/common/config.go @@ -63,7 +63,7 @@ type Config struct { AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"` VMInterface string `mapstructure:"vm_interface"` - Ctx interpolate.Context `mapstructure-to-hcl2:"skip"` + Ctx interpolate.Context `mapstructure-to-hcl2:",skip"` } type storageConfig struct { diff --git a/builder/proxmox/common/config.hcl2spec.go b/builder/proxmox/common/config.hcl2spec.go index 36176030e..2cc292dbd 100644 --- a/builder/proxmox/common/config.hcl2spec.go +++ b/builder/proxmox/common/config.hcl2spec.go @@ -285,6 +285,8 @@ type FlatstorageConfig struct { ISOFile *string `mapstructure:"iso_file" cty:"iso_file" hcl:"iso_file"` ISOStoragePool *string `mapstructure:"iso_storage_pool" cty:"iso_storage_pool" hcl:"iso_storage_pool"` Unmount *bool `mapstructure:"unmount" cty:"unmount" hcl:"unmount"` + ShouldUploadISO *bool `cty:"should_upload_iso" hcl:"should_upload_iso"` + DownloadPathKey *string `cty:"download_path_key" hcl:"download_path_key"` } // FlatMapstructure returns a new FlatstorageConfig. @@ -308,6 +310,8 @@ func (*FlatstorageConfig) HCL2Spec() map[string]hcldec.Spec { "iso_file": &hcldec.AttrSpec{Name: "iso_file", Type: cty.String, Required: false}, "iso_storage_pool": &hcldec.AttrSpec{Name: "iso_storage_pool", Type: cty.String, Required: false}, "unmount": &hcldec.AttrSpec{Name: "unmount", Type: cty.Bool, Required: false}, + "should_upload_iso": &hcldec.AttrSpec{Name: "should_upload_iso", Type: cty.Bool, Required: false}, + "download_path_key": &hcldec.AttrSpec{Name: "download_path_key", Type: cty.String, Required: false}, } return s } From a26e3e6887b89a57d1e5755735ff3cac8fa4a8d3 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Tue, 6 Oct 2020 16:04:18 -0700 Subject: [PATCH 16/24] [Proxmox] FIX: tests, add required iso_file to basic iso config tests --- builder/proxmox/common/config.go | 2 -- builder/proxmox/iso/config_test.go | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/builder/proxmox/common/config.go b/builder/proxmox/common/config.go index f4a7f7801..1428345f9 100644 --- a/builder/proxmox/common/config.go +++ b/builder/proxmox/common/config.go @@ -58,8 +58,6 @@ type Config struct { CloudInit bool `mapstructure:"cloud_init"` CloudInitStoragePool string `mapstructure:"cloud_init_storage_pool"` - shouldUploadISO bool - AdditionalISOFiles []storageConfig `mapstructure:"additional_iso_files"` VMInterface string `mapstructure:"vm_interface"` diff --git a/builder/proxmox/iso/config_test.go b/builder/proxmox/iso/config_test.go index c1de47b64..8164d02f6 100644 --- a/builder/proxmox/iso/config_test.go +++ b/builder/proxmox/iso/config_test.go @@ -227,5 +227,6 @@ func mandatoryConfig(t *testing.T) map[string]interface{} { "password": "supersecret", "node": "my-proxmox", "ssh_username": "root", + "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso", } } From 977022fb358960b2ec54555a3416774faff7ad75 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Tue, 6 Oct 2020 16:53:29 -0700 Subject: [PATCH 17/24] Go format --- builder/proxmox/iso/config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/proxmox/iso/config_test.go b/builder/proxmox/iso/config_test.go index 8164d02f6..fe519a05b 100644 --- a/builder/proxmox/iso/config_test.go +++ b/builder/proxmox/iso/config_test.go @@ -227,6 +227,6 @@ func mandatoryConfig(t *testing.T) map[string]interface{} { "password": "supersecret", "node": "my-proxmox", "ssh_username": "root", - "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso", + "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso", } } From fdda18e392a0816a6d9839e39eff3f4e95a3d3ea Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Tue, 6 Oct 2020 17:24:45 -0700 Subject: [PATCH 18/24] Use Trilean for boolean value, and allow for missing values for defaults --- builder/proxmox/clone/builder.go | 2 +- builder/proxmox/clone/config.go | 5 +++-- builder/proxmox/clone/config.hcl2spec.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index 0e21f05b6..8f088f81d 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -54,7 +54,7 @@ func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQ comm := state.Get("comm").(*communicator.Config) fullClone := 1 - if c.FullClone == false { + if c.FullClone.False() { fullClone = 0 } diff --git a/builder/proxmox/clone/config.go b/builder/proxmox/clone/config.go index 0fce27b4e..e9a8721d6 100644 --- a/builder/proxmox/clone/config.go +++ b/builder/proxmox/clone/config.go @@ -4,14 +4,15 @@ package proxmoxclone import ( proxmox "github.com/hashicorp/packer/builder/proxmox/common" + "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/packer" ) type Config struct { proxmox.Config `mapstructure:",squash"` - CloneVM string `mapstructure:"clone_vm"` - FullClone bool `mapstructure:"full_clone"` + CloneVM string `mapstructure:"clone_vm"` + FullClone config.Trilean `mapstructure:"full_clone" required:"false"` } func (c *Config) Prepare(raws ...interface{}) ([]string, []string, error) { diff --git a/builder/proxmox/clone/config.hcl2spec.go b/builder/proxmox/clone/config.hcl2spec.go index 4c946c17f..879549542 100644 --- a/builder/proxmox/clone/config.hcl2spec.go +++ b/builder/proxmox/clone/config.hcl2spec.go @@ -100,7 +100,7 @@ type FlatConfig struct { AdditionalISOFiles []proxmox.FlatstorageConfig `mapstructure:"additional_iso_files" cty:"additional_iso_files" hcl:"additional_iso_files"` VMInterface *string `mapstructure:"vm_interface" cty:"vm_interface" hcl:"vm_interface"` CloneVM *string `mapstructure:"clone_vm" cty:"clone_vm" hcl:"clone_vm"` - FullClone *bool `mapstructure:"full_clone" cty:"full_clone" hcl:"full_clone"` + FullClone *bool `mapstructure:"full_clone" required:"false" cty:"full_clone" hcl:"full_clone"` } // FlatMapstructure returns a new FlatConfig. From cd3bdc9e38f934346b1fb62582ba2c2834779f42 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Tue, 6 Oct 2020 22:44:05 -0700 Subject: [PATCH 19/24] REFACTOR: do not pass comm ref through statebag --- builder/proxmox/clone/builder.go | 5 +--- builder/proxmox/clone/step_ssh_key_pair.go | 30 +++++++++++----------- builder/proxmox/common/builder.go | 3 --- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/builder/proxmox/clone/builder.go b/builder/proxmox/clone/builder.go index 8f088f81d..178f73587 100644 --- a/builder/proxmox/clone/builder.go +++ b/builder/proxmox/clone/builder.go @@ -4,7 +4,6 @@ import ( proxmoxapi "github.com/Telmate/proxmox-api-go/proxmox" "github.com/hashicorp/hcl/v2/hcldec" proxmox "github.com/hashicorp/packer/builder/proxmox/common" - "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" @@ -31,13 +30,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) { state := new(multistep.BasicStateBag) state.Put("clone-config", &b.config) - state.Put("comm", &b.config.Comm) preSteps := []multistep.Step{ &StepSshKeyPair{ Debug: b.config.PackerDebug, DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName), - Comm: &b.config.Comm, }, } postSteps := []multistep.Step{} @@ -51,7 +48,7 @@ type cloneVMCreator struct{} func (*cloneVMCreator) Create(vmRef *proxmoxapi.VmRef, config proxmoxapi.ConfigQemu, state multistep.StateBag) error { client := state.Get("proxmoxClient").(*proxmoxapi.Client) c := state.Get("clone-config").(*Config) - comm := state.Get("comm").(*communicator.Config) + comm := state.Get("config").(*proxmox.Config).Comm fullClone := 1 if c.FullClone.False() { diff --git a/builder/proxmox/clone/step_ssh_key_pair.go b/builder/proxmox/clone/step_ssh_key_pair.go index 96e97d5a8..2aad603bb 100644 --- a/builder/proxmox/clone/step_ssh_key_pair.go +++ b/builder/proxmox/clone/step_ssh_key_pair.go @@ -5,8 +5,8 @@ import ( "fmt" "os" + common "github.com/hashicorp/packer/builder/proxmox/common" "github.com/hashicorp/packer/common/uuid" - "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/ssh" "github.com/hashicorp/packer/packer" @@ -17,19 +17,19 @@ import ( type StepSshKeyPair struct { Debug bool DebugKeyPath string - Comm *communicator.Config } func (s *StepSshKeyPair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) + c := state.Get("config").(*common.Config) - if s.Comm.SSHPassword != "" { + if c.Comm.SSHPassword != "" { return multistep.ActionContinue } - if s.Comm.SSHPrivateKeyFile != "" { + if c.Comm.SSHPrivateKeyFile != "" { ui.Say("Using existing SSH private key for the communicator...") - privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile() + privateKeyBytes, err := c.Comm.ReadSSHPrivateKeyFile() if err != nil { state.Put("error", err) return multistep.ActionHalt @@ -44,15 +44,15 @@ func (s *StepSshKeyPair) Run(ctx context.Context, state multistep.StateBag) mult return multistep.ActionHalt } - s.Comm.SSHPrivateKey = privateKeyBytes - s.Comm.SSHKeyPairName = kp.Comment - s.Comm.SSHTemporaryKeyPairName = kp.Comment - s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine + c.Comm.SSHPrivateKey = privateKeyBytes + c.Comm.SSHKeyPairName = kp.Comment + c.Comm.SSHTemporaryKeyPairName = kp.Comment + c.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine return multistep.ActionContinue } - if s.Comm.SSHAgentAuth { + if c.Comm.SSHAgentAuth { ui.Say("Using local SSH Agent to authenticate connections for the communicator...") return multistep.ActionContinue } @@ -67,11 +67,11 @@ func (s *StepSshKeyPair) Run(ctx context.Context, state multistep.StateBag) mult return multistep.ActionHalt } - s.Comm.SSHKeyPairName = kp.Comment - s.Comm.SSHTemporaryKeyPairName = kp.Comment - s.Comm.SSHPrivateKey = kp.PrivateKeyPemBlock - s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine - s.Comm.SSHClearAuthorizedKeys = true + c.Comm.SSHKeyPairName = kp.Comment + c.Comm.SSHTemporaryKeyPairName = kp.Comment + c.Comm.SSHPrivateKey = kp.PrivateKeyPemBlock + c.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine + c.Comm.SSHClearAuthorizedKeys = true ui.Say("Created ephemeral SSH key pair for communicator") diff --git a/builder/proxmox/common/builder.go b/builder/proxmox/common/builder.go index 1d33249b7..a4b407520 100644 --- a/builder/proxmox/common/builder.go +++ b/builder/proxmox/common/builder.go @@ -55,9 +55,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook, state state.Put("ui", ui) comm := &b.config.Comm - if state.Get("comm") != nil { - comm = state.Get("comm").(*communicator.Config) - } // Build the steps coreSteps := []multistep.Step{ From 3e0633fc20503cef67892d2cc13a8b4c2468927c Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 7 Oct 2020 11:43:15 +0200 Subject: [PATCH 20/24] scripts/generate-plugins.go: ignore "common" packages --- command/plugin.go | 1 - scripts/generate-plugins.go | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/command/plugin.go b/command/plugin.go index 38adb929c..e32fba0d0 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -148,7 +148,6 @@ var Builders = map[string]packer.Builder{ "profitbricks": new(profitbricksbuilder.Builder), "proxmox-clone": new(proxmoxclonebuilder.Builder), "proxmox-iso": new(proxmoxisobuilder.Builder), - "proxmox": new(proxmoxisobuilder.Builder), "qemu": new(qemubuilder.Builder), "scaleway": new(scalewaybuilder.Builder), "tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder), diff --git a/scripts/generate-plugins.go b/scripts/generate-plugins.go index 9b79e3ee2..8fe8feddd 100644 --- a/scripts/generate-plugins.go +++ b/scripts/generate-plugins.go @@ -136,15 +136,17 @@ func listDirectories(path string) ([]string, error) { for _, item := range items { // We only want directories - if item.IsDir() { - currentDir := filepath.Join(path, item.Name()) - names = append(names, currentDir) + if !item.IsDir() || + item.Name() == "common" { + continue + } + currentDir := filepath.Join(path, item.Name()) + names = append(names, currentDir) - // Do some recursion - subNames, err := listDirectories(currentDir) - if err == nil { - names = append(names, subNames...) - } + // Do some recursion + subNames, err := listDirectories(currentDir) + if err == nil { + names = append(names, subNames...) } } From a140c139435f305bb9b296ccff25b4a58c4e2114 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Wed, 7 Oct 2020 23:43:12 -0700 Subject: [PATCH 21/24] [proxmox] add proxmox builder alias Adds an alias for `proxmox` that points to proxmox-iso builder for backwards compatibility --- builder/proxmox/builder.go | 7 +++++++ command/plugin.go | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 builder/proxmox/builder.go diff --git a/builder/proxmox/builder.go b/builder/proxmox/builder.go new file mode 100644 index 000000000..2366cd6a9 --- /dev/null +++ b/builder/proxmox/builder.go @@ -0,0 +1,7 @@ +package proxmox + +import ( + "github.com/hashicorp/packer/builder/proxmox/iso" +) + +type Builder = proxmoxiso.Builder diff --git a/command/plugin.go b/command/plugin.go index e32fba0d0..b3bf09bc7 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -48,6 +48,7 @@ import ( parallelsisobuilder "github.com/hashicorp/packer/builder/parallels/iso" parallelspvmbuilder "github.com/hashicorp/packer/builder/parallels/pvm" profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks" + proxmoxbuilder "github.com/hashicorp/packer/builder/proxmox" proxmoxclonebuilder "github.com/hashicorp/packer/builder/proxmox/clone" proxmoxisobuilder "github.com/hashicorp/packer/builder/proxmox/iso" qemubuilder "github.com/hashicorp/packer/builder/qemu" @@ -146,6 +147,7 @@ var Builders = map[string]packer.Builder{ "parallels-iso": new(parallelsisobuilder.Builder), "parallels-pvm": new(parallelspvmbuilder.Builder), "profitbricks": new(profitbricksbuilder.Builder), + "proxmox": new(proxmoxbuilder.Builder), "proxmox-clone": new(proxmoxclonebuilder.Builder), "proxmox-iso": new(proxmoxisobuilder.Builder), "qemu": new(qemubuilder.Builder), From 93531b3ec527a8318f723ce10d725298ce21b83d Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Thu, 8 Oct 2020 00:04:43 -0700 Subject: [PATCH 22/24] [proxmox] Adds proxmox fixer and fixer test Add fixer for proxmox to proxmox-iso. Updated gofmt. --- builder/proxmox/builder.go | 2 +- fix/fixer_proxmox_type.go | 49 +++++++++++++++++++++++ fix/fixer_proxmox_type_test.go | 73 ++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 fix/fixer_proxmox_type.go create mode 100644 fix/fixer_proxmox_type_test.go diff --git a/builder/proxmox/builder.go b/builder/proxmox/builder.go index 2366cd6a9..bef6ea4b9 100644 --- a/builder/proxmox/builder.go +++ b/builder/proxmox/builder.go @@ -4,4 +4,4 @@ import ( "github.com/hashicorp/packer/builder/proxmox/iso" ) -type Builder = proxmoxiso.Builder +type Builder = proxmoxiso.Builder diff --git a/fix/fixer_proxmox_type.go b/fix/fixer_proxmox_type.go new file mode 100644 index 000000000..e1faf8bcf --- /dev/null +++ b/fix/fixer_proxmox_type.go @@ -0,0 +1,49 @@ +package fix + +import ( + "github.com/mitchellh/mapstructure" +) + +// FixerProxmoxType updates proxmox builder types to proxmox-iso +type FixerProxmoxType struct{} + +func (FixerProxmoxType) DeprecatedOptions() []string { + return []string{} +} + +func (FixerProxmoxType) Fix(input map[string]interface{}) (map[string]interface{}, error) { + type template struct { + Builders []map[string]interface{} + } + + // Decode the input into our structure, if we can + var tpl template + if err := mapstructure.Decode(input, &tpl); err != nil { + return nil, err + } + + for _, builder := range tpl.Builders { + builderTypeRaw, ok := builder["type"] + if !ok { + continue + } + + builderType, ok := builderTypeRaw.(string) + if !ok { + continue + } + + if builderType != "proxmox" { + continue + } + + builder["type"] = "proxmox-iso" + } + + input["builders"] = tpl.Builders + return input, nil +} + +func (FixerProxmoxType) Synopsis() string { + return `Updates the builder type proxmox to proxmox-iso` +} diff --git a/fix/fixer_proxmox_type_test.go b/fix/fixer_proxmox_type_test.go new file mode 100644 index 000000000..c66ab25bb --- /dev/null +++ b/fix/fixer_proxmox_type_test.go @@ -0,0 +1,73 @@ +package fix + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFixerProxmoxType_Impl(t *testing.T) { + var raw interface{} + raw = new(FixerProxmoxType) + if _, ok := raw.(Fixer); !ok { + t.Fatalf("must be a Fixer") + } +} + +func TestFixerProxmoxType_Fix(t *testing.T) { + + cases := []struct { + Input map[string]interface{} + Expected map[string]interface{} + }{ + + { + Input: map[string]interface{}{ + "type": "proxmox", + }, + + Expected: map[string]interface{}{ + "type": "proxmox-iso", + }, + }, + + { + Input: map[string]interface{}{ + "type": "proxmox-iso", + }, + + Expected: map[string]interface{}{ + "type": "proxmox-iso", + }, + }, + + { + Input: map[string]interface{}{ + "type": "proxmox-clone", + }, + + Expected: map[string]interface{}{ + "type": "proxmox-clone", + }, + }, + } + + for _, tc := range cases { + var f FixerProxmoxType + + input := map[string]interface{}{ + "builders": []map[string]interface{}{tc.Input}, + } + + expected := map[string]interface{}{ + "builders": []map[string]interface{}{tc.Expected}, + } + + output, err := f.Fix(input) + if err != nil { + t.Fatalf("err: %s", err) + } + + assert.Equal(t, expected, output, "Should be equal") + } +} From a35eda70d8c52883eee8a8f0f8021eb4e296f336 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Sun, 11 Oct 2020 11:39:24 -0700 Subject: [PATCH 23/24] Add proxmox fixer --- fix/fixer.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fix/fixer.go b/fix/fixer.go index d77c23152..82892bc7b 100644 --- a/fix/fixer.go +++ b/fix/fixer.go @@ -58,6 +58,7 @@ func init() { "vsphere-iso-net-disk": new(FixerVSphereNetworkDisk), "iso-checksum-type-and-url": new(FixerISOChecksumTypeAndURL), "qemu-host-port": new(FixerQEMUHostPort), + "proxmox-type": new(FixerProxmoxType), } FixerOrder = []string{ @@ -93,5 +94,6 @@ func init() { "vsphere-iso-net-disk", "iso-checksum-type-and-url", "qemu-host-port", + "proxmox-type", } } From 2861ad907415b63d8a97511594e655371793abbe Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Sun, 11 Oct 2020 11:44:31 -0700 Subject: [PATCH 24/24] clean up imports --- builder/proxmox/builder.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/builder/proxmox/builder.go b/builder/proxmox/builder.go index bef6ea4b9..6d99fc464 100644 --- a/builder/proxmox/builder.go +++ b/builder/proxmox/builder.go @@ -1,7 +1,5 @@ package proxmox -import ( - "github.com/hashicorp/packer/builder/proxmox/iso" -) +import proxmoxiso "github.com/hashicorp/packer/builder/proxmox/iso" type Builder = proxmoxiso.Builder