Created
January 20, 2014 15:45
-
-
Save rasa/8522368 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package vmware | |
import ( | |
"fmt" | |
"github.com/mitchellh/multistep" | |
"github.com/mitchellh/packer/packer" | |
"log" | |
"io/ioutil" | |
"math/rand" | |
"net" | |
"net/http" | |
"os" | |
"strconv" | |
"time" | |
) | |
const DEFAULT_RESET_WAIT_SECONDS = 10 | |
// This step creates and runs the HTTP server that is serving the files | |
// specified by the 'http_files` configuration parameter in the template. | |
// | |
// Uses: | |
// config *config | |
// ui packer.Ui | |
// | |
// Produces: | |
// http_port int - The port the HTTP server started on. | |
type stepHTTPServer struct { | |
l net.Listener | |
} | |
func (s *stepHTTPServer) reset(state multistep.StateBag, resetIn int) { | |
vmName := state.Get("vmx_path").(string) | |
if resetIn > 0 { | |
log.Printf("Sleeping %d seconds before resetting %v", resetIn, vmName) | |
time.Sleep(time.Duration(resetIn) * time.Second) | |
} | |
log.Printf("Resetting %s", vmName) | |
driver := state.Get("driver").(Driver) | |
config := state.Get("config").(*config) | |
err := driver.Reset(vmName, config.Headless) | |
if err != nil { | |
log.Printf("Error resetting %s: %s", vmName, err) | |
} else { | |
log.Printf("%s has been reset", vmName) | |
} | |
} | |
func (s *stepHTTPServer) Run(state multistep.StateBag) multistep.StepAction { | |
config := state.Get("config").(*config) | |
ui := state.Get("ui").(packer.Ui) | |
var httpPort uint = 0 | |
if config.HTTPDir == "" { | |
state.Put("http_port", httpPort) | |
return multistep.ActionContinue | |
} | |
// Find an available TCP port for our HTTP server | |
var httpAddr string | |
portRange := int(config.HTTPPortMax - config.HTTPPortMin) | |
for { | |
var err error | |
var offset uint = 0 | |
if portRange > 0 { | |
// Intn will panic if portRange == 0, so we do a check. | |
offset = uint(rand.Intn(portRange)) | |
} | |
httpPort = offset + config.HTTPPortMin | |
httpAddr = fmt.Sprintf(":%d", httpPort) | |
log.Printf("Trying port: %d", httpPort) | |
s.l, err = net.Listen("tcp", httpAddr) | |
if err == nil { | |
break | |
} | |
} | |
ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort)) | |
// Start the HTTP server and run it in the background | |
fileServer := http.FileServer(http.Dir(config.HTTPDir)) | |
http.Handle("/", fileServer) | |
http.HandleFunc("/reset", func(w http.ResponseWriter, r *http.Request) { | |
log.Printf("Received URL %v", r.RequestURI) | |
v := r.URL.Query() | |
in := v.Get("in") | |
resetIn := DEFAULT_RESET_WAIT_SECONDS | |
var err error | |
if len(in) > 0 { | |
resetIn, err = strconv.Atoi(in) | |
if err != nil { | |
resetIn = DEFAULT_RESET_WAIT_SECONDS | |
} | |
if resetIn < 0 { | |
resetIn = 0 | |
} | |
} | |
vmName := state.Get("vmx_path").(string) | |
ui.Say(fmt.Sprintf("Resetting %v in %d seconds", vmName, resetIn)) | |
fmt.Fprintf(w, "Resetting %v in %d seconds", vmName, resetIn) | |
go s.reset(state, resetIn) | |
}) | |
http.HandleFunc("/log", func(w http.ResponseWriter, r *http.Request) { | |
v := r.URL.Query() | |
message := v.Get("message") | |
if len(message) == 0 { | |
message = r.RequestURI | |
} | |
log.Printf("Log: %v", message) | |
fmt.Fprintf(w, message) | |
}) | |
http.HandleFunc("/save", func(w http.ResponseWriter, r *http.Request) { | |
v := r.URL.Query() | |
name := v.Get("name") | |
log.Printf("Save: name=%v", name) | |
if r.Method == "POST" { | |
// receive posted data | |
body, err := ioutil.ReadAll(r.Body) | |
if err != nil { | |
msg := fmt.Sprintf("Error saving %s: ReadAll() failed: %s", name, err) | |
log.Printf(msg) | |
http.Error(w, msg, http.StatusInternalServerError) | |
return | |
} | |
fo, err := os.Create(name) | |
if err != nil { | |
msg := fmt.Sprintf("Error saving %s: Create() failed: %s", name, err) | |
log.Printf(msg) | |
http.Error(w, msg, http.StatusInternalServerError) | |
} | |
bytes, err := fo.Write(body); | |
if err != nil { | |
msg := fmt.Sprintf("Error saving %s: Write() failed: %s", name, err) | |
log.Printf(msg) | |
http.Error(w, msg, http.StatusInternalServerError) | |
} | |
err = fo.Close(); | |
if err != nil { | |
msg := fmt.Sprintf("Error saving %s: Close() failed: %s", name, err) | |
log.Printf(msg) | |
http.Error(w, msg, http.StatusInternalServerError) | |
} | |
cwd, err := os.Getwd() | |
msg := fmt.Sprintf("Saved %v bytes to %s/%s OK", bytes, cwd, name) | |
log.Printf(msg) | |
fmt.Fprintf(w, msg) | |
return | |
} | |
msg := fmt.Sprintf("Expecting POST method, got %s", r.Method) | |
log.Printf(msg) | |
http.Error(w, msg, http.StatusInternalServerError) | |
}) | |
server := &http.Server{Addr: httpAddr} | |
go server.Serve(s.l) | |
// Save the address into the state so it can be accessed in the future | |
state.Put("http_port", httpPort) | |
return multistep.ActionContinue | |
} | |
func (s *stepHTTPServer) Cleanup(multistep.StateBag) { | |
if s.l != nil { | |
// Close the listener so that the HTTP server stops | |
s.l.Close() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment