From ed3b7a2eefa477f18eeb66394365c6b6a28c2fcd Mon Sep 17 00:00:00 2001 From: Ivan Krutov Date: Sun, 31 Dec 2023 10:59:48 +0300 Subject: [PATCH 1/2] Documentation improvements --- docs/cli-flags.adoc | 13 ++++++++----- docs/multiple-instances.adoc | 8 ++++---- docs/quick-start-guide.adoc | 2 +- docs/quota-files.adoc | 8 ++++---- docs/quota-reload.adoc | 11 ++++++----- docs/tls.adoc | 12 ++++++------ 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/docs/cli-flags.adoc b/docs/cli-flags.adoc index 8cf13d6..fe8af0f 100644 --- a/docs/cli-flags.adoc +++ b/docs/cli-flags.adoc @@ -1,7 +1,8 @@ == Ggr CLI Flags The following flags are supported by ```ggr``` command: -``` +[source,bash] +---- -graceful-period duration graceful shutdown period in time.Duration format, e.g. 300s or 500ms (default 5m0s) -guests-allowed @@ -20,13 +21,15 @@ The following flags are supported by ```ggr``` command: enable verbose mode -version show version and exit -``` +---- + For example: -``` +[source,bash] +---- $ ./ggr -quotaDir /my/custom/quota/dir -``` -When using Ggr inside Docker container these flags are passed like the following: +---- +When using Ggr inside Docker container these flags are passed like the following: [source,bash,subs="attributes+"] ---- diff --git a/docs/multiple-instances.adoc b/docs/multiple-instances.adoc index a9fcb03..3e63b70 100644 --- a/docs/multiple-instances.adoc +++ b/docs/multiple-instances.adoc @@ -8,12 +8,12 @@ $ curl -s http://example.com:4444/ping ---- .Result -[source,javascript] +[source,json] ---- {"uptime":"2m46.854829503s","lastReloadTime":"2017-05-12 12:33:06.322038542 +0300 MSK","numRequests":42, "numSessions":19, "version": "1.6.3"} ---- -It returns `200 OK` when Ggr operates normally. Additionally server uptime, last quota reload time and overall number of session requests from service startup are returned in JSON format. +It returns `200 OK` when Ggr operates normally. Additionally, server uptime, last quota reload time and overall number of session requests from service startup are returned in JSON format. === Why Ggr is Stateless Selenium uses an HTTP-based protocol. That means every action in Selenium, e.g. launching browser or taking screenshot is a separate HTTP request. When multiple instances of Ggr are handling requests behind load balancer every request can be routed to any of these instances. Here's how it works. @@ -25,7 +25,7 @@ On the picture above there is one SLB, two instances of Ggr and one Selenium hub For example let's assume that new session request is routed to `Ggr 1` (black arrows). This Ggr randomly chooses a hub `hub1.example.com` and creates a new session on it. This hub returns some session identifier marked as `ID` on the picture. `Ggr 1` in its turn knows that session was created on `hub1.example.com` and extends the session ID by adding an MD5 sum `S` of hub hostname. This is why it returns to user new longer session with identifier `S+ID` just by concatenating two strings. Every Ggr instance during startup creates an in-memory map - storing host names and their MD5 sums. When consequent request for the same session `S+ID` arrives e.g. to `Ggr 2` (red arrows) it extracts `S` from extended session ID and finds hub hostname in its map. Then it removes `S` from request session identifier and simply proxies this request to hub corresponding to `S`. -IMPORTANT: Because of stateless Ggr architecture you can use an unlimited number of Ggr instances behind load balancer. In order to work properly it is very important to have exactly the same XML quota files on every Ggr instance. Otherwise some Ggr instances will return `404` error when a request with unknown host `S` arrives. +IMPORTANT: Because of stateless Ggr architecture you can use an unlimited number of Ggr instances behind load balancer. In order to work properly it is very important to have exactly the same XML quota files on every Ggr instance. Otherwise, some Ggr instances will return `404` error when a request with unknown host `S` arrives. === Getting Host by Session ID Sometimes you may want to get real hostname behind Ggr that is executing browser session. This can be done using session ID: @@ -37,7 +37,7 @@ $ curl -s http://test:test-password@ggr.example.com:4444/host/4355afe3f54e61eb32 ---- .Result -[source,javascript] +[source,json] ---- {"Name":"my-host.example.com","Port":4444,"Count":5,"Username":"","Password":""} ---- diff --git a/docs/quick-start-guide.adoc b/docs/quick-start-guide.adoc index 9e6d950..021ca64 100644 --- a/docs/quick-start-guide.adoc +++ b/docs/quick-start-guide.adoc @@ -31,7 +31,7 @@ $ cat /etc/grid-router/quota/test.xml ---- + -NOTE: File name should correspond to user name you added to `htpasswd` file. +NOTE: File name should correspond to username you added to `htpasswd` file. For user `test` we added on previous steps you should create `test.xml`. . Start Ggr container: + diff --git a/docs/quota-files.adoc b/docs/quota-files.adoc index 8b087a6..dcabca7 100644 --- a/docs/quota-files.adoc +++ b/docs/quota-files.adoc @@ -36,7 +36,7 @@ NOTE: A frequent question being asked is the meaning of `count` attribute becaus . Browser name is matched against `browserName` capability. Values are compared as strings and should be exactly equal. When testing mobile applications (e.g. with http://github.com/appium/appium[Appium]) `browserName` capability makes no sense and can be replaced by `deviceName` or `appium:deviceName` capability. Ggr will try to match both against browser name specified in XML. . Version `number` is matched against `version` or `browserVersion` capability by prefix. For example both `61` and `61.0` in version capability (i.e. in your code) will match version number `61.0`. -. Similarly version `platform` attribute is matched against `platform` or `platformName` capability by prefix. When platform from capabilities equals to `ANY` - default platform will be chosen. +. Similarly, version `platform` attribute is matched against `platform` or `platformName` capability by prefix. When platform from capabilities equals to `ANY` - default platform will be chosen. . Sometimes you may need to have the same browser name and version on different platforms, e.g. Firefox on both Linux and Windows. To achieve this you need to add `defaultPlatform` and `platform` attributes to quota file as follows: + .Adding platform information to quota file @@ -63,7 +63,7 @@ Sometimes for debugging purposes you need to see the screen of the browser where ---- ws://ggr-host.example.com:4444/vnc/ ---- -Browser VNC clients like https://github.com/novnc/noVNC[noVNC] work with such URLs out of the box. By default having an XML host entry like this... +Browser VNC clients like https://github.com/novnc/noVNC[noVNC] work with such URLs out of the box. By default, having an XML host entry like this... [source,xml] ---- @@ -94,7 +94,7 @@ Having this URL Ggr will append session ID and proxy VNC traffic from: Although Ggr is mainly used for creating your own Selenium cluster you can also configure it to obtain some browsers in external Selenium services such as http://saucelabs.com/[Saucelabs], http://browserstack.com/[BrowserStack] or https://testingbot.com/[TestingBot]. These services always require username and password to be specified. Credentials should be set for each browser version in respective quota file: -.Providing user name and password for external Selenium service +.Providing username and password for external Selenium service [source,xml] ---- @@ -110,7 +110,7 @@ Although Ggr is mainly used for creating your own Selenium cluster you can also === Guest Quota -By default every quota file corresponds to a user. In some cases you may need to give anonymous (guest) access to some users. This is very useful to maintain a sandbox where users can debug their tests without disturbing other tests. Guest quota is enabled using Ggr flags: +By default, every quota file corresponds to a user. In some cases you may need to give anonymous (guest) access to some users. This is very useful to maintain a sandbox where users can debug their tests without disturbing other tests. Guest quota is enabled using Ggr flags: $ ./ggr -guests-allowed -guests-quota test diff --git a/docs/quota-reload.adoc b/docs/quota-reload.adoc index 8c1f4a6..69def33 100644 --- a/docs/quota-reload.adoc +++ b/docs/quota-reload.adoc @@ -1,9 +1,10 @@ == Quota Reloading * To **reload quota files** just send **SIGHUP** to process or Docker container: + -``` -# kill -HUP -# docker kill -s HUP -``` +[source,bash] +---- +$ kill -HUP +$ docker kill -s HUP +---- + -NOTE: Use only one of these commands depending on whether you have Docker installed. \ No newline at end of file +NOTE: Use only one of these commands depending on whether you have Docker installed. diff --git a/docs/tls.adoc b/docs/tls.adoc index 7895eec..44b19ea 100644 --- a/docs/tls.adoc +++ b/docs/tls.adoc @@ -1,8 +1,8 @@ == Encrypting Connection to Ggr -Ggr itself does not support any modern encryption technologies such as https://en.wikipedia.org/wiki/Transport_Layer_Security[TLS] or https://en.wikipedia.org/wiki/WebSocket[WebSocket Secure]. In order to use them you are expected to setup a reverse proxy having such capabilities. A typical http://nginx.org/[Nginx] configuration looks like the following: +Ggr itself does not support any modern encryption technologies such as https://en.wikipedia.org/wiki/Transport_Layer_Security[TLS] or https://en.wikipedia.org/wiki/WebSocket[WebSocket Secure]. In order to use them you are expected to set up a reverse proxy having such capabilities. A typical http://nginx.org/[Nginx] configuration looks like the following: -.Nginx configuration for encrypted connection +.Nginx's configuration for encrypted connection ---- map $http_upgrade $connection_upgrade { default upgrade; @@ -17,20 +17,20 @@ upstream ggr { server { server_name selenium.example.com; - + listen 4444 ssl; listen [::]:4444 ssl; - + ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers kEECDH+AESGCM+AES128:kEECDH+AES128:kRSA+AESGCM+AES128:kRSA+AES128:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2; ssl_session_cache shared:SSL:64m; ssl_session_timeout 28h; - + # These two files are private key and certificate from SSL certificate provider ssl_certificate /etc/ssl/selenium.pem; ssl_certificate_key /etc/ssl/selenium.key; - + access_log /var/log/nginx/selenium_access.log; error_log /var/log/nginx/selenium_error.log; From 85f53c6dd57dcdd21ad18d613cdea349ce87556b Mon Sep 17 00:00:00 2001 From: Ivan Krutov Date: Sun, 31 Dec 2023 11:04:20 +0300 Subject: [PATCH 2/2] Dependencies update --- go.mod | 6 +++--- go.sum | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 02357cd..377a473 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,16 @@ module github.com/aerokube/ggr -go 1.20 +go 1.21 require ( github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e github.com/aandryashin/reloader v0.0.0-20161127125235-da4f1b43ce40 github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f - golang.org/x/net v0.17.0 + golang.org/x/net v0.19.0 ) require ( - github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/sys v0.15.0 // indirect ) diff --git a/go.sum b/go.sum index c46886d..adfe306 100644 --- a/go.sum +++ b/go.sum @@ -6,12 +6,16 @@ github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f h1:R2ZVGCZzU9 github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f/go.mod h1:l2P3JyHa+fjy5Bxol6y1u2o4DV/mv3QMBdBu2cNR53w= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=