mirror of https://github.com/hashicorp/packer
parent
f909669670
commit
df40ffbe8d
@ -0,0 +1,24 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func CheckRunStatus(state *multistep.BasicStateBag) error {
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return rawErr.(error)
|
||||
}
|
||||
|
||||
// If we were interrupted or cancelled, then just exit.
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return errors.New("Build was cancelled.")
|
||||
}
|
||||
|
||||
if _, ok := state.GetOk(multistep.StateHalted); ok {
|
||||
return errors.New("Build was halted.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
func DecodeConfig(cfg interface{}, ctx *interpolate.Context, raws ...interface{}) error {
|
||||
err := config.Decode(cfg, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
InterpolateContext: ctx,
|
||||
}, raws...)
|
||||
return err
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
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"`
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func NewVMName() string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return fmt.Sprintf("test-%v", rand.Intn(1000))
|
||||
}
|
||||
|
||||
func RenderConfig(config map[string]interface{}) string {
|
||||
t := map[string][]map[string]interface{}{
|
||||
"builders": {
|
||||
map[string]interface{}{
|
||||
"type": "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range config {
|
||||
t["builders"][0][k] = v
|
||||
}
|
||||
|
||||
j, _ := json.Marshal(t)
|
||||
return string(j)
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package iso
|
||||
|
||||
import (
|
||||
packerCommon "github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/common"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
config *Config
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
c, warnings, errs := NewConfig(raws...)
|
||||
if errs != nil {
|
||||
return warnings, errs
|
||||
}
|
||||
b.config = c
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("comm", &b.config.Comm)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
steps := []multistep.Step{}
|
||||
|
||||
steps = append(steps,
|
||||
&common.StepConnect{
|
||||
Config: &b.config.ConnectConfig,
|
||||
},
|
||||
&StepCreateVM{
|
||||
config: &b.config.CreateConfig,
|
||||
},
|
||||
)
|
||||
|
||||
if b.config.CDRomConfig.ISOPath != "" {
|
||||
steps = append(steps,
|
||||
&StepAddCDRom{
|
||||
config: &b.config.CDRomConfig,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Run!
|
||||
b.runner = packerCommon.NewRunner(steps, b.config.PackerConfig, ui)
|
||||
b.runner.Run(state)
|
||||
|
||||
if err := common.CheckRunStatus(state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
artifact := &common.Artifact{
|
||||
Name: b.config.VMName,
|
||||
VM: state.Get("vm").(*driver.VirtualMachine),
|
||||
}
|
||||
return artifact, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Cancel() {
|
||||
if b.runner != nil {
|
||||
b.runner.Cancel()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package iso
|
||||
|
||||
import (
|
||||
builderT "github.com/hashicorp/packer/helper/builder/testing"
|
||||
commonT "github.com/jetbrains-infra/packer-builder-vsphere/common/testing"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuilderAcc_default(t *testing.T) {
|
||||
config := defaultConfig()
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
})
|
||||
}
|
||||
|
||||
func defaultConfig() map[string]interface{} {
|
||||
config := map[string]interface{}{
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"username": "root",
|
||||
"password": "jetbrains",
|
||||
"insecure_connection": true,
|
||||
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
|
||||
"ssh_username": "root",
|
||||
"ssh_password": "jetbrains",
|
||||
|
||||
"vm_name": commonT.NewVMName(),
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package iso
|
||||
|
||||
import (
|
||||
packerCommon "github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/common"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
packerCommon.PackerConfig `mapstructure:",squash"`
|
||||
common.ConnectConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
common.ShutdownConfig `mapstructure:",squash"`
|
||||
CreateSnapshot bool `mapstructure:"create_snapshot"`
|
||||
ConvertToTemplate bool `mapstructure:"convert_to_template"`
|
||||
|
||||
CreateConfig `mapstructure:",squash"`
|
||||
CDRomConfig `mapstructure:",squash"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
c := new(Config)
|
||||
if err := common.DecodeConfig(c, &c.ctx, raws...); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
errs := new(packer.MultiError)
|
||||
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, c.ConnectConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.CreateConfig.Prepare()...)
|
||||
|
||||
if len(errs.Errors) > 0 {
|
||||
return nil, nil, errs
|
||||
}
|
||||
|
||||
return c, nil, nil
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package iso
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
|
||||
type CDRomConfig struct {
|
||||
ISOPath string `mapstructure:"iso_path"`
|
||||
}
|
||||
|
||||
func (c *CDRomConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
type StepAddCDRom struct {
|
||||
config *CDRomConfig
|
||||
}
|
||||
|
||||
func (s *StepAddCDRom) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Adding CDRom ...")
|
||||
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
err := vm.AddCdrom(s.config.ISOPath)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepAddCDRom) Cleanup(state multistep.StateBag) {
|
||||
// nothing
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
package iso
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/common"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
|
||||
type CreateConfig struct {
|
||||
common.HardwareConfig `mapstructure:",squash"`
|
||||
|
||||
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
|
||||
DiskControllerType string `mapstructure:"disk_controller_type"`
|
||||
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
Folder string `mapstructure:"folder"`
|
||||
Host string `mapstructure:"host"`
|
||||
ResourcePool string `mapstructure:"resource_pool"`
|
||||
Datastore string `mapstructure:"datastore"`
|
||||
GuestOSType string `mapstructure:"guest_os_type"`
|
||||
}
|
||||
|
||||
func (c *CreateConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
// needed to avoid changing the original config in case of errors
|
||||
tmp := *c
|
||||
|
||||
// do recursive calls
|
||||
errs = append(errs, tmp.HardwareConfig.Prepare()...)
|
||||
|
||||
// check for errors
|
||||
if tmp.VMName == "" {
|
||||
errs = append(errs, fmt.Errorf("Target VM name is required"))
|
||||
}
|
||||
if tmp.Host == "" {
|
||||
errs = append(errs, fmt.Errorf("vSphere host is required"))
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
// set default values
|
||||
if tmp.GuestOSType == "" {
|
||||
tmp.GuestOSType = "otherGuest"
|
||||
}
|
||||
|
||||
// change the original config
|
||||
*c = tmp
|
||||
|
||||
return []error{}
|
||||
}
|
||||
|
||||
type StepCreateVM struct {
|
||||
config *CreateConfig
|
||||
}
|
||||
|
||||
func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
|
||||
ui.Say("Creating VM...")
|
||||
|
||||
vm, err := d.CreateVM(&driver.CreateConfig{
|
||||
HardwareConfig: s.config.HardwareConfig.ToDriverHardwareConfig(),
|
||||
|
||||
DiskThinProvisioned: s.config.DiskThinProvisioned,
|
||||
DiskControllerType: s.config.DiskControllerType,
|
||||
Name: s.config.VMName,
|
||||
Folder: s.config.Folder,
|
||||
Host: s.config.Host,
|
||||
ResourcePool: s.config.ResourcePool,
|
||||
Datastore: s.config.Datastore,
|
||||
GuestOS: s.config.GuestOSType,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("vm", vm)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCreateVM) Cleanup(state multistep.StateBag) {
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
if !cancelled && !halted {
|
||||
return
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
st := state.Get("vm")
|
||||
if st == nil {
|
||||
return
|
||||
}
|
||||
vm := st.(*driver.VirtualMachine)
|
||||
|
||||
ui.Say("Destroying VM...")
|
||||
|
||||
err := vm.Destroy()
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PACKER_ACC=1
|
||||
go test -v "$@"
|
||||
Loading…
Reference in new issue