Merge pull request #25 from jetbrains-infra/hardware
CPU and RAM reservation
This commit is contained in:
commit
310e10b19b
|
@ -59,7 +59,11 @@ Destination:
|
|||
|
||||
Hardware customization:
|
||||
* `CPUs` - number of CPU sockets. Inherited from source VM by default.
|
||||
* `CPU_reservation` - Amount of reserved CPU resources in MHz. Inherited from source VM by default.
|
||||
* `CPU_limit` - Upper limit of available CPU resources in MHz. Inherited from source VM by default, set to `-1` for reset.
|
||||
* `RAM` - Amount of RAM in megabytes. Inherited from source VM by default.
|
||||
* `RAM_reservation` - Amount of reserved RAM in MB. Inherited from source VM by default.
|
||||
* `RAM_reserve_all` - Reserve all available RAM (bool). `false` by default. Cannot be used together with `RAM_reservation`.
|
||||
|
||||
Provisioning:
|
||||
* `ssh_username` - [**mandatory**] username in guest OS.
|
||||
|
@ -98,7 +102,10 @@ Post-processing:
|
|||
"linked_clone": true,
|
||||
|
||||
"CPUs": 2,
|
||||
"CPU_reservation": 1000,
|
||||
"CPU_limit": 2000,
|
||||
"RAM": 8192,
|
||||
"RAM_reservation": 2048,
|
||||
|
||||
"ssh_username": "root",
|
||||
"ssh_password": "{{user `guest_password`}}",
|
||||
|
|
|
@ -70,8 +70,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
&StepCloneVM{
|
||||
config: b.config,
|
||||
},
|
||||
&StepConfigureHW{
|
||||
config: b.config,
|
||||
&StepConfigureHardware{
|
||||
config: &b.config.HardwareConfig,
|
||||
},
|
||||
&StepRun{},
|
||||
&communicator.StepConnect{
|
||||
|
|
16
config.go
16
config.go
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -32,8 +31,7 @@ type Config struct {
|
|||
LinkedClone bool `mapstructure:"linked_clone"`
|
||||
|
||||
// Customization
|
||||
CPUs string `mapstructure:"CPUs"`
|
||||
RAM string `mapstructure:"RAM"`
|
||||
HardwareConfig `mapstructure:",squash"`
|
||||
|
||||
// Provisioning
|
||||
communicator.Config `mapstructure:",squash"`
|
||||
|
@ -83,16 +81,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("vSphere host is required"))
|
||||
}
|
||||
|
||||
if c.CPUs != "" {
|
||||
if _, err := strconv.Atoi(c.CPUs); err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Invalid number of CPU sockets"))
|
||||
}
|
||||
}
|
||||
if c.RAM != "" {
|
||||
if _, err := strconv.Atoi(c.RAM); err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Invalid number for RAM"))
|
||||
}
|
||||
}
|
||||
errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...)
|
||||
|
||||
if c.RawShutdownTimeout != "" {
|
||||
timeout, err := time.ParseDuration(c.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
|
|
|
@ -11,20 +11,6 @@ func TestMinimalConfig(t *testing.T) {
|
|||
testConfigOk(t, warns, errs)
|
||||
}
|
||||
|
||||
func TestInvalidCpu(t *testing.T) {
|
||||
raw := minimalConfig()
|
||||
raw["CPUs"] = "string"
|
||||
_, warns, errs := NewConfig(raw)
|
||||
testConfigErr(t, warns, errs)
|
||||
}
|
||||
|
||||
func TestInvalidRam(t *testing.T) {
|
||||
raw := minimalConfig()
|
||||
raw["RAM"] = "string"
|
||||
_, warns, errs := NewConfig(raw)
|
||||
testConfigErr(t, warns, errs)
|
||||
}
|
||||
|
||||
func TestTimeout(t *testing.T) {
|
||||
raw := minimalConfig()
|
||||
raw["shutdown_timeout"] = "3m"
|
||||
|
@ -35,6 +21,14 @@ func TestTimeout(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRAMReservation(t *testing.T) {
|
||||
raw := minimalConfig()
|
||||
raw["RAM_reservation"] = 1000
|
||||
raw["RAM_reserve_all"] = true
|
||||
_, warns, err := NewConfig(raw)
|
||||
testConfigErr(t, warns, err)
|
||||
}
|
||||
|
||||
func minimalConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"vcenter_server": "vcenter.domain.local",
|
||||
|
@ -50,18 +44,18 @@ func minimalConfig() map[string]interface{} {
|
|||
|
||||
func testConfigOk(t *testing.T, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
t.Fatalf("Should be no warnings: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigErr(t *testing.T, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
t.Fatalf("Should be no warnings: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should error")
|
||||
t.Fatal("An error is not raised")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"strconv"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"context"
|
||||
"github.com/vmware/govmomi/object"
|
||||
)
|
||||
|
||||
type StepConfigureHW struct{
|
||||
config *Config
|
||||
}
|
||||
|
||||
type ConfigParametersFlag struct {
|
||||
NumCPUsPtr *int32
|
||||
MemoryMBPtr *int64
|
||||
}
|
||||
|
||||
func (s *StepConfigureHW) Run(state multistep.StateBag) multistep.StepAction {
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
ctx := state.Get("ctx").(context.Context)
|
||||
|
||||
var confSpec types.VirtualMachineConfigSpec
|
||||
parametersFlag := ConfigParametersFlag{}
|
||||
// configure HW
|
||||
if s.config.CPUs != "" {
|
||||
CPUs, err := strconv.Atoi(s.config.CPUs)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
confSpec.NumCPUs = int32(CPUs)
|
||||
parametersFlag.NumCPUsPtr = &(confSpec.NumCPUs)
|
||||
}
|
||||
if s.config.RAM != "" {
|
||||
ram, err := strconv.Atoi(s.config.RAM)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
confSpec.MemoryMB = int64(ram)
|
||||
parametersFlag.MemoryMBPtr = &(confSpec.MemoryMB)
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
if parametersFlag != (ConfigParametersFlag{}) {
|
||||
ui.Say("configuring virtual hardware...")
|
||||
// Reconfigure hardware
|
||||
task, err := vm.Reconfigure(ctx, confSpec)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
_, err = task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
} else {
|
||||
ui.Say("skipping the virtual hardware configration...")
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepConfigureHW) Cleanup(multistep.StateBag) {}
|
|
@ -0,0 +1,73 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"context"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"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"`
|
||||
}
|
||||
|
||||
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(state multistep.StateBag) multistep.StepAction {
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
ctx := state.Get("ctx").(context.Context)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if *s.config != (HardwareConfig{}) {
|
||||
ui.Say("Customizing hardware parameters...")
|
||||
|
||||
var confSpec types.VirtualMachineConfigSpec
|
||||
confSpec.NumCPUs = s.config.CPUs
|
||||
confSpec.MemoryMB = s.config.RAM
|
||||
|
||||
var cpuSpec types.ResourceAllocationInfo
|
||||
cpuSpec.Reservation = s.config.CPUReservation
|
||||
cpuSpec.Limit = s.config.CPULimit
|
||||
confSpec.CpuAllocation = &cpuSpec
|
||||
|
||||
var ramSpec types.ResourceAllocationInfo
|
||||
ramSpec.Reservation = s.config.RAMReservation
|
||||
confSpec.MemoryAllocation = &ramSpec
|
||||
|
||||
confSpec.MemoryReservationLockedToMax = &s.config.RAMReserveAll
|
||||
|
||||
task, err := vm.Reconfigure(ctx, confSpec)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
_, err = task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepConfigureHardware) Cleanup(multistep.StateBag) {}
|
Loading…
Reference in New Issue