Skip to content
This repository has been archived by the owner on Dec 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #158 from vania-pooh/master
Browse files Browse the repository at this point in the history
Ability to customize service startup timeout (fixes #157)
  • Loading branch information
aandryashin authored Jul 9, 2017
2 parents 9fb6ff3 + a65732a commit b7eff10
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 125 deletions.
19 changes: 9 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,26 @@ func (config *Config) Load(browsers, containerLogs string) error {
}

// Find - find concrete browser
func (config *Config) Find(name string, version *string) (*Browser, bool) {
func (config *Config) Find(name string, version string) (*Browser, string, bool) {
config.lock.RLock()
defer config.lock.RUnlock()
browser, ok := config.Browsers[name]
if !ok {
return nil, false
return nil, "", false
}
if *version == "" {
if version == "" {
log.Println("Using default version:", browser.Default)
*version = browser.Default
if *version == "" {
return nil, false
version = browser.Default
if version == "" {
return nil, "", false
}
}
for v, b := range browser.Versions {
if strings.HasPrefix(v, *version) {
*version = v
return b, true
if strings.HasPrefix(v, version) {
return b, v, true
}
}
return nil, false
return nil, version, false
}

// State - get current state
Expand Down
30 changes: 10 additions & 20 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ func TestConfigFindMissingBrowser(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := ""
_, ok := conf.Find("firefox", &v)
_, _, ok := conf.Find("firefox", "")
AssertThat(t, ok, Is{false})
}

Expand All @@ -131,8 +130,7 @@ func TestConfigFindDefaultVersionError(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := ""
_, ok := conf.Find("firefox", &v)
_, _, ok := conf.Find("firefox", "")
AssertThat(t, ok, Is{false})
}

Expand All @@ -142,8 +140,7 @@ func TestConfigFindDefaultVersion(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := ""
_, ok := conf.Find("firefox", &v)
_, v, ok := conf.Find("firefox", "")
AssertThat(t, ok, Is{false})
AssertThat(t, v, EqualTo{"49.0"})
}
Expand All @@ -154,8 +151,7 @@ func TestConfigFindFoundByEmptyPrefix(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := ""
_, ok := conf.Find("firefox", &v)
_, v, ok := conf.Find("firefox", "")
AssertThat(t, ok, Is{true})
AssertThat(t, v, EqualTo{"49.0"})
}
Expand All @@ -166,8 +162,7 @@ func TestConfigFindFoundByPrefix(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := "49"
_, ok := conf.Find("firefox", &v)
_, v, ok := conf.Find("firefox", "49")
AssertThat(t, ok, Is{true})
AssertThat(t, v, EqualTo{"49.0"})
}
Expand All @@ -178,8 +173,7 @@ func TestConfigFindFoundByMatch(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := "49.0"
_, ok := conf.Find("firefox", &v)
_, v, ok := conf.Find("firefox", "49.0")
AssertThat(t, ok, Is{true})
AssertThat(t, v, EqualTo{"49.0"})
}
Expand All @@ -190,8 +184,7 @@ func TestConfigFindImage(t *testing.T) {
conf := config.NewConfig()
conf.Load(confFile, logConfPath)

v := "49.0"
b, ok := conf.Find("firefox", &v)
b, v, ok := conf.Find("firefox", "49.0")
AssertThat(t, ok, Is{true})
AssertThat(t, v, EqualTo{"49.0"})
AssertThat(t, b.Image, EqualTo{"image"})
Expand Down Expand Up @@ -223,8 +216,7 @@ func TestConfigConcurrentLoadAndRead(t *testing.T) {
}
done := make(chan string)
go func() {
v := ""
browser, _ := conf.Find("firefox", &v)
browser, _, _ := conf.Find("firefox", "")
done <- browser.Tmpfs["/tmp"]
}()
conf.Load(confFile, logConfPath)
Expand All @@ -241,13 +233,11 @@ func TestConfigConcurrentRead(t *testing.T) {
}
done := make(chan string)
go func() {
v := ""
browser, _ := conf.Find("firefox", &v)
browser, _, _ := conf.Find("firefox", "")
done <- browser.Tmpfs["/tmp"]
}()
go func() {
v := ""
browser, _ := conf.Find("firefox", &v)
browser, _, _ := conf.Find("firefox", "")
done <- browser.Tmpfs["/tmp"]
}()
<-done
Expand Down
13 changes: 11 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ var (
timeout time.Duration
newSessionAttemptTimeout time.Duration
sessionDeleteTimeout time.Duration
serviceStartupTimeout time.Duration
limit int
sessions = session.NewMap()
confPath string
Expand Down Expand Up @@ -92,6 +93,7 @@ func init() {
flag.DurationVar(&timeout, "timeout", 60*time.Second, "Session idle timeout in time.Duration format")
flag.DurationVar(&newSessionAttemptTimeout, "session-attempt-timeout", 30*time.Second, "New session attempt timeout in time.Duration format")
flag.DurationVar(&sessionDeleteTimeout, "session-delete-timeout", 30*time.Second, "Session delete timeout in time.Duration format")
flag.DurationVar(&serviceStartupTimeout, "service-startup-timeout", 30*time.Second, "Service startup timeout in time.Duration format")
flag.BoolVar(&version, "version", false, "Show version and exit")
flag.Var(&mem, "mem", "Containers memory limit e.g. 128m or 1g")
flag.Var(&cpu, "cpu", "Containers cpu limit as float e.g. 0.2 or 1.0")
Expand Down Expand Up @@ -125,8 +127,14 @@ func init() {
if err == nil {
inDocker = true
}
environment := service.Environment{
InDocker: inDocker,
CPU: int64(cpu),
Memory: int64(mem),
StartupTimeout: serviceStartupTimeout,
}
if disableDocker {
manager = &service.DefaultManager{InDocker: inDocker, Config: conf}
manager = &service.DefaultManager{Environment: &environment, Config: conf}
return
}
dockerHost := os.Getenv("DOCKER_HOST")
Expand All @@ -138,11 +146,12 @@ func init() {
log.Fatal(err)
}
ip, _, _ := net.SplitHostPort(addr)
environment.IP = ip
cli, err = client.NewEnvClient()
if err != nil {
log.Fatalf("new docker client: %v\n", err)
}
manager = &service.DefaultManager{IP: ip, InDocker: inDocker, CPU: int64(cpu), Memory: int64(mem), Client: cli, Config: conf}
manager = &service.DefaultManager{Environment: &environment, Client: cli, Config: conf}
}

func cancelOnSignal() {
Expand Down
44 changes: 20 additions & 24 deletions selenoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"
"time"

"github.com/aerokube/selenoid/service"
"github.com/aerokube/selenoid/session"
"github.com/docker/docker/api/types"
"golang.org/x/net/websocket"
Expand Down Expand Up @@ -60,13 +61,6 @@ func (s *sess) url() string {
return fmt.Sprintf("http://%s/wd/hub/session/%s", s.addr, s.id)
}

type caps struct {
Name string `json:"browserName"`
Version string `json:"version"`
ScreenResolution string `json:"screenResolution"`
VNC bool `json:"enableVNC"`
}

func jsonError(w http.ResponseWriter, msg string, code int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
Expand Down Expand Up @@ -112,59 +106,61 @@ func serial() uint64 {

func create(w http.ResponseWriter, r *http.Request) {
sessionStartTime := time.Now()
id := serial()
requestId := serial()
quota, _, ok := r.BasicAuth()
if !ok {
quota = "unknown"
}
body, err := ioutil.ReadAll(r.Body)
r.Body.Close()
if err != nil {
log.Printf("[%d] [ERROR_READING_REQUEST] [%s] [%v]\n", id, quota, err)
log.Printf("[%d] [ERROR_READING_REQUEST] [%s] [%v]\n", requestId, quota, err)
jsonError(w, err.Error(), http.StatusBadRequest)
queue.Drop()
return
}
var browser struct {
Caps caps `json:"desiredCapabilities"`
Caps service.Caps `json:"desiredCapabilities"`
}
err = json.Unmarshal(body, &browser)
if err != nil {
log.Printf("[%d] [BAD_JSON_FORMAT] [%s] [%v]\n", id, quota, err)
log.Printf("[%d] [BAD_JSON_FORMAT] [%s] [%v]\n", requestId, quota, err)
jsonError(w, err.Error(), http.StatusBadRequest)
queue.Drop()
return
}
resolution, err := getScreenResolution(browser.Caps.ScreenResolution)
if err != nil {
log.Printf("[%d] [BAD_SCREEN_RESOLUTION] [%s] [%s]\n", id, quota, browser.Caps.ScreenResolution)
log.Printf("[%d] [BAD_SCREEN_RESOLUTION] [%s] [%s]\n", requestId, quota, browser.Caps.ScreenResolution)
jsonError(w, err.Error(), http.StatusBadRequest)
queue.Drop()
return
}
browser.Caps.ScreenResolution = resolution
starter, ok := manager.Find(browser.Caps.Name, &browser.Caps.Version, browser.Caps.ScreenResolution, browser.Caps.VNC, id)
starter, ok := manager.Find(browser.Caps, requestId)
if !ok {
log.Printf("[%d] [ENVIRONMENT_NOT_AVAILABLE] [%s] [%s-%s]\n", id, quota, browser.Caps.Name, browser.Caps.Version)
log.Printf("[%d] [ENVIRONMENT_NOT_AVAILABLE] [%s] [%s-%s]\n", requestId, quota, browser.Caps.Name, browser.Caps.Version)
jsonError(w, "Requested environment is not available", http.StatusBadRequest)
queue.Drop()
return
}
u, container, vnc, cancel, err := starter.StartWithCancel()
startedService, err := starter.StartWithCancel()
if err != nil {
log.Printf("[%d] [SERVICE_STARTUP_FAILED] [%s] [%v]\n", id, quota, err)
log.Printf("[%d] [SERVICE_STARTUP_FAILED] [%s] [%v]\n", requestId, quota, err)
jsonError(w, err.Error(), http.StatusInternalServerError)
queue.Drop()
return
}
u := startedService.Url
cancel := startedService.Cancel
var resp *http.Response
i := 1
for ; ; i++ {
r.URL.Host, r.URL.Path = u.Host, path.Join(u.Path, r.URL.Path)
req, _ := http.NewRequest(http.MethodPost, r.URL.String(), bytes.NewReader(body))
ctx, done := context.WithTimeout(r.Context(), newSessionAttemptTimeout)
defer done()
log.Printf("[%d] [SESSION_ATTEMPTED] [%s] [%s] [%d]\n", id, quota, u.String(), i)
log.Printf("[%d] [SESSION_ATTEMPTED] [%s] [%s] [%d]\n", requestId, quota, u.String(), i)
rsp, err := httpClient.Do(req.WithContext(ctx))
select {
case <-ctx.Done():
Expand All @@ -173,10 +169,10 @@ func create(w http.ResponseWriter, r *http.Request) {
}
switch ctx.Err() {
case context.DeadlineExceeded:
log.Printf("[%d] [SESSION_ATTEMPT_TIMED_OUT] [%s]\n", id, quota)
log.Printf("[%d] [SESSION_ATTEMPT_TIMED_OUT] [%s]\n", requestId, quota)
continue
case context.Canceled:
log.Printf("[%d] [CLIENT_DISCONNECTED] [%s]\n", id, quota)
log.Printf("[%d] [CLIENT_DISCONNECTED] [%s]\n", requestId, quota)
queue.Drop()
cancel()
return
Expand All @@ -187,7 +183,7 @@ func create(w http.ResponseWriter, r *http.Request) {
if rsp != nil {
rsp.Body.Close()
}
log.Printf("[%d] [SESSION_FAILED] [%s] - [%s]\n", id, u.String(), err)
log.Printf("[%d] [SESSION_FAILED] [%s] - [%s]\n", requestId, u.String(), err)
jsonError(w, err.Error(), http.StatusInternalServerError)
queue.Drop()
cancel()
Expand Down Expand Up @@ -230,7 +226,7 @@ func create(w http.ResponseWriter, r *http.Request) {
}
}
if s.ID == "" {
log.Printf("[%d] [SESSION_FAILED] [%s] [Bad response from %s - %v]\n", id, quota, u.String(), resp.Status)
log.Printf("[%d] [SESSION_FAILED] [%s] [Bad response from %s - %v]\n", requestId, quota, u.String(), resp.Status)
queue.Drop()
cancel()
return
Expand All @@ -240,15 +236,15 @@ func create(w http.ResponseWriter, r *http.Request) {
Browser: browser.Caps.Name,
Version: browser.Caps.Version,
URL: u,
Container: container,
VNC: vnc,
Container: startedService.ID,
VNC: startedService.VNCHostPort,
Screen: browser.Caps.ScreenResolution,
Cancel: cancel,
Timeout: onTimeout(timeout, func() {
request{r}.session(s.ID).Delete()
})})
queue.Create()
log.Printf("[%d] [SESSION_CREATED] [%s] [%s] [%s] [%d] [%v]\n", id, quota, s.ID, u, i, time.Since(sessionStartTime))
log.Printf("[%d] [SESSION_CREATED] [%s] [%s] [%s] [%d] [%v]\n", requestId, quota, s.ID, u, i, time.Since(sessionStartTime))
}

func getScreenResolution(input string) (string, error) {
Expand Down
3 changes: 1 addition & 2 deletions selenoid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,10 @@ func TestFileUploadTwoFiles(t *testing.T) {
var sess map[string]string
AssertThat(t, resp, AllOf{Code{http.StatusOK}, IsJson{&sess}})

resp, err = http.Post(With(srv.URL).Path(fmt.Sprintf("/wd/hub/session/%s/file", sess["sessionId"])), "", bytes.NewReader([]byte(`{"file":"UEsDBAoAAAAAAKGJ4koAAAAAAAAAAAAAAAAHABwAb25lLnR4dFVUCQADbv9YWZT/WFl1eAsAAQT1AQAABBQAAABQSwMECgAAAAAApIniSgAAAAAAAAAAAAAAAAcAHAB0d28udHh0VVQJAANz/1hZc/9YWXV4CwABBPUBAAAEFAAAAFBLAQIeAwoAAAAAAKGJ4koAAAAAAAAAAAAAAAAHABgAAAAAAAAAAACkgQAAAABvbmUudHh0VVQFAANu/1hZdXgLAAEE9QEAAAQUAAAAUEsBAh4DCgAAAAAApIniSgAAAAAAAAAAAAAAAAcAGAAAAAAAAAAAAKSBQQAAAHR3by50eHRVVAUAA3P/WFl1eAsAAQT1AQAABBQAAABQSwUGAAAAAAIAAgCaAAAAggAAAAAA"}`)))
resp, err = http.Post(With(srv.URL).Path(fmt.Sprintf("/wd/hub/session/%s/file", sess["sessionId"])), "", bytes.NewReader([]byte(`{"file":"UEsDBAoAAAAAAKGJ4koAAAAAAAAAAAAAAAAHABwAb25lLnR4dFVUCQADbv9YWZT/WFl1eAsAAQT1AQAABBQAAABQSwMECgAAAAAApIniSgAAAAAAAAAAAAAAAAcAHAB0d28udHh0VVQJAANz/1hZc/9YWXV4CwABBPUBAAAEFAAAAFBLAQIeAwoAAAAAAKGJ4koAAAAAAAAAAAAAAAAHABgAAAAAAAAAAACkgQAAAABvbmUudHh0VVQFAANu/1hZdXgLAAEE9QEAAAQUAAAAUEsBAh4DCgAAAAAApIniSgAAAAAAAAAAAAAAAAcAGAAAAAAAAAAAAKSBQQAAAHR3by50eHRVVAUAA3P/WFl1eAsAAQT1AQAABBQAAABQSwUGAAAAAAIAAgCaAAAAggAAAAAA"}`)))
AssertThat(t, err, Is{nil})
AssertThat(t, resp, Code{http.StatusBadRequest})

sessions.Remove(sess["sessionId"])
queue.Release()
}

Loading

0 comments on commit b7eff10

Please sign in to comment.