IP snooping

This commit is contained in:
Cheng Sun 2014-12-30 15:01:53 +00:00
parent 6ffa99d624
commit 176c4ad7a3
6 changed files with 106 additions and 108 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"net"
"net/http"
)
@ -21,9 +22,30 @@ import (
// Produces:
// http_port int - The port the HTTP server started on.
type StepHTTPServer struct {
Chan chan<- string
l net.Listener
}
type IPSnooper struct {
ch chan<- string
handler http.Handler
}
func (snooper IPSnooper) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
log.Printf("HTTP: %s %s %s", req.RemoteAddr, req.Method, req.URL)
ip, _, err := net.SplitHostPort(req.RemoteAddr)
if err == nil && ip != "" {
select {
case snooper.ch <- ip:
log.Printf("Remembering remote address '%s'", ip)
default:
// if ch is already full, don't block waiting to send the address, just drop it
}
}
snooper.handler.ServeHTTP(resp, req)
}
func (s *StepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("commonconfig").(CommonConfig)
ui := state.Get("ui").(packer.Ui)
@ -45,7 +67,13 @@ func (s *StepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
// Start the HTTP server and run it in the background
fileServer := http.FileServer(http.Dir(config.HTTPDir))
server := &http.Server{Addr: fmt.Sprintf(":%d", httpPort), Handler: fileServer}
server := &http.Server{
Addr: fmt.Sprintf(":%d", httpPort),
Handler: IPSnooper{
ch: s.Chan,
handler: fileServer,
},
}
go server.Serve(s.l)
// Save the address into the state so it can be accessed in the future

View File

@ -1,40 +0,0 @@
package common
import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type StepRemoveDevices struct{}
func (self *StepRemoveDevices) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
client := state.Get("client").(XenAPIClient)
ui.Say("Step: Remove devices from VM")
instance_id := state.Get("instance_uuid").(string)
instance, err := client.GetVMByUuid(instance_id)
if err != nil {
ui.Error(fmt.Sprintf("Could not get VM from UUID %s", instance_id))
ui.Error(err.Error())
return multistep.ActionHalt
}
// Destroy all connected VIFs
vifs, err := instance.GetVIFs()
if err != nil {
ui.Error(fmt.Sprintf("Could not get VIFs"))
ui.Error(err.Error())
return multistep.ActionHalt
}
for _, vif := range vifs {
ui.Message("Destroying VIF " + vif.Ref)
vif.Destroy()
}
return multistep.ActionContinue
}
func (self *StepRemoveDevices) Cleanup(state multistep.StateBag) {}

View File

@ -0,0 +1,45 @@
package common
import (
"fmt"
"time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type StepWaitForHTTPRequest struct {
Chan <-chan string
Timeout time.Duration
}
func (self *StepWaitForHTTPRequest) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ui.Say("Step: Wait for install to complete.")
timeout := time.After(self.Timeout)
var ip string
select {
case ip = <-self.Chan:
case <-timeout:
ui.Error("Timed out. Giving up waiting for installation to complete.")
return multistep.ActionHalt
}
ui.Say(fmt.Sprintf("Got IP address '%s'", ip))
state.Put("instance_ssh_address", ip)
return multistep.ActionContinue
}
func (self *StepWaitForHTTPRequest) Cleanup(state multistep.StateBag) {}
func InstanceSSHIP(state multistep.StateBag) (string, error) {
ip := state.Get("instance_ssh_address").(string)
return ip, nil
}
func InstanceSSHPort(state multistep.StateBag) (uint, error) {
return 22, nil
}

View File

@ -186,6 +186,8 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
state.Put("hook", hook)
state.Put("ui", ui)
httpReqChan := make(chan string, 1)
//Build the steps
steps := []multistep.Step{
&common.StepDownload{
@ -202,7 +204,9 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
&common.StepCreateFloppy{
Files: self.config.FloppyFiles,
},
new(xscommon.StepHTTPServer),
&xscommon.StepHTTPServer{
Chan: httpReqChan,
},
&xscommon.StepUploadVdi{
VdiName: "Packer-floppy-disk",
ImagePathFunc: func() string {
@ -250,18 +254,13 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
&xscommon.StepTypeBootCommand{
Tpl: self.config.tpl,
},
new(stepWait),
&xscommon.StepDetachVdi{
VdiUuidKey: "floppy_vdi_uuid",
&xscommon.StepWaitForHTTPRequest{
Chan: httpReqChan,
Timeout: self.config.InstallTimeout, // @todo change this
},
&xscommon.StepDetachVdi{
VdiUuidKey: "iso_vdi_uuid",
},
new(xscommon.StepRemoveDevices),
new(xscommon.StepStartOnHIMN),
&xscommon.StepForwardPortOverSSH{
RemotePort: xscommon.HimnSSHPort,
RemoteDest: xscommon.HimnSSHIP,
RemotePort: xscommon.InstanceSSHPort,
RemoteDest: xscommon.InstanceSSHIP,
HostPortMin: self.config.HostPortMin,
HostPortMax: self.config.HostPortMax,
ResultKey: "local_ssh_port",

View File

@ -1,52 +0,0 @@
package iso
import (
"fmt"
"log"
"time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
xscommon "github.com/rdobson/packer-builder-xenserver/builder/xenserver/common"
)
type stepWait struct{}
func (self *stepWait) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(config)
ui := state.Get("ui").(packer.Ui)
client := state.Get("client").(xscommon.XenAPIClient)
ui.Say("Step: Wait for install to complete.")
instance_id := state.Get("instance_uuid").(string)
instance, err := client.GetVMByUuid(instance_id)
if err != nil {
ui.Error(fmt.Sprintf("Could not get VM from UUID %s", instance_id))
ui.Error(err.Error())
return multistep.ActionHalt
}
//Expect install to be configured to shutdown on completion
err = xscommon.InterruptibleWait{
Predicate: func() (bool, error) {
log.Printf("Waiting for install to complete.")
power_state, err := instance.GetPowerState()
return power_state == "Halted", err
},
PredicateInterval: 30 * time.Second,
Timeout: config.InstallTimeout,
}.Wait(state)
if err != nil {
ui.Error(err.Error())
ui.Error("Giving up waiting for installation to complete.")
return multistep.ActionHalt
}
ui.Say("Install has completed. Moving on.")
return multistep.ActionContinue
}
func (self *stepWait) Cleanup(state multistep.StateBag) {}

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common"
@ -112,6 +113,8 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
state.Put("hook", hook)
state.Put("ui", ui)
httpReqChan := make(chan string, 1)
//Build the steps
steps := []multistep.Step{
&xscommon.StepPrepareOutputDir{
@ -145,11 +148,26 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
VdiUuidKey: "tools_vdi_uuid",
VdiType: xscommon.CD,
},
new(xscommon.StepRemoveDevices),
new(xscommon.StepStartOnHIMN),
new(xscommon.StepStartVmPaused),
new(xscommon.StepGetVNCPort),
&xscommon.StepForwardPortOverSSH{
RemotePort: xscommon.HimnSSHPort,
RemoteDest: xscommon.HimnSSHIP,
RemotePort: xscommon.InstanceVNCPort,
RemoteDest: xscommon.InstanceVNCIP,
HostPortMin: self.config.HostPortMin,
HostPortMax: self.config.HostPortMax,
ResultKey: "local_vnc_port",
},
new(xscommon.StepBootWait),
&xscommon.StepTypeBootCommand{
Tpl: self.config.tpl,
},
&xscommon.StepWaitForIP{
Chan: httpReqChan,
Timeout: 300 * time.Minute /*self.config.InstallTimeout*/, // @todo change this
},
&xscommon.StepForwardPortOverSSH{
RemotePort: xscommon.InstanceSSHPort,
RemoteDest: xscommon.InstanceSSHIP,
HostPortMin: self.config.HostPortMin,
HostPortMax: self.config.HostPortMax,
ResultKey: "local_ssh_port",