diff --git a/api.go b/api.go index 3d4a151..630a250 100644 --- a/api.go +++ b/api.go @@ -65,6 +65,8 @@ func main() { // Specific routes r.Host(`{subdomain:.*}{node:pwd[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}}-{port:[0-9]*}.{tld:.*}`).Handler(tcpHandler) r.Host(`{subdomain:.*}{node:pwd[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}}.{tld:.*}`).Handler(tcpHandler) + r.Host(`pwd{alias:.*}-{session:.*}-{port:[0-9]*}.{tld:.*}`).Handler(tcpHandler) + r.Host(`pwd{alias:.*}-{session:.*}.{tld:.*}`).Handler(tcpHandler) r.HandleFunc("/ping", handlers.Ping).Methods("GET") corsRouter.HandleFunc("/instances/images", handlers.GetInstanceImages).Methods("GET") corsRouter.HandleFunc("/sessions/{sessionId}", handlers.GetSession).Methods("GET") diff --git a/handlers/dns.go b/handlers/dns.go index 138690a..ff0ce92 100644 --- a/handlers/dns.go +++ b/handlers/dns.go @@ -8,16 +8,20 @@ import ( "strings" "github.com/miekg/dns" + "github.com/play-with-docker/play-with-docker/services" ) -var dnsFilter = regexp.MustCompile(`pwd[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}`) +var dnsFilter = regexp.MustCompile(`^.*pwd([0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}_[0-9]{1,3}(?:-[0-9]{1,5})?)\..*$`) +var aliasFilter = regexp.MustCompile(`^.*pwd(.*?)-(.*?)[\.-].*`) func DnsRequest(w dns.ResponseWriter, r *dns.Msg) { if len(r.Question) > 0 && dnsFilter.MatchString(r.Question[0].Name) { // this is something we know about and we should try to handle question := r.Question[0].Name - domainChunks := strings.Split(question, ".") - tldChunks := strings.Split(strings.TrimPrefix(domainChunks[0], "pwd"), "-") + + match := dnsFilter.FindStringSubmatch(question) + + tldChunks := strings.Split(match[1], "-") ip := strings.Replace(tldChunks[0], "_", ".", -1) m := new(dns.Msg) @@ -31,6 +35,25 @@ func DnsRequest(w dns.ResponseWriter, r *dns.Msg) { m.Answer = append(m.Answer, a) w.WriteMsg(m) return + } else if len(r.Question) > 0 && aliasFilter.MatchString(r.Question[0].Name) { + // this is something we know about and we should try to handle + question := r.Question[0].Name + + match := aliasFilter.FindStringSubmatch(question) + + i := services.FindInstanceByAlias(match[2], match[1]) + + m := new(dns.Msg) + m.SetReply(r) + m.Authoritative = true + m.RecursionAvailable = true + a, err := dns.NewRR(fmt.Sprintf("%s 60 IN A %s", question, i.IP)) + if err != nil { + log.Fatal(err) + } + m.Answer = append(m.Answer, a) + w.WriteMsg(m) + return } else { if len(r.Question) > 0 { question := r.Question[0].Name diff --git a/handlers/new_instance.go b/handlers/new_instance.go index 4ceb954..789f2a5 100644 --- a/handlers/new_instance.go +++ b/handlers/new_instance.go @@ -13,7 +13,7 @@ func NewInstance(rw http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) sessionId := vars["sessionId"] - body := struct{ ImageName string }{} + body := struct{ ImageName, Alias string }{} json.NewDecoder(req.Body).Decode(&body) @@ -26,7 +26,7 @@ func NewInstance(rw http.ResponseWriter, req *http.Request) { return } - i, err := services.NewInstance(s, body.ImageName) + i, err := services.NewInstance(s, body.ImageName, body.Alias) if err != nil { log.Println(err) rw.WriteHeader(http.StatusInternalServerError) diff --git a/handlers/reverseproxy.go b/handlers/reverseproxy.go index adef966..977d226 100644 --- a/handlers/reverseproxy.go +++ b/handlers/reverseproxy.go @@ -11,11 +11,14 @@ import ( "github.com/gorilla/mux" "github.com/play-with-docker/play-with-docker/config" + "github.com/play-with-docker/play-with-docker/services" ) func getTargetInfo(vars map[string]string, req *http.Request) (string, string) { node := vars["node"] port := vars["port"] + alias := vars["alias"] + sessionPrefix := vars["session"] hostPort := strings.Split(req.Host, ":") // give priority to the URL host port @@ -25,6 +28,14 @@ func getTargetInfo(vars map[string]string, req *http.Request) (string, string) { port = "80" } + if alias != "" { + instance := services.FindInstanceByAlias(sessionPrefix, alias) + if instance != nil { + node = instance.IP + return node, port + } + } + if strings.HasPrefix(node, "pwd") { // Node is actually an ip, need to convert underscores by dots. ip := strings.Replace(strings.TrimPrefix(node, "pwd"), "_", ".", -1) diff --git a/services/instance.go b/services/instance.go index ac2bcdb..8003a3b 100644 --- a/services/instance.go +++ b/services/instance.go @@ -34,6 +34,7 @@ type Instance struct { IsManager *bool `json:"is_manager"` Mem string `json:"mem"` Cpu string `json:"cpu"` + Alias string `json:"alias"` Ports UInt16Slice tempPorts []uint16 `json:"-"` ServerCert []byte `json:"server_cert"` @@ -96,7 +97,7 @@ func getDindImageName() string { return dindImage } -func NewInstance(session *Session, imageName string) (*Instance, error) { +func NewInstance(session *Session, imageName, alias string) (*Instance, error) { if imageName == "" { imageName = dindImage } @@ -105,6 +106,9 @@ func NewInstance(session *Session, imageName string) (*Instance, error) { if err != nil { return nil, err } + + instance.Alias = alias + instance.session = session if session.Instances == nil { @@ -174,6 +178,19 @@ func FindInstanceByIP(ip string) *Instance { return nil } +func FindInstanceByAlias(sessionPrefix, alias string) *Instance { + for id, s := range sessions { + if strings.HasPrefix(id, sessionPrefix) { + for _, i := range s.Instances { + if i.Alias == alias { + return i + } + } + } + } + return nil +} + func DeleteInstance(session *Session, instance *Instance) error { if instance.conn != nil { instance.conn.Close()