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:
Elizaveta Tretyakova 2017-06-13 14:11:41 +03:00 committed by GitHub
parent 66705e4a26
commit 39099ad3af
5 changed files with 77 additions and 24 deletions

View File

@ -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,
}, },
} }

View File

@ -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 {

View File

@ -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)

33
step_post_process.go Normal file
View File

@ -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) {}

View File

@ -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)
} }
} }