diff --git a/cmd/selenosis/main.go b/cmd/selenosis/main.go index 0a9700e..83c01a2 100644 --- a/cmd/selenosis/main.go +++ b/cmd/selenosis/main.go @@ -100,7 +100,7 @@ func command() *cobra.Command { router.PathPrefix("/download/{sessionId}").HandlerFunc(app.HandleReverseProxy) router.PathPrefix("/clipboard/{sessionId}").HandlerFunc(app.HandleReverseProxy) router.PathPrefix("/status").HandlerFunc(app.HandleStatus) - router.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + router.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }).Methods(http.MethodGet) diff --git a/config/config.go b/config/config.go index fb7a40b..bb83e59 100644 --- a/config/config.go +++ b/config/config.go @@ -62,12 +62,13 @@ func (cfg *BrowsersConfig) Reload() error { } //Find return Container if it present in config -func (cfg *BrowsersConfig) Find(name, version string) (*platform.BrowserSpec, error) { +func (cfg *BrowsersConfig) Find(name, version string) (platform.BrowserSpec, error) { cfg.lock.Lock() defer cfg.lock.Unlock() + c, ok := cfg.containers[name] if !ok { - return nil, fmt.Errorf("unknown browser name %s", name) + return platform.BrowserSpec{}, fmt.Errorf("unknown browser name %s", name) } v, ok := c.Versions[version] @@ -76,17 +77,17 @@ func (cfg *BrowsersConfig) Find(name, version string) (*platform.BrowserSpec, er if c.DefaultVersion != "" { v, ok = c.Versions[c.DefaultVersion] if !ok { - return nil, fmt.Errorf("unknown browser version %s", version) + return platform.BrowserSpec{}, fmt.Errorf("unknown browser version %s", version) } v.BrowserName = name v.BrowserVersion = c.DefaultVersion - return v, nil + return *v, nil } - return nil, fmt.Errorf("unknown browser version %s", version) + return platform.BrowserSpec{}, fmt.Errorf("unknown browser version %s", version) } v.BrowserName = name v.BrowserVersion = version - return v, nil + return *v, nil } //GetBrowserVersions ... @@ -94,12 +95,14 @@ func (cfg *BrowsersConfig) GetBrowserVersions() map[string][]string { cfg.lock.Lock() defer cfg.lock.Unlock() - browsers := make(map[string][]string) + browsers := make(map[string][]string, len(cfg.containers)) for name, layout := range cfg.containers { - versions := make([]string, 0) + versions := make([]string, len(layout.Versions)) + i := 0 for version := range layout.Versions { - versions = append(versions, version) + versions[i] = version + i++ } sort.Slice(versions[:], func(i, j int) bool { ii := tools.StrToFloat64(versions[i]) @@ -118,9 +121,9 @@ func readConfig(configFile string) (map[string]*Layout, error) { return nil, fmt.Errorf("read error: %v", err) } - layouts := make(map[string]*Layout) decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(content), 1000) + layouts := make(map[string]*Layout) if err := decoder.Decode(&layouts); err != nil { return nil, fmt.Errorf("parse error: %v", err) } diff --git a/go.mod b/go.mod index fddfdab..53ddfda 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.15 require ( github.com/fsnotify/fsnotify v1.4.9 - github.com/google/uuid v1.1.2 + github.com/google/uuid v1.2.0 github.com/gorilla/mux v1.8.0 - github.com/imdario/mergo v0.3.11 - github.com/sirupsen/logrus v1.7.0 - github.com/spf13/cobra v1.1.1 - github.com/stretchr/testify v1.6.1 - golang.org/x/net v0.0.0-20201029055024-942e2f445f3c + github.com/imdario/mergo v0.3.12 + github.com/sirupsen/logrus v1.8.1 + github.com/spf13/cobra v1.1.3 + github.com/stretchr/testify v1.7.0 + golang.org/x/net v0.0.0-20210525063256-abc453219eb5 gotest.tools v2.2.0+incompatible k8s.io/api v0.19.3 k8s.io/apimachinery v0.19.3 diff --git a/go.sum b/go.sum index 9c252bd..dd3ad9d 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= @@ -162,8 +162,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -243,8 +243,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -252,8 +252,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -261,12 +261,13 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -325,8 +326,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201029055024-942e2f445f3c h1:rpcgRPA7OvNEOdprt2Wx8/Re2cBTd8NPo/lvo3AyMqk= -golang.org/x/net v0.0.0-20201029055024-942e2f445f3c/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -358,13 +359,17 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= @@ -455,6 +460,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/handlers.go b/handlers.go index ce0b42c..953d4f2 100644 --- a/handlers.go +++ b/handlers.go @@ -30,8 +30,34 @@ var ( return http.ErrUseLastResponse }, } + dialer net.Dialer ) +const browser = "browser" + +type capabilities struct { + DesiredCapabilities selenium.Capabilities `json:"desiredCapabilities"` + Capabilities struct { + AlwaysMatch selenium.Capabilities `json:"alwaysMatch"` + FirstMatch []*selenium.Capabilities `json:"firstMatch"` + } `json:"capabilities"` +} + +type Status struct { + Total int `json:"total"` + Active int `json:"active"` + Pending int `json:"pending"` + Browsers map[string][]string `json:"config,omitempty"` + Sessions []platform.Service `json:"sessions,omitempty"` +} + +type response struct { + Status int `json:"status"` + Version string `json:"version"` + Error string `json:"err,omitempty"` + Selenosis Status `json:"selenosis,omitempty"` +} + //HandleSession ... func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { start := time.Now() @@ -49,13 +75,7 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { } defer r.Body.Close() - var request struct { - DesiredCapabilities selenium.Capabilities `json:"desiredCapabilities"` - Capabilities struct { - AlwaysMatch selenium.Capabilities `json:"alwaysMatch"` - FirstMatch []*selenium.Capabilities `json:"firstMatch"` - } `json:"capabilities"` - } + request := capabilities{} err = json.Unmarshal(body, &request) if err != nil { @@ -73,7 +93,7 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { firstMatchCaps = append(firstMatchCaps, &selenium.Capabilities{}) } - var browser *platform.BrowserSpec + var browser platform.BrowserSpec var caps selenium.Capabilities for _, fmc := range firstMatchCaps { @@ -93,16 +113,14 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { return } + logger.WithField("time_elapsed", tools.TimeElapsed(start)).Infof("starting browser from image: %s", browser.Image) + image := parseImage(browser.Image) - template := &platform.ServiceSpec{ + service, err := app.client.Service().Create(platform.ServiceSpec{ SessionID: fmt.Sprintf("%s-%s", image, uuid.New()), RequestedCapabilities: caps, Template: browser, - } - - logger.WithField("time_elapsed", tools.TimeElapsed(start)).Infof("starting browser from image: %s", template.Template.Image) - - service, err := app.client.Service().Create(template) + }) if err != nil { logger.WithField("time_elapsed", tools.TimeElapsed(start)).Errorf("failed to start browser: %v", err) tools.JSONError(w, err.Error(), http.StatusBadRequest) @@ -120,6 +138,7 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { i := 1 for ; ; i++ { req, _ := http.NewRequest(http.MethodPost, service.URL.String(), bytes.NewReader(body)) + req.Close = true req.Header.Set("X-Forwarded-Selenosis", app.selenosisHost) ctx, done := context.WithTimeout(r.Context(), app.browserWaitTimeout) rsp, err := httpClient.Do(req.WithContext(ctx)) @@ -156,7 +175,6 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { resp = rsp break } - defer resp.Body.Close() var msg map[string]interface{} @@ -178,8 +196,7 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) { //HandleProxy ... func (app *App) HandleProxy(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - sessionID, ok := vars["sessionId"] + sessionID, ok := mux.Vars(r)["sessionId"] if !ok { app.logger.WithField("request", fmt.Sprintf("%s %s", r.Method, r.URL.Path)).Error("session id not found") tools.JSONError(w, "session id not found", http.StatusBadRequest) @@ -192,7 +209,6 @@ func (app *App) HandleProxy(w http.ResponseWriter, r *http.Request) { return } - host := tools.BuildHostPort(sessionID, app.serviceName, app.sidecarPort) logger := app.logger.WithFields(logrus.Fields{ "request_id": uuid.New(), "session_id": sessionID, @@ -202,8 +218,8 @@ func (app *App) HandleProxy(w http.ResponseWriter, r *http.Request) { (&httputil.ReverseProxy{ Director: func(r *http.Request) { r.URL.Scheme = "http" - r.Host = host - r.URL.Host = host + r.Host = sessionID + "." + app.serviceName + ":" + app.sidecarPort + r.URL.Host = r.Host r.Header.Set("X-Forwarded-Selenosis", app.selenosisHost) logger.Info("proxying session") }, @@ -216,32 +232,21 @@ func (app *App) HandleProxy(w http.ResponseWriter, r *http.Request) { } //HandleHubStatus ... -func (app *App) HandleHubStatus(w http.ResponseWriter, r *http.Request) { - logger := app.logger.WithFields(logrus.Fields{ - "request_id": uuid.New(), - "request": fmt.Sprintf("%s %s", r.Method, r.URL.Path), - }) - +func (app *App) HandleHubStatus(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") - active, pending := getSessionStats(app.stats.Sessions().List()) - total := len(active) + len(pending) - json.NewEncoder(w).Encode( map[string]interface{}{ "value": map[string]interface{}{ "message": "selenosis up and running", - "ready": total, + "ready": len(app.stats.Sessions().List()), }, }) - - logger.WithField("active_sessions", total).Infof("hub status") } //HandleReverseProxy ... func (app *App) HandleReverseProxy(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - sessionID, ok := vars["sessionId"] + sessionID, ok := mux.Vars(r)["sessionId"] if !ok { app.logger.WithField("request", fmt.Sprintf("%s %s", r.Method, r.URL.Path)).Error("session id not found") tools.JSONError(w, "session id not found", http.StatusBadRequest) @@ -264,7 +269,8 @@ func (app *App) HandleReverseProxy(w http.ResponseWriter, r *http.Request) { (&httputil.ReverseProxy{ Director: func(r *http.Request) { r.URL.Scheme = "http" - r.URL.Host = tools.BuildHostPort(sessionID, app.serviceName, app.sidecarPort) + r.Host = sessionID + "." + app.serviceName + ":" + app.sidecarPort + r.URL.Host = r.Host r.Header.Set("X-Forwarded-Selenosis", app.selenosisHost) logger.Infof("proxying %s", fragments[1]) }, @@ -280,8 +286,7 @@ func (app *App) HandleVNC() websocket.Handler { return func(wsconn *websocket.Conn) { defer wsconn.Close() - vars := mux.Vars(wsconn.Request()) - sessionID, ok := vars["sessionId"] + sessionID, ok := mux.Vars(wsconn.Request())["sessionId"] if !ok { app.logger.WithField("request", fmt.Sprintf("%s %s", wsconn.Request().Method, wsconn.Request().URL.Path)).Error("session id not found") return @@ -300,7 +305,6 @@ func (app *App) HandleVNC() websocket.Handler { }) logger.Infof("vnc request: %s", host) - var dialer net.Dialer conn, err := dialer.DialContext(wsconn.Request().Context(), "tcp", host) if err != nil { logger.Errorf("vnc connection error: %v", err) @@ -311,7 +315,6 @@ func (app *App) HandleVNC() websocket.Handler { wsconn.PayloadType = websocket.BinaryFrame go func() { io.Copy(wsconn, conn) - wsconn.Close() logger.Warnf("vnc connection closed") }() io.Copy(conn, wsconn) @@ -324,8 +327,7 @@ func (app *App) HandleLogs() websocket.Handler { return func(wsconn *websocket.Conn) { defer wsconn.Close() - vars := mux.Vars(wsconn.Request()) - sessionID, ok := vars["sessionId"] + sessionID, ok := mux.Vars(wsconn.Request())["sessionId"] if !ok { app.logger.WithField("request", fmt.Sprintf("%s %s", wsconn.Request().Method, wsconn.Request().URL.Path)).Error("session id not found") return @@ -362,33 +364,29 @@ func (app *App) HandleLogs() websocket.Handler { } //HandleStatus ... -func (app *App) HandleStatus(w http.ResponseWriter, r *http.Request) { +func (app *App) HandleStatus(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") - type Status struct { - Total int `json:"total"` - Active int `json:"active"` - Pending int `json:"pending"` - Browsers map[string][]string `json:"config,omitempty"` - Sessions []platform.Service `json:"sessions,omitempty"` - } - - type Response struct { - Status int `json:"status"` - Version string `json:"version"` - Error string `json:"err,omitempty"` - Selenosis Status `json:"selenosis,omitempty"` + var active []platform.Service + var pending int + for _, s := range app.stats.Sessions().List() { + switch s.Status { + case platform.Running: + s.Uptime = tools.TimeElapsed(s.Started) + active = append(active, s) + case platform.Pending: + pending++ + } } - active, pending := getSessionStats(app.stats.Sessions().List()) json.NewEncoder(w).Encode( - Response{ + response{ Status: http.StatusOK, Version: app.buildVersion, Selenosis: Status{ Total: app.sessionLimit, Active: len(active), - Pending: len(pending), + Pending: pending, Browsers: app.browsers.GetBrowserVersions(), Sessions: active, }, @@ -397,7 +395,6 @@ func (app *App) HandleStatus(w http.ResponseWriter, r *http.Request) { } func parseImage(image string) (container string) { - browser := "browser" if len(image) > 0 { pref, err := regexp.Compile("[^a-zA-Z0-9]+") if err != nil { @@ -431,18 +428,3 @@ func isValidSession(session string) bool { } return false } - -func getSessionStats(sessions []platform.Service) (active []platform.Service, pending []platform.Service) { - active = make([]platform.Service, 0) - pending = make([]platform.Service, 0) - - for _, s := range sessions { - switch s.Status { - case platform.Running: - active = append(active, s) - case platform.Pending: - pending = append(pending, s) - } - } - return -} diff --git a/handlers_test.go b/handlers_test.go index 47956dd..aede759 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -154,7 +154,7 @@ func TestNewSessionOnBrowserNetworkError(t *testing.T) { t.Logf("TC: %s", name) client := &PlatformMock{ - service: &platform.Service{ + service: platform.Service{ SessionID: "sessionID", CancelFunc: func() {}, URL: &url.URL{ @@ -215,7 +215,7 @@ func TestNewSessionOnCancelRequest(t *testing.T) { u, _ := url.Parse(s.URL) platform := &PlatformMock{ - service: &platform.Service{ + service: platform.Service{ SessionID: "sessionID", CancelFunc: func() {}, URL: u, @@ -277,7 +277,7 @@ func TestNewSessionOnRequestTimeout(t *testing.T) { u, _ := url.Parse(s.URL) platform := &PlatformMock{ - service: &platform.Service{ + service: platform.Service{ SessionID: "sessionID", CancelFunc: func() {}, URL: u, @@ -338,7 +338,7 @@ func TestNewSessionResponseCodeError(t *testing.T) { u, _ := url.Parse(s.URL) platform := &PlatformMock{ - service: &platform.Service{ + service: platform.Service{ SessionID: "sessionID", CancelFunc: func() {}, URL: u, @@ -396,7 +396,7 @@ func TestNewSessionResponseBodyError(t *testing.T) { u, _ := url.Parse(s.URL) platform := &PlatformMock{ - service: &platform.Service{ + service: platform.Service{ SessionID: "sessionID", CancelFunc: func() {}, URL: u, @@ -455,7 +455,7 @@ func TestNewSessionCreated(t *testing.T) { u, _ := url.Parse(s.URL) platform := &PlatformMock{ - service: &platform.Service{ + service: platform.Service{ SessionID: "sessionID", CancelFunc: func() {}, URL: u, @@ -587,7 +587,7 @@ func initApp(p *PlatformMock) *App { type PlatformMock struct { err error - service *platform.Service + service platform.Service stats *storage.Storage } @@ -605,7 +605,7 @@ func (p *PlatformMock) Service() platform.ServiceInterface { func (p *PlatformMock) Quota() platform.QuotaInterface { return "aMock{ err: nil, - quota: &platform.Quota{ + quota: platform.Quota{ Name: "test", CurrentMaxLimit: 10, }, @@ -627,12 +627,12 @@ func (p *PlatformMock) List() ([]*platform.Service, error) { type serviceMock struct { err error - service *platform.Service + service platform.Service } -func (p *serviceMock) Create(*platform.ServiceSpec) (*platform.Service, error) { +func (p *serviceMock) Create(platform.ServiceSpec) (platform.Service, error) { if p.err != nil { - return nil, p.err + return platform.Service{}, p.err } return p.service, nil @@ -650,18 +650,18 @@ func (p *serviceMock) Logs(ctx context.Context, name string) (io.ReadCloser, err type quotaMock struct { err error - quota *platform.Quota + quota platform.Quota } -func (s *quotaMock) Create(int64) (*platform.Quota, error) { +func (s *quotaMock) Create(int64) (platform.Quota, error) { return s.quota, nil } -func (s *quotaMock) Get() (*platform.Quota, error) { +func (s *quotaMock) Get() (platform.Quota, error) { return s.quota, nil } -func (s *quotaMock) Update(int64) (*platform.Quota, error) { +func (s *quotaMock) Update(int64) (platform.Quota, error) { return s.quota, nil } diff --git a/platform/kubernetes.go b/platform/kubernetes.go index fbbb651..205ec9a 100644 --- a/platform/kubernetes.go +++ b/platform/kubernetes.go @@ -133,8 +133,8 @@ func (cl *Client) State() (PlatformState, error) { return PlatformState{}, fmt.Errorf("failed to get pods: %v", err) } - var services []*Service - var workers []*Worker + var services []Service + var workers []Worker for _, pod := range pods.Items { podName := pod.GetName() @@ -153,16 +153,15 @@ func (cl *Client) State() (PlatformState, error) { if application, ok := pod.GetLabels()[label]; ok { switch application { case "worker": - worker := &Worker{ + workers = append(workers, Worker{ Name: podName, Labels: pod.Labels, Status: status, Started: creationTime, - } - workers = append(workers, worker) + }) case "browser": - service := &Service{ + services = append(services, Service{ SessionID: podName, URL: &url.URL{ Scheme: "http", @@ -174,9 +173,7 @@ func (cl *Client) State() (PlatformState, error) { }, Status: status, Started: creationTime, - } - - services = append(services, service) + }) } } } @@ -218,7 +215,7 @@ func (cl *Client) Watch() <-chan Event { case "worker": ch <- Event{ Type: eventType, - PlatformObject: &Worker{ + PlatformObject: Worker{ Name: podName, Labels: pod.Labels, Status: status, @@ -229,7 +226,7 @@ func (cl *Client) Watch() <-chan Event { case "browser": ch <- Event{ Type: eventType, - PlatformObject: &Service{ + PlatformObject: Service{ SessionID: podName, URL: &url.URL{ Scheme: "http", @@ -267,7 +264,7 @@ func (cl *Client) Watch() <-chan Event { rqName := rq.GetName() ch <- Event{ Type: eventType, - PlatformObject: &Quota{ + PlatformObject: Quota{ Name: rqName, CurrentMaxLimit: rq.Spec.Hard.Pods().Value(), }, @@ -306,7 +303,7 @@ type service struct { } //Create ... -func (cl *service) Create(layout *ServiceSpec) (*Service, error) { +func (cl *service) Create(layout ServiceSpec) (Service, error) { annontations := map[string]string{ defaultsAnnotations.browserName: layout.Template.BrowserName, defaultsAnnotations.browserVersion: layout.Template.BrowserVersion, @@ -426,8 +423,8 @@ func (cl *service) Create(layout *ServiceSpec) (*Service, error) { NodeSelector: layout.Template.Spec.NodeSelector, HostAliases: layout.Template.Spec.HostAliases, RestartPolicy: apiv1.RestartPolicyNever, - Affinity: layout.Template.Spec.Affinity, - DNSConfig: layout.Template.Spec.DNSConfig, + Affinity: &layout.Template.Spec.Affinity, + DNSConfig: &layout.Template.Spec.DNSConfig, Tolerations: layout.Template.Spec.Tolerations, ImagePullSecrets: getImagePullSecretList(cl.imagePullSecretName), SecurityContext: getSecurityContext(layout.Template.RunAs), @@ -438,7 +435,7 @@ func (cl *service) Create(layout *ServiceSpec) (*Service, error) { pod, err := cl.clientset.CoreV1().Pods(cl.ns).Create(context, pod, metav1.CreateOptions{}) if err != nil { - return nil, fmt.Errorf("failed to create pod %v", err) + return Service{}, fmt.Errorf("failed to create pod %v", err) } podName := pod.GetName() @@ -452,7 +449,7 @@ func (cl *service) Create(layout *ServiceSpec) (*Service, error) { }) if err != nil { - return nil, fmt.Errorf("failed to watch pod status: %v", err) + return Service{}, fmt.Errorf("failed to watch pod status: %v", err) } statusFn := func() error { @@ -491,21 +488,22 @@ func (cl *service) Create(layout *ServiceSpec) (*Service, error) { err = statusFn() if err != nil { cancel() - return nil, fmt.Errorf("pod is not ready after creation: %v", err) + return Service{}, fmt.Errorf("pod is not ready after creation: %v", err) } u := &url.URL{ Scheme: "http", - Host: tools.BuildHostPort(podName, cl.svc, browserPorts.selenium.StrVal), + Host: podName + "." + cl.svc + ":" + browserPorts.selenium.StrVal, } if err := waitForService(*u, cl.readinessTimeout); err != nil { cancel() - return nil, fmt.Errorf("container service is not ready %v", u.String()) + return Service{}, fmt.Errorf("container service is not ready %v", u.String()) } - u.Host = tools.BuildHostPort(podName, cl.svc, cl.svcPort.StrVal) - svc := &Service{ + u.Host = podName + "." + cl.svc + ":" + cl.svcPort.StrVal + + return Service{ SessionID: podName, URL: u, Labels: getRequestedCapabilities(pod.GetAnnotations()), @@ -514,9 +512,7 @@ func (cl *service) Create(layout *ServiceSpec) (*Service, error) { }, Status: Running, Started: pod.CreationTimestamp.Time, - } - - return svc, nil + }, nil } //Delete ... @@ -541,11 +537,11 @@ type quota struct { } //Create ... -func (cl quota) Create(limit int64) (*Quota, error) { +func (cl quota) Create(limit int64) (Quota, error) { context := context.Background() quantity, err := resource.ParseQuantity(strconv.FormatInt(limit, 10)) if err != nil { - return nil, fmt.Errorf("failed to parse limit amount") + return Quota{}, fmt.Errorf("failed to parse limit amount") } quota := &apiv1.ResourceQuota{ ObjectMeta: metav1.ObjectMeta{ @@ -558,33 +554,33 @@ func (cl quota) Create(limit int64) (*Quota, error) { } quota, err = cl.clientset.CoreV1().ResourceQuotas(cl.ns).Create(context, quota, metav1.CreateOptions{}) if err != nil { - return nil, fmt.Errorf("failed to create resourceQuota") + return Quota{}, fmt.Errorf("failed to create resourceQuota") } - return &Quota{ + return Quota{ Name: quota.GetName(), CurrentMaxLimit: quota.Spec.Hard.Pods().Value(), }, nil } -func (cl quota) Get() (*Quota, error) { +func (cl quota) Get() (Quota, error) { context := context.Background() quota, err := cl.clientset.CoreV1().ResourceQuotas(cl.ns).Get(context, quotaName, metav1.GetOptions{}) if err != nil { - return nil, fmt.Errorf("quota not found") + return Quota{}, fmt.Errorf("quota not found") } - return &Quota{ + return Quota{ Name: quota.GetName(), CurrentMaxLimit: quota.Spec.Hard.Pods().Value(), }, nil } //Update ... -func (cl quota) Update(limit int64) (*Quota, error) { +func (cl quota) Update(limit int64) (Quota, error) { context := context.Background() quantity, err := resource.ParseQuantity(strconv.FormatInt(limit, 10)) if err != nil { - return nil, fmt.Errorf("failed to parse limit amount") + return Quota{}, fmt.Errorf("failed to parse limit amount") } rq := &apiv1.ResourceQuota{ ObjectMeta: metav1.ObjectMeta{ @@ -597,10 +593,10 @@ func (cl quota) Update(limit int64) (*Quota, error) { } quota, err := cl.clientset.CoreV1().ResourceQuotas(cl.ns).Update(context, rq, metav1.UpdateOptions{}) if err != nil { - return nil, fmt.Errorf("resourse quota update error: %v", err) + return Quota{}, fmt.Errorf("resourse quota update error: %v", err) } - return &Quota{ + return Quota{ Name: quota.GetName(), CurrentMaxLimit: rq.Spec.Hard.Pods().Value(), }, err diff --git a/platform/kubernetes_test.go b/platform/kubernetes_test.go index d34d7da..cc5c0c6 100644 --- a/platform/kubernetes_test.go +++ b/platform/kubernetes_test.go @@ -23,7 +23,7 @@ func TestErrorsOnServiceCreate(t *testing.T) { tests := map[string]struct { ns string podName string - layout *ServiceSpec + layout ServiceSpec eventType watch.EventType podPhase apiv1.PodPhase err error @@ -31,12 +31,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup phase PodSucceeded": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", @@ -50,12 +50,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup phase PodFailed": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", @@ -69,12 +69,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup phase PodUnknown": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", @@ -88,12 +88,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup phase Unknown": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", @@ -106,12 +106,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup event Error": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", @@ -125,12 +125,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup event Deleted": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", @@ -144,12 +144,12 @@ func TestErrorsOnServiceCreate(t *testing.T) { "Verify platform error on pod startup event Unknown": { ns: "selenosis", podName: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", - layout: &ServiceSpec{ + layout: ServiceSpec{ SessionID: "chrome-85-0-de44c3c4-1a35-412b-b526-f5da802144911", RequestedCapabilities: selenium.Capabilities{ VNC: true, }, - Template: &BrowserSpec{ + Template: BrowserSpec{ BrowserName: "chrome", BrowserVersion: "85.0", Image: "selenoid/vnc:chrome_85.0", diff --git a/platform/platform.go b/platform/platform.go index 60c0a83..84dc360 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -22,8 +22,8 @@ type Spec struct { HostAliases []apiv1.HostAlias `yaml:"hostAliases,omitempty" json:"hostAliases,omitempty"` EnvVars []apiv1.EnvVar `yaml:"env,omitempty" json:"env,omitempty"` NodeSelector map[string]string `yaml:"nodeSelector,omitempty" json:"nodeSelector,omitempty"` - Affinity *apiv1.Affinity `yaml:"affinity,omitempty" json:"affinity,omitempty"` - DNSConfig *apiv1.PodDNSConfig `yaml:"dnsConfig,omitempty" json:"dnsConfig,omitempty"` + Affinity apiv1.Affinity `yaml:"affinity,omitempty" json:"affinity,omitempty"` + DNSConfig apiv1.PodDNSConfig `yaml:"dnsConfig,omitempty" json:"dnsConfig,omitempty"` Tolerations []apiv1.Toleration `yaml:"tolerations,omitempty" json:"tolerations,omitempty"` VolumeMounts []apiv1.VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"` } @@ -50,7 +50,7 @@ type BrowserSpec struct { type ServiceSpec struct { SessionID string RequestedCapabilities selenium.Capabilities - Template *BrowserSpec + Template BrowserSpec } //Service ... @@ -71,8 +71,8 @@ type Quota struct { } type PlatformState struct { - Services []*Service - Workers []*Worker + Services []Service + Workers []Worker } type Worker struct { @@ -114,13 +114,13 @@ type Platform interface { } type ServiceInterface interface { - Create(*ServiceSpec) (*Service, error) + Create(ServiceSpec) (Service, error) Delete(string) error Logs(context.Context, string) (io.ReadCloser, error) } type QuotaInterface interface { - Create(int64) (*Quota, error) - Get() (*Quota, error) - Update(int64) (*Quota, error) + Create(int64) (Quota, error) + Get() (Quota, error) + Update(int64) (Quota, error) } diff --git a/selenosis.go b/selenosis.go index 88edcdd..e1e433d 100644 --- a/selenosis.go +++ b/selenosis.go @@ -59,7 +59,7 @@ func New(logger *log.Logger, client platform.Platform, browsers *config.Browsers currentTotal := func() int64 { return int64(storage.Workers().Len() + limit) } - var quota *platform.Quota + var quota platform.Quota if quota, err = client.Quota().Get(); err != nil { quota, err = client.Quota().Create(currentTotal()) if err != nil { @@ -84,8 +84,8 @@ func New(logger *log.Logger, client platform.Platform, browsers *config.Browsers select { case event := <- ch: switch event.PlatformObject.(type) { - case *platform.Service: - service := event.PlatformObject.(*platform.Service) + case platform.Service: + service := event.PlatformObject.(platform.Service) switch event.Type { case platform.Added: storage.Sessions().Put(service.SessionID, service) @@ -95,8 +95,8 @@ func New(logger *log.Logger, client platform.Platform, browsers *config.Browsers storage.Sessions().Delete(service.SessionID) } - case *platform.Worker: - worker := event.PlatformObject.(*platform.Worker) + case platform.Worker: + worker := event.PlatformObject.(platform.Worker) switch event.Type { case platform.Added: storage.Workers().Put(worker.Name, worker) @@ -118,8 +118,8 @@ func New(logger *log.Logger, client platform.Platform, browsers *config.Browsers logger.Infof("selenosis worker: %s removed, current namespace quota limit: %d", worker.Name, storage.Quota().Get().CurrentMaxLimit) } - case *platform.Quota: - quota := event.PlatformObject.(*platform.Quota) + case platform.Quota: + quota := event.PlatformObject.(platform.Quota) switch event.Type { case platform.Added: if quota.CurrentMaxLimit != currentTotal() { diff --git a/storage/storage.go b/storage/storage.go index bcc6fbf..3d0174d 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -8,11 +8,11 @@ import ( ) type sessions struct { - m map[string]*platform.Service + m map[string]platform.Service } //Put ... -func (s *sessions) Put(sessionID string, service *platform.Service) { +func (s *sessions) Put(sessionID string, service platform.Service) { if sessionID != "" { s.m[sessionID] = service } @@ -24,15 +24,8 @@ func (s *sessions) Delete(sessionID string) { } //List ... -func (s *sessions) List() []platform.Service { - var l []platform.Service - for _, p := range s.m { - c := *p - c.Uptime = tools.TimeElapsed(c.Started) - l = append(l, c) - } - - return l +func (s *sessions) List() map[string]platform.Service { + return s.m } @@ -42,11 +35,11 @@ func (s *sessions) Len() int { } type workers struct { - m map[string]*platform.Worker + m map[string]platform.Worker } //Put ... -func (w *workers) Put(name string, worker *platform.Worker) { +func (w *workers) Put(name string, worker platform.Worker) { if name != "" { w.m[name] = worker } @@ -60,10 +53,9 @@ func (w *workers) Delete(name string) { //List ... func (w *workers) List() []platform.Worker { var l []platform.Worker - for _, p := range w.m { - c := *p - c.Uptime = tools.TimeElapsed(c.Started) - l = append(l, c) + for _, w := range w.m { + w.Uptime = tools.TimeElapsed(w.Started) + l = append(l, w) } return l @@ -77,16 +69,16 @@ func (s *workers) Len() int { type quota struct { w *workers - q *platform.Quota + q platform.Quota } //Put ... -func (q *quota) Put(quota *platform.Quota) { +func (q *quota) Put(quota platform.Quota) { q.q = quota } //Put ... -func (q *quota) Get() *platform.Quota { +func (q *quota) Get() platform.Quota { return q.q } @@ -100,8 +92,8 @@ type Storage struct { //New ... func New() *Storage { - sessions := &sessions{m: make(map[string]*platform.Service)} - workers := &workers{m: make(map[string]*platform.Worker)} + sessions := &sessions{m: make(map[string]platform.Service)} + workers := &workers{m: make(map[string]platform.Worker)} quota := "a{w: workers} return &Storage{ sessions: sessions, diff --git a/storage/storage_test.go b/storage/storage_test.go index 0685b58..0f25cb9 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -30,19 +30,19 @@ func TestPut(t *testing.T) { tests := map[string]struct { strg *Storage session string - service *platform.Service + service platform.Service len int }{ "Verify service put to storage": { strg: New(), session: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee93", - service: &platform.Service{}, + service: platform.Service{}, len: 1, }, "Verify service put to storage on empty session": { strg: New(), session: "", - service: &platform.Service{}, + service: platform.Service{}, len: 0, }, } @@ -61,7 +61,7 @@ func TestDelete(t *testing.T) { strg *Storage sessionToAdd string sessionToDelete string - service *platform.Service + service platform.Service lenOnAdd int lenOnDelete int }{ @@ -69,7 +69,7 @@ func TestDelete(t *testing.T) { strg: New(), sessionToAdd: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee93", sessionToDelete: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee93", - service: &platform.Service{}, + service: platform.Service{}, lenOnAdd: 1, lenOnDelete: 0, }, @@ -77,7 +77,7 @@ func TestDelete(t *testing.T) { strg: New(), sessionToAdd: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee93", sessionToDelete: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee92", - service: &platform.Service{}, + service: platform.Service{}, lenOnAdd: 1, lenOnDelete: 1, }, @@ -100,13 +100,13 @@ func TestList(t *testing.T) { tests := map[string]struct { strg *Storage session string - service *platform.Service + service platform.Service len int }{ "Verify storage listing": { strg: New(), session: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee93", - service: &platform.Service{ + service: platform.Service{ SessionID: "selenoid-vnc-chrome-85-0-c3fa5fa2-ea17-4b16-adec-97f7d535ee93", }, len: 1,