package proxmox 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 TestTemplateFinalize(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: "empty config changes only description", builderConfig: &Config{}, 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": nil, "description": "", "ide2": nil, }, expectedAction: multistep.ActionContinue, }, { name: "all options", 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, }, { name: "all options with cloud-init", 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", }, expectCallSetConfig: true, expectedVMConfig: map[string]interface{}{ "name": "my-template", "description": "some-description", "ide2": "none,media=cdrom", "ide3": "ceph01:cloudinit", }, expectedAction: multistep.ActionContinue, }, { name: "no available controller for cloud-init drive", builderConfig: &Config{ TemplateName: "my-template", TemplateDescription: "some-description", UnmountISO: false, CloudInit: true, }, initialVMConfig: map[string]interface{}{ "name": "dummy", "description": "Packer ephemeral build VM", "ide0": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", "ide1": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", "ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom", "ide3": "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", }, 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, }, getConfigErr: fmt.Errorf("some error"), expectCallSetConfig: false, expectedAction: multistep.ActionHalt, }, { name: "SetVmConfig error should return halt", 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"), 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("config", c.builderConfig) state.Put("vmRef", proxmox.NewVmRef(1)) state.Put("proxmoxClient", finalizer) step := stepFinalizeTemplateConfig{} action := step.Run(context.TODO(), state) if action != c.expectedAction { t.Errorf("Expected action to be %v, got %v", c.expectedAction, action) } }) } }