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/packer/common"
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"
)
@ -41,10 +41,12 @@ type CommonConfig struct {
// SSHHostPortMin uint `mapstructure:"ssh_host_port_min"`
// SSHHostPortMax uint `mapstructure:"ssh_host_port_max"`
SSHKeyPath string `mapstructure:"ssh_key_path"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"`
SSHUser string `mapstructure:"ssh_username"`
SSHKeyPath string `mapstructure:"ssh_key_path"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"`
SSHUser string `mapstructure:"ssh_username"`
SSHConfig `mapstructure:",squash"`
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"`
SSHWaitTimeout time.Duration
@ -54,8 +56,9 @@ type CommonConfig struct {
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 errs []error
// Set default values
@ -129,40 +132,6 @@ func (c *CommonConfig) Prepare(t *packer.ConfigTemplate, pc *common.PackerConfig
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
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))
}
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 _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))

View File

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

View File

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

View File

@ -10,7 +10,10 @@ import (
"github.com/mitchellh/multistep"
"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/template/interpolate"
xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common"
xsclient "github.com/xenserver/go-xenserver-client"
)
@ -34,7 +37,7 @@ type config struct {
RawInstallTimeout string `mapstructure:"install_timeout"`
InstallTimeout time.Duration ``
tpl *packer.ConfigTemplate
ctx interpolate.Context
}
type Builder struct {
@ -44,20 +47,23 @@ type Builder struct {
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 {
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, self.config.CommonConfig.Prepare(self.config.tpl, &self.config.PackerConfig)...)
errs, self.config.CommonConfig.Prepare(&self.config.ctx, &self.config.PackerConfig)...)
// 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]
}
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
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),
&xscommon.StepTypeBootCommand{
Tpl: self.config.tpl,
Ctx: self.config.ctx,
},
&xscommon.StepWaitForIP{
Chan: httpReqChan,
@ -298,10 +296,11 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
HostPortMax: self.config.HostPortMax,
ResultKey: "local_ssh_port",
},
&common.StepConnectSSH{
SSHAddress: xscommon.SSHLocalAddress,
SSHConfig: xscommon.SSHConfig,
SSHWaitTimeout: self.config.SSHWaitTimeout,
&communicator.StepConnect{
Config: &self.config.SSHConfig.Comm,
Host: xscommon.CommHost,
SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
SSHPort: xscommon.SSHPort,
},
new(xscommon.StepShutdown),
&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.StepBootWait),
&common.StepConnectSSH{
SSHAddress: xscommon.SSHLocalAddress,
SSHConfig: xscommon.SSHConfig,
SSHWaitTimeout: self.config.SSHWaitTimeout,
&communicator.StepConnectSSH{
Config: &self.config.SSHConfig.Comm,
Host: xscommon.CommHost,
SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
SSHPort: xscommon.SSHPort,
},
new(common.StepProvision),
new(xscommon.StepShutdown),

View File

@ -8,7 +8,10 @@ import (
"github.com/mitchellh/multistep"
"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/template/interpolate"
xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common"
xsclient "github.com/xenserver/go-xenserver-client"
)
@ -22,7 +25,7 @@ type config struct {
PlatformArgs map[string]string `mapstructure:"platform_args"`
tpl *packer.ConfigTemplate
ctx interpolate.Context
}
type Builder struct {
@ -32,20 +35,23 @@ type Builder struct {
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 {
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, self.config.CommonConfig.Prepare(self.config.tpl, &self.config.PackerConfig)...)
errs, self.config.CommonConfig.Prepare(&self.config.ctx, &self.config.PackerConfig)...)
// Set default values
@ -64,21 +70,6 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
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
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),
&xscommon.StepTypeBootCommand{
Tpl: self.config.tpl,
Ctx: self.config.ctx,
},
&xscommon.StepWaitForIP{
Chan: httpReqChan,
@ -175,10 +166,11 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
HostPortMax: self.config.HostPortMax,
ResultKey: "local_ssh_port",
},
&common.StepConnectSSH{
SSHAddress: xscommon.SSHLocalAddress,
SSHConfig: xscommon.SSHConfig,
SSHWaitTimeout: self.config.SSHWaitTimeout,
&communicator.StepConnect{
Config: &self.config.SSHConfig.Comm,
Host: xscommon.CommHost,
SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
SSHPort: xscommon.SSHPort,
},
new(common.StepProvision),
new(xscommon.StepShutdown),