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{},
|
||||
&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/template/interpolate"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -27,7 +28,12 @@ type Config struct {
|
|||
Host string `mapstructure:"host"`
|
||||
ResourcePool string `mapstructure:"resource_pool"`
|
||||
Datastore string `mapstructure:"datastore"`
|
||||
|
||||
// Settings
|
||||
LinkedClone bool `mapstructure:"linked_clone"`
|
||||
ToTemplate bool `mapstructure:"to_template"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
ShutdownTimeout time.Duration ``
|
||||
|
||||
// Hardware
|
||||
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"))
|
||||
}
|
||||
}
|
||||
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
|
||||
var warnings []string
|
||||
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 {
|
||||
|
|
|
@ -49,6 +49,7 @@ func (s *StepConfigureHW) Run(state multistep.StateBag) multistep.StepAction {
|
|||
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)
|
||||
|
|
|
@ -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"
|
||||
"time"
|
||||
"bytes"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type StepShutdown struct{
|
||||
Command string
|
||||
Command string
|
||||
ShutdownTimeout time.Duration
|
||||
}
|
||||
|
||||
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())
|
||||
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 {
|
||||
ui.Say("Forcibly halting virtual machine...")
|
||||
|
||||
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 {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if powerState == "poweredOff" {
|
||||
break
|
||||
}
|
||||
|
||||
task, err := vm.PowerOff(ctx)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
_, err = task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
default:
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue