Added template conversion (#18)
* Added conversion to template without timeout * Added timeout * Extracted converting to template to a separate step
This commit is contained in:
parent
66705e4a26
commit
39099ad3af
|
@ -62,7 +62,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
},
|
},
|
||||||
&common.StepProvision{},
|
&common.StepProvision{},
|
||||||
&StepShutdown{
|
&StepShutdown{
|
||||||
Command: b.config.ShutdownCommand,
|
Command: b.config.ShutdownCommand,
|
||||||
|
ShutdownTimeout: b.config.ShutdownTimeout,
|
||||||
|
},
|
||||||
|
&StepPostProcess{
|
||||||
|
ToTemplate: b.config.ToTemplate,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
config.go
16
config.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -27,7 +28,12 @@ type Config struct {
|
||||||
Host string `mapstructure:"host"`
|
Host string `mapstructure:"host"`
|
||||||
ResourcePool string `mapstructure:"resource_pool"`
|
ResourcePool string `mapstructure:"resource_pool"`
|
||||||
Datastore string `mapstructure:"datastore"`
|
Datastore string `mapstructure:"datastore"`
|
||||||
|
|
||||||
|
// Settings
|
||||||
LinkedClone bool `mapstructure:"linked_clone"`
|
LinkedClone bool `mapstructure:"linked_clone"`
|
||||||
|
ToTemplate bool `mapstructure:"to_template"`
|
||||||
|
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||||
|
ShutdownTimeout time.Duration ``
|
||||||
|
|
||||||
// Hardware
|
// Hardware
|
||||||
Cpus string `mapstructure:"cpus"`
|
Cpus string `mapstructure:"cpus"`
|
||||||
|
@ -84,11 +90,19 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Invalid number for Ram"))
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Invalid number for Ram"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if c.RawShutdownTimeout == "" {
|
||||||
|
c.RawShutdownTimeout = "5m"
|
||||||
|
}
|
||||||
|
c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout)
|
||||||
|
if err != nil {
|
||||||
|
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Warnings
|
// Warnings
|
||||||
var warnings []string
|
var warnings []string
|
||||||
if c.Datastore == "" {
|
if c.Datastore == "" {
|
||||||
warnings = append(warnings, "Datastore is not specified, will try to find a default one")
|
warnings = append(warnings, "Datastore is not specified, will try to find the default one")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs.Errors) > 0 {
|
if len(errs.Errors) > 0 {
|
||||||
|
|
|
@ -49,6 +49,7 @@ func (s *StepConfigureHW) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
if parametersFlag != (ConfigParametersFlag{}) {
|
if parametersFlag != (ConfigParametersFlag{}) {
|
||||||
ui.Say("configuring virtual hardware...")
|
ui.Say("configuring virtual hardware...")
|
||||||
|
// Reconfigure hardware
|
||||||
task, err := vm.Reconfigure(ctx, confSpec)
|
task, err := vm.Reconfigure(ctx, confSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"github.com/vmware/govmomi/object"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepPostProcess struct{
|
||||||
|
ToTemplate bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepPostProcess) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
vm := state.Get("vm").(*object.VirtualMachine)
|
||||||
|
ctx := state.Get("ctx").(context.Context)
|
||||||
|
|
||||||
|
// Turning into template if needed
|
||||||
|
if s.ToTemplate {
|
||||||
|
ui.Say("turning into template...")
|
||||||
|
err := vm.MarkAsTemplate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
ui.Say("done")
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepPostProcess) Cleanup(state multistep.StateBag) {}
|
|
@ -9,10 +9,12 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StepShutdown struct{
|
type StepShutdown struct{
|
||||||
Command string
|
Command string
|
||||||
|
ShutdownTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
@ -40,38 +42,37 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add timeout
|
|
||||||
for !cmd.Exited {
|
|
||||||
ui.Say("Waiting for remote cmd to finish...")
|
|
||||||
time.Sleep(150 * time.Millisecond)
|
|
||||||
}
|
|
||||||
if cmd.ExitStatus != 0 && cmd.ExitStatus != packer.CmdDisconnect {
|
|
||||||
err := fmt.Errorf("Cmd exit status %v, not 0", cmd.ExitStatus)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
} else if cmd.ExitStatus == packer.CmdDisconnect {
|
|
||||||
ui.Say("VM disconnected")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ui.Say("Forcibly halting virtual machine...")
|
ui.Say("Forcibly halting virtual machine...")
|
||||||
|
|
||||||
err := vm.ShutdownGuest(ctx)
|
err := vm.ShutdownGuest(ctx)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", fmt.Errorf("Could not shutdown guest: %v", err))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the machine to actually shut down
|
||||||
|
log.Printf("Waiting max %s for shutdown to complete", s.ShutdownTimeout)
|
||||||
|
shutdownTimer := time.After(s.ShutdownTimeout)
|
||||||
|
for {
|
||||||
|
powerState, err := vm.PowerState(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
if powerState == "poweredOff" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
task, err := vm.PowerOff(ctx)
|
select {
|
||||||
if err != nil {
|
case <-shutdownTimer:
|
||||||
state.Put("error", err)
|
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
_, err = task.WaitForResult(ctx, nil)
|
|
||||||
if err != nil {
|
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
|
default:
|
||||||
|
time.Sleep(150 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue