diff --git a/api.go b/api.go index 7ec2981..277ea0c 100644 --- a/api.go +++ b/api.go @@ -73,11 +73,7 @@ func main() { corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}", handlers.DeleteInstance).Methods("DELETE") corsRouter.HandleFunc("/sessions/{sessionId}/instances/{instanceName}/exec", handlers.Exec).Methods("POST") - h := func(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, "./www/index.html") - } - - r.HandleFunc("/p/{sessionId}", h).Methods("GET") + r.HandleFunc("/p/{sessionId}", handlers.Home).Methods("GET") r.PathPrefix("/assets").Handler(http.FileServer(http.Dir("./www"))) r.HandleFunc("/robots.txt", func(rw http.ResponseWriter, r *http.Request) { http.ServeFile(rw, r, "www/robots.txt") diff --git a/handlers/home.go b/handlers/home.go new file mode 100644 index 0000000..b3bd008 --- /dev/null +++ b/handlers/home.go @@ -0,0 +1,41 @@ +package handlers + +import ( + "log" + "net/http" + "path" + + "github.com/gorilla/mux" + "github.com/play-with-docker/play-with-docker/services" +) + +func Home(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + sessionId := vars["sessionId"] + + stack := r.URL.Query().Get("stack") + s := services.GetSession(sessionId) + if stack != "" { + go deployStack(s, stack) + } + http.ServeFile(w, r, "./www/index.html") +} + +func deployStack(s *services.Session, stack string) { + i, err := services.NewInstance(s, services.InstanceConfig{}) + if err != nil { + log.Printf("Error creating instance for stack [%s]: %s\n", stack, err) + } + err = i.UploadFromURL("https://raw.githubusercontent.com/play-with-docker/stacks/master" + stack) + if err != nil { + log.Printf("Error uploading stack file [%s]: %s\n", stack, err) + } + + fileName := path.Base(stack) + code, err := services.Exec(i.Name, []string{"docker-compose", "-f", "/var/run/pwd/uploads/" + fileName, "up", "-d"}) + if err != nil { + log.Printf("Error executing stack [%s]: %s\n", stack, err) + } + + log.Printf("Stack execution finished with code %d\n", code) +} diff --git a/handlers/new_session.go b/handlers/new_session.go index d8f6873..cf79084 100644 --- a/handlers/new_session.go +++ b/handlers/new_session.go @@ -26,13 +26,24 @@ func NewSession(rw http.ResponseWriter, req *http.Request) { reqDur := req.Form.Get("session-duration") stack := req.Form.Get("stack") + if stack != "" { + if ok, err := stackExists(stack); err != nil { + log.Printf("Error retrieving stack: %s", err) + rw.WriteHeader(http.StatusInternalServerError) + return + } else if !ok { + log.Printf("Stack [%s] could not be found", stack) + rw.WriteHeader(http.StatusBadRequest) + return + } + + } duration := services.GetDuration(reqDur) s, err := services.NewSession(duration) if err != nil { log.Println(err) //TODO: Return some error code } else { - s.StackFile = stack hostname := fmt.Sprintf("%s.%s", config.PWDCName, req.Host) // If request is not a form, return sessionId in the body if req.Header.Get("X-Requested-With") == "XMLHttpRequest" { @@ -41,6 +52,22 @@ func NewSession(rw http.ResponseWriter, req *http.Request) { json.NewEncoder(rw).Encode(resp) return } + + if stack != "" { + http.Redirect(rw, req, fmt.Sprintf("http://%s/p/%s?stack=%s", hostname, s.Id, stack), http.StatusFound) + return + } http.Redirect(rw, req, fmt.Sprintf("http://%s/p/%s", hostname, s.Id), http.StatusFound) } } + +func stackExists(stack string) (bool, error) { + resp, err := http.Head("https://raw.githubusercontent.com/play-with-docker/stacks/master" + stack) + if err != nil { + return false, err + } + defer resp.Body.Close() + + return resp.StatusCode == 200, nil + +} diff --git a/services/docker.go b/services/docker.go index 2d716da..02af4be 100644 --- a/services/docker.go +++ b/services/docker.go @@ -10,6 +10,7 @@ import ( "os" "strconv" "strings" + "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -350,9 +351,16 @@ func Exec(instanceName string, command []string) (int, error) { if err != nil { return 0, err } - ins, err := c.ContainerExecInspect(context.Background(), e.ID) - if err != nil { - return 0, err + var ins types.ContainerExecInspect + for _ = range time.Tick(1 * time.Second) { + ins, err = c.ContainerExecInspect(context.Background(), e.ID) + if ins.Running { + continue + } + if err != nil { + return 0, err + } + break } return ins.ExitCode, nil diff --git a/services/session.go b/services/session.go index b52c2d2..61babac 100644 --- a/services/session.go +++ b/services/session.go @@ -56,7 +56,6 @@ type Session struct { scheduled bool `json:"-"` ticker *time.Ticker `json:"-"` PwdIpAddress string `json:"pwd_ip_address"` - StackFile string `json:"-"` } func (s *Session) Lock() {