share hardware customization step

This commit is contained in:
Michael Kuzmin 2018-05-06 00:41:14 +03:00
parent 0b4729c9e4
commit c44221a800
9 changed files with 146 additions and 159 deletions

View File

@ -39,8 +39,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&StepCloneVM{ &StepCloneVM{
config: &b.config.CloneConfig, config: &b.config.CloneConfig,
}, },
&StepConfigureHardware{ &common.StepConfigureHardware{
config: &b.config.HardwareConfig, Config: &b.config.HardwareConfig,
}, },
&common.StepConfigParams{ &common.StepConfigParams{
Config: &b.config.ConfigParamsConfig, Config: &b.config.ConfigParamsConfig,

View File

@ -10,9 +10,10 @@ import (
) )
type CloneConfig struct { type CloneConfig struct {
Template string `mapstructure:"template"` Template string `mapstructure:"template"`
common.VMConfig `mapstructure:",squash"` common.VMConfig `mapstructure:",squash"`
LinkedClone bool `mapstructure:"linked_clone"` LinkedClone bool `mapstructure:"linked_clone"`
DiskSize int64 `mapstructure:"disk_size"`
} }
func (c *CloneConfig) Prepare() []error { func (c *CloneConfig) Prepare() []error {
@ -44,7 +45,7 @@ func (s *StepCloneVM) Run(_ context.Context, state multistep.StateBag) multistep
vm, err := template.Clone(&driver.CloneConfig{ vm, err := template.Clone(&driver.CloneConfig{
Name: s.config.VMName, Name: s.config.VMName,
Folder: s.config.Folder, Folder: s.config.Folder,
Cluster: s.config.Cluster, Cluster: s.config.Cluster,
Host: s.config.Host, Host: s.config.Host,
ResourcePool: s.config.ResourcePool, ResourcePool: s.config.ResourcePool,
Datastore: s.config.Datastore, Datastore: s.config.Datastore,
@ -54,8 +55,16 @@ func (s *StepCloneVM) Run(_ context.Context, state multistep.StateBag) multistep
state.Put("error", err) state.Put("error", err)
return multistep.ActionHalt return multistep.ActionHalt
} }
state.Put("vm", vm) state.Put("vm", vm)
if s.config.DiskSize > 0 {
err = vm.ResizeDisk(s.config.DiskSize)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
}
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -1,43 +0,0 @@
package clone
import (
"github.com/hashicorp/packer/packer"
"github.com/jetbrains-infra/packer-builder-vsphere/common"
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
"github.com/hashicorp/packer/helper/multistep"
"context"
)
type StepConfigureHardware struct {
config *common.HardwareConfig
}
func (s *StepConfigureHardware) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
if *s.config != (common.HardwareConfig{}) {
ui.Say("Customizing hardware parameters...")
err := vm.Configure(&driver.HardwareConfig{
CPUs: s.config.CPUs,
CPUReservation: s.config.CPUReservation,
CPULimit: s.config.CPULimit,
RAM: s.config.RAM,
RAMReservation: s.config.RAMReservation,
RAMReserveAll: s.config.RAMReserveAll,
DiskSize: s.config.DiskSize,
NestedHV: s.config.NestedHV,
CpuHotAddEnabled: s.config.CpuHotAddEnabled,
MemoryHotAddEnabled: s.config.MemoryHotAddEnabled,
})
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}
func (s *StepConfigureHardware) Cleanup(multistep.StateBag) {}

View File

@ -1,44 +0,0 @@
package common
import (
"fmt"
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
)
type HardwareConfig struct {
CPUs int32 `mapstructure:"CPUs"`
CPUReservation int64 `mapstructure:"CPU_reservation"`
CPULimit int64 `mapstructure:"CPU_limit"`
RAM int64 `mapstructure:"RAM"`
RAMReservation int64 `mapstructure:"RAM_reservation"`
RAMReserveAll bool `mapstructure:"RAM_reserve_all"`
DiskSize int64 `mapstructure:"disk_size"`
NestedHV bool `mapstructure:"NestedHV"`
CpuHotAddEnabled bool `mapstructure:"CPU_hot_plug"`
MemoryHotAddEnabled bool `mapstructure:"RAM_hot_plug"`
}
func (c *HardwareConfig) Prepare() []error {
var errs []error
if c.RAMReservation > 0 && c.RAMReserveAll != false {
errs = append(errs, fmt.Errorf("'RAM_reservation' and 'RAM_reserve_all' cannot be used together"))
}
return errs
}
func (c *HardwareConfig) ToDriverHardwareConfig() driver.HardwareConfig {
return driver.HardwareConfig{
CPUs: c.CPUs,
CPUReservation: c.CPUReservation,
CPULimit: c.CPULimit,
RAM: c.RAM,
RAMReservation: c.RAMReservation,
RAMReserveAll: c.RAMReserveAll,
DiskSize: c.DiskSize,
NestedHV: c.NestedHV,
CpuHotAddEnabled: c.CpuHotAddEnabled,
MemoryHotAddEnabled: c.MemoryHotAddEnabled,
}
}

64
common/step_hardware.go Normal file
View File

@ -0,0 +1,64 @@
package common
import (
"github.com/hashicorp/packer/packer"
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
"github.com/hashicorp/packer/helper/multistep"
"context"
"fmt"
)
type HardwareConfig struct {
CPUs int32 `mapstructure:"CPUs"`
CPUReservation int64 `mapstructure:"CPU_reservation"`
CPULimit int64 `mapstructure:"CPU_limit"`
RAM int64 `mapstructure:"RAM"`
RAMReservation int64 `mapstructure:"RAM_reservation"`
RAMReserveAll bool `mapstructure:"RAM_reserve_all"`
NestedHV bool `mapstructure:"NestedHV"`
CpuHotAddEnabled bool `mapstructure:"CPU_hot_plug"`
MemoryHotAddEnabled bool `mapstructure:"RAM_hot_plug"`
}
func (c *HardwareConfig) Prepare() []error {
var errs []error
if c.RAMReservation > 0 && c.RAMReserveAll != false {
errs = append(errs, fmt.Errorf("'RAM_reservation' and 'RAM_reserve_all' cannot be used together"))
}
return errs
}
type StepConfigureHardware struct {
Config *HardwareConfig
}
func (s *StepConfigureHardware) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
if *s.Config != (HardwareConfig{}) {
ui.Say("Customizing hardware parameters...")
err := vm.Configure(&driver.HardwareConfig{
CPUs: s.Config.CPUs,
CPUReservation: s.Config.CPUReservation,
CPULimit: s.Config.CPULimit,
RAM: s.Config.RAM,
RAMReservation: s.Config.RAMReservation,
RAMReserveAll: s.Config.RAMReserveAll,
NestedHV: s.Config.NestedHV,
CpuHotAddEnabled: s.Config.CpuHotAddEnabled,
MemoryHotAddEnabled: s.Config.MemoryHotAddEnabled,
})
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}
func (s *StepConfigureHardware) Cleanup(multistep.StateBag) {}

View File

@ -18,7 +18,7 @@ type VirtualMachine struct {
type CloneConfig struct { type CloneConfig struct {
Name string Name string
Folder string Folder string
Cluster string Cluster string
Host string Host string
ResourcePool string ResourcePool string
Datastore string Datastore string
@ -32,22 +32,20 @@ type HardwareConfig struct {
RAM int64 RAM int64
RAMReservation int64 RAMReservation int64
RAMReserveAll bool RAMReserveAll bool
DiskSize int64
NestedHV bool NestedHV bool
CpuHotAddEnabled bool CpuHotAddEnabled bool
MemoryHotAddEnabled bool MemoryHotAddEnabled bool
} }
type CreateConfig struct { type CreateConfig struct {
HardwareConfig
DiskThinProvisioned bool DiskThinProvisioned bool
DiskControllerType string // example: "scsi", "pvscsi" DiskControllerType string // example: "scsi", "pvscsi"
DiskSize int64
Annotation string Annotation string
Name string Name string
Folder string Folder string
Cluster string Cluster string
Host string Host string
ResourcePool string ResourcePool string
Datastore string Datastore string
@ -77,7 +75,14 @@ func (d *Driver) FindVM(name string) (*VirtualMachine, error) {
} }
func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) { func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) {
createSpec := config.toConfigSpec() createSpec := types.VirtualMachineConfigSpec{
Name: config.Name,
Annotation: config.Annotation,
GuestId: config.GuestOS,
}
if config.Version != 0 {
createSpec.Version = fmt.Sprintf("%s%d", "vmx-", config.Version)
}
folder, err := d.FindFolder(config.Folder) folder, err := d.FindFolder(config.Folder)
if err != nil { if err != nil {
@ -238,27 +243,54 @@ func (vm *VirtualMachine) Destroy() error {
} }
func (vm *VirtualMachine) Configure(config *HardwareConfig) error { func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
confSpec := config.toConfigSpec() var confSpec types.VirtualMachineConfigSpec
confSpec.NumCPUs = config.CPUs
confSpec.MemoryMB = config.RAM
if config.DiskSize > 0 { var cpuSpec types.ResourceAllocationInfo
devices, err := vm.vm.Device(vm.driver.ctx) cpuSpec.Reservation = config.CPUReservation
if err != nil { cpuSpec.Limit = config.CPULimit
return err confSpec.CpuAllocation = &cpuSpec
}
disk, err := findDisk(devices) var ramSpec types.ResourceAllocationInfo
if err != nil { ramSpec.Reservation = config.RAMReservation
return err confSpec.MemoryAllocation = &ramSpec
}
disk.CapacityInKB = config.DiskSize * 1024 confSpec.MemoryReservationLockedToMax = &config.RAMReserveAll
confSpec.NestedHVEnabled = &config.NestedHV
confSpec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{ confSpec.CpuHotAddEnabled = &config.CpuHotAddEnabled
&types.VirtualDeviceConfigSpec{ confSpec.MemoryHotAddEnabled = &config.MemoryHotAddEnabled
Device: disk,
Operation: types.VirtualDeviceConfigSpecOperationEdit, task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec)
}, if err != nil {
} return err
}
_, err = task.WaitForResult(vm.driver.ctx, nil)
return err
}
func (vm *VirtualMachine) ResizeDisk(diskSize int64) error {
var confSpec types.VirtualMachineConfigSpec
devices, err := vm.vm.Device(vm.driver.ctx)
if err != nil {
return err
}
disk, err := findDisk(devices)
if err != nil {
return err
}
disk.CapacityInKB = diskSize * 1024
confSpec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{
&types.VirtualDeviceConfigSpec{
Device: disk,
Operation: types.VirtualDeviceConfigSpecOperationEdit,
},
} }
task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec) task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec)
@ -374,40 +406,6 @@ func (vm *VirtualMachine) GetDir() (string, error) {
return "", fmt.Errorf("cannot find '%s'", vmxName) return "", fmt.Errorf("cannot find '%s'", vmxName)
} }
func (config HardwareConfig) toConfigSpec() types.VirtualMachineConfigSpec {
var confSpec types.VirtualMachineConfigSpec
confSpec.NumCPUs = config.CPUs
confSpec.MemoryMB = config.RAM
var cpuSpec types.ResourceAllocationInfo
cpuSpec.Reservation = config.CPUReservation
cpuSpec.Limit = config.CPULimit
confSpec.CpuAllocation = &cpuSpec
var ramSpec types.ResourceAllocationInfo
ramSpec.Reservation = config.RAMReservation
confSpec.MemoryAllocation = &ramSpec
confSpec.MemoryReservationLockedToMax = &config.RAMReserveAll
confSpec.NestedHVEnabled = &config.NestedHV
confSpec.CpuHotAddEnabled = &config.CpuHotAddEnabled
confSpec.MemoryHotAddEnabled = &config.MemoryHotAddEnabled
return confSpec
}
func (config CreateConfig) toConfigSpec() types.VirtualMachineConfigSpec {
confSpec := config.HardwareConfig.toConfigSpec()
confSpec.Name = config.Name
confSpec.Annotation = config.Annotation
confSpec.GuestId = config.GuestOS
if config.Version != 0 {
confSpec.Version = fmt.Sprintf("%s%d", "vmx-", config.Version)
}
return confSpec
}
func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) { func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
device, err := devices.CreateSCSIController(config.DiskControllerType) device, err := devices.CreateSCSIController(config.DiskControllerType)
if err != nil { if err != nil {

View File

@ -39,6 +39,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&StepCreateVM{ &StepCreateVM{
Config: &b.config.CreateConfig, Config: &b.config.CreateConfig,
}, },
&common.StepConfigureHardware{
Config: &b.config.HardwareConfig,
},
&common.StepConfigParams{ &common.StepConfigParams{
Config: &b.config.ConfigParamsConfig, Config: &b.config.ConfigParamsConfig,
}, },

View File

@ -6,7 +6,6 @@ import (
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
"github.com/jetbrains-infra/packer-builder-vsphere/common" "github.com/jetbrains-infra/packer-builder-vsphere/common"
"fmt"
) )
type Config struct { type Config struct {
@ -20,6 +19,7 @@ type Config struct {
ConvertToTemplate bool `mapstructure:"convert_to_template"` ConvertToTemplate bool `mapstructure:"convert_to_template"`
CreateConfig `mapstructure:",squash"` CreateConfig `mapstructure:",squash"`
common.HardwareConfig `mapstructure:",squash"`
CDRomConfig `mapstructure:",squash"` CDRomConfig `mapstructure:",squash"`
FloppyConfig `mapstructure:",squash"` FloppyConfig `mapstructure:",squash"`
common.ConfigParamsConfig `mapstructure:",squash"` common.ConfigParamsConfig `mapstructure:",squash"`
@ -38,9 +38,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare()...)
errs = packer.MultiErrorAppend(errs, c.ConnectConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.ConnectConfig.Prepare()...)
errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...)
if c.DiskSize <= 0 {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("'disk_size' must be provided"))
}
errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...)
errs = packer.MultiErrorAppend(errs, c.CreateConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.CreateConfig.Prepare()...)

View File

@ -11,10 +11,10 @@ import (
type CreateConfig struct { type CreateConfig struct {
common.VMConfig `mapstructure:",squash"` common.VMConfig `mapstructure:",squash"`
common.HardwareConfig `mapstructure:",squash"`
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"` DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
DiskControllerType string `mapstructure:"disk_controller_type"` DiskControllerType string `mapstructure:"disk_controller_type"`
DiskSize int64 `mapstructure:"disk_size"`
GuestOSType string `mapstructure:"guest_os_type"` GuestOSType string `mapstructure:"guest_os_type"`
Network string `mapstructure:"network"` Network string `mapstructure:"network"`
@ -31,12 +31,16 @@ func (c *CreateConfig) Prepare() []error {
// do recursive calls // do recursive calls
errs = append(errs, tmp.VMConfig.Prepare()...) errs = append(errs, tmp.VMConfig.Prepare()...)
errs = append(errs, tmp.HardwareConfig.Prepare()...)
if tmp.Version < 0 { if tmp.Version < 0 {
errs = append(errs, fmt.Errorf("'vm_version' cannot be a negative number")) errs = append(errs, fmt.Errorf("'vm_version' cannot be a negative number"))
} }
if tmp.DiskSize == 0 {
errs = append(errs, fmt.Errorf("'disk_size' must be provided"))
}
if len(errs) > 0 { if len(errs) > 0 {
return errs return errs
} }
@ -63,10 +67,9 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
ui.Say("Creating VM...") ui.Say("Creating VM...")
vm, err := d.CreateVM(&driver.CreateConfig{ vm, err := d.CreateVM(&driver.CreateConfig{
HardwareConfig: s.Config.HardwareConfig.ToDriverHardwareConfig(),
DiskThinProvisioned: s.Config.DiskThinProvisioned, DiskThinProvisioned: s.Config.DiskThinProvisioned,
DiskControllerType: s.Config.DiskControllerType, DiskControllerType: s.Config.DiskControllerType,
DiskSize: s.Config.DiskSize,
Name: s.Config.VMName, Name: s.Config.VMName,
Folder: s.Config.Folder, Folder: s.Config.Folder,
Cluster: s.Config.Cluster, Cluster: s.Config.Cluster,