diff --git a/README.md b/README.md index 6ab71d0..498227f 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ To get you started, there is an example config file which you can use `examples/ "host_ip": "10.81.2.105", "instance_name": "packer-centos-6-4", "instance_memory": "2048000000", - "root_disk_size": "5000000000", + "root_disk_size": "40000000000", "iso_name": "CentOS-6.4-x86_64-minimal.iso", "http_directory": "http", "local_ip": "10.80.3.223", diff --git a/builder/xenserver/artifact.go b/builder/xenserver/artifact.go index acac1a7..002b82f 100644 --- a/builder/xenserver/artifact.go +++ b/builder/xenserver/artifact.go @@ -1,57 +1,55 @@ package xenserver import ( - "fmt" - "os" - "github.com/mitchellh/packer/packer" - "path/filepath" + "fmt" + "github.com/mitchellh/packer/packer" + "os" + "path/filepath" ) - type LocalArtifact struct { - dir string - f []string + dir string + f []string } - func NewArtifact(dir string) (packer.Artifact, error) { - files := make([]string, 0, 1) - visit := func(path string, info os.FileInfo, err error) error { - if !info.IsDir() { - files = append(files, path) - } - return err - } - if err := filepath.Walk(dir, visit); err != nil { - return nil, err - } + files := make([]string, 0, 1) + visit := func(path string, info os.FileInfo, err error) error { + if !info.IsDir() { + files = append(files, path) + } + return err + } + if err := filepath.Walk(dir, visit); err != nil { + return nil, err + } - return &LocalArtifact{ - dir: dir, - f: files, - }, nil + return &LocalArtifact{ + dir: dir, + f: files, + }, nil } func (*LocalArtifact) BuilderId() string { - return BuilderId + return BuilderId } func (a *LocalArtifact) Files() []string { - return a.f + return a.f } func (*LocalArtifact) Id() string { - return "VM" + return "VM" } func (a *LocalArtifact) String() string { - return fmt.Sprintf("VM files in directory: %s", a.dir) + return fmt.Sprintf("VM files in directory: %s", a.dir) } func (a *LocalArtifact) State(name string) interface{} { - return nil + return nil } func (a *LocalArtifact) Destroy() error { - return os.RemoveAll(a.dir) + return os.RemoveAll(a.dir) } diff --git a/builder/xenserver/builder.go b/builder/xenserver/builder.go index 221a616..9c9e9e5 100644 --- a/builder/xenserver/builder.go +++ b/builder/xenserver/builder.go @@ -1,387 +1,379 @@ package xenserver import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/common" - "fmt" - "log" - "errors" - "time" - "os" - commonssh "github.com/mitchellh/packer/common/ssh" + "errors" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/common" + commonssh "github.com/mitchellh/packer/common/ssh" + "github.com/mitchellh/packer/packer" + "log" + "os" + "time" ) - // Set the unique ID for this builder const BuilderId = "packer.xenserver" - type config struct { - common.PackerConfig `mapstructure:",squash"` + common.PackerConfig `mapstructure:",squash"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - HostIp string `mapstructure:"host_ip"` - IsoUrl string `mapstructure:"iso_url"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + HostIp string `mapstructure:"host_ip"` + IsoUrl string `mapstructure:"iso_url"` - InstanceName string `mapstructure:"instance_name"` - InstanceMemory string `mapstructure:"instance_memory"` - RootDiskSize string `mapstructure:"root_disk_size"` - CloneTemplate string `mapstructure:"clone_template"` - IsoName string `mapstructure:"iso_name"` - SrName string `mapstructure:"sr_name"` - NetworkName string `mapstructure:"network_name"` + InstanceName string `mapstructure:"instance_name"` + InstanceMemory string `mapstructure:"instance_memory"` + RootDiskSize string `mapstructure:"root_disk_size"` + CloneTemplate string `mapstructure:"clone_template"` + IsoName string `mapstructure:"iso_name"` + SrName string `mapstructure:"sr_name"` + NetworkName string `mapstructure:"network_name"` - HostPortMin uint `mapstructure:"host_port_min"` - HostPortMax uint `mapstructure:"host_port_max"` + HostPortMin uint `mapstructure:"host_port_min"` + HostPortMax uint `mapstructure:"host_port_max"` - BootCommand []string `mapstructure:"boot_command"` - RawBootWait string `mapstructure:"boot_wait"` + BootCommand []string `mapstructure:"boot_command"` + RawBootWait string `mapstructure:"boot_wait"` - BootWait time.Duration `` - sshWaitTimeout time.Duration `` + BootWait time.Duration `` + SSHWaitTimeout time.Duration `` - ISOChecksum string `mapstructure:"iso_checksum"` - ISOChecksumType string `mapstructure:"iso_checksum_type"` - ISOUrls []string `mapstructure:"iso_urls"` - ISOUrl string `mapstructure:"iso_url"` + ISOChecksum string `mapstructure:"iso_checksum"` + ISOChecksumType string `mapstructure:"iso_checksum_type"` + ISOUrls []string `mapstructure:"iso_urls"` + ISOUrl string `mapstructure:"iso_url"` - HTTPDir string `mapstructure:"http_directory"` - HTTPPortMin uint `mapstructure:"http_port_min"` - HTTPPortMax uint `mapstructure:"http_port_max"` + HTTPDir string `mapstructure:"http_directory"` + HTTPPortMin uint `mapstructure:"http_port_min"` + HTTPPortMax uint `mapstructure:"http_port_max"` - LocalIp string `mapstructure:"local_ip"` - PlatformArgs map[string]string `mapstructure:"platform_args"` + LocalIp string `mapstructure:"local_ip"` + PlatformArgs map[string]string `mapstructure:"platform_args"` - RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` + RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` - SSHPassword string `mapstructure:"ssh_password"` - SSHUser string `mapstructure:"ssh_username"` - SSHKeyPath string `mapstructure:"ssh_key_path"` + SSHPassword string `mapstructure:"ssh_password"` + SSHUser string `mapstructure:"ssh_username"` + SSHKeyPath string `mapstructure:"ssh_key_path"` - OutputDir string `mapstructure:"output_directory"` + OutputDir string `mapstructure:"output_directory"` - tpl *packer.ConfigTemplate + tpl *packer.ConfigTemplate } - type Builder struct { - config config - runner multistep.Runner + config config + runner multistep.Runner } +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...) + if err != nil { + return nil, err + } - md, err := common.DecodeConfig(&self.config, raws...) - if err != nil { - return nil, err - } + errs := common.CheckUnusedConfig(md) + if errs == nil { + errs = &packer.MultiError{} + } - errs := common.CheckUnusedConfig(md) - if errs == nil { - errs = &packer.MultiError{} - } + self.config.tpl, err = packer.NewConfigTemplate() - self.config.tpl, err = packer.NewConfigTemplate() + if err != nil { + return nil, err + } - if err != nil { - return nil, err - } + // Set default vaules - // Set default vaules + if self.config.HostPortMin == 0 { + self.config.HostPortMin = 5900 + } - if self.config.HostPortMin == 0 { - self.config.HostPortMin = 5900 - } + if self.config.HostPortMax == 0 { + self.config.HostPortMax = 6000 + } - if self.config.HostPortMax == 0 { - self.config.HostPortMax = 6000 - } + if self.config.RawBootWait == "" { + self.config.RawBootWait = "5s" + } - if self.config.RawBootWait == "" { - self.config.RawBootWait = "5s" - } + if self.config.HTTPPortMin == 0 { + self.config.HTTPPortMin = 8000 + } - if self.config.HTTPPortMin == 0 { - self.config.HTTPPortMin = 8000 - } + if self.config.HTTPPortMax == 0 { + self.config.HTTPPortMax = 9000 + } - if self.config.HTTPPortMax == 0 { - self.config.HTTPPortMax = 9000 - } + if self.config.RawSSHWaitTimeout == "" { + self.config.RawSSHWaitTimeout = "200m" + } - if self.config.RawSSHWaitTimeout == "" { - self.config.RawSSHWaitTimeout = "200m" - } + if self.config.OutputDir == "" { + self.config.OutputDir = fmt.Sprintf("output-%s", self.config.PackerBuildName) + } - if self.config.OutputDir == "" { - self.config.OutputDir = fmt.Sprintf("output-%s", self.config.PackerBuildName) - } + templates := map[string]*string{ + "username": &self.config.Username, + "password": &self.config.Password, + "host_ip": &self.config.HostIp, + "iso_url": &self.config.IsoUrl, + "instance_name": &self.config.InstanceName, + "instance_memory": &self.config.InstanceMemory, + "root_disk_size": &self.config.RootDiskSize, + "clone_template": &self.config.CloneTemplate, + "iso_name": &self.config.IsoName, + "sr_name": &self.config.SrName, + "network_name": &self.config.NetworkName, + "boot_wait": &self.config.RawBootWait, + "iso_checksum": &self.config.ISOChecksum, + "iso_checksum_type": &self.config.ISOChecksumType, + "http_directory": &self.config.HTTPDir, + "local_ip": &self.config.LocalIp, + "ssh_wait_timeout": &self.config.RawSSHWaitTimeout, + "ssh_username": &self.config.SSHUser, + "ssh_password": &self.config.SSHPassword, + "ssh_key_path": &self.config.SSHKeyPath, + "output_directory": &self.config.OutputDir, + } - templates := map[string]*string { - "username": &self.config.Username, - "password": &self.config.Password, - "host_ip": &self.config.HostIp, - "iso_url": &self.config.IsoUrl, - "instance_name": &self.config.InstanceName, - "instance_memory": &self.config.InstanceMemory, - "root_disk_size": &self.config.RootDiskSize, - "clone_template": &self.config.CloneTemplate, - "iso_name": &self.config.IsoName, - "sr_name": &self.config.SrName, - "network_name": &self.config.NetworkName, - "boot_wait": &self.config.RawBootWait, - "iso_checksum": &self.config.ISOChecksum, - "iso_checksum_type": &self.config.ISOChecksumType, - "http_directory": &self.config.HTTPDir, - "local_ip": &self.config.LocalIp, - "ssh_wait_timeout": &self.config.RawSSHWaitTimeout, - "ssh_username": &self.config.SSHUser, - "ssh_password": &self.config.SSHPassword, - "ssh_key_path": &self.config.SSHKeyPath, - "output_directory": &self.config.OutputDir, - } + 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)) + } + } + /* + if self.config.IsoUrl == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("a iso url must be specified")) + } + */ - 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)) - } - } + self.config.BootWait, err = time.ParseDuration(self.config.RawBootWait) + if err != nil { + errs = packer.MultiErrorAppend( + errs, errors.New("Failed to parse boot_wait.")) + } -/* - if self.config.IsoUrl == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("a iso url must be specified")) - } -*/ + self.config.SSHWaitTimeout, err = time.ParseDuration(self.config.RawSSHWaitTimeout) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Failed to parse ssh_wait_timeout: %s", err)) + } - self.config.BootWait, err = time.ParseDuration(self.config.RawBootWait) - if err != nil { - errs = packer.MultiErrorAppend( - errs, errors.New("Failed to parse boot_wait.")) - } + for i, command := range self.config.BootCommand { + if err := self.config.tpl.Validate(command); err != nil { + errs = packer.MultiErrorAppend(errs, + fmt.Errorf("Error processing boot_command[%d]: %s", i, err)) + } + } - self.config.sshWaitTimeout, err = time.ParseDuration(self.config.RawSSHWaitTimeout) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Failed to parse ssh_wait_timeout: %s", err)) - } + if self.config.SSHUser == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("An ssh_username must be specified.")) + } - for i, command := range self.config.BootCommand { - if err := self.config.tpl.Validate(command); err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing boot_command[%d]: %s", i, err)) - } - } + if self.config.SSHKeyPath != "" { + if _, err := os.Stat(self.config.SSHKeyPath); err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) + } else if _, err := commonssh.FileSigner(self.config.SSHKeyPath); err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) + } + } - if self.config.SSHUser == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("An ssh_username must be specified.")) - } + if self.config.Username == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("A username for the xenserver host must be specified.")) + } - if self.config.SSHKeyPath != "" { - if _, err := os.Stat(self.config.SSHKeyPath); err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) - } else if _, err := commonssh.FileSigner(self.config.SSHKeyPath); err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) - } - } + if self.config.Password == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("A password for the xenserver host must be specified.")) + } - if self.config.Username == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("A username for the xenserver host must be specified.")) - } + if self.config.HostIp == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("An ip for the xenserver host must be specified.")) + } - if self.config.Password == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("A password for the xenserver host must be specified.")) - } + if self.config.InstanceName == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("An insatnce name must be specified.")) + } - if self.config.HostIp == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("An ip for the xenserver host must be specified.")) - } + if self.config.InstanceMemory == "" { + self.config.InstanceMemory = "1024000000" + } - if self.config.InstanceName == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("An insatnce name must be specified.")) - } + if self.config.RootDiskSize == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("A root disk size must be specified.")) + } - if self.config.InstanceMemory == "" { - self.config.InstanceMemory = "1024000000" - } + if self.config.CloneTemplate == "" { + self.config.CloneTemplate = "Other install media" + } - if self.config.RootDiskSize == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("A root disk size must be specified.")) - } + /* + if self.config.LocalIp == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("A local IP visible to XenServer's mangement interface is required to serve files.")) + } + */ - if self.config.CloneTemplate == "" { - self.config.CloneTemplate = "Other install media" - } + if len(self.config.PlatformArgs) == 0 { + pargs := make(map[string]string) + pargs["viridian"] = "false" + pargs["nx"] = "true" + pargs["pae"] = "true" + pargs["apic"] = "true" + pargs["timeoffset"] = "0" + pargs["acpi"] = "1" + self.config.PlatformArgs = pargs + } -/* - if self.config.LocalIp == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("A local IP visible to XenServer's mangement interface is required to serve files.")) - } -*/ + if self.config.HTTPPortMin > self.config.HTTPPortMax { + errs = packer.MultiErrorAppend( + errs, errors.New("the HTTP min port must be less than the max")) + } - if len(self.config.PlatformArgs) == 0 { - pargs := make(map[string]string) - pargs["viridian"] = "false" - pargs["nx"] = "true" - pargs["pae"] = "true" - pargs["apic"] = "true" - pargs["timeoffset"] = "0" - pargs["acpi"] = "1" - self.config.PlatformArgs = pargs - } + if self.config.HostPortMin > self.config.HostPortMax { + errs = packer.MultiErrorAppend( + errs, errors.New("the host min port must be less than the max")) + } + /* + if self.config.ISOChecksumType == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("The iso_checksum_type must be specified.")) + } else { + self.config.ISOChecksumType = strings.ToLower(self.config.ISOChecksumType) + if self.config.ISOChecksumType != "none" { + if self.config.ISOChecksum == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("Due to the file size being large, an iso_checksum is required.")) + } else { + self.config.ISOChecksum = strings.ToLower(self.config.ISOChecksum) + } - if self.config.HTTPPortMin > self.config.HTTPPortMax { - errs = packer.MultiErrorAppend( - errs, errors.New("the HTTP min port must be less than the max")) - } + if hash := common.HashForType(self.config.ISOChecksumType); hash == nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Unsupported checksum type: %s", self.config.ISOChecksumType)) + } - if self.config.HostPortMin > self.config.HostPortMax { - errs = packer.MultiErrorAppend( - errs, errors.New("the host min port must be less than the max")) - } -/* - if self.config.ISOChecksumType == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("The iso_checksum_type must be specified.")) - } else { - self.config.ISOChecksumType = strings.ToLower(self.config.ISOChecksumType) - if self.config.ISOChecksumType != "none" { - if self.config.ISOChecksum == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("Due to the file size being large, an iso_checksum is required.")) - } else { - self.config.ISOChecksum = strings.ToLower(self.config.ISOChecksum) - } + } + } - if hash := common.HashForType(self.config.ISOChecksumType); hash == nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Unsupported checksum type: %s", self.config.ISOChecksumType)) - } + if self.config.ISOUrl == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("A ISO URL must be specfied.")) + } else { + self.config.ISOUrls = []string{self.config.ISOUrl} + } - } - } + for i, url := range self.config.ISOUrls { + self.config.ISOUrls[i], err = common.DownloadableURL(url) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Failed to parse the iso_url (%d): %s", i, err)) + } + } + */ + if len(errs.Errors) > 0 { + retErr = errors.New(errs.Error()) + } - if self.config.ISOUrl == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("A ISO URL must be specfied.")) - } else { - self.config.ISOUrls = []string{self.config.ISOUrl} - } - - for i, url := range self.config.ISOUrls { - self.config.ISOUrls[i], err = common.DownloadableURL(url) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Failed to parse the iso_url (%d): %s", i, err)) - } - } -*/ - if len(errs.Errors) > 0 { - retErr = errors.New(errs.Error()) - } - - return nil, retErr + return nil, retErr } func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { - //Setup XAPI client - client := NewXenAPIClient(self.config.HostIp, self.config.Username, self.config.Password) + //Setup XAPI client + client := NewXenAPIClient(self.config.HostIp, self.config.Username, self.config.Password) - err := client.Login() - if err != nil { - return nil, err.(error) - } - ui.Say("XAPI client session established") + err := client.Login() + if err != nil { + return nil, err.(error) + } + ui.Say("XAPI client session established") - client.GetHosts() + client.GetHosts() - //Share state between the other steps using a statebag - state := new(multistep.BasicStateBag) - state.Put("cache", cache) - state.Put("client", client) - state.Put("config", self.config) - state.Put("hook", hook) - state.Put("ui", ui) + //Share state between the other steps using a statebag + state := new(multistep.BasicStateBag) + state.Put("cache", cache) + state.Put("client", client) + state.Put("config", self.config) + state.Put("hook", hook) + state.Put("ui", ui) + //Build the steps + steps := []multistep.Step{ + /* + &common.StepDownload{ + Checksum: self.config.ISOChecksum, + ChecksumType: self.config.ISOChecksumType, + Description: "ISO", + ResultKey: "iso_path", + Url: self.config.ISOUrls, + }, + */ + new(stepPrepareOutputDir), + new(stepHTTPServer), + //new(stepUploadIso), + new(stepCreateInstance), + new(stepStartVmPaused), + new(stepGetVNCPort), + &stepForwardPortOverSSH{ + RemotePort: instanceVNCPort, + RemoteDest: instanceVNCIP, + HostPortMin: self.config.HostPortMin, + HostPortMax: self.config.HostPortMax, + ResultKey: "local_vnc_port", + }, + new(stepBootWait), + new(stepTypeBootCommand), + new(stepWait), + new(stepStartOnHIMN), + &stepForwardPortOverSSH{ + RemotePort: himnSSHPort, + RemoteDest: himnSSHIP, + HostPortMin: self.config.HostPortMin, + HostPortMax: self.config.HostPortMax, + ResultKey: "local_ssh_port", + }, + &common.StepConnectSSH{ + SSHAddress: sshLocalAddress, + SSHConfig: sshConfig, + SSHWaitTimeout: self.config.SSHWaitTimeout, + }, + new(common.StepProvision), + new(stepShutdownAndExport), + } - //Build the steps - steps := []multistep.Step{ - /* - &common.StepDownload{ - Checksum: self.config.ISOChecksum, - ChecksumType: self.config.ISOChecksumType, - Description: "ISO", - ResultKey: "iso_path", - Url: self.config.ISOUrls, - }, - */ - new(stepPrepareOutputDir), - new(stepHTTPServer), - //new(stepUploadIso), - new(stepCreateInstance), - new(stepStartVmPaused), - new(stepGetVNCPort), - &stepForwardPortOverSSH{ - RemotePort: instanceVNCPort, - RemoteDest: instanceVNCIP, - HostPortMin: self.config.HostPortMin, - HostPortMax: self.config.HostPortMax, - ResultKey: "local_vnc_port", - }, - new(stepBootWait), - new(stepTypeBootCommand), - new(stepWait), - new(stepStartOnHIMN), - &stepForwardPortOverSSH{ - RemotePort: himnSSHPort, - RemoteDest: himnSSHIP, - HostPortMin: self.config.HostPortMin, - HostPortMax: self.config.HostPortMax, - ResultKey: "local_ssh_port", - }, - &common.StepConnectSSH{ - SSHAddress: sshLocalAddress, - SSHConfig: sshConfig, - SSHWaitTimeout: self.config.sshWaitTimeout, - }, - new(common.StepProvision), - new(stepShutdownAndExport), - } + self.runner = &multistep.BasicRunner{Steps: steps} + self.runner.Run(state) - self.runner = &multistep.BasicRunner{Steps: steps} - self.runner.Run(state) + artifact, _ := NewArtifact(self.config.OutputDir) - artifact, _ := NewArtifact(self.config.OutputDir) + if rawErr, ok := state.GetOk("error"); ok { + return nil, rawErr.(error) + } - if rawErr, ok := state.GetOk("error"); ok { - return nil, rawErr.(error) - } - - return artifact, nil + return artifact, nil } - func (self *Builder) Cancel() { - if self.runner != nil { - log.Println("Cancelling the step runner...") - self.runner.Cancel() - } - fmt.Println("Cancelling the builder") + if self.runner != nil { + log.Println("Cancelling the step runner...") + self.runner.Cancel() + } + fmt.Println("Cancelling the builder") } - diff --git a/builder/xenserver/client.go b/builder/xenserver/client.go index 64eec8e..17351cd 100644 --- a/builder/xenserver/client.go +++ b/builder/xenserver/client.go @@ -1,761 +1,745 @@ package xenserver import ( - "github.com/nilshell/xmlrpc" - "log" - "fmt" - "errors" + "errors" + "fmt" + "github.com/nilshell/xmlrpc" + "log" ) func check(err error) { - if err != nil { - log.Fatal(err) - } + if err != nil { + log.Fatal(err) + } } - type XenAPIClient struct { - Session interface{} - Host string - Url string - Username string - Password string - RPC *xmlrpc.Client + Session interface{} + Host string + Url string + Username string + Password string + RPC *xmlrpc.Client } - type APIResult struct { - Status string - Value interface{} - ErrorDescription string + Status string + Value interface{} + ErrorDescription string } type VM struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type SR struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type VDI struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type Network struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type VBD struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type VIF struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type PIF struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } type Pool struct { - Ref string - Client *XenAPIClient + Ref string + Client *XenAPIClient } -func (c *XenAPIClient) RPCCall (result interface{}, method string, params []interface{}) (err error) { - fmt.Println(params) - p := new(xmlrpc.Params) - p.Params = params - err = c.RPC.Call(method, *p, result) - return err +func (c *XenAPIClient) RPCCall(result interface{}, method string, params []interface{}) (err error) { + fmt.Println(params) + p := new(xmlrpc.Params) + p.Params = params + err = c.RPC.Call(method, *p, result) + return err } +func (client *XenAPIClient) Login() (err error) { + //Do loging call + result := xmlrpc.Struct{} -func (client *XenAPIClient) Login () (err error) { - //Do loging call - result := xmlrpc.Struct{} + params := make([]interface{}, 2) + params[0] = client.Username + params[1] = client.Password - params := make([]interface{}, 2) - params[0] = client.Username - params[1] = client.Password - - err = client.RPCCall(&result, "session.login_with_password", params) - client.Session = result["Value"] - return err + err = client.RPCCall(&result, "session.login_with_password", params) + client.Session = result["Value"] + return err } -func (client *XenAPIClient) APICall (result *APIResult, method string, params ...interface{}) (err error) { - if client.Session == nil { - fmt.Println("Error: no session") - return fmt.Errorf("No session. Unable to make call") - } +func (client *XenAPIClient) APICall(result *APIResult, method string, params ...interface{}) (err error) { + if client.Session == nil { + fmt.Println("Error: no session") + return fmt.Errorf("No session. Unable to make call") + } - //Make a params slice which will include the session - p := make([]interface{}, len(params) + 1) - p[0] = client.Session + //Make a params slice which will include the session + p := make([]interface{}, len(params)+1) + p[0] = client.Session - if params != nil { - for idx, element := range params { - p[idx+1] = element - } - } + if params != nil { + for idx, element := range params { + p[idx+1] = element + } + } - res := xmlrpc.Struct{} + res := xmlrpc.Struct{} - err = client.RPCCall(&res, method, p) + err = client.RPCCall(&res, method, p) - if err != nil { - return err - } + if err != nil { + return err + } - result.Status = res["Status"].(string) + result.Status = res["Status"].(string) - if result.Status != "Success" { - fmt.Println("Encountered an API error: ", result.Status) - fmt.Println(res["ErrorDescription"]) - log.Fatal(res["ErrorDescription"]) - return errors.New("API Error occurred") - } else { - result.Value = res["Value"] - } - return + if result.Status != "Success" { + fmt.Println("Encountered an API error: ", result.Status) + fmt.Println(res["ErrorDescription"]) + log.Fatal(res["ErrorDescription"]) + return errors.New("API Error occurred") + } else { + result.Value = res["Value"] + } + return } - -func (client *XenAPIClient) GetHosts () (err error) { - result := APIResult{} - _ = client.APICall(&result, "host.get_all") - hosts := result.Value - fmt.Println(hosts) - return nil +func (client *XenAPIClient) GetHosts() (err error) { + result := APIResult{} + _ = client.APICall(&result, "host.get_all") + hosts := result.Value + fmt.Println(hosts) + return nil } +func (client *XenAPIClient) GetPools() (pools []*Pool, err error) { + pools = make([]*Pool, 0) + result := APIResult{} + err = client.APICall(&result, "pool.get_all") + if err != nil { + return pools, err + } -func (client *XenAPIClient) GetPools () (pools []*Pool, err error) { - pools = make([]*Pool, 0) - result := APIResult{} - err = client.APICall(&result, "pool.get_all") - if err != nil { - return pools, err - } + for _, elem := range result.Value.([]interface{}) { + pool := new(Pool) + pool.Ref = elem.(string) + pool.Client = client + pools = append(pools, pool) + } - for _, elem := range result.Value.([]interface{}) { - pool := new(Pool) - pool.Ref = elem.(string) - pool.Client = client - pools = append(pools, pool) - } - - return pools, nil + return pools, nil } +func (client *XenAPIClient) GetDefaultSR() (sr *SR, err error) { + pools, err := client.GetPools() -func (client *XenAPIClient) GetDefaultSR () (sr *SR, err error) { - pools, err := client.GetPools() + if err != nil { + return nil, err + } - if err != nil { - return nil, err - } + pool_rec, err := pools[0].GetRecord() - pool_rec, err := pools[0].GetRecord() + if err != nil { + return nil, err + } - if err != nil { - return nil, err - } + if pool_rec["default_SR"] == "" { + return nil, errors.New("No default_SR specified for the pool.") + } - if pool_rec["default_SR"] == "" { - return nil, errors.New("No default_SR specified for the pool.") - } + sr = new(SR) + sr.Ref = pool_rec["default_SR"].(string) + sr.Client = client - sr = new(SR) - sr.Ref = pool_rec["default_SR"].(string) - sr.Client = client - - return sr, nil + return sr, nil } - -func (client *XenAPIClient) GetVMByUuid (vm_uuid string) (vm *VM, err error) { - vm = new(VM) - result := APIResult{} - err = client.APICall(&result, "VM.get_by_uuid", vm_uuid) - if err != nil { - return nil, err - } - vm.Ref = result.Value.(string) - vm.Client = client - return +func (client *XenAPIClient) GetVMByUuid(vm_uuid string) (vm *VM, err error) { + vm = new(VM) + result := APIResult{} + err = client.APICall(&result, "VM.get_by_uuid", vm_uuid) + if err != nil { + return nil, err + } + vm.Ref = result.Value.(string) + vm.Client = client + return } +func (client *XenAPIClient) GetVMByNameLabel(name_label string) (vms []*VM, err error) { + vms = make([]*VM, 0) + result := APIResult{} + err = client.APICall(&result, "VM.get_by_name_label", name_label) + if err != nil { + return vms, err + } -func (client *XenAPIClient) GetVMByNameLabel (name_label string) (vms []*VM, err error) { - vms = make([]*VM, 0) - result := APIResult{} - err = client.APICall(&result, "VM.get_by_name_label", name_label) - if err != nil { - return vms, err - } + for _, elem := range result.Value.([]interface{}) { + vm := new(VM) + vm.Ref = elem.(string) + vm.Client = client + vms = append(vms, vm) + } - for _, elem := range result.Value.([]interface{}) { - vm := new(VM) - vm.Ref = elem.(string) - vm.Client = client - vms = append(vms, vm) - } - - return vms, nil + return vms, nil } +func (client *XenAPIClient) GetSRByNameLabel(name_label string) (srs []*SR, err error) { + srs = make([]*SR, 0) + result := APIResult{} + err = client.APICall(&result, "SR.get_by_name_label", name_label) + if err != nil { + return srs, err + } -func (client *XenAPIClient) GetSRByNameLabel (name_label string) (srs []*SR, err error) { - srs = make([]*SR, 0) - result := APIResult{} - err = client.APICall(&result, "SR.get_by_name_label", name_label) - if err != nil { - return srs, err - } + for _, elem := range result.Value.([]interface{}) { + sr := new(SR) + sr.Ref = elem.(string) + sr.Client = client + srs = append(srs, sr) + } - for _, elem := range result.Value.([]interface{}) { - sr := new(SR) - sr.Ref = elem.(string) - sr.Client = client - srs = append(srs, sr) - } - - return srs, nil + return srs, nil } -func (client *XenAPIClient) GetNetworkByUuid (network_uuid string) (network *Network, err error) { - network = new(Network) - result := APIResult{} - err = client.APICall(&result, "network.get_by_uuid", network_uuid) - if err != nil { - return nil, err - } - network.Ref = result.Value.(string) - network.Client = client - return +func (client *XenAPIClient) GetNetworkByUuid(network_uuid string) (network *Network, err error) { + network = new(Network) + result := APIResult{} + err = client.APICall(&result, "network.get_by_uuid", network_uuid) + if err != nil { + return nil, err + } + network.Ref = result.Value.(string) + network.Client = client + return } +func (client *XenAPIClient) GetNetworkByNameLabel(name_label string) (networks []*Network, err error) { + networks = make([]*Network, 0) + result := APIResult{} + err = client.APICall(&result, "network.get_by_name_label", name_label) + if err != nil { + return networks, err + } -func (client *XenAPIClient) GetNetworkByNameLabel (name_label string) (networks []*Network, err error) { - networks = make([]*Network, 0) - result := APIResult{} - err = client.APICall(&result, "network.get_by_name_label", name_label) - if err != nil { - return networks, err - } + for _, elem := range result.Value.([]interface{}) { + network := new(Network) + network.Ref = elem.(string) + network.Client = client + networks = append(networks, network) + } - for _, elem := range result.Value.([]interface{}) { - network := new(Network) - network.Ref = elem.(string) - network.Client = client - networks = append(networks, network) - } - - return networks, nil + return networks, nil } -func (client *XenAPIClient) GetVdiByNameLabel (name_label string) (vdis []*VDI, err error) { - vdis = make([]*VDI, 0) - result := APIResult{} - err = client.APICall(&result, "VDI.get_by_name_label", name_label) - if err != nil { - return vdis, err - } +func (client *XenAPIClient) GetVdiByNameLabel(name_label string) (vdis []*VDI, err error) { + vdis = make([]*VDI, 0) + result := APIResult{} + err = client.APICall(&result, "VDI.get_by_name_label", name_label) + if err != nil { + return vdis, err + } - for _, elem := range result.Value.([]interface{}) { - vdi := new(VDI) - vdi.Ref = elem.(string) - vdi.Client = client - vdis = append(vdis, vdi) - } + for _, elem := range result.Value.([]interface{}) { + vdi := new(VDI) + vdi.Ref = elem.(string) + vdi.Client = client + vdis = append(vdis, vdi) + } - return vdis, nil + return vdis, nil } - -func (client *XenAPIClient) GetSRByUuid (sr_uuid string) (sr *SR, err error) { - sr = new(SR) - result := APIResult{} - err = client.APICall(&result, "SR.get_by_uuid", sr_uuid) - if err != nil { - return nil, err - } - sr.Ref = result.Value.(string) - sr.Client = client - return +func (client *XenAPIClient) GetSRByUuid(sr_uuid string) (sr *SR, err error) { + sr = new(SR) + result := APIResult{} + err = client.APICall(&result, "SR.get_by_uuid", sr_uuid) + if err != nil { + return nil, err + } + sr.Ref = result.Value.(string) + sr.Client = client + return } -func (client *XenAPIClient) GetVdiByUuid (vdi_uuid string) (vdi *VDI, err error) { - vdi = new(VDI) - result := APIResult{} - err = client.APICall(&result, "VDI.get_by_uuid", vdi_uuid) - if err != nil { - return nil, err - } - vdi.Ref = result.Value.(string) - vdi.Client = client - return +func (client *XenAPIClient) GetVdiByUuid(vdi_uuid string) (vdi *VDI, err error) { + vdi = new(VDI) + result := APIResult{} + err = client.APICall(&result, "VDI.get_by_uuid", vdi_uuid) + if err != nil { + return nil, err + } + vdi.Ref = result.Value.(string) + vdi.Client = client + return } func (client *XenAPIClient) GetPIFs() (pifs []*PIF, err error) { - pifs = make([]*PIF, 0) - result := APIResult{} - err = client.APICall(&result, "PIF.get_all") - if err != nil { - return pifs, err - } - for _, elem := range result.Value.([]interface{}) { - pif := new(PIF) - pif.Ref = elem.(string) - pif.Client = client - pifs = append(pifs, pif) - } + pifs = make([]*PIF, 0) + result := APIResult{} + err = client.APICall(&result, "PIF.get_all") + if err != nil { + return pifs, err + } + for _, elem := range result.Value.([]interface{}) { + pif := new(PIF) + pif.Ref = elem.(string) + pif.Client = client + pifs = append(pifs, pif) + } - return pifs, nil + return pifs, nil } // VM associated functions -func (self *VM) Clone (label string) (new_instance *VM, err error) { - new_instance = new(VM) +func (self *VM) Clone(label string) (new_instance *VM, err error) { + new_instance = new(VM) - result := APIResult{} - err = self.Client.APICall(&result, "VM.clone", self.Ref, label) - if err != nil { - return nil, err - } - new_instance.Ref = result.Value.(string) - new_instance.Client = self.Client - return + result := APIResult{} + err = self.Client.APICall(&result, "VM.clone", self.Ref, label) + if err != nil { + return nil, err + } + new_instance.Ref = result.Value.(string) + new_instance.Client = self.Client + return } func (self *VM) Start(paused, force bool) (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.start", self.Ref, paused, force) - if err != nil { - return err - } - return + result := APIResult{} + err = self.Client.APICall(&result, "VM.start", self.Ref, paused, force) + if err != nil { + return err + } + return } func (self *VM) CleanShutdown() (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.clean_shutdown", self.Ref) - if err != nil { - return err - } - return + result := APIResult{} + err = self.Client.APICall(&result, "VM.clean_shutdown", self.Ref) + if err != nil { + return err + } + return } -func (self *VM) Unpause () (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.unpause", self.Ref) - if err != nil { - return err - } - return +func (self *VM) Unpause() (err error) { + result := APIResult{} + err = self.Client.APICall(&result, "VM.unpause", self.Ref) + if err != nil { + return err + } + return } func (self *VM) SetPVBootloader(pv_bootloader, pv_args string) (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.set_PV_bootloader", self.Ref, pv_bootloader) - if err != nil { - return err - } - result = APIResult{} - err = self.Client.APICall(&result, "VM.set_PV_bootloader_args", self.Ref, pv_args) - if err != nil { - return err - } - return + result := APIResult{} + err = self.Client.APICall(&result, "VM.set_PV_bootloader", self.Ref, pv_bootloader) + if err != nil { + return err + } + result = APIResult{} + err = self.Client.APICall(&result, "VM.set_PV_bootloader_args", self.Ref, pv_args) + if err != nil { + return err + } + return } func (self *VM) GetDomainId() (domid string, err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.get_domid", self.Ref) - if err != nil { - return "", err - } - domid = result.Value.(string) - return domid, nil + result := APIResult{} + err = self.Client.APICall(&result, "VM.get_domid", self.Ref) + if err != nil { + return "", err + } + domid = result.Value.(string) + return domid, nil } func (self *VM) GetPowerState() (state string, err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.get_power_state", self.Ref) - if err != nil { - return "", err - } - state = result.Value.(string) - return state, nil + result := APIResult{} + err = self.Client.APICall(&result, "VM.get_power_state", self.Ref) + if err != nil { + return "", err + } + state = result.Value.(string) + return state, nil } func (self *VM) GetUuid() (uuid string, err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.get_uuid", self.Ref) - if err != nil { - return "", err - } - uuid = result.Value.(string) - return uuid, nil + result := APIResult{} + err = self.Client.APICall(&result, "VM.get_uuid", self.Ref) + if err != nil { + return "", err + } + uuid = result.Value.(string) + return uuid, nil } func (self *VM) GetVBDs() (vbds []VBD, err error) { - vbds = make([]VBD, 0) - result := APIResult{} - err = self.Client.APICall(&result, "VM.get_VBDs", self.Ref) - if err != nil { - return vbds, err - } - for _, elem := range result.Value.([]interface{}) { - vbd := VBD{} - vbd.Ref = elem.(string) - vbd.Client = self.Client - vbds = append(vbds, vbd) - } + vbds = make([]VBD, 0) + result := APIResult{} + err = self.Client.APICall(&result, "VM.get_VBDs", self.Ref) + if err != nil { + return vbds, err + } + for _, elem := range result.Value.([]interface{}) { + vbd := VBD{} + vbd.Ref = elem.(string) + vbd.Client = self.Client + vbds = append(vbds, vbd) + } - return vbds, nil + return vbds, nil } - func (self *VM) GetVIFs() (vifs []VIF, err error) { - vifs = make([]VIF, 0) - result := APIResult{} - err = self.Client.APICall(&result, "VM.get_VIFs", self.Ref) - if err != nil { - return vifs, err - } - for _, elem := range result.Value.([]interface{}) { - vif := VIF{} - vif.Ref = elem.(string) - vif.Client = self.Client - vifs = append(vifs, vif) - } + vifs = make([]VIF, 0) + result := APIResult{} + err = self.Client.APICall(&result, "VM.get_VIFs", self.Ref) + if err != nil { + return vifs, err + } + for _, elem := range result.Value.([]interface{}) { + vif := VIF{} + vif.Ref = elem.(string) + vif.Client = self.Client + vifs = append(vifs, vif) + } - return vifs, nil + return vifs, nil } func (self *VM) GetDisks() (vdis []*VDI, err error) { - // Return just data disks (non-isos) - vdis = make([]*VDI, 0) - vbds, err := self.GetVBDs() - if err != nil { - return nil, err - } + // Return just data disks (non-isos) + vdis = make([]*VDI, 0) + vbds, err := self.GetVBDs() + if err != nil { + return nil, err + } - for _, vbd := range vbds { - rec, err := vbd.GetRecord() - if err != nil { - return nil, err - } - if rec["type"] == "Disk" { + for _, vbd := range vbds { + rec, err := vbd.GetRecord() + if err != nil { + return nil, err + } + if rec["type"] == "Disk" { - vdi, err := vbd.GetVDI() - if err != nil { - return nil, err - } - vdis = append(vdis, vdi) + vdi, err := vbd.GetVDI() + if err != nil { + return nil, err + } + vdis = append(vdis, vdi) - } - } - return vdis, nil + } + } + return vdis, nil } func (self *VM) GetGuestMetricsRef() (ref string, err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.get_guest_metrics", self.Ref) - if err != nil { - return "", nil - } - ref = result.Value.(string) - return ref, err + result := APIResult{} + err = self.Client.APICall(&result, "VM.get_guest_metrics", self.Ref) + if err != nil { + return "", nil + } + ref = result.Value.(string) + return ref, err } func (self *VM) GetGuestMetrics() (metrics map[string]interface{}, err error) { - metrics = make(map[string]interface{}) - metrics_ref, err := self.GetGuestMetricsRef() - if err != nil { - return metrics, err - } + metrics = make(map[string]interface{}) + metrics_ref, err := self.GetGuestMetricsRef() + if err != nil { + return metrics, err + } - result := APIResult{} - err = self.Client.APICall(&result, "VM_guest_metrics.get_record", metrics_ref) - if err != nil { - return metrics, nil - } - for k, v := range result.Value.(xmlrpc.Struct) { - metrics[k] = v - } - return metrics, nil + result := APIResult{} + err = self.Client.APICall(&result, "VM_guest_metrics.get_record", metrics_ref) + if err != nil { + return metrics, nil + } + for k, v := range result.Value.(xmlrpc.Struct) { + metrics[k] = v + } + return metrics, nil } func (self *VM) SetStaticMemoryRange(min, max string) (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.set_memory_limits", self.Ref, min, max, min, max) - if err != nil { - return err - } - return + result := APIResult{} + err = self.Client.APICall(&result, "VM.set_memory_limits", self.Ref, min, max, min, max) + if err != nil { + return err + } + return } -func (self *VM) ConnectVdi (vdi *VDI, iso bool) (err error) { +func (self *VM) ConnectVdi(vdi *VDI, iso bool) (err error) { - // 1. Create a VBD + // 1. Create a VBD - vbd_rec := make(xmlrpc.Struct) - vbd_rec["VM"] = self.Ref - vbd_rec["VDI"] = vdi.Ref - vbd_rec["userdevice"] = "autodetect" - vbd_rec["unpluggable"] = false - vbd_rec["empty"] = false - vbd_rec["other_config"] = make(xmlrpc.Struct) - vbd_rec["qos_algorithm_type"] = "" - vbd_rec["qos_algorithm_params"] = make(xmlrpc.Struct) + vbd_rec := make(xmlrpc.Struct) + vbd_rec["VM"] = self.Ref + vbd_rec["VDI"] = vdi.Ref + vbd_rec["userdevice"] = "autodetect" + vbd_rec["unpluggable"] = false + vbd_rec["empty"] = false + vbd_rec["other_config"] = make(xmlrpc.Struct) + vbd_rec["qos_algorithm_type"] = "" + vbd_rec["qos_algorithm_params"] = make(xmlrpc.Struct) - if iso { - vbd_rec["mode"] = "RO" - vbd_rec["bootable"] = true - vbd_rec["type"] = "CD" - } else { - vbd_rec["mode"] = "RW" - vbd_rec["bootable"] = false - vbd_rec["type"] = "Disk" - } + if iso { + vbd_rec["mode"] = "RO" + vbd_rec["bootable"] = true + vbd_rec["type"] = "CD" + } else { + vbd_rec["mode"] = "RW" + vbd_rec["bootable"] = false + vbd_rec["type"] = "Disk" + } - result := APIResult{} - err = self.Client.APICall(&result, "VBD.create", vbd_rec) + result := APIResult{} + err = self.Client.APICall(&result, "VBD.create", vbd_rec) - if err != nil { - return err - } + if err != nil { + return err + } - vbd_ref := result.Value.(string) - fmt.Println("VBD Ref:", vbd_ref) + vbd_ref := result.Value.(string) + fmt.Println("VBD Ref:", vbd_ref) - result = APIResult{} - err = self.Client.APICall(&result, "VBD.get_uuid", vbd_ref) + result = APIResult{} + err = self.Client.APICall(&result, "VBD.get_uuid", vbd_ref) - fmt.Println("VBD UUID: ", result.Value.(string)) -/* - // 2. Plug VBD (Non need - the VM hasn't booted. - // @todo - check VM state - result = APIResult{} - err = self.Client.APICall(&result, "VBD.plug", vbd_ref) + fmt.Println("VBD UUID: ", result.Value.(string)) + /* + // 2. Plug VBD (Non need - the VM hasn't booted. + // @todo - check VM state + result = APIResult{} + err = self.Client.APICall(&result, "VBD.plug", vbd_ref) - if err != nil { - return err - } -*/ - return + if err != nil { + return err + } + */ + return } func (self *VM) SetPlatform(params map[string]string) (err error) { - result := APIResult{} - platform_rec := make(xmlrpc.Struct) - for key, value := range params { - platform_rec[key] = value - } + result := APIResult{} + platform_rec := make(xmlrpc.Struct) + for key, value := range params { + platform_rec[key] = value + } - err = self.Client.APICall(&result, "VM.set_platform", self.Ref, platform_rec) + err = self.Client.APICall(&result, "VM.set_platform", self.Ref, platform_rec) - if err != nil { - return err - } - return + if err != nil { + return err + } + return } +func (self *VM) ConnectNetwork(network *Network, device string) (vif *VIF, err error) { + // Create the VIF -func (self *VM) ConnectNetwork (network *Network, device string) (vif *VIF, err error) { - // Create the VIF + vif_rec := make(xmlrpc.Struct) + vif_rec["network"] = network.Ref + vif_rec["VM"] = self.Ref + vif_rec["MAC"] = "" + vif_rec["device"] = device + vif_rec["MTU"] = "1504" + vif_rec["other_config"] = make(xmlrpc.Struct) + vif_rec["qos_algorithm_type"] = "" + vif_rec["qos_algorithm_params"] = make(xmlrpc.Struct) - vif_rec := make(xmlrpc.Struct) - vif_rec["network"] = network.Ref - vif_rec["VM"] = self.Ref - vif_rec["MAC"] = "" - vif_rec["device"] = device - vif_rec["MTU"] = "1504" - vif_rec["other_config"] = make(xmlrpc.Struct) - vif_rec["qos_algorithm_type"] = "" - vif_rec["qos_algorithm_params"] = make(xmlrpc.Struct) + result := APIResult{} + err = self.Client.APICall(&result, "VIF.create", vif_rec) - result := APIResult{} - err = self.Client.APICall(&result, "VIF.create", vif_rec) + if err != nil { + return nil, err + } - if err != nil { - return nil, err - } + vif = new(VIF) + vif.Ref = result.Value.(string) + vif.Client = self.Client - vif = new(VIF) - vif.Ref = result.Value.(string) - vif.Client = self.Client - - return vif, nil + return vif, nil } // Setters -func (self *VM) SetIsATemplate (is_a_template bool) (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VM.set_is_a_template", self.Ref, is_a_template) - if err != nil { - return err - } - return +func (self *VM) SetIsATemplate(is_a_template bool) (err error) { + result := APIResult{} + err = self.Client.APICall(&result, "VM.set_is_a_template", self.Ref, is_a_template) + if err != nil { + return err + } + return } // SR associated functions -func (self *SR) CreateVdi (name_label, size string) (vdi *VDI, err error) { - vdi = new(VDI) +func (self *SR) CreateVdi(name_label, size string) (vdi *VDI, err error) { + vdi = new(VDI) - vdi_rec := make(xmlrpc.Struct) - vdi_rec["name_label"] = name_label - vdi_rec["SR"] = self.Ref - vdi_rec["virtual_size"] = size - vdi_rec["type"] = "user" - vdi_rec["sharable"] = false - vdi_rec["read_only"] = false + vdi_rec := make(xmlrpc.Struct) + vdi_rec["name_label"] = name_label + vdi_rec["SR"] = self.Ref + vdi_rec["virtual_size"] = size + vdi_rec["type"] = "user" + vdi_rec["sharable"] = false + vdi_rec["read_only"] = false - oc := make(xmlrpc.Struct) - oc["temp"] = "temp" - vdi_rec["other_config"] = oc + oc := make(xmlrpc.Struct) + oc["temp"] = "temp" + vdi_rec["other_config"] = oc + result := APIResult{} + err = self.Client.APICall(&result, "VDI.create", vdi_rec) + if err != nil { + return nil, err + } - result := APIResult{} - err = self.Client.APICall(&result, "VDI.create", vdi_rec) - if err != nil { - return nil, err - } + vdi.Ref = result.Value.(string) + vdi.Client = self.Client - vdi.Ref = result.Value.(string) - vdi.Client = self.Client - - return + return } // Network associated functions -func (self *Network) GetAssignedIPs () (ip_map map[string]string, err error) { - ip_map = make(map[string]string, 0) - result := APIResult{} - err = self.Client.APICall(&result, "network.get_assigned_ips", self.Ref) - if err != nil { - return ip_map, err - } - for k, v := range result.Value.(xmlrpc.Struct) { - ip_map[k] = v.(string) - } - return ip_map, nil +func (self *Network) GetAssignedIPs() (ip_map map[string]string, err error) { + ip_map = make(map[string]string, 0) + result := APIResult{} + err = self.Client.APICall(&result, "network.get_assigned_ips", self.Ref) + if err != nil { + return ip_map, err + } + for k, v := range result.Value.(xmlrpc.Struct) { + ip_map[k] = v.(string) + } + return ip_map, nil } // PIF associated functions -func (self *PIF) GetRecord () (record map[string]interface{}, err error) { - record = make(map[string]interface{}) - result := APIResult{} - err = self.Client.APICall(&result, "PIF.get_record", self.Ref) - if err != nil { - return record, err - } - for k, v := range result.Value.(xmlrpc.Struct) { - record[k] = v - } - return record, nil +func (self *PIF) GetRecord() (record map[string]interface{}, err error) { + record = make(map[string]interface{}) + result := APIResult{} + err = self.Client.APICall(&result, "PIF.get_record", self.Ref) + if err != nil { + return record, err + } + for k, v := range result.Value.(xmlrpc.Struct) { + record[k] = v + } + return record, nil } // Pool associated functions -func (self *Pool) GetRecord () (record map[string]interface{}, err error) { - record = make(map[string]interface{}) - result := APIResult{} - err = self.Client.APICall(&result, "pool.get_record", self.Ref) - if err != nil { - return record, err - } - for k, v := range result.Value.(xmlrpc.Struct) { - record[k] = v - } - return record, nil +func (self *Pool) GetRecord() (record map[string]interface{}, err error) { + record = make(map[string]interface{}) + result := APIResult{} + err = self.Client.APICall(&result, "pool.get_record", self.Ref) + if err != nil { + return record, err + } + for k, v := range result.Value.(xmlrpc.Struct) { + record[k] = v + } + return record, nil } - // VBD associated functions -func (self *VBD) GetRecord () (record map[string]interface{}, err error) { - record = make(map[string]interface{}) - result := APIResult{} - err = self.Client.APICall(&result, "VBD.get_record", self.Ref) - if err != nil { - return record, err - } - for k, v := range result.Value.(xmlrpc.Struct) { - record[k] = v - } - return record, nil +func (self *VBD) GetRecord() (record map[string]interface{}, err error) { + record = make(map[string]interface{}) + result := APIResult{} + err = self.Client.APICall(&result, "VBD.get_record", self.Ref) + if err != nil { + return record, err + } + for k, v := range result.Value.(xmlrpc.Struct) { + record[k] = v + } + return record, nil } -func (self *VBD) GetVDI () (vdi *VDI, err error) { - vbd_rec, err := self.GetRecord() - if err != nil { - return nil, err - } +func (self *VBD) GetVDI() (vdi *VDI, err error) { + vbd_rec, err := self.GetRecord() + if err != nil { + return nil, err + } - vdi = new(VDI) - vdi.Ref = vbd_rec["VDI"].(string) - vdi.Client = self.Client + vdi = new(VDI) + vdi.Ref = vbd_rec["VDI"].(string) + vdi.Client = self.Client - return vdi, nil + return vdi, nil } -func (self *VBD) Eject () (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VBD.eject", self.Ref) - if err != nil { - return err - } - return nil +func (self *VBD) Eject() (err error) { + result := APIResult{} + err = self.Client.APICall(&result, "VBD.eject", self.Ref) + if err != nil { + return err + } + return nil } // VIF associated functions -func (self *VIF) Destroy () (err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VIF.destroy", self.Ref) - if err != nil { - return err - } - return nil +func (self *VIF) Destroy() (err error) { + result := APIResult{} + err = self.Client.APICall(&result, "VIF.destroy", self.Ref) + if err != nil { + return err + } + return nil } // VDI associated functions -func (self *VDI) GetUuid () (vdi_uuid string, err error) { - result := APIResult{} - err = self.Client.APICall(&result, "VDI.get_uuid", self.Ref) - if err != nil { - return "", err - } - vdi_uuid = result.Value.(string) - return vdi_uuid, nil +func (self *VDI) GetUuid() (vdi_uuid string, err error) { + result := APIResult{} + err = self.Client.APICall(&result, "VDI.get_uuid", self.Ref) + if err != nil { + return "", err + } + vdi_uuid = result.Value.(string) + return vdi_uuid, nil } - // Client Initiator -func NewXenAPIClient (host, username, password string) (client XenAPIClient) { - client.Host = host - client.Url = "http://" + host - client.Username = username - client.Password = password - client.RPC, _ = xmlrpc.NewClient(client.Url, nil) - return +func NewXenAPIClient(host, username, password string) (client XenAPIClient) { + client.Host = host + client.Url = "http://" + host + client.Username = username + client.Password = password + client.RPC, _ = xmlrpc.NewClient(client.Url, nil) + return } diff --git a/builder/xenserver/ssh.go b/builder/xenserver/ssh.go index 52ac08c..4d68684 100644 --- a/builder/xenserver/ssh.go +++ b/builder/xenserver/ssh.go @@ -1,29 +1,29 @@ package xenserver import ( - "fmt" + "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" - "strings" - "log" - "bytes" - "net" - "io" + "io" + "log" + "net" + "strings" ) func sshAddress(state multistep.StateBag) (string, error) { - sshIP := state.Get("ssh_address").(string) + sshIP := state.Get("ssh_address").(string) sshHostPort := 22 return fmt.Sprintf("%s:%d", sshIP, sshHostPort), nil } func sshLocalAddress(state multistep.StateBag) (string, error) { - sshLocalPort := state.Get("local_ssh_port").(uint) - conn_str := fmt.Sprintf("%s:%d", "127.0.0.1", sshLocalPort) - log.Printf("sshLocalAddress: %s", conn_str) - return conn_str, nil + sshLocalPort := state.Get("local_ssh_port").(uint) + conn_str := fmt.Sprintf("%s:%d", "127.0.0.1", sshLocalPort) + log.Printf("sshLocalAddress: %s", conn_str) + return conn_str, nil } func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { @@ -50,103 +50,101 @@ func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { }, nil } +func execute_ssh_cmd(cmd, host, port, username, password string) (stdout string, err error) { + // Setup connection config + config := &gossh.ClientConfig{ + User: username, + Auth: []gossh.AuthMethod{ + gossh.Password(password), + }, + } + client, err := gossh.Dial("tcp", host+":"+port, config) + if err != nil { + return "", err + } -func execute_ssh_cmd (cmd, host, port, username, password string) (stdout string, err error) { - // Setup connection config - config := &gossh.ClientConfig { - User: username, - Auth: []gossh.AuthMethod { - gossh.Password(password), - }, - } + //Create session + session, err := client.NewSession() - client, err := gossh.Dial("tcp", host + ":" + port, config) + if err != nil { + return "", err + } - if err != nil { - return "", err - } + defer session.Close() - //Create session - session, err := client.NewSession() + var b bytes.Buffer + session.Stdout = &b + if err := session.Run(cmd); err != nil { + return "", err + } - if err != nil { - return "", err - } - - defer session.Close() - - var b bytes.Buffer - session.Stdout = &b - if err := session.Run(cmd); err != nil { - return "", err - } - - session.Close() - return strings.Trim(b.String(), "\n"), nil + session.Close() + return strings.Trim(b.String(), "\n"), nil } -func forward(local_conn net.Conn, config *gossh.ClientConfig, server, remote_dest string, remote_port uint) { - ssh_client_conn, err := gossh.Dial("tcp", server + ":22", config) - if err != nil { - log.Fatalf("local ssh.Dial error: %s", err) - } +func forward(local_conn net.Conn, config *gossh.ClientConfig, server, remote_dest string, remote_port uint) error { + ssh_client_conn, err := gossh.Dial("tcp", server+":22", config) + if err != nil { + log.Printf("local ssh.Dial error: %s", err) + return err + } - remote_loc := fmt.Sprintf("%s:%d", remote_dest, remote_port) - ssh_conn, err := ssh_client_conn.Dial("tcp", remote_loc) - if err != nil { - log.Fatalf("ssh.Dial error: %s", err) - } + remote_loc := fmt.Sprintf("%s:%d", remote_dest, remote_port) + ssh_conn, err := ssh_client_conn.Dial("tcp", remote_loc) + if err != nil { + log.Printf("ssh.Dial error: %s", err) + return err + } - go func() { - _, err = io.Copy(ssh_conn, local_conn) - if err != nil { - log.Fatalf("io.copy failed: %v", err) - } - }() + go func() { + _, err = io.Copy(ssh_conn, local_conn) + if err != nil { + log.Printf("io.copy failed: %v", err) + } + }() - go func() { - _, err = io.Copy(local_conn, ssh_conn) - if err != nil { - log.Fatalf("io.copy failed: %v", err) - } - }() + go func() { + _, err = io.Copy(local_conn, ssh_conn) + if err != nil { + log.Printf("io.copy failed: %v", err) + } + }() + + return nil } -func ssh_port_forward(local_port uint, remote_port uint, remote_dest, host, username, password string) (err error) { +func ssh_port_forward(local_port uint, remote_port uint, remote_dest, host, username, password string) error { - config := &gossh.ClientConfig { - User: username, - Auth: []gossh.AuthMethod{ - gossh.Password(password), - }, - } + config := &gossh.ClientConfig{ + User: username, + Auth: []gossh.AuthMethod{ + gossh.Password(password), + }, + } - // Listen on a local port - local_listener, err := net.Listen("tcp", - fmt.Sprintf("%s:%d", - "127.0.0.1", - local_port)) - if err != nil { - log.Fatalf("Local listen failed: %s", err) - return err - } + // Listen on a local port + local_listener, err := net.Listen("tcp", + fmt.Sprintf("%s:%d", + "127.0.0.1", + local_port)) + if err != nil { + log.Printf("Local listen failed: %s", err) + return err + } - for { - local_connection, err := local_listener.Accept() + for { + local_connection, err := local_listener.Accept() - if err != nil { - log.Fatalf("Local accept failed: %s", err) - return err - } + if err != nil { + log.Printf("Local accept failed: %s", err) + return err + } + // Forward to a remote port + go forward(local_connection, config, host, remote_dest, remote_port) + } - // Forward to a remote port - go forward(local_connection, config, host, remote_dest, remote_port) - } - - - - return nil + return nil } diff --git a/builder/xenserver/step_boot_wait.go b/builder/xenserver/step_boot_wait.go index 0497d38..58f8126 100644 --- a/builder/xenserver/step_boot_wait.go +++ b/builder/xenserver/step_boot_wait.go @@ -1,30 +1,28 @@ package xenserver import ( - "fmt" - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "time" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "time" ) - type stepBootWait struct{} func (self *stepBootWait) Run(state multistep.StateBag) multistep.StepAction { - client := state.Get("client").(XenAPIClient) - config := state.Get("config").(config) - ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) - instance, _ := client.GetVMByUuid(state.Get("instance_uuid").(string)) - ui.Say("Unpausing VM " + state.Get("instance_uuid").(string)) - instance.Unpause() + instance, _ := client.GetVMByUuid(state.Get("instance_uuid").(string)) + ui.Say("Unpausing VM " + state.Get("instance_uuid").(string)) + instance.Unpause() - if int64(config.BootWait) > 0 { - ui.Say(fmt.Sprintf("Waiting %s for boot...", config.BootWait)) - time.Sleep(config.BootWait) - } - return multistep.ActionContinue + if int64(config.BootWait) > 0 { + ui.Say(fmt.Sprintf("Waiting %s for boot...", config.BootWait)) + time.Sleep(config.BootWait) + } + return multistep.ActionContinue } func (self *stepBootWait) Cleanup(state multistep.StateBag) {} - diff --git a/builder/xenserver/step_create_instance.go b/builder/xenserver/step_create_instance.go index ce3c51b..353a40a 100644 --- a/builder/xenserver/step_create_instance.go +++ b/builder/xenserver/step_create_instance.go @@ -1,198 +1,192 @@ package xenserver - import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "fmt" - "log" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" ) type stepCreateInstance struct { - InstanceId string + InstanceId string } func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { - client := state.Get("client").(XenAPIClient) - config := state.Get("config").(config) - ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) - ui.Say("Step: Create Instance") + ui.Say("Step: Create Instance") + // Get the template to clone from - // Get the template to clone from + vms, err := client.GetVMByNameLabel(config.CloneTemplate) - vms, err := client.GetVMByNameLabel(config.CloneTemplate) + switch { + case len(vms) == 0: + log.Fatal(fmt.Sprintf("Couldn't find a template with the name-label '%s'. Aborting.", config.CloneTemplate)) + return multistep.ActionHalt + case len(vms) > 1: + log.Fatal(fmt.Sprintf("Found more than one template with the name '%s'. The name must be unique. Aborting.", config.CloneTemplate)) + return multistep.ActionHalt + } - switch { - case len(vms) == 0: - log.Fatal(fmt.Sprintf("Couldn't find a template with the name-label '%s'. Aborting.", config.CloneTemplate)) - return multistep.ActionHalt - case len(vms) > 1: - log.Fatal(fmt.Sprintf("Found more than one template with the name '%s'. The name must be unique. Aborting.", config.CloneTemplate)) - return multistep.ActionHalt - } + template := vms[0] - template := vms[0] + // Clone that VM template + instance, _ := template.Clone(config.InstanceName) + instance.SetIsATemplate(false) + instance.SetStaticMemoryRange(config.InstanceMemory, config.InstanceMemory) + instance.SetPlatform(config.PlatformArgs) - // Clone that VM template - instance, _ := template.Clone(config.InstanceName) - instance.SetIsATemplate(false) - instance.SetStaticMemoryRange(config.InstanceMemory, config.InstanceMemory) - instance.SetPlatform(config.PlatformArgs) + // Create VDI for the instance + var sr *SR - // Create VDI for the instance - var sr *SR + if config.SrName == "" { + // Find the default SR + default_sr, err := client.GetDefaultSR() + sr = default_sr - if config.SrName == "" { - // Find the default SR - default_sr, err := client.GetDefaultSR() - sr = default_sr + if err != nil { + log.Fatal(fmt.Sprintf("Error getting default SR: %s", err.Error())) + return multistep.ActionHalt + } - if err != nil { - log.Fatal(fmt.Sprintf("Error getting default SR: %s", err.Error())) - return multistep.ActionHalt - } + } else { + // Use the provided name label to find the SR to use + srs, err := client.GetSRByNameLabel(config.SrName) + if err != nil { + log.Fatal(fmt.Sprintf("Error getting default SR: %s", err.Error())) + return multistep.ActionHalt + } - } else { - // Use the provided name label to find the SR to use - srs, err := client.GetSRByNameLabel(config.SrName) + switch { + case len(srs) == 0: + log.Fatal(fmt.Sprintf("Couldn't find a SR with the specified name-label '%s'. Aborting.", config.SrName)) + return multistep.ActionHalt + case len(srs) > 1: + log.Fatal(fmt.Sprintf("Found more than one SR with the name '%s'. The name must be unique. Aborting.", config.SrName)) + return multistep.ActionHalt + } - if err != nil { - log.Fatal(fmt.Sprintf("Error getting default SR: %s", err.Error())) - return multistep.ActionHalt - } + sr = srs[0] + } - switch { - case len(srs) == 0: - log.Fatal(fmt.Sprintf("Couldn't find a SR with the specified name-label '%s'. Aborting.", config.SrName)) - return multistep.ActionHalt - case len(srs) > 1: - log.Fatal(fmt.Sprintf("Found more than one SR with the name '%s'. The name must be unique. Aborting.", config.SrName)) - return multistep.ActionHalt - } + vdi, _ := sr.CreateVdi("Packer-disk", config.RootDiskSize) - sr = srs[0] - } + instance.ConnectVdi(vdi, false) - vdi, _ := sr.CreateVdi("Packer-disk", config.RootDiskSize) + // Connect Network - instance.ConnectVdi(vdi, false) + var network *Network - // Connect Network + if config.NetworkName == "" { + // No network has be specified. Use the management interface + network = new(Network) + network.Ref = "" + network.Client = &client - var network *Network + pifs, err := client.GetPIFs() - if config.NetworkName == "" { - // No network has be specified. Use the management interface - network = new(Network) - network.Ref = "" - network.Client = &client + if err != nil { + log.Fatal(fmt.Sprintf("Error getting PIFs %s", err.Error())) + return multistep.ActionHalt + } - pifs, err := client.GetPIFs() + for _, pif := range pifs { + pif_rec, err := pif.GetRecord() - if err != nil { - log.Fatal(fmt.Sprintf("Error getting PIFs %s", err.Error())) - return multistep.ActionHalt - } + if err != nil { + log.Fatal(fmt.Sprintf("Error getting PIF record: %s", err.Error())) + return multistep.ActionHalt + } - for _, pif := range pifs { - pif_rec, err := pif.GetRecord() + if pif_rec["management"].(bool) { + network.Ref = pif_rec["network"].(string) + } - if err != nil { - log.Fatal(fmt.Sprintf("Error getting PIF record: %s", err.Error())) - return multistep.ActionHalt - } + } - if pif_rec["management"].(bool) { - network.Ref = pif_rec["network"].(string) - } + if network.Ref == "" { + log.Fatal("Error: couldn't find management network. Aborting.") + return multistep.ActionHalt + } - } + } else { + // Look up the network by it's name label - if network.Ref == "" { - log.Fatal("Error: couldn't find management network. Aborting.") - return multistep.ActionHalt - } + networks, err := client.GetNetworkByNameLabel(config.NetworkName) - } else { - // Look up the network by it's name label + if err != nil { + log.Fatal(fmt.Sprintf("Error occured getting Network by name-label: %s", err.Error())) + return multistep.ActionHalt + } - networks, err := client.GetNetworkByNameLabel(config.NetworkName) + switch { + case len(networks) == 0: + log.Fatal(fmt.Sprintf("Couldn't find a network with the specified name-label '%s'. Aborting.", config.NetworkName)) + return multistep.ActionHalt + case len(networks) > 1: + log.Fatal(fmt.Sprintf("Found more than one SR with the name '%s'. The name must be unique. Aborting.", config.NetworkName)) + return multistep.ActionHalt + } - if err != nil { - log.Fatal(fmt.Sprintf("Error occured getting Network by name-label: %s", err.Error())) - return multistep.ActionHalt - } + network = networks[0] + } - switch { - case len(networks) == 0: - log.Fatal(fmt.Sprintf("Couldn't find a network with the specified name-label '%s'. Aborting.", config.NetworkName)) - return multistep.ActionHalt - case len(networks) > 1: - log.Fatal(fmt.Sprintf("Found more than one SR with the name '%s'. The name must be unique. Aborting.", config.NetworkName)) - return multistep.ActionHalt - } + if err != nil { + ui.Say(err.Error()) + } + _, err = instance.ConnectNetwork(network, "0") - network = networks[0] - } + if err != nil { + ui.Say(err.Error()) + } - if err != nil { - ui.Say(err.Error()) - } - _, err = instance.ConnectNetwork(network, "0") + // Connect the ISO + //iso_vdi_uuid := state.Get("iso_vdi_uuid").(string) - if err != nil { - ui.Say(err.Error()) - } + isos, err := client.GetVdiByNameLabel(config.IsoName) - // Connect the ISO - //iso_vdi_uuid := state.Get("iso_vdi_uuid").(string) + switch { + case len(isos) == 0: + log.Fatal(fmt.Sprintf("Couldn't find an ISO named '%s'. Aborting", config.IsoName)) + return multistep.ActionHalt + case len(isos) > 1: + log.Fatal(fmt.Sprintf("Found more than one VDI with name '%s'. Name must be unique. Aborting.", config.IsoName)) + return multistep.ActionHalt + } + iso := isos[0] - isos, err := client.GetVdiByNameLabel(config.IsoName) + //iso, _ := client.GetVdiByUuid(config.IsoUuid) + //ui.Say("Using VDI: " + iso_vdi_uuid) + //iso, _ := client.GetVdiByUuid(iso_vdi_uuid) + instance.ConnectVdi(iso, true) + // Stash the VM reference + self.InstanceId, _ = instance.GetUuid() + state.Put("instance_uuid", self.InstanceId) + state.Put("instance", instance) + ui.Say(fmt.Sprintf("Created instance '%s'", self.InstanceId)) - switch { - case len(isos) == 0: - log.Fatal(fmt.Sprintf("Couldn't find an ISO named '%s'. Aborting", config.IsoName)) - return multistep.ActionHalt - case len(isos) > 1: - log.Fatal(fmt.Sprintf("Found more than one VDI with name '%s'. Name must be unique. Aborting.", config.IsoName)) - return multistep.ActionHalt - } - - iso := isos[0] - - //iso, _ := client.GetVdiByUuid(config.IsoUuid) - //ui.Say("Using VDI: " + iso_vdi_uuid) - //iso, _ := client.GetVdiByUuid(iso_vdi_uuid) - instance.ConnectVdi(iso, true) - - // Stash the VM reference - self.InstanceId, _ = instance.GetUuid() - state.Put("instance_uuid", self.InstanceId) - state.Put("instance", instance) - ui.Say(fmt.Sprintf("Created instance '%s'", self.InstanceId)) - - return multistep.ActionContinue + return multistep.ActionContinue } - func (self *stepCreateInstance) Cleanup(state multistep.StateBag) { -// client := state.Get("client").(*XenAPIClient) -// config := state.Get("config").(config) -// ui := state.Get("ui").(packer.Ui) + // client := state.Get("client").(*XenAPIClient) + // config := state.Get("config").(config) + // ui := state.Get("ui").(packer.Ui) - // If instance hasn't been created, we have nothing to do. - if self.InstanceId == "" { - return - } + // If instance hasn't been created, we have nothing to do. + if self.InstanceId == "" { + return + } - // @todo: destroy the created instance. + // @todo: destroy the created instance. - return + return } diff --git a/builder/xenserver/step_forward_port_over_ssh.go b/builder/xenserver/step_forward_port_over_ssh.go index 19d6e6b..58f9d83 100644 --- a/builder/xenserver/step_forward_port_over_ssh.go +++ b/builder/xenserver/step_forward_port_over_ssh.go @@ -1,73 +1,68 @@ package xenserver import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "log" - "net" - "fmt" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "net" ) type stepForwardPortOverSSH struct { + RemotePort func(state multistep.StateBag) (uint, error) + RemoteDest func(state multistep.StateBag) (string, error) - RemotePort func (state multistep.StateBag) (uint, error) - RemoteDest func (state multistep.StateBag) (string, error) + HostPortMin uint + HostPortMax uint - HostPortMin uint - HostPortMax uint - - ResultKey string + ResultKey string } - func (self *stepForwardPortOverSSH) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(config) - ui := state.Get("ui").(packer.Ui) + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) - // Find a free local port: + // Find a free local port: - log.Printf("Looking for an available port between %d and %d", - self.HostPortMin, - self.HostPortMax) + log.Printf("Looking for an available port between %d and %d", + self.HostPortMin, + self.HostPortMax) + var sshHostPort uint + var foundPort bool - var sshHostPort uint - var foundPort bool + foundPort = false - foundPort = false + for i := self.HostPortMin; i < self.HostPortMax; i++ { + sshHostPort = i + log.Printf("Trying port: %d", sshHostPort) + l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", sshHostPort)) + if err == nil { + l.Close() + foundPort = true + break + } - for i := self.HostPortMin; i < self.HostPortMax; i++ { - sshHostPort = i - log.Printf("Trying port: %d", sshHostPort) - l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", sshHostPort)) - if err == nil { - l.Close() - foundPort = true - break - } + } - } + if !foundPort { + log.Fatal("Error: unable to find free host port. Try providing a larger range") + return multistep.ActionHalt + } - if !foundPort { - log.Fatal("Error: unable to find free host port. Try providing a larger range") - return multistep.ActionHalt - } + ui.Say(fmt.Sprintf("Creating a local port forward over SSH on local port %d", sshHostPort)) + remotePort, _ := self.RemotePort(state) + remoteDest, _ := self.RemoteDest(state) - ui.Say(fmt.Sprintf("Creating a local port forward over SSH on local port %d", sshHostPort)) + go ssh_port_forward(sshHostPort, remotePort, remoteDest, config.HostIp, config.Username, config.Password) + ui.Say(fmt.Sprintf("Port forward setup. %d ---> %s:%d on %s", sshHostPort, remoteDest, remotePort, config.HostIp)) - remotePort, _ := self.RemotePort(state) - remoteDest, _ := self.RemoteDest(state) + // Provide the local port to future steps. + state.Put(self.ResultKey, sshHostPort) - - go ssh_port_forward(sshHostPort, remotePort, remoteDest, config.HostIp, config.Username, config.Password) - ui.Say(fmt.Sprintf("Port forward setup. %d ---> %s:%d on %s", sshHostPort, remoteDest, remotePort, config.HostIp)) - - // Provide the local port to future steps. - state.Put(self.ResultKey, sshHostPort) - - return multistep.ActionContinue + return multistep.ActionContinue } func (self *stepForwardPortOverSSH) Cleanup(state multistep.StateBag) {} diff --git a/builder/xenserver/step_get_vnc_port.go b/builder/xenserver/step_get_vnc_port.go index f0e51f9..46c1ac8 100644 --- a/builder/xenserver/step_get_vnc_port.go +++ b/builder/xenserver/step_get_vnc_port.go @@ -1,52 +1,49 @@ package xenserver - import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "fmt" - "strconv" - "log" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "strconv" ) -type stepGetVNCPort struct {} - +type stepGetVNCPort struct{} func (self *stepGetVNCPort) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(config) - ui := state.Get("ui").(packer.Ui) + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) - ui.Say("Step: forward the instances VNC port over SSH") + ui.Say("Step: forward the instances VNC port over SSH") - domid := state.Get("domid").(string) - cmd := fmt.Sprintf("xenstore-read /local/domain/%s/console/vnc-port", domid) + domid := state.Get("domid").(string) + cmd := fmt.Sprintf("xenstore-read /local/domain/%s/console/vnc-port", domid) - remote_vncport, _ := execute_ssh_cmd(cmd, config.HostIp, "22", config.Username, config.Password) + remote_vncport, _ := execute_ssh_cmd(cmd, config.HostIp, "22", config.Username, config.Password) - remote_port, err := strconv.ParseUint(remote_vncport, 10, 16) + remote_port, err := strconv.ParseUint(remote_vncport, 10, 16) - if err != nil { - log.Fatal(err.Error()) - log.Fatal(fmt.Sprintf("Unable to convert '%s' to an int", remote_vncport)) - return multistep.ActionHalt - } + if err != nil { + log.Fatal(err.Error()) + log.Fatal(fmt.Sprintf("Unable to convert '%s' to an int", remote_vncport)) + return multistep.ActionHalt + } - state.Put("instance_vnc_port", uint(remote_port)) + state.Put("instance_vnc_port", uint(remote_port)) - return multistep.ActionContinue + return multistep.ActionContinue } - func (self *stepGetVNCPort) Cleanup(state multistep.StateBag) { } -func instanceVNCPort (state multistep.StateBag) (uint, error) { - vncPort := state.Get("instance_vnc_port").(uint) - return vncPort, nil +func instanceVNCPort(state multistep.StateBag) (uint, error) { + vncPort := state.Get("instance_vnc_port").(uint) + return vncPort, nil } -func instanceVNCIP (state multistep.StateBag) (string, error) { - // The port is in Dom0, so we want to forward from localhost - return "127.0.0.1", nil +func instanceVNCIP(state multistep.StateBag) (string, error) { + // The port is in Dom0, so we want to forward from localhost + return "127.0.0.1", nil } diff --git a/builder/xenserver/step_shutdown_and_export.go b/builder/xenserver/step_shutdown_and_export.go index 449cf48..81dca51 100644 --- a/builder/xenserver/step_shutdown_and_export.go +++ b/builder/xenserver/step_shutdown_and_export.go @@ -3,95 +3,93 @@ package xenserver /* Taken from https://raw.githubusercontent.com/mitchellh/packer/master/builder/qemu/step_prepare_output_dir.go */ import ( + "crypto/tls" + "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "io" + "net/http" "os" - "fmt" - "net/http" - "crypto/tls" - "io" ) type stepShutdownAndExport struct{} func downloadFile(url, filename string) (err error) { - // Create the file - fh, err := os.Create(filename) - if err != nil { - return err - } + // Create the file + fh, err := os.Create(filename) + if err != nil { + return err + } - // Define a new transport which allows self-signed certs - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } + // Define a new transport which allows self-signed certs + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } - // Create a client - client := &http.Client{Transport: tr} + // Create a client + client := &http.Client{Transport: tr} - // Create request and download file + // Create request and download file - resp, err := client.Get(url) - if err != nil { - return err - } + resp, err := client.Get(url) + if err != nil { + return err + } - defer resp.Body.Close() - io.Copy(fh, resp.Body) + defer resp.Body.Close() + io.Copy(fh, resp.Body) - return nil + return nil } - func (stepShutdownAndExport) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(config) ui := state.Get("ui").(packer.Ui) - client := state.Get("client").(XenAPIClient) - instance_uuid := state.Get("instance_uuid").(string) + client := state.Get("client").(XenAPIClient) + instance_uuid := state.Get("instance_uuid").(string) - instance, _ := client.GetVMByUuid(instance_uuid) + instance, _ := client.GetVMByUuid(instance_uuid) - ui.Say("Step: Shutdown and export VPX") + ui.Say("Step: Shutdown and export VPX") - // Shutdown the VM - ui.Say("Shutting down the VM...") - instance.CleanShutdown() + // Shutdown the VM + ui.Say("Shutting down the VM...") + instance.CleanShutdown() - //Export the VM + //Export the VM - export_url := fmt.Sprintf("https://%s/export?vm=%s&session_id=%s", - client.Host, - instance.Ref, - client.Session.(string), - ) + export_url := fmt.Sprintf("https://%s/export?vm=%s&session_id=%s", + client.Host, + instance.Ref, + client.Session.(string), + ) - export_filename := fmt.Sprintf("%s/%s.xva", config.OutputDir, config.InstanceName) - ui.Say("Getting metadata " + export_url) - downloadFile(export_url, export_filename) + export_filename := fmt.Sprintf("%s/%s.xva", config.OutputDir, config.InstanceName) + ui.Say("Getting metadata " + export_url) + downloadFile(export_url, export_filename) - disks, _ := instance.GetDisks() - for _, disk := range disks { - disk_uuid, _ := disk.GetUuid() + disks, _ := instance.GetDisks() + for _, disk := range disks { + disk_uuid, _ := disk.GetUuid() - // Basic auth in URL request is required as session token is not - // accepted for some reason. - // @todo: raise with XAPI team. - disk_export_url := fmt.Sprintf("https://%s:%s@%s/export_raw_vdi?vdi=%s", - client.Username, - client.Password, - client.Host, - disk_uuid, - ) + // Basic auth in URL request is required as session token is not + // accepted for some reason. + // @todo: raise with XAPI team. + disk_export_url := fmt.Sprintf("https://%s:%s@%s/export_raw_vdi?vdi=%s", + client.Username, + client.Password, + client.Host, + disk_uuid, + ) - ui.Say("Getting " + disk_export_url) - disk_export_filename := fmt.Sprintf("%s/%s.raw", config.OutputDir, disk_uuid) - ui.Say("Downloading " + disk_uuid) - downloadFile(disk_export_url, disk_export_filename) - } + ui.Say("Getting " + disk_export_url) + disk_export_filename := fmt.Sprintf("%s/%s.raw", config.OutputDir, disk_uuid) + ui.Say("Downloading " + disk_uuid) + downloadFile(disk_export_url, disk_export_filename) + } - - ui.Say("Download complteded: " + config.OutputDir) + ui.Say("Download completed: " + config.OutputDir) return multistep.ActionContinue } diff --git a/builder/xenserver/step_start_on_himn.go b/builder/xenserver/step_start_on_himn.go index c095795..4048a6f 100644 --- a/builder/xenserver/step_start_on_himn.go +++ b/builder/xenserver/step_start_on_himn.go @@ -1,16 +1,15 @@ package xenserver import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "time" - "log" - "fmt" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "time" ) type stepStartOnHIMN struct{} - /* * This step starts the installed guest on the Host Internal Management Network * as there exists an API to obtain the IP allocated to the VM by XAPI. @@ -21,104 +20,99 @@ type stepStartOnHIMN struct{} func (self *stepStartOnHIMN) Run(state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packer.Ui) - client := state.Get("client").(XenAPIClient) - config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) + config := state.Get("config").(config) - ui.Say("Step: Start VM on the Host Internal Mangement Network") + ui.Say("Step: Start VM on the Host Internal Mangement Network") - instance := state.Get("instance").(*VM) + instance := state.Get("instance").(*VM) - // Find the HIMN Ref - networks, err := client.GetNetworkByNameLabel("Host internal management network") - if err != nil || len(networks) == 0 { - log.Fatal("Unable to find a host internal management network") - log.Fatal(err.Error()) - return multistep.ActionHalt - } + // Find the HIMN Ref + networks, err := client.GetNetworkByNameLabel("Host internal management network") + if err != nil || len(networks) == 0 { + log.Fatal("Unable to find a host internal management network") + log.Fatal(err.Error()) + return multistep.ActionHalt + } + himn := networks[0] - himn := networks[0] + // Create a VIF for the HIMN + himn_vif, err := instance.ConnectNetwork(himn, "0") + if err != nil { + log.Fatal("Error creating VIF") + log.Fatal(err.Error()) + return multistep.ActionHalt + } - // Create a VIF for the HIMN - himn_vif, err := instance.ConnectNetwork(himn, "0") - if err != nil { - log.Fatal("Error creating VIF") - log.Fatal(err.Error()) - return multistep.ActionHalt - } + // Start the VM + instance.Start(false, false) - // Start the VM - instance.Start(false, false) + var himn_iface_ip string = "" + // Obtain the allocated IP + for i := 0; i < 10; i++ { + ips, _ := himn.GetAssignedIPs() + log.Printf("IPs: %s", ips) + log.Printf("Ref: %s", instance.Ref) - var himn_iface_ip string = "" + //Check for instance.Ref in map + if vm_ip, ok := ips[himn_vif.Ref]; ok { + ui.Say("Found the VM's IP " + vm_ip) + himn_iface_ip = vm_ip + break + } - // Obtain the allocated IP - for i:=0; i < 10; i++ { - ips, _ := himn.GetAssignedIPs() - log.Printf("IPs: %s", ips) - log.Printf("Ref: %s", instance.Ref) + ui.Say("Wait for IP address...") + time.Sleep(10 * time.Second) - //Check for instance.Ref in map - if vm_ip, ok := ips[himn_vif.Ref]; ok { - ui.Say("Found the VM's IP " + vm_ip) - himn_iface_ip = vm_ip - break - } + } - ui.Say("Wait for IP address...") - time.Sleep(10*time.Second) + if himn_iface_ip != "" { + state.Put("himn_ssh_address", himn_iface_ip) + ui.Say("Stored VM's IP " + himn_iface_ip) + } else { + log.Fatal("Unable to find an IP on the Host-internal management interface") + return multistep.ActionHalt + } - } + // Wait for the VM to boot, and check we can ping this interface - if himn_iface_ip != "" { - state.Put("himn_ssh_address", himn_iface_ip) - ui.Say("Stored VM's IP " + himn_iface_ip) - } else { - log.Fatal("Unable to find an IP on the Host-internal management interface") - return multistep.ActionHalt - } + ping_cmd := fmt.Sprintf("ping -c 1 %s", himn_iface_ip) + err = nil + for i := 0; i < 30; i++ { + ui.Message(fmt.Sprintf("Attempting to ping interface: %s", ping_cmd)) + _, err := execute_ssh_cmd(ping_cmd, config.HostIp, "22", config.Username, config.Password) - // Wait for the VM to boot, and check we can ping this interface + if err == nil { + ui.Message("Ping success! Continuing...") + break + } - ping_cmd := fmt.Sprintf("ping -c 1 %s", himn_iface_ip) + time.Sleep(10 * time.Second) + } - err = nil - for i:=0; i < 30; i++ { - ui.Message(fmt.Sprintf("Attempting to ping interface: %s", ping_cmd)) - _, err := execute_ssh_cmd(ping_cmd, config.HostIp, "22", config.Username, config.Password) + if err != nil { + log.Fatal("Unable to ping interface. Something is wrong. Has the VM not booted?") + log.Fatal(err.Error()) + return multistep.ActionHalt + } - if err == nil { - ui.Message("Ping success! Continuing...") - break - } + time.Sleep(10 * time.Second) - time.Sleep(10 * time.Second) - } - - if err != nil { - log.Fatal("Unable to ping interface. Something is wrong. Has the VM not booted?") - log.Fatal(err.Error()) - return multistep.ActionHalt - } - - time.Sleep(10 * time.Second) - - return multistep.ActionContinue + return multistep.ActionContinue } func (self *stepStartOnHIMN) Cleanup(state multistep.StateBag) {} - -func himnSSHIP (state multistep.StateBag) (string, error) { - ip := state.Get("himn_ssh_address").(string) - return ip, nil +func himnSSHIP(state multistep.StateBag) (string, error) { + ip := state.Get("himn_ssh_address").(string) + return ip, nil } - -func himnSSHPort (state multistep.StateBag) (uint, error) { - return 22, nil +func himnSSHPort(state multistep.StateBag) (uint, error) { + return 22, nil } diff --git a/builder/xenserver/step_start_vm_paused.go b/builder/xenserver/step_start_vm_paused.go index 89f78b0..fd10f4d 100644 --- a/builder/xenserver/step_start_vm_paused.go +++ b/builder/xenserver/step_start_vm_paused.go @@ -1,30 +1,28 @@ package xenserver - import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" ) -type stepStartVmPaused struct {} +type stepStartVmPaused struct{} func (self *stepStartVmPaused) Run(state multistep.StateBag) multistep.StepAction { - client := state.Get("client").(XenAPIClient) - ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) + ui := state.Get("ui").(packer.Ui) - ui.Say("Step: Start VM Paused") + ui.Say("Step: Start VM Paused") - instance, _ := client.GetVMByUuid(state.Get("instance_uuid").(string)) + instance, _ := client.GetVMByUuid(state.Get("instance_uuid").(string)) - instance.Start(true, false) + instance.Start(true, false) - domid, _ := instance.GetDomainId() - state.Put("domid", domid) + domid, _ := instance.GetDomainId() + state.Put("domid", domid) - return multistep.ActionContinue + return multistep.ActionContinue } - func (self *stepStartVmPaused) Cleanup(state multistep.StateBag) { } diff --git a/builder/xenserver/step_type_boot_command.go b/builder/xenserver/step_type_boot_command.go index 49b3113..f8b8a0d 100644 --- a/builder/xenserver/step_type_boot_command.go +++ b/builder/xenserver/step_type_boot_command.go @@ -3,92 +3,91 @@ package xenserver /* Heavily borrowed from builder/quemu/step_type_boot_command.go */ import ( - "fmt" - "github.com/mitchellh/go-vnc" - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "log" - "net" - "strings" - "time" - "unicode" - "unicode/utf8" + "fmt" + "github.com/mitchellh/go-vnc" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "net" + "strings" + "time" + "unicode" + "unicode/utf8" ) const KeyLeftShift uint = 0xFFE1 type bootCommandTemplateData struct { - HTTPIP string - HTTPPort uint + HTTPIP string + HTTPPort uint } - type stepTypeBootCommand struct{} -func (self *stepTypeBootCommand) Run (state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(config) - ui := state.Get("ui").(packer.Ui) - vnc_port := state.Get("local_vnc_port").(uint) - http_port := state.Get("http_port").(uint) +func (self *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) + vnc_port := state.Get("local_vnc_port").(uint) + http_port := state.Get("http_port").(uint) - // Connect to the local VNC port as we have set up a SSH port forward - ui.Say("Connecting to the VM over VNC") - ui.Message(fmt.Sprintf("Using local port: %d", vnc_port)) - net_conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vnc_port)) + // Connect to the local VNC port as we have set up a SSH port forward + ui.Say("Connecting to the VM over VNC") + ui.Message(fmt.Sprintf("Using local port: %d", vnc_port)) + net_conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vnc_port)) - if err != nil { - err := fmt.Errorf("Error connecting to VNC: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } + if err != nil { + err := fmt.Errorf("Error connecting to VNC: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } - defer net_conn.Close() + defer net_conn.Close() - c, err := vnc.Client(net_conn, &vnc.ClientConfig{Exclusive: true}) + c, err := vnc.Client(net_conn, &vnc.ClientConfig{Exclusive: true}) - if err != nil { - err := fmt.Errorf("Error establishing VNC session: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } + if err != nil { + err := fmt.Errorf("Error establishing VNC session: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } - defer c.Close() + defer c.Close() - log.Printf("Connected to the VNC console: %s", c.DesktopName) + log.Printf("Connected to the VNC console: %s", c.DesktopName) - // @todo - include http port/ip so kickstarter files can be grabbed - tplData := &bootCommandTemplateData { - config.LocalIp, - http_port, - } + // @todo - include http port/ip so kickstarter files can be grabbed + tplData := &bootCommandTemplateData{ + config.LocalIp, + http_port, + } - ui.Say("About to type boot commands over VNC...") - for _, command := range config.BootCommand { + ui.Say("About to type boot commands over VNC...") + for _, command := range config.BootCommand { - command, err := config.tpl.Process(command, tplData) - if err != nil { - err := fmt.Errorf("Error preparing boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } + command, err := config.tpl.Process(command, tplData) + if err != nil { + err := fmt.Errorf("Error preparing boot command: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } - // Check for interrupts - if _, ok := state.GetOk(multistep.StateCancelled); ok { - return multistep.ActionHalt - } + // Check for interrupts + if _, ok := state.GetOk(multistep.StateCancelled); ok { + return multistep.ActionHalt + } - vncSendString(c, command) - } + vncSendString(c, command) + } - ui.Say("Finished typing.") + ui.Say("Finished typing.") - return multistep.ActionContinue + return multistep.ActionContinue } -func (self *stepTypeBootCommand) Cleanup (multistep.StateBag) {} +func (self *stepTypeBootCommand) Cleanup(multistep.StateBag) {} // Taken from qemu's builder plugin - not an exported function. func vncSendString(c *vnc.ClientConn, original string) { diff --git a/builder/xenserver/step_upload_iso.go b/builder/xenserver/step_upload_iso.go index 27e76e0..b4dcaa5 100644 --- a/builder/xenserver/step_upload_iso.go +++ b/builder/xenserver/step_upload_iso.go @@ -1,81 +1,78 @@ package xenserver - import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "os" - "strconv" - "os/exec" - "log" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "os" + "os/exec" + "strconv" ) -type stepUploadIso struct {} +type stepUploadIso struct{} func (self *stepUploadIso) Run(state multistep.StateBag) multistep.StepAction { - client := state.Get("client").(XenAPIClient) - config := state.Get("config").(config) - ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) + config := state.Get("config").(config) + ui := state.Get("ui").(packer.Ui) - ui.Say("Step: Upload ISO to server") - iso_path := state.Get("iso_path").(string) + ui.Say("Step: Upload ISO to server") + iso_path := state.Get("iso_path").(string) - // Determine the ISO's filesize - file, err := os.Open(iso_path) - if err != nil { - ui.Error(err.Error()) - return multistep.ActionHalt - } - stat, err := file.Stat() + // Determine the ISO's filesize + file, err := os.Open(iso_path) + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } + stat, err := file.Stat() - if err != nil { - ui.Error(err.Error()) - return multistep.ActionHalt - } + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } - iso_filesize := stat.Size() + iso_filesize := stat.Size() - // Create a VDI with the write size - srs, err := client.GetSRByNameLabel(config.SrName) + // Create a VDI with the write size + srs, err := client.GetSRByNameLabel(config.SrName) - sr := srs[0] + sr := srs[0] - if err != nil { - ui.Error(err.Error()) - return multistep.ActionHalt - } + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } - filesize_str := strconv.FormatInt(iso_filesize, 10) - log.Printf("Filesize of the ISO is %d", filesize_str) - vdi, err := sr.CreateVdi("Packer Gen " + stat.Name(), filesize_str) + filesize_str := strconv.FormatInt(iso_filesize, 10) + log.Printf("Filesize of the ISO is %d", filesize_str) + vdi, err := sr.CreateVdi("Packer Gen "+stat.Name(), filesize_str) - if err != nil { - ui.Error(err.Error()) - return multistep.ActionHalt - } + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } - // Upload the ISO to this VDI - vdi_uuid, _ := vdi.GetUuid() - host_url := "https://" + client.Host - log.Printf("Host URL: %s", host_url) - ui.Say("Uploading ISO to " + vdi_uuid) - out, err := exec.Command("/usr/bin/importdisk.py", host_url, client.Username, client.Password, vdi_uuid, iso_path).CombinedOutput() - log.Printf("Output: %s", out) + // Upload the ISO to this VDI + vdi_uuid, _ := vdi.GetUuid() + host_url := "https://" + client.Host + log.Printf("Host URL: %s", host_url) + ui.Say("Uploading ISO to " + vdi_uuid) + out, err := exec.Command("/usr/bin/importdisk.py", host_url, client.Username, client.Password, vdi_uuid, iso_path).CombinedOutput() + log.Printf("Output: %s", out) - if err != nil { - log.Printf("%s", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } + if err != nil { + log.Printf("%s", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } - // Stash the vdi uuid to be used in preference - state.Put("iso_vdi_uuid", vdi_uuid) + // Stash the vdi uuid to be used in preference + state.Put("iso_vdi_uuid", vdi_uuid) - - return multistep.ActionContinue + return multistep.ActionContinue } - func (self *stepUploadIso) Cleanup(state multistep.StateBag) { } diff --git a/builder/xenserver/step_wait.go b/builder/xenserver/step_wait.go index b056bc4..f68dcb9 100644 --- a/builder/xenserver/step_wait.go +++ b/builder/xenserver/step_wait.go @@ -1,66 +1,61 @@ package xenserver import ( - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" - "time" - "reflect" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "time" ) - type stepWait struct{} func (self *stepWait) Run(state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packer.Ui) - client := state.Get("client").(XenAPIClient) + ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) - ui.Say("Step: Wait for install to complete.") + ui.Say("Step: Wait for install to complete.") + //Expect install to be configured to shutdown on completion - //Expect install to be configured to shutdown on completion + instance_id := state.Get("instance_uuid").(string) + instance, _ := client.GetVMByUuid(instance_id) - instance_id := state.Get("instance_uuid").(string) - instance, _ := client.GetVMByUuid(instance_id) + for { + time.Sleep(30 * time.Second) + ui.Say("Waiting for VM install...") - for { - time.Sleep(30 * time.Second) - ui.Say("Waiting for VM install...") + power_state, _ := instance.GetPowerState() + if power_state == "Halted" { + ui.Say("Install has completed. Moving on.") + break + } + } - power_state, _ := instance.GetPowerState() - if power_state == "Halted" { - ui.Say("Install has completed. Moving on.") - break - } - } + // Eject ISO from drive + vbds, _ := instance.GetVBDs() + for _, vbd := range vbds { + rec, _ := vbd.GetRecord() - // Eject ISO from drive - vbds, _ := instance.GetVBDs() - for _, vbd := range vbds { - rec, _ := vbd.GetRecord() + // Hack - should encapsulate this in the client really + // This is needed because we can't guarentee the type + // returned by the xmlrpc lib will be string + if recType, ok := rec["type"].(string); ok { + if recType == "CD" { + ui.Say("Ejecting CD...") + vbd.Eject() + } + } else { + break + } + } - // Hack - should encapsulate this in the client really - // This is needed because we can't guarentee the type - // returned by the xmlrpc lib will be string - switch reflect.TypeOf(rec["type"]).Kind() { - case reflect.String: - if rec["type"].(string) == "CD" { - ui.Say("Ejecting CD...") - vbd.Eject() - } - default: - break - } - } + // Destroy all connected VIFs + vifs, _ := instance.GetVIFs() + for _, vif := range vifs { + ui.Message("Destroying VIF " + vif.Ref) + vif.Destroy() + } - // Destroy all connected VIFs - vifs, _ := instance.GetVIFs() - for _, vif := range vifs { - ui.Message("Destroying VIF " + vif.Ref) - vif.Destroy() - } - - return multistep.ActionContinue + return multistep.ActionContinue } func (self *stepWait) Cleanup(state multistep.StateBag) {} - diff --git a/main.go b/main.go index c0c4be9..983ed22 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,15 @@ package main import ( - "github.com/rdobson/packer-builder-xenserver/builder/xenserver" - "github.com/mitchellh/packer/packer/plugin" + "github.com/mitchellh/packer/packer/plugin" + "github.com/rdobson/packer-builder-xenserver/builder/xenserver" ) func main() { - server, err := plugin.Server() - if err != nil { - panic(err) - } - server.RegisterBuilder(new(xenserver.Builder)) - server.Serve() + server, err := plugin.Server() + if err != nil { + panic(err) + } + server.RegisterBuilder(new(xenserver.Builder)) + server.Serve() }