Refactoring to work with upstream packer changes around templates and SSH connect.

Signed-off-by: Rob Dobson <rob.dobson@citrix.com>
This commit is contained in:
Rob Dobson 2015-06-19 18:33:11 +01:00
parent 274d86cdc6
commit 351fdbba9d
5 changed files with 95 additions and 128 deletions

View File

@ -9,7 +9,7 @@ import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common"
commonssh "github.com/mitchellh/packer/common/ssh" commonssh "github.com/mitchellh/packer/common/ssh"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate"
xsclient "github.com/xenserver/go-xenserver-client" xsclient "github.com/xenserver/go-xenserver-client"
) )
@ -41,10 +41,12 @@ type CommonConfig struct {
// SSHHostPortMin uint `mapstructure:"ssh_host_port_min"` // SSHHostPortMin uint `mapstructure:"ssh_host_port_min"`
// SSHHostPortMax uint `mapstructure:"ssh_host_port_max"` // SSHHostPortMax uint `mapstructure:"ssh_host_port_max"`
SSHKeyPath string `mapstructure:"ssh_key_path"` SSHKeyPath string `mapstructure:"ssh_key_path"`
SSHPassword string `mapstructure:"ssh_password"` SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"` SSHPort uint `mapstructure:"ssh_port"`
SSHUser string `mapstructure:"ssh_username"` SSHUser string `mapstructure:"ssh_username"`
SSHConfig `mapstructure:",squash"`
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"`
SSHWaitTimeout time.Duration SSHWaitTimeout time.Duration
@ -54,8 +56,9 @@ type CommonConfig struct {
IPGetter string `mapstructure:"ip_getter"` IPGetter string `mapstructure:"ip_getter"`
} }
func (c *CommonConfig) Prepare(t *packer.ConfigTemplate, pc *common.PackerConfig) []error { func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error {
var err error var err error
var errs []error
// Set default values // Set default values
@ -129,40 +132,6 @@ func (c *CommonConfig) Prepare(t *packer.ConfigTemplate, pc *common.PackerConfig
c.IPGetter = "auto" c.IPGetter = "auto"
} }
// Template substitution
templates := map[string]*string{
"remote_username": &c.Username,
"remote_password": &c.Password,
"remote_host": &c.HostIp,
"vm_name": &c.VMName,
"vm_description": &c.VMDescription,
"sr_name": &c.SrName,
"shutdown_command": &c.ShutdownCommand,
"boot_wait": &c.RawBootWait,
"tools_iso_name": &c.ToolsIsoName,
"http_directory": &c.HTTPDir,
"ssh_key_path": &c.SSHKeyPath,
"ssh_password": &c.SSHPassword,
"ssh_username": &c.SSHUser,
"ssh_wait_timeout": &c.RawSSHWaitTimeout,
"output_directory": &c.OutputDir,
"format": &c.Format,
"keep_vm": &c.KeepVM,
"ip_getter": &c.IPGetter,
}
for i := range c.FloppyFiles {
templates[fmt.Sprintf("floppy_files[%d]", i)] = &c.FloppyFiles[i]
}
errs := make([]error, 0)
for n, ptr := range templates {
*ptr, err = t.Process(*ptr, nil)
if err != nil {
errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err))
}
}
// Validation // Validation
if c.Username == "" { if c.Username == "" {
@ -190,13 +159,6 @@ func (c *CommonConfig) Prepare(t *packer.ConfigTemplate, pc *common.PackerConfig
errs = append(errs, fmt.Errorf("Failed to parse boot_wait: %s", err)) errs = append(errs, fmt.Errorf("Failed to parse boot_wait: %s", err))
} }
for i, command := range c.BootCommand {
if err := t.Validate(command); err != nil {
errs = append(errs,
fmt.Errorf("Error processing boot_command[%d]: %s", i, err))
}
}
if c.SSHKeyPath != "" { if c.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil { if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))

View File

@ -2,11 +2,11 @@ package common
import ( import (
"bytes" "bytes"
gossh "code.google.com/p/go.crypto/ssh"
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
commonssh "github.com/mitchellh/packer/common/ssh" commonssh "github.com/mitchellh/packer/common/ssh"
"github.com/mitchellh/packer/communicator/ssh" "github.com/mitchellh/packer/communicator/ssh"
gossh "golang.org/x/crypto/ssh"
"io" "io"
"log" "log"
"net" "net"
@ -28,27 +28,38 @@ func SSHLocalAddress(state multistep.StateBag) (string, error) {
return conn_str, nil return conn_str, nil
} }
func SSHConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { func SSHPort(state multistep.StateBag) (int, error) {
config := state.Get("commonconfig").(CommonConfig) sshHostPort := state.Get("local_ssh_port").(uint)
auth := []gossh.AuthMethod{ return int(sshHostPort), nil
gossh.Password(config.SSHPassword), }
gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)),
}
if config.SSHKeyPath != "" { func CommHost(state multistep.StateBag) (string, error) {
signer, err := commonssh.FileSigner(config.SSHKeyPath) return "127.0.0.1", nil
if err != nil { }
return nil, err
func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
config := state.Get("commonconfig").(CommonConfig)
auth := []gossh.AuthMethod{
gossh.Password(config.SSHPassword),
gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)),
} }
auth = append(auth, gossh.PublicKeys(signer)) if config.SSHKeyPath != "" {
} signer, err := commonssh.FileSigner(config.SSHKeyPath)
if err != nil {
return nil, err
}
return &gossh.ClientConfig{ auth = append(auth, gossh.PublicKeys(signer))
User: config.SSHUser, }
Auth: auth,
}, nil return &gossh.ClientConfig{
User: config.SSHUser,
Auth: auth,
}, nil
}
} }
func doExecuteSSHCmd(cmd, target string, config *gossh.ClientConfig) (stdout string, err error) { func doExecuteSSHCmd(cmd, target string, config *gossh.ClientConfig) (stdout string, err error) {
@ -87,11 +98,12 @@ func ExecuteHostSSHCmd(state multistep.StateBag, cmd string) (stdout string, err
} }
func ExecuteGuestSSHCmd(state multistep.StateBag, cmd string) (stdout string, err error) { func ExecuteGuestSSHCmd(state multistep.StateBag, cmd string) (stdout string, err error) {
config := state.Get("commonconfig").(CommonConfig)
localAddress, err := SSHLocalAddress(state) localAddress, err := SSHLocalAddress(state)
if err != nil { if err != nil {
return return
} }
sshConfig, err := SSHConfig(state) sshConfig, err := SSHConfigFunc(config.SSHConfig)(state)
if err != nil { if err != nil {
return return
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/mitchellh/go-vnc" "github.com/mitchellh/go-vnc"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
"log" "log"
"net" "net"
"strings" "strings"
@ -24,7 +25,7 @@ type bootCommandTemplateData struct {
} }
type StepTypeBootCommand struct { type StepTypeBootCommand struct {
Tpl *packer.ConfigTemplate Ctx interpolate.Context
} }
func (self *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { func (self *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
@ -78,7 +79,7 @@ func (self *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAct
localIp := strings.Split(envVar, " ")[0] localIp := strings.Split(envVar, " ")[0]
ui.Message(fmt.Sprintf("Found local IP: %s", localIp)) ui.Message(fmt.Sprintf("Found local IP: %s", localIp))
tplData := &bootCommandTemplateData{ self.Ctx.Data = &bootCommandTemplateData{
config.VMName, config.VMName,
localIp, localIp,
http_port, http_port,
@ -87,7 +88,7 @@ func (self *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAct
ui.Say("Typing boot commands over VNC...") ui.Say("Typing boot commands over VNC...")
for _, command := range config.BootCommand { for _, command := range config.BootCommand {
command, err := self.Tpl.Process(command, tplData) command, err := interpolate.Render(command, &self.Ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing boot command: %s", err) err := fmt.Errorf("Error preparing boot command: %s", err)
state.Put("error", err) state.Put("error", err)

View File

@ -10,7 +10,10 @@ import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/helper/communicator"
hconfig "github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common" xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common"
xsclient "github.com/xenserver/go-xenserver-client" xsclient "github.com/xenserver/go-xenserver-client"
) )
@ -34,7 +37,7 @@ type config struct {
RawInstallTimeout string `mapstructure:"install_timeout"` RawInstallTimeout string `mapstructure:"install_timeout"`
InstallTimeout time.Duration `` InstallTimeout time.Duration ``
tpl *packer.ConfigTemplate ctx interpolate.Context
} }
type Builder struct { type Builder struct {
@ -44,20 +47,23 @@ type Builder struct {
func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error) { func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error) {
md, err := common.DecodeConfig(&self.config, raws...) var errs *packer.MultiError
err := hconfig.Decode(&self.config, &hconfig.DecodeOpts{
Interpolate: true,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"boot_command",
},
},
}, raws...)
if err != nil { if err != nil {
return nil, err packer.MultiErrorAppend(errs, err)
} }
self.config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return nil, err
}
self.config.tpl.UserVars = self.config.PackerUserVars
errs := common.CheckUnusedConfig(md)
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, self.config.CommonConfig.Prepare(self.config.tpl, &self.config.PackerConfig)...) errs, self.config.CommonConfig.Prepare(&self.config.ctx, &self.config.PackerConfig)...)
// Set default values // Set default values
@ -103,14 +109,6 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
templates[fmt.Sprintf("iso_urls[%d]", i)] = &self.config.ISOUrls[i] templates[fmt.Sprintf("iso_urls[%d]", i)] = &self.config.ISOUrls[i]
} }
for n, ptr := range templates {
var err error
*ptr, err = self.config.tpl.Process(*ptr, nil)
if err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Error processing %s: %s", n, err))
}
}
// Validation // Validation
self.config.InstallTimeout, err = time.ParseDuration(self.config.RawInstallTimeout) self.config.InstallTimeout, err = time.ParseDuration(self.config.RawInstallTimeout)
@ -285,7 +283,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
}, },
new(xscommon.StepBootWait), new(xscommon.StepBootWait),
&xscommon.StepTypeBootCommand{ &xscommon.StepTypeBootCommand{
Tpl: self.config.tpl, Ctx: self.config.ctx,
}, },
&xscommon.StepWaitForIP{ &xscommon.StepWaitForIP{
Chan: httpReqChan, Chan: httpReqChan,
@ -298,10 +296,11 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
HostPortMax: self.config.HostPortMax, HostPortMax: self.config.HostPortMax,
ResultKey: "local_ssh_port", ResultKey: "local_ssh_port",
}, },
&common.StepConnectSSH{ &communicator.StepConnect{
SSHAddress: xscommon.SSHLocalAddress, Config: &self.config.SSHConfig.Comm,
SSHConfig: xscommon.SSHConfig, Host: xscommon.CommHost,
SSHWaitTimeout: self.config.SSHWaitTimeout, SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
SSHPort: xscommon.SSHPort,
}, },
new(xscommon.StepShutdown), new(xscommon.StepShutdown),
&xscommon.StepDetachVdi{ &xscommon.StepDetachVdi{
@ -312,10 +311,11 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
}, },
new(xscommon.StepStartVmPaused), new(xscommon.StepStartVmPaused),
new(xscommon.StepBootWait), new(xscommon.StepBootWait),
&common.StepConnectSSH{ &communicator.StepConnectSSH{
SSHAddress: xscommon.SSHLocalAddress, Config: &self.config.SSHConfig.Comm,
SSHConfig: xscommon.SSHConfig, Host: xscommon.CommHost,
SSHWaitTimeout: self.config.SSHWaitTimeout, SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
SSHPort: xscommon.SSHPort,
}, },
new(common.StepProvision), new(common.StepProvision),
new(xscommon.StepShutdown), new(xscommon.StepShutdown),

View File

@ -8,7 +8,10 @@ import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/helper/communicator"
hconfig "github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common" xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common"
xsclient "github.com/xenserver/go-xenserver-client" xsclient "github.com/xenserver/go-xenserver-client"
) )
@ -22,7 +25,7 @@ type config struct {
PlatformArgs map[string]string `mapstructure:"platform_args"` PlatformArgs map[string]string `mapstructure:"platform_args"`
tpl *packer.ConfigTemplate ctx interpolate.Context
} }
type Builder struct { type Builder struct {
@ -32,20 +35,23 @@ type Builder struct {
func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error) { func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error) {
md, err := common.DecodeConfig(&self.config, raws...) var errs *packer.MultiError
err := hconfig.Decode(&self.config, &hconfig.DecodeOpts{
Interpolate: true,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"boot_command",
},
},
}, raws...)
if err != nil { if err != nil {
return nil, err packer.MultiErrorAppend(errs, err)
} }
self.config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return nil, err
}
self.config.tpl.UserVars = self.config.PackerUserVars
errs := common.CheckUnusedConfig(md)
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, self.config.CommonConfig.Prepare(self.config.tpl, &self.config.PackerConfig)...) errs, self.config.CommonConfig.Prepare(&self.config.ctx, &self.config.PackerConfig)...)
// Set default values // Set default values
@ -64,21 +70,6 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
self.config.PlatformArgs = pargs self.config.PlatformArgs = pargs
} }
// Template substitution
templates := map[string]*string{
"source_path": &self.config.SourcePath,
"network_name": &self.config.NetworkName,
}
for n, ptr := range templates {
var err error
*ptr, err = self.config.tpl.Process(*ptr, nil)
if err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Error processing %s: %s", n, err))
}
}
// Validation // Validation
if self.config.SourcePath == "" { if self.config.SourcePath == "" {
@ -162,7 +153,7 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
}, },
new(xscommon.StepBootWait), new(xscommon.StepBootWait),
&xscommon.StepTypeBootCommand{ &xscommon.StepTypeBootCommand{
Tpl: self.config.tpl, Ctx: self.config.ctx,
}, },
&xscommon.StepWaitForIP{ &xscommon.StepWaitForIP{
Chan: httpReqChan, Chan: httpReqChan,
@ -175,10 +166,11 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
HostPortMax: self.config.HostPortMax, HostPortMax: self.config.HostPortMax,
ResultKey: "local_ssh_port", ResultKey: "local_ssh_port",
}, },
&common.StepConnectSSH{ &communicator.StepConnect{
SSHAddress: xscommon.SSHLocalAddress, Config: &self.config.SSHConfig.Comm,
SSHConfig: xscommon.SSHConfig, Host: xscommon.CommHost,
SSHWaitTimeout: self.config.SSHWaitTimeout, SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
SSHPort: xscommon.SSHPort,
}, },
new(common.StepProvision), new(common.StepProvision),
new(xscommon.StepShutdown), new(xscommon.StepShutdown),