Multiple playgrounds support (#215)

* Add Playground struct and basic support for creating it and retrieving
it

* Add missing functions in pwd mock

* Get playground from request domain and validate it exists. If valid set
it on the newly created session.

* Move playground specific configurations to the playground struct and use
it everytime we need that conf.

* Don't allow to specify a duration bigger that the allowed in the
playground
This commit is contained in:
Jonathan Leibiusky
2017-11-14 15:50:04 -03:00
committed by GitHub
parent 3dee0d3f0b
commit 3f5b3882dd
24 changed files with 784 additions and 159 deletions

View File

@@ -1,6 +1,7 @@
package handlers
import (
"context"
"crypto/tls"
"fmt"
"log"
@@ -11,6 +12,7 @@ import (
gh "github.com/gorilla/handlers"
"github.com/gorilla/mux"
lru "github.com/hashicorp/golang-lru"
"github.com/play-with-docker/play-with-docker/config"
"github.com/play-with-docker/play-with-docker/event"
"github.com/play-with-docker/play-with-docker/pwd"
@@ -92,10 +94,22 @@ func Register(extend HandlerExtender) {
}
if config.UseLetsEncrypt {
domainCache, err := lru.New(5000)
if err != nil {
log.Fatalf("Could not start domain cache. Got: %v", err)
}
certManager := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(config.LetsEncryptDomains...),
Cache: autocert.DirCache(config.LetsEncryptCertsDir),
Prompt: autocert.AcceptTOS,
HostPolicy: func(ctx context.Context, host string) error {
if _, found := domainCache.Get(host); !found {
if playground := core.PlaygroundFindByDomain(host); playground == nil {
return fmt.Errorf("Playground for domain %s was not found", host)
}
domainCache.Add(host, true)
}
return nil
},
Cache: autocert.DirCache(config.LetsEncryptCertsDir),
}
httpServer.TLSConfig = &tls.Config{

View File

@@ -2,15 +2,16 @@ package handlers
import (
"encoding/json"
"log"
"net/http"
"github.com/play-with-docker/play-with-docker/config"
)
func GetInstanceImages(rw http.ResponseWriter, req *http.Request) {
instanceImages := []string{
config.GetDindImageName(),
"franela/dind:dev",
playground := core.PlaygroundFindByDomain(req.Host)
if playground == nil {
log.Printf("Playground for domain %s was not found!", req.Host)
rw.WriteHeader(http.StatusBadRequest)
return
}
json.NewEncoder(rw).Encode(instanceImages)
json.NewEncoder(rw).Encode(playground.AvailableDinDInstanceImages)
}

View File

@@ -1,10 +1,10 @@
package handlers
import (
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/play-with-docker/play-with-docker/config"
)
func Home(w http.ResponseWriter, r *http.Request) {
@@ -21,7 +21,14 @@ func Home(w http.ResponseWriter, r *http.Request) {
go core.SessionDeployStack(s)
}
if config.NoWindows {
playground := core.PlaygroundGet(s.PlaygroundId)
if playground == nil {
log.Printf("Playground with id %s for session %s was not found!", s.PlaygroundId, s.Id)
w.WriteHeader(http.StatusBadRequest)
return
}
if !playground.AllowWindowsInstances {
http.ServeFile(w, r, "./www/index-nw.html")
} else {
http.ServeFile(w, r, "./www/index.html")

View File

@@ -7,7 +7,6 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/play-with-docker/play-with-docker/config"
"github.com/play-with-docker/play-with-docker/provisioner"
"github.com/play-with-docker/play-with-docker/pwd"
"github.com/play-with-docker/play-with-docker/pwd/types"
@@ -23,7 +22,14 @@ func NewInstance(rw http.ResponseWriter, req *http.Request) {
s := core.SessionGet(sessionId)
if body.Type == "windows" && config.NoWindows {
playground := core.PlaygroundGet(s.PlaygroundId)
if playground == nil {
log.Printf("Playground with id %s for session %s was not found!", s.PlaygroundId, s.Id)
rw.WriteHeader(http.StatusBadRequest)
return
}
if body.Type == "windows" && !playground.AllowWindowsInstances {
rw.WriteHeader(http.StatusUnauthorized)
return
}

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"path"
"strings"
"time"
"github.com/play-with-docker/play-with-docker/config"
"github.com/play-with-docker/play-with-docker/provisioner"
@@ -49,8 +50,32 @@ func NewSession(rw http.ResponseWriter, req *http.Request) {
}
}
duration := config.GetDuration(reqDur)
s, err := core.SessionNew(userId, duration, stack, stackName, imageName)
playground := core.PlaygroundFindByDomain(req.Host)
if playground == nil {
log.Printf("Playground for domain %s was not found!", req.Host)
rw.WriteHeader(http.StatusBadRequest)
return
}
var duration time.Duration
if reqDur != "" {
d, err := time.ParseDuration(reqDur)
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
return
}
if d > playground.DefaultSessionDuration {
log.Printf("Specified session duration was %s but maximum allowed by this playground is %d\n", d.String(), playground.DefaultSessionDuration.String())
rw.WriteHeader(http.StatusBadRequest)
return
}
duration = d
} else {
duration = playground.DefaultSessionDuration
}
s, err := core.SessionNew(playground, userId, duration, stack, stackName, imageName)
if err != nil {
if provisioner.OutOfCapacity(err) {
http.Redirect(rw, req, "/ooc", http.StatusFound)
@@ -62,9 +87,6 @@ func NewSession(rw http.ResponseWriter, req *http.Request) {
//TODO: Return some error code
} else {
hostname := req.Host
if config.PWDCName != "" {
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" {
resp := NewSessionResponse{SessionId: s.Id, Hostname: hostname}