IP snooping
This commit is contained in:
parent
6ffa99d624
commit
176c4ad7a3
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@ -21,9 +22,30 @@ import (
|
|||||||
// Produces:
|
// Produces:
|
||||||
// http_port int - The port the HTTP server started on.
|
// http_port int - The port the HTTP server started on.
|
||||||
type StepHTTPServer struct {
|
type StepHTTPServer struct {
|
||||||
|
Chan chan<- string
|
||||||
|
|
||||||
l net.Listener
|
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 {
|
func (s *StepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
config := state.Get("commonconfig").(CommonConfig)
|
config := state.Get("commonconfig").(CommonConfig)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
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
|
// Start the HTTP server and run it in the background
|
||||||
fileServer := http.FileServer(http.Dir(config.HTTPDir))
|
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)
|
go server.Serve(s.l)
|
||||||
|
|
||||||
// Save the address into the state so it can be accessed in the future
|
// Save the address into the state so it can be accessed in the future
|
||||||
|
@ -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) {}
|
|
45
builder/xenserver/common/step_wait_for_http_request.go
Normal file
45
builder/xenserver/common/step_wait_for_http_request.go
Normal 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
|
||||||
|
}
|
@ -186,6 +186,8 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
|
|||||||
state.Put("hook", hook)
|
state.Put("hook", hook)
|
||||||
state.Put("ui", ui)
|
state.Put("ui", ui)
|
||||||
|
|
||||||
|
httpReqChan := make(chan string, 1)
|
||||||
|
|
||||||
//Build the steps
|
//Build the steps
|
||||||
steps := []multistep.Step{
|
steps := []multistep.Step{
|
||||||
&common.StepDownload{
|
&common.StepDownload{
|
||||||
@ -202,7 +204,9 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
|
|||||||
&common.StepCreateFloppy{
|
&common.StepCreateFloppy{
|
||||||
Files: self.config.FloppyFiles,
|
Files: self.config.FloppyFiles,
|
||||||
},
|
},
|
||||||
new(xscommon.StepHTTPServer),
|
&xscommon.StepHTTPServer{
|
||||||
|
Chan: httpReqChan,
|
||||||
|
},
|
||||||
&xscommon.StepUploadVdi{
|
&xscommon.StepUploadVdi{
|
||||||
VdiName: "Packer-floppy-disk",
|
VdiName: "Packer-floppy-disk",
|
||||||
ImagePathFunc: func() string {
|
ImagePathFunc: func() string {
|
||||||
@ -250,18 +254,13 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
|
|||||||
&xscommon.StepTypeBootCommand{
|
&xscommon.StepTypeBootCommand{
|
||||||
Tpl: self.config.tpl,
|
Tpl: self.config.tpl,
|
||||||
},
|
},
|
||||||
new(stepWait),
|
&xscommon.StepWaitForHTTPRequest{
|
||||||
&xscommon.StepDetachVdi{
|
Chan: httpReqChan,
|
||||||
VdiUuidKey: "floppy_vdi_uuid",
|
Timeout: self.config.InstallTimeout, // @todo change this
|
||||||
},
|
},
|
||||||
&xscommon.StepDetachVdi{
|
|
||||||
VdiUuidKey: "iso_vdi_uuid",
|
|
||||||
},
|
|
||||||
new(xscommon.StepRemoveDevices),
|
|
||||||
new(xscommon.StepStartOnHIMN),
|
|
||||||
&xscommon.StepForwardPortOverSSH{
|
&xscommon.StepForwardPortOverSSH{
|
||||||
RemotePort: xscommon.HimnSSHPort,
|
RemotePort: xscommon.InstanceSSHPort,
|
||||||
RemoteDest: xscommon.HimnSSHIP,
|
RemoteDest: xscommon.InstanceSSHIP,
|
||||||
HostPortMin: self.config.HostPortMin,
|
HostPortMin: self.config.HostPortMin,
|
||||||
HostPortMax: self.config.HostPortMax,
|
HostPortMax: self.config.HostPortMax,
|
||||||
ResultKey: "local_ssh_port",
|
ResultKey: "local_ssh_port",
|
||||||
|
@ -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) {}
|
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/common"
|
"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("hook", hook)
|
||||||
state.Put("ui", ui)
|
state.Put("ui", ui)
|
||||||
|
|
||||||
|
httpReqChan := make(chan string, 1)
|
||||||
|
|
||||||
//Build the steps
|
//Build the steps
|
||||||
steps := []multistep.Step{
|
steps := []multistep.Step{
|
||||||
&xscommon.StepPrepareOutputDir{
|
&xscommon.StepPrepareOutputDir{
|
||||||
@ -145,11 +148,26 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
|
|||||||
VdiUuidKey: "tools_vdi_uuid",
|
VdiUuidKey: "tools_vdi_uuid",
|
||||||
VdiType: xscommon.CD,
|
VdiType: xscommon.CD,
|
||||||
},
|
},
|
||||||
new(xscommon.StepRemoveDevices),
|
new(xscommon.StepStartVmPaused),
|
||||||
new(xscommon.StepStartOnHIMN),
|
new(xscommon.StepGetVNCPort),
|
||||||
&xscommon.StepForwardPortOverSSH{
|
&xscommon.StepForwardPortOverSSH{
|
||||||
RemotePort: xscommon.HimnSSHPort,
|
RemotePort: xscommon.InstanceVNCPort,
|
||||||
RemoteDest: xscommon.HimnSSHIP,
|
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,
|
HostPortMin: self.config.HostPortMin,
|
||||||
HostPortMax: self.config.HostPortMax,
|
HostPortMax: self.config.HostPortMax,
|
||||||
ResultKey: "local_ssh_port",
|
ResultKey: "local_ssh_port",
|
||||||
|
Loading…
Reference in New Issue
Block a user